فهرست منبع

- ComponentBox usage in 2 windows: levelup and build screen
- Components have selectable image size
- fixed #794

Ivan Savenko 13 سال پیش
والد
کامیت
55c78e9f16

+ 11 - 2
AI/VCAI/VCAI.cpp

@@ -1128,6 +1128,15 @@ bool VCAI::tryBuildStructure(const CGTownInstance * t, int building, unsigned in
 	std::set<int> toBuild = cb->getBuildingRequiments(t, building);
 	toBuild.insert(building);
 
+	BOOST_FOREACH(int buildID, toBuild)
+	{
+		int canBuild = cb->canBuildStructure(t, buildID);
+		if (canBuild == EBuildingState::HAVE_CAPITAL
+		 || canBuild == EBuildingState::FORBIDDEN
+		 || canBuild == EBuildingState::NO_WATER)
+			return false; //we won't be able to build this
+	}
+
 	if (maxDays && toBuild.size() > maxDays)
 		return false;
 
@@ -1211,8 +1220,8 @@ void VCAI::buildStructure(const CGTownInstance * t)
 	if (tryBuildAnyStructure(t, std::vector<int>(essential, essential + ARRAY_COUNT(essential))))
 		return;
 
-	//we're running out of gold - try to build something gold-producing. Multiplier can be tweaked
-	if (currentRes[Res::GOLD] < income[Res::GOLD] * 4)
+	//we're running out of gold - try to build something gold-producing. Multiplier can be tweaked, 6 is minimum due to buildings costs
+	if (currentRes[Res::GOLD] < income[Res::GOLD] * 6)
 		if (tryBuildNextStructure(t, std::vector<int>(goldSource, goldSource + ARRAY_COUNT(goldSource))))
 			return;
 

+ 0 - 1
client/AdventureMapClasses.cpp

@@ -791,7 +791,6 @@ void CInfoBar::CVisibleInfo::loadComponent(const Component compToDisplay, std::s
 	comp->moveTo(Point(pos.x+52, pos.y+54));
 
 	new CTextBox(message, Rect(8, 8, 164, 50), 0, FONT_SMALL, CENTER, Colors::Cornsilk);
-	new CLabel(91, 158, FONT_SMALL, CENTER, Colors::Cornsilk, comp->getSubtitle());
 }
 
 void CInfoBar::CVisibleInfo::updateEnemyTurn(double progress)

+ 12 - 40
client/CCastleInterface.cpp

@@ -1405,61 +1405,33 @@ std::string CBuildWindow::getTextForState(int state)
 	return ret;
 }
 
-CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Building, int State, bool rightClick):
+CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Building, int state, bool rightClick):
     CWindowObject(PLAYER_COLORED | (rightClick ? RCLICK_POPUP : 0), "TPUBUILD"),
 	town(Town),
-    building(Building),
-    state(State)
+    building(Building)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 
-	buildingPic = new CAnimImage(graphics->buildingPics[town->subID], building->bid, 0, 125, 50);
-	Rect barRect(9, 494, 380, 18);
-	statusBar = new CGStatusBar(new CPicture(*background, barRect, 9, 494, false));
+	new CAnimImage(graphics->buildingPics[town->subID], building->bid, 0, 125, 50);
+	new CGStatusBar(new CPicture(*background, Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26));
 
-	title = new CLabel(197, 30, FONT_MEDIUM, CENTER, Colors::Cornsilk, 
+	new CLabel(197, 30, FONT_MEDIUM, CENTER, Colors::Cornsilk,
 	            boost::str(boost::format(CGI->generaltexth->hcommands[7]) % building->Name()));
-	buildingDescr = new CTextBox(building->Description(), Rect(33, 135, 329, 67), 0, FONT_MEDIUM, CENTER);
-	buildingState = new CTextBox(getTextForState(state),  Rect(33, 216, 329, 67), 0, FONT_SMALL,  CENTER);
+	new CTextBox(building->Description(), Rect(33, 135, 329, 67), 0, FONT_MEDIUM, CENTER);
+	new CTextBox(getTextForState(state),  Rect(33, 216, 329, 67), 0, FONT_SMALL,  CENTER);
+
+	//Create components for all required resources
+	std::vector<CComponent *> components;
 
-	//Create objects for all required resources
 	for(int i = 0; i<GameConstants::RESOURCE_QUANTITY; i++)
 	{
 		if(building->resources[i])
 		{
-			resPicture.push_back(new CAnimImage("RESOURCE", i));
-			resAmount.push_back(new CLabel(0,0, FONT_SMALL, CENTER, Colors::Cornsilk, 
-			                        boost::lexical_cast<std::string>(building->resources[i])));
+			components.push_back(new CComponent(CComponent::resource, i, building->resources[i], CComponent::small));
 		}
 	}
 
-	ui32 rowSize[2];
-	int posY;
-	if (resAmount.size() > 4)
-	{//Resources will be placed in multiple rows
-		rowSize[0] = (resAmount.size()+1)/2;
-		posY = 303;
-	}
-	else
-	{//one row
-		rowSize[0] = resAmount.size();
-		posY = 340;
-	}
-	rowSize[1] = resAmount.size() - rowSize[0];
-
-	ui32 index=0;
-	for (size_t row=0; row<2; row++)
-	{
-		int posX = pos.w/2 - rowSize[row] * 40 + 24;
-		for (size_t i=0; i<rowSize[row]; i++)
-		{//Move current resource to correct position
-			resPicture[index]->moveBy(Point(posX, posY));
-			resAmount[index]->moveBy(Point(posX+16, posY+48));
-			posX += 80;
-			index++;
-		}
-		posY +=75;
-	}
+	new CComponentBox(components, Rect(25, 300, pos.w - 50, 130));
 
 	if(!rightClick)
 	{	//normal window

+ 0 - 10
client/CCastleInterface.h

@@ -267,20 +267,10 @@ class CBuildWindow: public CWindowObject
 {
 	const CGTownInstance *town;
 	const CBuilding *building;
-	int state; //state - same as CHallInterface::CBuildingBox::state
 
-	CAnimImage *buildingPic;
 	CAdventureMapButton *buy;
 	CAdventureMapButton *cancel;
 
-	CLabel * title;
-	CTextBox * buildingDescr;
-	CTextBox * buildingState;
-	CGStatusBar *statusBar;
-
-	std::vector<CAnimImage *> resPicture;
-	std::vector<CLabel *> resAmount;
-
 	std::string getTextForState(int state);
 	void buyFunc();
 

+ 146 - 101
client/GUIClasses.cpp

@@ -768,12 +768,12 @@ void CInfoPopup::init(int x, int y)
 	vstd::amin(pos.y, screen->h - bitmap->h);
 }
 
-CComponent::CComponent(Etype Type, int Subtype, int Val, bool showSubtitles):
+CComponent::CComponent(Etype Type, int Subtype, int Val, ESize imageSize):
 	image(nullptr),
     perDay(false)
 {
 	addUsedEvents(RCLICK);
-	init(Type, Subtype, Val, showSubtitles);
+	init(Type, Subtype, Val, imageSize);
 }
 
 CComponent::CComponent(const Component &c):
@@ -786,66 +786,79 @@ CComponent::CComponent(const Component &c):
 		perDay = true;
 
 	if(c.id == Component::EXPERIENCE)
-		init(experience,c.subtype,c.val, true);
+		init(experience,c.subtype,c.val, large);
 	else if(c.id == Component::SPELL)
-		init(spell,c.subtype,c.val, true);
+		init(spell,c.subtype,c.val, large);
 	else
-		init((Etype)c.id,c.subtype,c.val, true);
+		init((Etype)c.id,c.subtype,c.val, large);
 }
 
-void CComponent::init(Etype Type, int Subtype, int Val, bool showSubtitles)
+void CComponent::init(Etype Type, int Subtype, int Val, ESize imageSize)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 
 	compType = Type;
 	subtype = Subtype;
 	val = Val;
+	size = imageSize;
 
-	setSurface(getFileName(), getIndex());
+	setSurface(getFileName()[size], getIndex());
 
 	pos.w = image->pos.w;
 	pos.h = image->pos.h;
 
-	if (showSubtitles)
+	pos.h += 4; //distance between text and image
+
+	std::vector<std::string> textLines = CMessage::breakText(getSubtitle(), std::max<int>(80, pos.w), FONT_SMALL);
+	BOOST_FOREACH(auto & line, textLines)
 	{
-		pos.h += 4; //distance between text and image
+		int height = graphics->fonts[FONT_SMALL]->height;
+		CLabel * label = new CLabel(pos.w/2, pos.h + height/2, FONT_SMALL, CENTER, Colors::Cornsilk, line);
 
-		std::vector<std::string> textLines = CMessage::breakText(getSubtitle(), std::max<int>(64, pos.w), FONT_SMALL);
-		BOOST_FOREACH(auto & line, textLines)
+		pos.h += height;
+		if (label->pos.w > pos.w)
 		{
-			int height = graphics->fonts[FONT_SMALL]->height;
-			CLabel * label = new CLabel(pos.w/2, pos.h + height/2, FONT_SMALL, CENTER, Colors::Cornsilk, line);
-
-			pos.h += height;
-			if (label->pos.w > pos.w)
-			{
-				pos.x -= (label->pos.w - pos.w)/2;
-				pos.w = label->pos.w;
-			}
+			pos.x -= (label->pos.w - pos.w)/2;
+			pos.w = label->pos.w;
 		}
 	}
 }
 
-std::string CComponent::getFileName()
+const std::vector<std::string> CComponent::getFileName()
 {
+	static const std::string  primSkillsArr [] = {"PSKIL32",        "PSKIL32",        "PSKIL42",        "PSKILL"};
+	static const std::string  secSkillsArr [] =  {"SECSK32",        "SECSK32",        "SECSKILL",       "SECSK82"};
+	static const std::string  resourceArr [] =   {"SMALRES",        "RESOURCE",       "RESOUR82",       "RESOUR82"};
+	static const std::string  creatureArr [] =   {"CPRSMALL",       "CPRSMALL",       "TWCRPORT",       "TWCRPORT"};
+	static const std::string  artifactArr[]  =   {"Artifact",       "Artifact",       "Artifact",       "Artifact"};
+	static const std::string  spellsArr [] =     {"SpellInt",       "SpellInt",       "SPELLSCR",       "SPELLSCR"};
+	static const std::string  moraleArr [] =     {"IMRL22",         "IMRL30",         "IMRL42",         "imrl82"};
+	static const std::string  luckArr [] =       {"ILCK22",         "ILCK30",         "ILCK42",         "ilck82"};
+	static const std::string  heroArr [] =       {"PortraitsSmall", "PortraitsSmall", "PortraitsLarge", "PortraitsLarge"};
+	static const std::string  flagArr [] =       {"CREST58",        "CREST58",        "CREST58",        "CREST58"};
+
+	auto gen = [](const std::string * arr)
+	{
+		return std::vector<std::string>(arr, arr + 4);
+	};
+
 	switch(compType)
 	{
-	case primskill:  return "PSKILL";
-	case secskill:   return "SECSK82";
-	case resource:   return "RESOUR82";
-	case creature:   return "TWCRPORT";
-	case artifact:   return "ARTIFACT";
-	case experience: return "PSKILL";
-	case secskill44: return "SECSKILL";
-	case spell:      return "SPELLSCR";
-	case morale:     return "IMRL82";
-	case luck:       return "ILCK82";
-	case building:   return graphics->buildingPics[subtype];
-	case hero:       return "PortraitsLarge";
-	case flag:       return "CREST58";
+	case primskill:  return gen(primSkillsArr);
+	case secskill:   return gen(secSkillsArr);
+	case resource:   return gen(resourceArr);
+	case creature:   return gen(creatureArr);
+	case artifact:   return gen(artifactArr);
+	case experience: return gen(primSkillsArr);
+	case spell:      return gen(spellsArr);
+	case morale:     return gen(moraleArr);
+	case luck:       return gen(luckArr);
+	case building:   return std::vector<std::string>(4, graphics->buildingPics[subtype]);
+	case hero:       return gen(heroArr);
+	case flag:       return gen(flagArr);
 	}
 	assert(0);
-	return "";
+	return std::vector<std::string>();
 }
 
 size_t CComponent::getIndex()
@@ -858,7 +871,6 @@ size_t CComponent::getIndex()
 	case creature:   return subtype+2;
 	case artifact:   return subtype;
 	case experience: return 4;
-	case secskill44: return subtype*3 + 3 + val - 1;
 	case spell:      return subtype;
 	case morale:     return val+3;
 	case luck:       return val+3;
@@ -881,7 +893,6 @@ std::string CComponent::getDescription()
 	case creature:   return "";
 	case artifact:   return  CGI->arth->artifacts[subtype]->Description();
 	case experience: return CGI->generaltexth->allTexts[241];
-	case secskill44: return CGI->generaltexth->skillInfoTexts[subtype][val-1];
 	case spell:      return CGI->spellh->spells[subtype]->descriptions[val];
 	case morale:     return CGI->generaltexth->heroscrn[ 4 - (val>0) + (val<0)];
 	case luck:       return CGI->generaltexth->heroscrn[ 7 - (val>0) + (val<0)];
@@ -909,12 +920,11 @@ std::string CComponent::getSubtitleInternal()
 	switch(compType)
 	{
 	case primskill:  return boost::str(boost::format("%+d %s") % val % (subtype < 4 ? CGI->generaltexth->primarySkillNames[subtype] : CGI->generaltexth->allTexts[387]));
-	case secskill:   return CGI->generaltexth->levels[val-1] + " " + CGI->generaltexth->skillName[subtype];
+	case secskill:   return CGI->generaltexth->levels[val-1] + "\n" + CGI->generaltexth->skillName[subtype];
 	case resource:   return boost::lexical_cast<std::string>(val);
 	case creature:   return (val? boost::lexical_cast<std::string>(val) + " " : "") + CGI->creh->creatures[subtype]->*(val != 1 ? &CCreature::namePl : &CCreature::nameSing);
 	case artifact:   return CGI->arth->artifacts[subtype]->Name();
 	case experience: return (subtype && val==1) ? CGI->generaltexth->allTexts[442] : boost::lexical_cast<std::string>(val);
-	case secskill44: return CGI->generaltexth->levels[val-1] + " " + CGI->generaltexth->skillName[subtype];
 	case spell:      return CGI->spellh->spells[subtype]->name;
 	case morale:     return "";
 	case luck:       return "";
@@ -961,8 +971,8 @@ CSelectableComponent::CSelectableComponent(const Component &c, boost::function<v
 	init();
 }
 
-CSelectableComponent::CSelectableComponent(Etype Type, int Sub, int Val, boost::function<void()> OnSelect):
-	CComponent(Type,Sub,Val),onSelect(OnSelect)
+CSelectableComponent::CSelectableComponent(Etype Type, int Sub, int Val, ESize imageSize, boost::function<void()> OnSelect):
+	CComponent(Type,Sub,Val, imageSize),onSelect(OnSelect)
 {
 	type |= REDRAW_PARENT;
 	addUsedEvents(LCLICK | KEYBOARD);
@@ -989,13 +999,15 @@ void CSelectableComponent::showAll(SDL_Surface * to)
 
 void CComponentBox::selectionChanged(CSelectableComponent * newSelection)
 {
-	assert(newSelection != selected);
+	if (newSelection == selected)
+		return;
 
 	if (selected)
 		selected->select(false);
 
 	selected = newSelection;
-	onSelect(selectedIndex());
+	if (onSelect)
+		onSelect(selectedIndex());
 
 	if (selected)
 		selected->select(true);
@@ -1008,14 +1020,35 @@ int CComponentBox::selectedIndex()
 	return -1;
 }
 
+Point CComponentBox::getOrTextPos(CComponent *left, CComponent *right)
+{
+	int leftSubtitle  = ( left->pos.w -  left->image->pos.w) / 2;
+	int rightSubtitle = (right->pos.w - right->image->pos.w) / 2;
+	int fullDistance = getDistance(left, right) + leftSubtitle + rightSubtitle;
+
+	return Point(fullDistance/2 - leftSubtitle, (left->image->pos.h + right->image->pos.h) / 4);
+}
+
+int CComponentBox::getDistance(CComponent *left, CComponent *right)
+{
+	static const int betweenImagesMin = 50;
+	static const int betweenSubtitlesMin = 10;
+
+	int leftSubtitle  = ( left->pos.w -  left->image->pos.w) / 2;
+	int rightSubtitle = (right->pos.w - right->image->pos.w) / 2;
+	int subtitlesOffset = leftSubtitle + rightSubtitle;
+
+	return std::max(betweenSubtitlesMin, betweenImagesMin - subtitlesOffset);
+}
+
 void CComponentBox::placeComponents(bool selectable)
 {
+	static const int betweenRows = 22;
+
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	if (components.empty())
 		return;
 
-	static const int betweenComponents = 50;
-	static const int betweenRows = 22;
-
 	//prepare components
 	BOOST_FOREACH(auto & comp, components)
 	{
@@ -1032,35 +1065,46 @@ void CComponentBox::placeComponents(bool selectable)
 		comps(Comps), width (Width), height (Height){};
 	};
 	std::vector<RowData> rows;
-	//rows.push_back({0, 0, 0}); //there is NO such syntax!
 	rows.push_back (RowData (0,0,0));
 
 	//split components in rows
-	BOOST_FOREACH(auto & comp, components)
+	CComponent * prevComp = nullptr;
+
+	BOOST_FOREACH(CComponent * comp, components)
 	{
 		//make sure that components are smaller than our width
-		assert(pos.w == 0 || pos.w < comp->pos.w);
+		//assert(pos.w == 0 || pos.w < comp->pos.w);
+
+		const int distance = prevComp ? getDistance(prevComp, comp) : 0;
 
 		//start next row
-		if (pos.w != 0 && rows.back().width + comp->pos.w > pos.w)
+		if (pos.w != 0 && rows.back().width + comp->pos.w + distance > pos.w)
+		{
+			prevComp = nullptr;
 			rows.push_back (RowData (0,0,0));
+		}
+
+		if (prevComp)
+			rows.back().width += distance;
 
 		rows.back().comps++;
 		rows.back().width += comp->pos.w;
+
 		vstd::amax(rows.back().height, comp->pos.h);
+		prevComp = comp;
 	}
 
 	if (pos.w == 0)
 	{
 		BOOST_FOREACH(auto & row, rows)
-			vstd::amax(pos.w, row.width + (row.comps - 1) * betweenComponents);
+			vstd::amax(pos.w, row.width);
 	}
 
 	int height = (rows.size() - 1) * betweenRows;
 	BOOST_FOREACH(auto & row, rows)
 		height += row.height;
 
-	assert(pos.h == 0 || pos.h < height);
+	//assert(pos.h == 0 || pos.h < height);
 	if (pos.h == 0)
 		pos.h = height;
 
@@ -1070,12 +1114,26 @@ void CComponentBox::placeComponents(bool selectable)
 	//move components to their positions
 	for (size_t row = 0; row < rows.size(); row++)
 	{
+		prevComp = nullptr;
+
 		int currentX = (pos.w - rows[row].width) / 2;
 		for (size_t col = 0; col < rows[row].comps; col++)
 		{
+			if (prevComp)
+			{
+				if (selectable)
+				{
+					Point orPos = Point(currentX, currentY) + getOrTextPos(prevComp, *iter);
+
+					new CLabel(orPos.x, orPos.y, FONT_MEDIUM, CENTER, Colors::Cornsilk, CGI->generaltexth->allTexts[4]);
+				}
+				currentX += getDistance(prevComp, *iter);
+			}
+
 			(*iter)->moveBy(Point(currentX, currentY));
-			currentX += (*iter)->pos.w + betweenComponents;
-			iter++;
+			currentX += (*iter)->pos.w;
+
+			prevComp = *(iter++);
 		}
 		currentY += rows[row].height + betweenRows;
 	}
@@ -1085,6 +1143,8 @@ CComponentBox::CComponentBox(CComponent * _components, Rect position):
     components(1, _components),
     selected(nullptr)
 {
+	type |= REDRAW_PARENT;
+	pos = position + pos;
 	placeComponents(false);
 }
 
@@ -1092,14 +1152,29 @@ CComponentBox::CComponentBox(std::vector<CComponent *> _components, Rect positio
     components(_components),
     selected(nullptr)
 {
+	type |= REDRAW_PARENT;
+	pos = position + pos;
 	placeComponents(false);
 }
 
 CComponentBox::CComponentBox(std::vector<CSelectableComponent *> _components, Rect position, boost::function<void(int newID)> _onSelect):
     components(_components.begin(), _components.end()),
-    selected(nullptr)
+    selected(nullptr),
+    onSelect(_onSelect)
 {
+	type |= REDRAW_PARENT;
+	pos = position + pos;
 	placeComponents(true);
+
+	assert(!components.empty());
+
+	int key = SDLK_1;
+	BOOST_FOREACH(auto & comp, _components)
+	{
+		comp->onSelect = boost::bind(&CComponentBox::selectionChanged, this, comp);
+		comp->assignedKeys.insert(key++);
+	}
+	selectionChanged(_components.front());
 }
 
 void CSelWindow::selectionChange(unsigned to)
@@ -1552,17 +1627,6 @@ CLevelWindow::CLevelWindow(const CGHeroInstance *hero, int pskill, std::vector<u
 
 	LOCPLINT->showingDialog->setn(true);
 
-	for(size_t i=0;i<skills.size();i++)
-	{
-		comps.push_back(new CSelectableComponent(
-		                    CComponent::secskill44,
-		                    skills[i],
-		                    hero->getSecSkillLevel( static_cast<CGHeroInstance::SecondarySkill>(skills[i]) )+1,
-		                    boost::bind(&CLevelWindow::selectionChanged,this,i)));
-
-		comps.back()->assignedKeys.insert(SDLK_1 + i);
-	}
-
 	new CAnimImage("PortraitsLarge", hero->portrait, 0, 170, 66);
 	new CAdventureMapButton("", "", boost::bind(&CLevelWindow::close, this), 297, 413, "IOKAY", SDLK_RETURN);
 
@@ -1579,49 +1643,30 @@ CLevelWindow::CLevelWindow(const CGHeroInstance *hero, int pskill, std::vector<u
 	new CLabel(192, 253, FONT_MEDIUM, CENTER, Colors::Cornsilk,
 	           CGI->generaltexth->primarySkillNames[pskill] + " +1");
 
-	// "or"
-	std::string text = CGI->generaltexth->allTexts[4];
-
-	int fontWidth = graphics->fonts[FONT_MEDIUM]->getWidth(text.c_str())/2;
-
-	int curx = pos.w/2 - ( skills.size()*44 + (skills.size()-1)*(36+fontWidth) )/2;
-
-	for(size_t i=0; i<comps.size(); i++)
+	if (!skills.empty())
 	{
-		comps[i]->moveTo(Point(pos.x + curx, pos.y + 326));
-		if( i < (comps.size()-1) )
+		std::vector<CSelectableComponent *> comps;
+
+		for(size_t i=0;i<skills.size();i++)
 		{
-			curx += comps[i]->pos.w + 10; //skill width + margin to "or"
-			new CLabel(curx, 346, FONT_MEDIUM, CENTER, Colors::Cornsilk, text);
-			curx += fontWidth+10;
+			comps.push_back(new CSelectableComponent(
+								CComponent::secskill,
+								skills[i],
+								hero->getSecSkillLevel( static_cast<CGHeroInstance::SecondarySkill>(skills[i]) )+1,
+								CComponent::medium));
 		}
+		box = new CComponentBox(comps, Rect(25, 300, pos.w - 50, 100));
 	}
-
-	if(!comps.empty())
-	{
-		comps[0]->select(true);
-	}
-}
-
-void CLevelWindow::selectionChanged(unsigned to)
-{
-	for(int i=0;i<comps.size();i++)
-		if(i==to)
-			comps[i]->select(true);
-		else
-			comps[i]->select(false);
+	else
+		box = nullptr;
 }
 
 CLevelWindow::~CLevelWindow()
 {
-	for(int i=0;i<comps.size();i++)
-	{
-		if(comps[i]->selected)
-		{
-			cb(i);
-			break;
-		}
-	}
+	//FIXME: call callback if there was nothing to select?
+	if (box && box->selectedIndex() != -1)
+		cb(box->selectedIndex());
+
 	LOCPLINT->showingDialog->setn(false);
 }
 

+ 28 - 10
client/GUIClasses.h

@@ -176,22 +176,31 @@ class CComponent : public virtual CIntObject
 public:
 	enum Etype
 	{
-		primskill, secskill, resource, creature, artifact, experience, secskill44, spell, morale, luck, building, hero, flag
+		primskill, secskill, resource, creature, artifact, experience, spell, morale, luck, building, hero, flag
+	};
+
+	//NOTE: not all types have exact these sizes or have less than 4 of them. In such cases closest one will be used
+	enum ESize
+	{
+		tiny,  // ~22-24px
+		small, // ~30px
+		medium,// ~42px
+		large  // ~82px
 	};
 
 private:
 	size_t getIndex();
-	std::string getFileName();
+	const std::vector<std::string> getFileName();
 	void setSurface(std::string defName, int imgPos);
 	std::string getSubtitleInternal();
 
-	void init(Etype Type, int Subtype, int Val, bool showSubtitles);
+	void init(Etype Type, int Subtype, int Val, ESize imageSize);
 
-protected:
+public:
 	CAnimImage *image; //our image
 
-public:
 	Etype compType; //component type
+	ESize size; //component size.
 	int subtype; //type-dependant subtype. See getSomething methods for details
 	int val; // value \ strength \ amount of component. See getSomething methods for details
 	bool perDay; // add "per day" text to subtitle
@@ -199,7 +208,7 @@ public:
 	std::string getDescription();
 	std::string getSubtitle();
 
-	CComponent(Etype Type, int Subtype, int Val, bool showSubtitles = true); //c-tor
+	CComponent(Etype Type, int Subtype, int Val, ESize imageSize=large);//c-tor
 	CComponent(const Component &c); //c-tor
 
 	void clickRight(tribool down, bool previousState); //call-in
@@ -217,7 +226,7 @@ public:
 	void select(bool on);
 
 	void clickLeft(tribool down, bool previousState); //call-in
-	CSelectableComponent(Etype Type, int Sub, int Val, boost::function<void()> OnSelect = 0); //c-tor
+	CSelectableComponent(Etype Type, int Sub, int Val, ESize imageSize=large, boost::function<void()> OnSelect = 0); //c-tor
 	CSelectableComponent(const Component &c, boost::function<void()> OnSelect = 0); //c-tor
 };
 
@@ -231,6 +240,13 @@ class CComponentBox : public CIntObject
 	boost::function<void(int newID)> onSelect;
 
 	void selectionChanged(CSelectableComponent * newSelection);
+
+	//get position of "or" text between these comps
+	//it will place "or" equidistant to both images
+	Point getOrTextPos(CComponent *left, CComponent * right);
+
+	//get distance between these copmonents
+	int getDistance(CComponent *left, CComponent * right);
 	void placeComponents(bool selectable);
 
 public:
@@ -459,13 +475,15 @@ public:
 /// Raised up level windowe where you can select one out of two skills
 class CLevelWindow : public CWindowObject
 {
-public:
-	std::vector<CSelectableComponent *> comps; //skills to select
+	CComponentBox * box; //skills to select
 	boost::function<void(ui32)> cb;
 
+	void selectionChanged(unsigned to);
+public:
+
 	CLevelWindow(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback); //c-tor
 	~CLevelWindow(); //d-tor
-	void selectionChanged(unsigned to);
+
 };
 
 /// Resource bar like that at the bottom of the adventure map screen

+ 1 - 8
client/UIFramework/CGuiHandler.cpp

@@ -108,13 +108,6 @@ void CGuiHandler::totalRedraw()
 {
 	for(int i=0;i<objsToBlit.size();i++)
 		objsToBlit[i]->showAll(screen2);
-
-// 	static int a = 0;
-// 	if(a)
-// 	{
-// 		SDL_SaveBMP(screen, "s1.bmp");
-// 		SDL_SaveBMP(screen2, "s2.bmp");
-// 	}
 	blitAt(screen2,0,0,screen);
 }
 
@@ -431,7 +424,7 @@ SDLKey CGuiHandler::numToDigit( SDLKey key )
 	case SDLK_KP_ENTER:
 		return SDLK_RETURN;
 	default:
-		tlog3 << "Illegal numkey conversion!" << std::endl;
+		//tlog3 << "Illegal numkey conversion!" << std::endl;
 		return SDLK_UNKNOWN;
 	}
 #undef REMOVE_KP

+ 2 - 1
client/UIFramework/CIntObject.cpp

@@ -456,7 +456,8 @@ bool CIntObject::captureThisEvent(const SDL_KeyboardEvent & key)
 
 void CKeyShortcut::keyPressed(const SDL_KeyboardEvent & key)
 {
-	if(vstd::contains(assignedKeys,key.keysym.sym))
+	if(vstd::contains(assignedKeys,key.keysym.sym)
+	 || vstd::contains(assignedKeys, CGuiHandler::numToDigit(key.keysym.sym)))
 	{
 		bool prev = pressedL;
 		if(key.state == SDL_PRESSED)