소스 검색

- first part of CIntObject API clean-up.
- - mostly remove usage of (de)activateSomething functions
- - CIntObject's can be safely deleted in active state or without removing from parent first
- - Added CWindowObject to use as base of all windows (will be required for such features as shadows)

Report any crashes or glitches - it should not cause any issues apart from more console output.

TODO:
- remove redundant (de)activate and show(All) calls
- decrease usage of blitAtLoc\printAtLoc methods
- switch all windows to new base

Ivan Savenko 13 년 전
부모
커밋
d60f2d57a0

+ 24 - 25
client/BattleInterface/CBattleInterface.cpp

@@ -202,29 +202,29 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
 // 	blitAt(menu, pos.x, 556 + pos.y);
 
 	//preparing buttons and console
-	bOptions = new CAdventureMapButton (CGI->generaltexth->zelp[381].first, CGI->generaltexth->zelp[381].second, boost::bind(&CBattleInterface::bOptionsf,this), 3 + pos.x, 561 + pos.y, "icm003.def", SDLK_o);
-	bSurrender = new CAdventureMapButton (CGI->generaltexth->zelp[379].first, CGI->generaltexth->zelp[379].second, boost::bind(&CBattleInterface::bSurrenderf,this), 54 + pos.x, 561 + pos.y, "icm001.def", SDLK_s);
-	bFlee = new CAdventureMapButton (CGI->generaltexth->zelp[380].first, CGI->generaltexth->zelp[380].second, boost::bind(&CBattleInterface::bFleef,this), 105 + pos.x, 561 + pos.y, "icm002.def", SDLK_r);
+	bOptions = new CAdventureMapButton (CGI->generaltexth->zelp[381].first, CGI->generaltexth->zelp[381].second, boost::bind(&CBattleInterface::bOptionsf,this), 3, 561, "icm003.def", SDLK_o);
+	bSurrender = new CAdventureMapButton (CGI->generaltexth->zelp[379].first, CGI->generaltexth->zelp[379].second, boost::bind(&CBattleInterface::bSurrenderf,this), 54, 561, "icm001.def", SDLK_s);
+	bFlee = new CAdventureMapButton (CGI->generaltexth->zelp[380].first, CGI->generaltexth->zelp[380].second, boost::bind(&CBattleInterface::bFleef,this), 105, 561, "icm002.def", SDLK_r);
 	bFlee->block(!curInt->cb->battleCanFlee());
 	bSurrender->block(curInt->cb->battleGetSurrenderCost() < 0);
-	bAutofight  = new CAdventureMapButton (CGI->generaltexth->zelp[382].first, CGI->generaltexth->zelp[382].second, boost::bind(&CBattleInterface::bAutofightf,this), 157 + pos.x, 561 + pos.y, "icm004.def", SDLK_a);
-	bSpell = new CAdventureMapButton (CGI->generaltexth->zelp[385].first, CGI->generaltexth->zelp[385].second, boost::bind(&CBattleInterface::bSpellf,this), 645 + pos.x, 561 + pos.y, "icm005.def", SDLK_c);
+	bAutofight  = new CAdventureMapButton (CGI->generaltexth->zelp[382].first, CGI->generaltexth->zelp[382].second, boost::bind(&CBattleInterface::bAutofightf,this), 157, 561, "icm004.def", SDLK_a);
+	bSpell = new CAdventureMapButton (CGI->generaltexth->zelp[385].first, CGI->generaltexth->zelp[385].second, boost::bind(&CBattleInterface::bSpellf,this), 645, 561, "icm005.def", SDLK_c);
 	bSpell->block(true);
-	bWait = new CAdventureMapButton (CGI->generaltexth->zelp[386].first, CGI->generaltexth->zelp[386].second, boost::bind(&CBattleInterface::bWaitf,this), 696 + pos.x, 561 + pos.y, "icm006.def", SDLK_w);
-	bDefence = new CAdventureMapButton (CGI->generaltexth->zelp[387].first, CGI->generaltexth->zelp[387].second, boost::bind(&CBattleInterface::bDefencef,this), 747 + pos.x, 561 + pos.y, "icm007.def", SDLK_d);
+	bWait = new CAdventureMapButton (CGI->generaltexth->zelp[386].first, CGI->generaltexth->zelp[386].second, boost::bind(&CBattleInterface::bWaitf,this), 696, 561, "icm006.def", SDLK_w);
+	bDefence = new CAdventureMapButton (CGI->generaltexth->zelp[387].first, CGI->generaltexth->zelp[387].second, boost::bind(&CBattleInterface::bDefencef,this), 747, 561, "icm007.def", SDLK_d);
 	bDefence->assignedKeys.insert(SDLK_SPACE);
-	bConsoleUp = new CAdventureMapButton (std::string(), std::string(), boost::bind(&CBattleInterface::bConsoleUpf,this), 624 + pos.x, 561 + pos.y, "ComSlide.def", SDLK_UP);
-	bConsoleDown = new CAdventureMapButton (std::string(), std::string(), boost::bind(&CBattleInterface::bConsoleDownf,this), 624 + pos.x, 580 + pos.y, "ComSlide.def", SDLK_DOWN);
+	bConsoleUp = new CAdventureMapButton (std::string(), std::string(), boost::bind(&CBattleInterface::bConsoleUpf,this), 624, 561, "ComSlide.def", SDLK_UP);
+	bConsoleDown = new CAdventureMapButton (std::string(), std::string(), boost::bind(&CBattleInterface::bConsoleDownf,this), 624, 580, "ComSlide.def", SDLK_DOWN);
 	bConsoleDown->setOffset(2);
 	console = new CBattleConsole();
-	console->pos.x = 211 + pos.x;
-	console->pos.y = 560 + pos.y;
+	console->pos.x += 211;
+	console->pos.y += 560;
 	console->pos.w = 406;
 	console->pos.h = 38;
 	if(tacticsMode)
 	{
-		btactNext = new CAdventureMapButton(std::string(), std::string(), boost::bind(&CBattleInterface::bTacticNextStack,this, (CStack*)NULL), 213 + pos.x, 560 + pos.y, "icm011.def", SDLK_SPACE);
-		btactEnd = new CAdventureMapButton(std::string(), std::string(), boost::bind(&CBattleInterface::bEndTacticPhase,this), 419 + pos.x, 560 + pos.y, "icm012.def", SDLK_RETURN);
+		btactNext = new CAdventureMapButton(std::string(), std::string(), boost::bind(&CBattleInterface::bTacticNextStack,this, (CStack*)NULL), 213, 560, "icm011.def", SDLK_SPACE);
+		btactEnd = new CAdventureMapButton(std::string(), std::string(), boost::bind(&CBattleInterface::bEndTacticPhase,this), 419, 560, "icm012.def", SDLK_RETURN);
 		bDefence->block(true);
 		bWait->block(true);
 		menu = BitmapHandler::loadBitmap("COPLACBR.BMP");
@@ -363,15 +363,11 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
 
 	for (int i = 0; i < bfield.size(); i++)
 	{
-		children.push_back(&bfield[i]);
+		addChild(&bfield[i]);
 	}
 
 	if(tacticsMode)
-	{
-		active = 1;
 		bTacticNextStack();
-		active = 0;
-	}
 
 	CCS->musich->stopMusic();
 
@@ -381,6 +377,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
 
 	currentAction = INVALID;
 	selectedAction = INVALID;
+	addUsedEvents(RCLICK | MOVE | KEYBOARD);
 }
 
 CBattleInterface::~CBattleInterface()
@@ -476,9 +473,7 @@ void CBattleInterface::setPrintMouseShadow(bool set)
 
 void CBattleInterface::activate()
 {
-	activateKeys();
-	activateMouseMove();
-	activateRClick();
+	CIntObject::activate();
 	bOptions->activate();
 	bSurrender->activate();
 	bFlee->activate();
@@ -513,9 +508,8 @@ void CBattleInterface::activate()
 
 void CBattleInterface::deactivate()
 {
-	deactivateKeys();
-	deactivateMouseMove();
-	deactivateRClick();
+	CIntObject::deactivate();
+
 	bOptions->deactivate();
 	bSurrender->deactivate();
 	bFlee->deactivate();
@@ -548,6 +542,11 @@ void CBattleInterface::deactivate()
 	LOCPLINT->cingconsole->deactivate();
 }
 
+void CBattleInterface::showAll(SDL_Surface * to)
+{
+	show(to);
+}
+
 void CBattleInterface::show(SDL_Surface * to)
 {
 	std::vector<const CStack*> stacks = curInt->cb->battleGetAllStacks(); //used in a few places
@@ -2236,7 +2235,6 @@ void CBattleInterface::showPieceOfWall(SDL_Surface * to, int hex, const std::vec
 	if(!siegeH)
 		return;
 
-	using namespace boost::assign;
 #ifdef CPP11_USE_INITIALIZERS_LIST
 	//note - std::list<int> must be specified to avoid type deduction by gcc (may not work in other compilers)
 	static const std::map<int, std::list<int> > hexToPart = {
@@ -2244,6 +2242,7 @@ void CBattleInterface::showPieceOfWall(SDL_Surface * to, int hex, const std::vec
 		{101, std::list<int>{10}},      {118, std::list<int>{2}},
 		{165, std::list<int>{11}},      {186, std::list<int>{3}}};
 #else
+	using namespace boost::assign;
 	static const std::map<int, std::list<int> > hexToPart = map_list_of<int, std::list<int> >(12, list_of<int>(8)(1)(7))(45, list_of<int>(12)(6))
 		(101, list_of<int>(10))(118, list_of<int>(2))(165, list_of<int>(11))(186, list_of<int>(3));
 #endif

+ 1 - 0
client/BattleInterface/CBattleInterface.h

@@ -243,6 +243,7 @@ public:
 	//napisz tu klase odpowiadajaca za wyswietlanie bitwy i obsluge uzytkownika, polecenia ma przekazywac callbackiem
 	void activate();
 	void deactivate();
+	void showAll(SDL_Surface * to);
 	void show(SDL_Surface * to);
 	void keyPressed(const SDL_KeyboardEvent & key);
 	void mouseMoved(const SDL_MouseMotionEvent &sEvent);

+ 2 - 24
client/BattleInterface/CBattleInterfaceClasses.cpp

@@ -176,15 +176,6 @@ void CBattleHero::show(SDL_Surface * to)
 	}
 }
 
-void CBattleHero::activate()
-{
-	activateLClick();
-}
-void CBattleHero::deactivate()
-{
-	deactivateLClick();
-}
-
 void CBattleHero::setPhase(int newPhase)
 {
 	if(phase != 4)
@@ -242,6 +233,7 @@ CBattleHero::CBattleHero(const std::string & defName, int phaseG, int imageG, bo
 		CSDL_Ext::alphaTransform(flag->ourImages[i].bitmap);
 		graphics->blueToPlayersAdv(flag->ourImages[i].bitmap, player);
 	}
+	addUsedEvents(LCLICK);
 }
 
 CBattleHero::~CBattleHero()
@@ -543,21 +535,6 @@ Point CClickableHex::getXYUnitAnim(const int & hexNum, const bool & attacker, co
 	//returning
 	return ret +CPlayerInterface::battleInt->pos;
 }
-void CClickableHex::activate()
-{
-	activateHover();
-	activateMouseMove();
-	activateLClick();
-	activateRClick();
-}
-
-void CClickableHex::deactivate()
-{
-	deactivateHover();
-	deactivateMouseMove();
-	deactivateLClick();
-	deactivateRClick();
-}
 
 void CClickableHex::hover(bool on)
 {
@@ -572,6 +549,7 @@ void CClickableHex::hover(bool on)
 
 CClickableHex::CClickableHex() : setAlterText(false), myNumber(-1), accessible(true), hovered(false), strictHovered(false), myInterface(NULL)
 {
+	addUsedEvents(LCLICK | RCLICK | HOVER | MOVE);
 }
 
 void CClickableHex::mouseMoved(const SDL_MouseMotionEvent &sEvent)

+ 0 - 4
client/BattleInterface/CBattleInterfaceClasses.h

@@ -58,8 +58,6 @@ public:
 	int image; //frame of animation
 	ui8 flagAnim, flagAnimCount; //for flag animation
 	void show(SDL_Surface * to); //prints next frame of animation to to
-	void activate();
-	void deactivate();
 	void setPhase(int newPhase); //sets phase of hero animation
 	void clickLeft(tribool down, bool previousState); //call-in
 	CBattleHero(const std::string &defName, int phaseG, int imageG, bool filpG, ui8 player, const CGHeroInstance *hero, const CBattleInterface *owner); //c-tor
@@ -115,8 +113,6 @@ public:
 
 	//for user interactions
 	void hover (bool on);
-	void activate();
-	void deactivate();
 	void mouseMoved (const SDL_MouseMotionEvent &sEvent);
 	void clickLeft(tribool down, bool previousState);
 	void clickRight(tribool down, bool previousState);

+ 33 - 72
client/CAdvmapInterface.cpp

@@ -56,7 +56,7 @@ CAdvMapInt *adventureInt;
 CMinimap::CMinimap()
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	used = LCLICK | RCLICK | HOVER;
+	addUsedEvents(LCLICK | RCLICK | HOVER);
 	int3 mapSizes = LOCPLINT->cb->getMapSize();
 	statusbarTxt = CGI->generaltexth->zelp[291].first;
 	rcText = CGI->generaltexth->zelp[291].second;
@@ -266,10 +266,10 @@ void CMinimap::clickRight(tribool down, bool previousState)
 
 void CMinimap::clickLeft(tribool down, bool previousState)
 {
-	if (down && !(used & MOVE))
-		changeUsedEvents(MOVE, true);
-	else if (!down	&&	used & MOVE)
-		changeUsedEvents(MOVE, false);
+	if (down)
+		addUsedEvents(MOVE);
+	else
+		removeUsedEvents(MOVE);
 
 	//ClickableL::clickLeft(down);
 	if (!((bool)down))
@@ -472,25 +472,15 @@ CTerrainRect::CTerrainRect()
 	pos.w=ADVOPT.advmapW;
 	pos.h=ADVOPT.advmapH;
 	moveX = moveY = 0;
+	addUsedEvents(LCLICK | RCLICK | HOVER | MOVE);
 }
-CTerrainRect::~CTerrainRect()
-{
-}
-void CTerrainRect::activate()
-{
-	activateLClick();
-	activateRClick();
-	activateHover();
-	activateMouseMove();
-}
+
 void CTerrainRect::deactivate()
 {
-	deactivateLClick();
-	deactivateRClick();
-	deactivateHover();
-	deactivateMouseMove();
+	CIntObject::deactivate();
 	curHoveredTile = int3(-1,-1,-1); //we lost info about hovered tile when disabling
 }
+
 void CTerrainRect::clickLeft(tribool down, bool previousState)
 {
 	if ((down==false) || indeterminate(down))
@@ -502,6 +492,7 @@ void CTerrainRect::clickLeft(tribool down, bool previousState)
 
 	adventureInt->tileLClicked(mp);
 }
+
 void CTerrainRect::clickRight(tribool down, bool previousState)
 {
 	int3 mp = whichTileIsIt();
@@ -668,6 +659,7 @@ void CTerrainRect::showPath(const SDL_Rect * extRect, SDL_Surface * to)
 		}
 	} //for (int i=0;i<currentPath->nodes.size()-1;i++)
 }
+
 void CTerrainRect::show(SDL_Surface * to)
 {
 	if(ADVOPT.smoothMove)
@@ -697,6 +689,7 @@ int3 CTerrainRect::whichTileIsIt(const int & x, const int & y)
 	ret.z = adventureInt->position.z;
 	return ret;
 }
+
 int3 CTerrainRect::whichTileIsIt()
 {
 	return whichTileIsIt(GH.current->motion.x,GH.current->motion.y);
@@ -705,14 +698,7 @@ int3 CTerrainRect::whichTileIsIt()
 void CResDataBar::clickRight(tribool down, bool previousState)
 {
 }
-void CResDataBar::activate()
-{
-	activateRClick();
-}
-void CResDataBar::deactivate()
-{
-	deactivateRClick();
-}
+
 CResDataBar::CResDataBar(const std::string &defname, int x, int y, int offx, int offy, int resdist, int datedist)
 {
 	bg = BitmapHandler::loadBitmap(defname);
@@ -729,7 +715,9 @@ CResDataBar::CResDataBar(const std::string &defname, int x, int y, int offx, int
 	txtpos[7].first = txtpos[6].first + datedist;
 	datetext =  CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63]
 	+ ": %s, " + CGI->generaltexth->allTexts[64] + ": %s";
+	addUsedEvents(RCLICK);
 }
+
 CResDataBar::CResDataBar()
 {
 	bg = BitmapHandler::loadBitmap(ADVOPT.resdatabarG);
@@ -784,7 +772,7 @@ void CResDataBar::showAll(SDL_Surface * to)
 
 CInfoBar::CInfoBar()
 {
-	toNextTick = pom = -1;
+	pom = -1;
 	mode = NOTHING;
 	pos.x=ADVOPT.infoboxX;
 	pos.y=ADVOPT.infoboxY;
@@ -872,7 +860,7 @@ void CInfoBar::blitAnim(EMode mode)//0 - day, 1 - week
 	blitAt(anim->ourImages[pom].bitmap,pos.x+9,pos.y+10);
 	printAtMiddle(txt.str(),pos.x+95,pos.y+31,FONT_MEDIUM,Colors::Cornsilk);
 	if (pom == anim->ourImages.size()-1)
-		toNextTick+=750;
+		setTimer(750);
 }
 
 void CInfoBar::newDay(int Day)
@@ -903,10 +891,7 @@ void CInfoBar::newDay(int Day)
 		}
 	}
 	pom = 0;
-	if(!(active & TIME))
-		activateTimer();
-
-	toNextTick = 500;
+	setTimer(500);
 	blitAnim(mode);
 }
 
@@ -926,10 +911,8 @@ void CInfoBar::showComp(const CComponent * comp, int time/*=5000*/)
 	printAtMiddle(comp->subtitle,pos.x+91,pos.y+158,FONT_SMALL,Colors::Cornsilk);
 	printAtMiddleWB(comp->description,pos.x+94,pos.y+31,FONT_SMALL,26,Colors::Cornsilk);
 	SDL_FreeSurface(b);
-	if(!(active & TIME))
-		activateTimer();
+	setTimer(time);
 	mode = SHOW_COMPONENT;
-	toNextTick = time;
 }
 
 void CInfoBar::tick()
@@ -939,16 +922,13 @@ void CInfoBar::tick()
 		pom++;
 		if (pom >= getAnim(mode)->ourImages.size())
 		{
-			deactivateTimer();
-			toNextTick = -1;
+			removeUsedEvents(TIME);
 			mode = NOTHING;
 		}
-		toNextTick = 150;
 	}
 	else if(mode == SHOW_COMPONENT)
 	{
-		deactivateTimer();
-		toNextTick = -1;
+		removeUsedEvents(TIME);
 		mode = NOTHING;
 	}
 
@@ -961,18 +941,10 @@ void CInfoBar::show(SDL_Surface * to)
 
 }
 
-void CInfoBar::activate()
-{
-	//CIntObject::activate();
-}
-
 void CInfoBar::deactivate()
 {
-	//CIntObject::deactivate();
-	if(active & TIME)
-		deactivateTimer();
+	CIntObject::deactivate();
 
-	toNextTick = -1;
 	mode = NOTHING;
 }
 
@@ -993,9 +965,7 @@ void CInfoBar::enemyTurn(ui8 color, double progress)
 	enemyTurnInfo.color = color;
 	enemyTurnInfo.progress = progress;
 	redraw();
-	if(!(active & TIME))
-		activateTimer();
-	toNextTick = 250;
+	setTimer(250);
 }
 
 CAdvMapInt::CAdvMapInt()
@@ -1064,6 +1034,7 @@ townList(ADVOPT.tlistSize,ADVOPT.tlistX,ADVOPT.tlistY,ADVOPT.tlistAU,ADVOPT.tlis
 
 	setPlayer(LOCPLINT->playerID);
 	underground.block(!CGI->mh->map->twoLevel);
+	addUsedEvents(MOVE);
 }
 
 CAdvMapInt::~CAdvMapInt()
@@ -1236,20 +1207,12 @@ void CAdvMapInt::updateNextHero(const CGHeroInstance *h)
 
 void CAdvMapInt::activate()
 {
-	if(isActive())
-	{
-		tlog1 << "Error: advmapint already active...\n";
-		return;
-	}
-	active |= GENERAL;
+	CIntObject::activate();
 
 	screenBuf = screen;
 	GH.statusbar = &statusbar;
 	if(!duringAITurn)
 	{
-		//assert(selection);
-		activateMouseMove();
-
 		kingOverview.activate();
 		underground.activate();
 		questlog.activate();
@@ -1266,18 +1229,17 @@ void CAdvMapInt::activate()
 		townList.activate();
 		terrain.activate();
 		infoBar.activate();
+		LOCPLINT->cingconsole->activate();
 
-		if(!LOCPLINT->cingconsole->active)
-			LOCPLINT->cingconsole->activate();
 		GH.fakeMouseMove(); //to restore the cursor
 	}
 }
 void CAdvMapInt::deactivate()
 {
-	active &= ~GENERAL;
+	CIntObject::deactivate();
+
 	if(!duringAITurn)
 	{
-		deactivateMouseMove();
 		scrollingDir = 0;
 
 		CCS->curh->changeGraphic(0,0);
@@ -1296,9 +1258,7 @@ void CAdvMapInt::deactivate()
 		townList.deactivate();
 		terrain.deactivate();
 		infoBar.deactivate();
-
-		if(LOCPLINT->cingconsole->active) //TODO
-			LOCPLINT->cingconsole->deactivate();
+		LOCPLINT->cingconsole->deactivate();
 	}
 }
 void CAdvMapInt::showAll(SDL_Surface * to)
@@ -1330,7 +1290,7 @@ void CAdvMapInt::showAll(SDL_Surface * to)
 	statusbar.show(to);
 
 	infoBar.showAll(to);
-	LOCPLINT->cingconsole->show(to);
+	LOCPLINT->cingconsole->showAll(to);
 }
 
 bool CAdvMapInt::isHeroSleeping(const CGHeroInstance *hero)
@@ -1399,7 +1359,7 @@ void CAdvMapInt::show(SDL_Surface * to)
 		for(int i=0;i<4;i++)
 			blitAt(gems[i]->ourImages[LOCPLINT->playerID].bitmap,ADVOPT.gemX[i],ADVOPT.gemY[i],to);
 		updateScreen=false;
-		LOCPLINT->cingconsole->show(to);
+		LOCPLINT->cingconsole->showAll(to);
 	}
 	if (updateMinimap)
 	{
@@ -1876,7 +1836,6 @@ void CAdvMapInt::tileHovered(const int3 &mapPos)
 	}
 
 	const CGPathNode *pnode = LOCPLINT->cb->getPathInfo(mapPos);
-	bool accessible  =  pnode->turns < 255;
 
 	int turns = pnode->turns;
 	vstd::amin(turns, 3);
@@ -1925,6 +1884,8 @@ void CAdvMapInt::tileHovered(const int3 &mapPos)
 	}
 	else if(const CGHeroInstance *h = curHero())
 	{
+		bool accessible  =  pnode->turns < 255;
+
 		if(objAtTile)
 		{
 			if(objAtTile->ID == GameConstants::HEROI_TYPE)

+ 0 - 5
client/CAdvmapInterface.h

@@ -98,9 +98,7 @@ public:
 	int moveX, moveY; //shift between actual position of screen and the one we wil blit; ranges from -31 to 31 (in pixels)
 
 	CTerrainRect();
-	~CTerrainRect();
 	CGPath * currentPath;
-	void activate();
 	void deactivate();
 	void clickLeft(tribool down, bool previousState);
 	void clickRight(tribool down, bool previousState);
@@ -123,8 +121,6 @@ public:
 	std::string datetext;
 
 	void clickRight(tribool down, bool previousState);
-	void activate();
-	void deactivate();
 	CResDataBar();
 	CResDataBar(const std::string &defname, int x, int y, int offx, int offy, int resdist, int datedist);
 	~CResDataBar();
@@ -169,7 +165,6 @@ public:
 	void blitAnim(EMode mode);//0 - day, 1 - week
 
 	void show(SDL_Surface * to);
-	void activate();
 	void deactivate();
 	void updateSelection(const CGObjectInstance *obj);
 };

+ 48 - 91
client/CCastleInterface.cpp

@@ -57,7 +57,7 @@ CBuildingRect::CBuildingRect(CCastleBuildings * Par, const CGTownInstance *Town,
 	stateCounter(80)
 {
 	recActions = ACTIVATE | DEACTIVATE | DISPOSE | SHARE_POS;
-	used |= LCLICK | RCLICK | HOVER;
+	addUsedEvents(LCLICK | RCLICK | HOVER);
 	pos.x += str->pos.x;
 	pos.y += str->pos.y;
 
@@ -91,12 +91,12 @@ void CBuildingRect::hover(bool on)
 	if(on)
 	{
 		if(!(active & MOVE))
-			changeUsedEvents(MOVE, true, true);
+			addUsedEvents(MOVE);
 	}
 	else
 	{
 		if(active & MOVE)
-			changeUsedEvents(MOVE, false, true);
+			removeUsedEvents(MOVE);
 
 		if(parent->selectedBuilding == this)
 		{
@@ -249,7 +249,7 @@ void CBuildingRect::mouseMoved (const SDL_MouseMotionEvent & sEvent)
 CDwellingInfoBox::CDwellingInfoBox(int centerX, int centerY, const CGTownInstance *Town, int level)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	used |= RCLICK;
+	addUsedEvents(RCLICK);
 	background = new CPicture("CRTOINFO");
 	background->colorize(LOCPLINT->playerID);
 	pos.w = background->pos.w;
@@ -392,13 +392,12 @@ void CHeroGSlot::clickLeft(tribool down, bool previousState)
 
 void CHeroGSlot::deactivate()
 {
-	delChildNUll(selection, true);
+	vstd::clear_pointer(selection);
 	CIntObject::deactivate();
 }
 
 CHeroGSlot::CHeroGSlot(int x, int y, int updown, const CGHeroInstance *h, HeroSlots * Owner)
 {
-	used = LCLICK | HOVER;
 	owner = Owner;
 	pos.x += x;
 	pos.y += y;
@@ -408,6 +407,8 @@ CHeroGSlot::CHeroGSlot(int x, int y, int updown, const CGHeroInstance *h, HeroSl
 	selection = nullptr;
 	image = nullptr;
 	set(h);
+
+	addUsedEvents(LCLICK | HOVER);
 }
 
 CHeroGSlot::~CHeroGSlot()
@@ -416,17 +417,11 @@ CHeroGSlot::~CHeroGSlot()
 
 void CHeroGSlot::setHighlight( bool on )
 {
-	if (active && selection)
-		selection->deactivate();
-
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	delChildNUll(selection, true);
+	vstd::clear_pointer(selection);
 	if (on)
 		selection = new CAnimImage("TWCRPORT", 1, 0);
 
-	if (active && selection)
-		selection->activate();
-
 	if(owner->garrisonedHero->hero && owner->visitingHero->hero) //two heroes in town
 	{
 		for(size_t i = 0; i<owner->garr->splitButtons.size(); i++) //splitting enabled when slot higlighted
@@ -436,12 +431,9 @@ void CHeroGSlot::setHighlight( bool on )
 
 void CHeroGSlot::set(const CGHeroInstance *newHero)
 {
-	if (active && image)
-		image->deactivate();
-
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	if (image)
-		delChild(image);
+		delete image;
 	hero = newHero;
 	if (newHero)
 		image = new CAnimImage("PortraitsLarge", newHero->portrait, 0, 0, 0);
@@ -449,9 +441,6 @@ void CHeroGSlot::set(const CGHeroInstance *newHero)
 		image = new CAnimImage("CREST58", LOCPLINT->castleInt->town->getOwner(), 0, 0, 0);
 	else 
 		image = NULL;
-
-	if (active && image)
-		image->activate();
 }
 
 template <class ptr>
@@ -591,7 +580,7 @@ void CCastleBuildings::addBuilding(int building)
 				{
 					if ((*it)->str->ID == newBuilding)
 					{
-						delChild(*it);
+						delete *it;
 						buildings.erase(it);
 						break;
 					}
@@ -619,7 +608,7 @@ void CCastleBuildings::removeBuilding(int building)
 			{
 				if ((*it)->str->ID == building)
 				{
-					delChild(*it);
+					delete *it;
 					buildings.erase(it);
 					break;
 				}
@@ -628,7 +617,7 @@ void CCastleBuildings::removeBuilding(int building)
 		else
 		{
 			groups[structure->second->group].pop_back();
-			delChild(buildings[building]);
+			delete buildings[building];
 			if (!groups[structure->second->group].empty())
 				buildings.push_back(new CBuildingRect(this, town, structure->second));
 		}
@@ -877,15 +866,17 @@ void CCastleBuildings::enterMagesGuild()
 	{
 		if(LOCPLINT->cb->getResourceAmount(Res::GOLD) < 500) //not enough gold to buy spellbook
 		{
+			openMagesGuild();
 			LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[213]);
 		}
 		else
 		{
-			CFunctionList<void()> functionList = boost::bind(&CCallback::buyArtifact,LOCPLINT->cb, hero,0);
-			functionList += boost::bind(&CCastleBuildings::openMagesGuild,this);
+			CFunctionList<void()> onYes = boost::bind(&CCastleBuildings::openMagesGuild,this);
+			CFunctionList<void()> onNo = onYes;
+			onYes += boost::bind(&CCallback::buyArtifact,LOCPLINT->cb, hero,0);
 			std::vector<CComponent*> components(1, new CComponent(CComponent::artifact,0,0));
 
-			LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[214], functionList, 0, true, components);
+			LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[214], onYes, onNo, true, components);
 		}
 	}
 	else
@@ -928,13 +919,14 @@ void CCastleBuildings::openTownHall()
 }
 
 CCastleInterface::CCastleInterface(const CGTownInstance * Town, int listPos):
+    CWindowObject("", PLAYER_COLORED | BORDERED),
 	hall(NULL),
 	fort(NULL),
 	town(Town)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	LOCPLINT->castleInt = this;
-	used |= KEYBOARD;
+	addUsedEvents(KEYBOARD);
 
 	builds = new CCastleBuildings(town);
 	panel = new CPicture("TOWNSCRN", 0, builds->pos.h);
@@ -993,13 +985,6 @@ void CCastleInterface::close()
 	GH.popIntTotally(this);
 }
 
-void CCastleInterface::showAll(SDL_Surface * to)
-{
-	CIntObject::showAll(to);
-	if(screen->w != 800 || screen->h !=600)
-		CMessage::drawBorder(LOCPLINT->playerID,to,828,628,pos.x-14,pos.y-15);
-}
-
 void CCastleInterface::castleTeleport(int where)
 {
 	const CGTownInstance * dest = LOCPLINT->cb->getTown(where);
@@ -1035,10 +1020,8 @@ void CCastleInterface::removeBuilding(int bid)
 void CCastleInterface::recreateIcons()
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	if (fort)
-		delChild(fort);
-	if (hall)
-		delChild(hall);
+	delete fort;
+	delete hall;
 
 	size_t iconIndex = town->subID*2;
 	if (!town->hasFort())
@@ -1054,7 +1037,7 @@ void CCastleInterface::recreateIcons()
 	fort = new CTownInfo(122, 413, town, false);
 
 	for (size_t i=0; i<creainfo.size(); i++)
-		delChild(creainfo[i]);
+		delete creainfo[i];
 	creainfo.clear();
 
 	for (size_t i=0; i<4; i++)
@@ -1079,7 +1062,7 @@ CCreaInfo::CCreaInfo(Point position, const CGTownInstance *Town, int Level, bool
 		picture = NULL;
 		return;//No creature
 	}
-	used = LCLICK | RCLICK | HOVER;
+	addUsedEvents(LCLICK | RCLICK | HOVER);
 
 	ui32 creatureID = town->creatures[level].second.back();
 	creature = CGI->creh->creatures[creatureID];
@@ -1193,7 +1176,7 @@ CTownInfo::CTownInfo(int posX, int posY, const CGTownInstance* Town, bool townHa
 	building(NULL)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	used = RCLICK | HOVER;
+	addUsedEvents(RCLICK | HOVER);
 	pos.x += posX;
 	pos.y += posY;
 	int buildID;
@@ -1339,7 +1322,7 @@ CHallInterface::CBuildingBox::CBuildingBox(int x, int y, const CGTownInstance *
 	building(Building)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	used = LCLICK | RCLICK | HOVER;
+	addUsedEvents(LCLICK | RCLICK | HOVER);
 	pos.x += x;
 	pos.y += y;
 	pos.w = 154;
@@ -1358,12 +1341,10 @@ CHallInterface::CBuildingBox::CBuildingBox(int x, int y, const CGTownInstance *
 }
 
 CHallInterface::CHallInterface(const CGTownInstance *Town):
+    CWindowObject(CGI->buildh->hall[Town->subID].first, PLAYER_COLORED | BORDERED),
 	town(Town)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	background = new CPicture(CGI->buildh->hall[town->subID].first);
-	background->colorize(LOCPLINT->playerID);
-	pos = background->center();
 
 	resdatabar = new CMinorResDataBar;
 	resdatabar->pos.x += pos.x;
@@ -1410,22 +1391,12 @@ CHallInterface::CHallInterface(const CGTownInstance *Town):
 	}
 }
 
-void CHallInterface::close()
-{
-	GH.popIntTotally(this);
-}
-
 void CBuildWindow::buyFunc()
 {
 	LOCPLINT->cb->buildBuilding(town,building->bid);
 	GH.popInts(2); //we - build window and hall screen
 }
 
-void CBuildWindow::close()
-{
-	GH.popIntTotally(this);
-}
-
 void CBuildWindow::clickRight(tribool down, bool previousState)
 {
 	if((!down || indeterminate(down)))
@@ -1461,13 +1432,11 @@ std::string CBuildWindow::getTextForState(int state)
 	return ret;
 }
 
-CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Building, int State, bool Mode)
-:town(Town), building(Building), state(State), mode(Mode)
+CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Building, int State, bool Mode):
+	CWindowObject("TPUBUILD", PLAYER_COLORED),
+	town(Town), building(Building), state(State), mode(Mode)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	background = new CPicture("TPUBUILD");
-	pos = background->center();
-	background->colorize(LOCPLINT->playerID);
 
 	buildingPic = new CAnimImage(graphics->buildingPics[town->subID], building->bid, 0, 125, 50);
 	Rect barRect(9, 494, 380, 18);
@@ -1519,7 +1488,7 @@ CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Buildin
 
 	if(mode)
 	{	//popup
-		used |= RCLICK;
+		addUsedEvents(RCLICK);
 	}
 	else
 	{	//normal window
@@ -1539,25 +1508,26 @@ CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Buildin
 CBuildWindow::~CBuildWindow()
 {}
 
-void CFortScreen::close()
+std::string CFortScreen::getBgName(const CGTownInstance *town)
 {
-	GH.popIntTotally(this);
+	ui32 fortSize = town->creatures.size();
+	if (fortSize > GameConstants::CREATURES_PER_TOWN && town->creatures.back().second.empty())
+		fortSize--;
+
+	if (fortSize == GameConstants::CREATURES_PER_TOWN)
+		return "TPCASTL7";
+	else
+		return "TPCASTL8";
 }
 
-CFortScreen::CFortScreen(const CGTownInstance * town)
+CFortScreen::CFortScreen(const CGTownInstance * town):
+    CWindowObject(getBgName(town), PLAYER_COLORED | BORDERED)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	ui32 fortSize = town->creatures.size();
 	if (fortSize > GameConstants::CREATURES_PER_TOWN && town->creatures.back().second.empty())
 		fortSize--;
 	
-	if (fortSize == GameConstants::CREATURES_PER_TOWN)
-		background = new CPicture("TPCASTL7");
-	else
-		background = new CPicture("TPCASTL8");
-	background->colorize(LOCPLINT->playerID);
-	pos = background->center();
-
 	const CBuilding *fortBuilding = CGI->buildh->buildings[town->subID][town->fortLevel()+6];
 	title = new CLabel(400, 12, FONT_BIG, CENTER, Colors::Cornsilk, fortBuilding->Name());
 	
@@ -1624,7 +1594,7 @@ LabeledValue::LabeledValue(Rect size, std::string name, std::string descr, int v
 void LabeledValue::init(std::string nameText, std::string descr, int min, int max)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	used |= HOVER;
+	addUsedEvents(HOVER);
 	hoverText = descr;
 	std::string valueText;
 	if (min && max)
@@ -1660,7 +1630,7 @@ CFortScreen::RecruitArea::RecruitArea(int posX, int posY, const CGTownInstance *
 	pos.h = 126;
 	
 	if (!town->creatures[level].second.empty())
-		used |= LCLICK | RCLICK | HOVER;//Activate only if dwelling is present
+		addUsedEvents(LCLICK | RCLICK | HOVER);//Activate only if dwelling is present
 	
 	icons = new CPicture("ZPCAINFO", 261, 3);
 	buildingPic = new CAnimImage(graphics->buildingPics[town->subID], buildingID, 0, 4, 21);
@@ -1728,12 +1698,11 @@ void CFortScreen::RecruitArea::clickRight(tribool down, bool previousState)
 	clickLeft(down, false); //r-click does same as l-click - opens recr. window
 }
 
-CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner)
+CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner):
+    CWindowObject("TPMAGE", BORDERED)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	
-	background = new CPicture("TPMAGE.bmp");
-	pos = background->center();
 	window = new CPicture(graphics->guildBgs[owner->town->subID], 332, 76);
 	
 	resdatabar = new CMinorResDataBar;
@@ -1767,16 +1736,11 @@ CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner)
 	}
 }
 
-void CMageGuildScreen::close()
-{
-	GH.popIntTotally(this);
-}
-
 CMageGuildScreen::Scroll::Scroll(Point position, const CSpell *Spell)
 	:spell(Spell)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	used = LCLICK | RCLICK | HOVER;
+	addUsedEvents(LCLICK | RCLICK | HOVER);
 	pos += position;
 	image = new CAnimImage("SPELLSCR", spell->id);
 	pos = image->pos;
@@ -1818,13 +1782,11 @@ void CMageGuildScreen::Scroll::hover(bool on)
 
 }
 
-CBlacksmithDialog::CBlacksmithDialog(bool possible, int creMachineID, int aid, int hid)
+CBlacksmithDialog::CBlacksmithDialog(bool possible, int creMachineID, int aid, int hid):
+    CWindowObject("TPSMITH", PLAYER_COLORED)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 
-	background = new CPicture("TPSMITH");
-	pos = background->center();
-	background->colorize(LOCPLINT->playerID);
 	statusBar = new CGStatusBar(164, 370);
 	
 	animBG = new CPicture("TPSMITBK", 64, 50);
@@ -1853,8 +1815,3 @@ CBlacksmithDialog::CBlacksmithDialog(bool possible, int creMachineID, int aid, i
 
 	new CAnimImage("RESOURCE", 6, 0, 148, 244);
 }
-
-void CBlacksmithDialog::close()
-{
-	GH.popIntTotally(this);
-}

+ 8 - 20
client/CCastleInterface.h

@@ -190,7 +190,7 @@ public:
 };
 
 /// Class which manages the castle window
-class CCastleInterface : public CWindowWithGarrison
+class CCastleInterface : public CWindowObject, public CWindowWithGarrison
 {
 	CLabel *title;
 	CLabel *income;
@@ -223,7 +223,6 @@ public:
 	void castleTeleport(int where);
 	void townChange();
 	void keyPressed(const SDL_KeyboardEvent & key);
-	void showAll(SDL_Surface * to);
 	void close();
 	void addBuilding(int bid);
 	void removeBuilding(int bid);
@@ -231,7 +230,7 @@ public:
 };
 
 /// Hall window where you can build things
-class CHallInterface : public CIntObject
+class CHallInterface : public CWindowObject
 {
 	/// Building box from town hall (building icon + subtitle)
 	class CBuildingBox : public CIntObject
@@ -255,7 +254,6 @@ class CHallInterface : public CIntObject
 	const CGTownInstance * town;
 	
 	std::vector< std::vector<CBuildingBox*> >boxes;
-	CPicture *background;
 	CLabel *title;
 	CGStatusBar *statusBar;
 	CMinorResDataBar * resdatabar;
@@ -263,18 +261,16 @@ class CHallInterface : public CIntObject
 
 public:
 	CHallInterface(const CGTownInstance * Town); //c-tor
-	void close();
 };
 
 ///  Window where you can decide to buy a building or not
-class CBuildWindow: public CIntObject
+class CBuildWindow: public CWindowObject
 {
 	const CGTownInstance *town;
 	const CBuilding *building;
 	int state; //state - same as CHallInterface::CBuildingBox::state
 	bool mode; // 0 - normal (with buttons), 1 - r-click popup
 
-	CPicture *background;
 	CAnimImage *buildingPic;
 	CAdventureMapButton *buy;
 	CAdventureMapButton *cancel;
@@ -289,7 +285,6 @@ class CBuildWindow: public CIntObject
 
 	std::string getTextForState(int state);
 	void buyFunc();
-	void close();
 
 public:
 	void clickRight(tribool down, bool previousState);
@@ -312,7 +307,7 @@ public:
 };
 
 /// The fort screen where you can afford units
-class CFortScreen : public CIntObject
+class CFortScreen : public CWindowObject
 {
 	class RecruitArea : public CIntObject
 	{
@@ -337,23 +332,22 @@ class CFortScreen : public CIntObject
 		void clickLeft(tribool down, bool previousState);
 		void clickRight(tribool down, bool previousState);
 	};
-	
-	CPicture *background;
 	CLabel *title;
 	std::vector<RecruitArea*> recAreas;
 	CMinorResDataBar * resdatabar;
 	CGStatusBar *statusBar;
 	CAdventureMapButton *exit;
 
+	std::string getBgName(const CGTownInstance *town);
+
 public:
 	CFortScreen(const CGTownInstance * town); //c-tor
 
 	void creaturesChanged();
-	void close();
 };
 
 /// The mage guild screen where you can see which spells you have
-class CMageGuildScreen : public CIntObject
+class CMageGuildScreen : public CWindowObject
 {
 	class Scroll : public CIntObject
 	{
@@ -366,24 +360,20 @@ class CMageGuildScreen : public CIntObject
 		void clickRight(tribool down, bool previousState);
 		void hover(bool on);
 	};
-	CPicture *background;
 	CPicture *window;
 	CAdventureMapButton *exit;
 	std::vector<Scroll *> spells;
 	CMinorResDataBar * resdatabar;
 	CGStatusBar *statusBar;
 
-	void close();
-
 public:
 	CMageGuildScreen(CCastleInterface * owner);
 };
 
 /// The blacksmith window where you can buy available in town war machine
-class CBlacksmithDialog : public CIntObject
+class CBlacksmithDialog : public CWindowObject
 {
 	CAdventureMapButton *buy, *cancel;
-	CPicture *background;
 	CPicture *animBG;
 	CCreatureAnim * anim;
 	CLabel * title;
@@ -391,8 +381,6 @@ class CBlacksmithDialog : public CIntObject
 	CLabel * costValue;
 	CGStatusBar *statusBar;
 
-	void close();
-
 public:
 	CBlacksmithDialog(bool possible, int creMachineID, int aid, int hid);
 };

+ 3 - 3
client/CCreatureWindow.cpp

@@ -586,7 +586,7 @@ CBonusItem::CBonusItem(const Rect &Pos, const std::string &Name, const std::stri
 	else
 		bonusGraphics = NULL;
 
-	used = 0; //no actions atm
+	removeUsedEvents(ALL); //no actions atm
 }
 
 void CBonusItem::showAll (SDL_Surface * to)
@@ -698,9 +698,9 @@ void CCreInfoWindow::printLine(int position, const std::string &text, int baseVa
 
 void CCreInfoWindow::init(const CCreature *creature, const CBonusSystemNode *stackNode, const CGHeroInstance *heroOwner, int count, bool LClicked)
 {
-	used = 0;
+	removeUsedEvents(ALL);
 	if (!LClicked)
-		used |= RCLICK;
+		addUsedEvents(RCLICK);
 
 	if(!stackNode)
 		stackNode = creature;

+ 3 - 8
client/CHeroWindow.cpp

@@ -83,7 +83,7 @@ CHeroSwitcher::CHeroSwitcher(Point _pos, const CGHeroInstance * _hero):
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	pos += _pos;
-	used = LCLICK;
+	addUsedEvents(LCLICK);
 
 	image = new CAnimImage("PortraitsSmall", hero->portrait);
 	pos.w = image->pos.w;
@@ -210,15 +210,10 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
 		}
 
 		int serial = LOCPLINT->cb->getHeroSerial(curHero, false);
-		if (listSelection && active)
-			listSelection->deactivate();
-		delChildNUll(listSelection);
+
+		vstd::clear_pointer(listSelection);
 		if (serial >= 0)
-		{
 			listSelection = new CPicture("HPSYYY", 612, 33 + serial * 54);
-			if (active)
-				listSelection->activate();
-		}
 	}
 
 	//primary skills support

+ 2 - 2
client/CKingdomInterface.cpp

@@ -35,7 +35,7 @@ InfoBox::InfoBox(Point position, InfoPos Pos, InfoSize Size, IInfoBoxData *Data)
 	name(NULL)
 {
 	assert(data);
-	used = LCLICK | RCLICK;
+	addUsedEvents(LCLICK | RCLICK);
 	EFonts font = (size < SIZE_MEDIUM)? FONT_SMALL: FONT_MEDIUM;
 
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
@@ -597,7 +597,7 @@ void CKingdomInterface::generateMinesList(const std::vector<const CGObjectInstan
 		minesBox[i] = new InfoBox(Point(20+i*80, 31+footerPos), InfoBox::POS_INSIDE, InfoBox::SIZE_SMALL,
 		              new InfoBoxCustom(value, "", "OVMINES", i, CGI->generaltexth->mines[i].first));
 
-		minesBox[i]->used &= ~(LCLICK|RCLICK); //fixes #890 - mines boxes ignore clicks
+		minesBox[i]->removeUsedEvents(LCLICK|RCLICK); //fixes #890 - mines boxes ignore clicks
 	}
 	incomeArea = new CHoverableArea;
 	incomeArea->pos = Rect(pos.x+580, pos.y+31+footerPos, 136, 68);

+ 19 - 4
client/CMT.cpp

@@ -308,10 +308,25 @@ int main(int argc, char** argv)
 
 void printInfoAboutIntObject(const CIntObject *obj, int level)
 {
-	int tabs = level;
-	while(tabs--) tlog4 << '\t';
-
-	tlog4 << typeid(*obj).name() << " *** " << (obj->active ? "" : "not ") << "active";
+	tlog4 << std::string(level, '\t');
+
+	tlog4 << typeid(*obj).name() << " *** ";
+	if (obj->active)
+	{
+#define PRINT(check, text) if (obj->active & CIntObject::check) tlog4 << text
+		PRINT(LCLICK, 'L');
+		PRINT(RCLICK, 'R');
+		PRINT(HOVER, 'H');
+		PRINT(MOVE, 'M');
+		PRINT(KEYBOARD, 'K');
+		PRINT(TIME, 'T');
+		PRINT(GENERAL, 'A');
+		PRINT(WHEEL, 'W');
+		PRINT(DOUBLECLICK, 'D');
+#undef  PRINT
+	}
+	else
+		tlog4 << "inactive";
 	tlog4 << " at " << obj->pos.x <<"x"<< obj->pos.y << "\n";
 
 	BOOST_FOREACH(const CIntObject *child, obj->children)

+ 1 - 1
client/CMessage.cpp

@@ -389,7 +389,7 @@ void CMessage::drawIWindow(CInfoWindow * ret, std::string text, int player)
 	}
 
 	if(ret->text->slider)
-		ret->text->slider->changeUsedEvents(CIntObject::WHEEL | CIntObject::KEYBOARD, true);
+		ret->text->slider->addUsedEvents(CIntObject::WHEEL | CIntObject::KEYBOARD);
 
 	std::pair<int,int> winSize(ret->text->pos.w, ret->text->pos.h); //start with text size
 

+ 0 - 2
client/CPlayerInterface.cpp

@@ -128,8 +128,6 @@ CPlayerInterface::~CPlayerInterface()
 		adventureInt = NULL;
 	}
 
-	if(cingconsole->active) //TODO
-		cingconsole->deactivate();
 	delete cingconsole;
 
 	LOCPLINT = NULL;

+ 30 - 37
client/CPreGame.cpp

@@ -380,7 +380,7 @@ CMenuEntry::CMenuEntry(CMenuScreen* parent, const JsonNode &config)
 
 CreditsScreen::CreditsScreen()
 {
-	used |= LCLICK | RCLICK;
+	addUsedEvents(LCLICK | RCLICK);
 	type |= REDRAW_PARENT;
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	pos.w = CGP->menu->pos.w;
@@ -434,7 +434,7 @@ void CreditsScreen::clickRight(tribool down, bool previousState)
 CGPreGame::CGPreGame():
 	pregameConfig(new JsonNode(GameConstants::DATA_DIR + "/config/mainmenu.json"))
 {
-	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	//OBJ_CONSTRUCTION_CAPTURING_ALL;
 	GH.defActionsDef = 63;
 	CGP = this;
 	menu = new CMenuScreen((*pregameConfig)["window"]);
@@ -1104,7 +1104,7 @@ SelectionTab::SelectionTab(CMenuScreen::EState Type, const boost::function<void(
 {
 	OBJ_CONSTRUCTION;
 	selectionPos = 0;
-	used = LCLICK | WHEEL | KEYBOARD | DOUBLECLICK;
+	addUsedEvents(LCLICK | WHEEL | KEYBOARD | DOUBLECLICK);
 	slider = NULL;
 	txt = NULL;
 	tabType = Type;
@@ -1215,7 +1215,7 @@ SelectionTab::SelectionTab(CMenuScreen::EState Type, const boost::function<void(
 	}
 
 	slider = new CSlider(372, 86, tabType != CMenuScreen::saveGame ? 480 : 430, bind(&SelectionTab::sliderMove, this, _1), positions, curItems.size(), 0, false, 1);
-	slider->changeUsedEvents(WHEEL, true);
+	slider->addUsedEvents(WHEEL);
 	slider->slider->keepFrame = true;
 	format =  CDefHandler::giveDef("SCSELC.DEF");
 
@@ -1546,12 +1546,12 @@ CChatBox::CChatBox(const Rect &rect)
 {
 	OBJ_CONSTRUCTION;
 	pos += rect;
-	used = KEYBOARD;
+	addUsedEvents(KEYBOARD);
 	captureAllKeys = true;
 
 	const int height = graphics->fonts[FONT_SMALL]->height;
 	inputBox = new CTextInput(Rect(0, rect.h - height, rect.w, height));
-	inputBox->used &= ~KEYBOARD;
+	inputBox->removeUsedEvents(KEYBOARD);
 	chatHistory = new CTextBox("", Rect(0, 0, rect.w, rect.h - height), 1);
 
 	SDL_Color green = {0,252,0, SDL_ALPHA_OPAQUE};
@@ -1583,7 +1583,7 @@ InfoCard::InfoCard( bool Network )
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	pos.x += 393;
 	pos.y += 6;
-	used = RCLICK;
+	addUsedEvents(RCLICK);
 	mapDescription = NULL;
 
 	Rect descriptionRect(26, 149, 320, 115);
@@ -1592,12 +1592,12 @@ InfoCard::InfoCard( bool Network )
 	if(SEL->screenType == CMenuScreen::campaignList)
 	{
 		CSelectionScreen *ss = static_cast<CSelectionScreen*>(parent);
-		CGuiHandler::moveChild(new CPicture(*ss->bg, descriptionRect + Point(-393, 0)), this, mapDescription, true); //move subpicture bg to our description control (by default it's our (Infocard) child)
+		mapDescription->addChild(new CPicture(*ss->bg, descriptionRect + Point(-393, 0)), true); //move subpicture bg to our description control (by default it's our (Infocard) child)
 	}
 	else
 	{
 		bg = new CPicture("GSELPOP1.bmp", 0, 0);
-		CGuiHandler::moveChild(bg, this, parent);
+		parent->addChild(bg);
 		auto it = vstd::find(parent->children, this); //our position among parent children
 		parent->children.insert(it, bg); //put BG before us
 		parent->children.pop_back();
@@ -1619,13 +1619,13 @@ InfoCard::InfoCard( bool Network )
 			difficulty->block(true);
 
 		//description needs bg
-		CGuiHandler::moveChild(new CPicture(*bg, descriptionRect), this, mapDescription, true); //move subpicture bg to our description control (by default it's our (Infocard) child)
+		mapDescription->addChild(new CPicture(*bg, descriptionRect), true); //move subpicture bg to our description control (by default it's our (Infocard) child)
 
 		if(network)
 		{
 			playerListBg = new CPicture("CHATPLUG.bmp", 16, 276);
 			chat = new CChatBox(descriptionRect);
-			CGuiHandler::moveChild(new CPicture(*bg, chat->chatHistory->pos - pos), this, chat->chatHistory, true); //move subpicture bg to our description control (by default it's our (Infocard) child)
+			chat->chatHistory->addChild(new CPicture(*bg, chat->chatHistory->pos - pos), true); //move subpicture bg to our description control (by default it's our (Infocard) child)
 
 			chatOn = true;
 			mapDescription->disable();
@@ -2070,13 +2070,8 @@ void OptionsTab::nextBonus( int player, int dir )
 
 void OptionsTab::recreate()
 {
-	bool wasActive = active;
-	if(active)
-		deactivate();
-
 	for(std::map<int, PlayerOptionsEntry*>::iterator it = entries.begin(); it != entries.end(); ++it)
 	{
-		children -= it->second;
 		delete it->second;
 	}
 	entries.clear();
@@ -2092,8 +2087,6 @@ void OptionsTab::recreate()
 			usedHeroes.insert(heroes[hi].heroID);
 	}
 
-	if(wasActive)
-		activate();
 }
 
 void OptionsTab::setTurnLength( int npos )
@@ -2199,7 +2192,8 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry( OptionsTab *owner, PlayerSet
 			serial++;
 	}
 
-	pos = parent->pos + Point(54, 122 + serial*50);
+	pos.x += 54;
+	pos.y += 122 + serial*50;
 
 	static const char *flags[] = {"AOFLGBR.DEF", "AOFLGBB.DEF", "AOFLGBY.DEF", "AOFLGBG.DEF",
 		"AOFLGBO.DEF", "AOFLGBP.DEF", "AOFLGBT.DEF", "AOFLGBS.DEF"};
@@ -2242,13 +2236,15 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry( OptionsTab *owner, PlayerSet
 	else
 		flag = NULL;
 
-	defActions &= ~SHARE_POS;
 	town = new SelectedBox(TOWN, s.color);
-	town->pos += pos + Point(119, 2);
+	town->pos.x += 119;
+	town->pos.y += 2;
 	hero = new SelectedBox(HERO, s.color);
-	hero->pos += pos + Point(195, 2);
+	hero->pos.x += 195;
+	hero->pos.y += 2;
 	bonus = new SelectedBox(BONUS, s.color);
-	bonus->pos += pos + Point(271, 2);
+	bonus->pos.x += 271;
+	bonus->pos.y += 2;
 }
 
 void OptionsTab::PlayerOptionsEntry::showAll(SDL_Surface * to)
@@ -2271,8 +2267,8 @@ void OptionsTab::PlayerOptionsEntry::selectButtons()
 	}
 	else
 	{
-		btns[0]->enable(active);
-		btns[1]->enable(active);
+		btns[0]->enable();
+		btns[1]->enable();
 	}
 
 	if( (pi.defaultHero() != -1  ||  !s.human  ||  s.castle < 0) //fixed hero
@@ -2283,8 +2279,8 @@ void OptionsTab::PlayerOptionsEntry::selectButtons()
 	}
 	else
 	{
-		btns[2]->enable(active);
-		btns[3]->enable(active);
+		btns[2]->enable();
+		btns[3]->enable();
 	}
 
 	if(SEL->isGuest() && s.color != playerColor)//or not our player
@@ -2294,8 +2290,8 @@ void OptionsTab::PlayerOptionsEntry::selectButtons()
 	}
 	else
 	{
-		btns[4]->enable(active);
-		btns[5]->enable(active);
+		btns[4]->enable();
+		btns[5]->enable();
 	}
 }
 
@@ -2314,7 +2310,7 @@ OptionsTab::SelectedBox::SelectedBox( SelType Which, ui8 Player )
 	SDL_Surface *img = getImg();
 	pos.w = img->w;
 	pos.h = img->h;
-	used = RCLICK;
+	addUsedEvents(RCLICK);
 }
 
 SDL_Surface * OptionsTab::SelectedBox::getImg() const
@@ -3032,7 +3028,7 @@ void CBonusSelection::updateBonusSelection()
 	{
 		if (bonuses->buttons[i]->active)
 			bonuses->buttons[i]->deactivate();
-		bonuses->delChild(bonuses->buttons[i]);
+		delete bonuses->buttons[i];
 	}
 	bonuses->buttons.clear();
 
@@ -3196,9 +3192,6 @@ void CBonusSelection::updateBonusSelection()
 			bonusButton->borderColor = Colors::Maize; // yellow border
 			bonuses->addButton(bonusButton);
 		}
-	if (active)
-		for (size_t i=0; i<bonuses->buttons.size(); i++)
-			bonuses->buttons[i]->activate();
 }
 
 void CBonusSelection::startMap()
@@ -3253,7 +3246,7 @@ CBonusSelection::CRegion::CRegion( CBonusSelection * _owner, bool _accessible, b
 : owner(_owner), accessible(_accessible), selectable(_selectable), myNumber(_myNumber)
 {
 	OBJ_CONSTRUCTION;
-	used = LCLICK | RCLICK;
+	addUsedEvents(LCLICK | RCLICK);
 
 	static const std::string colors[2][8] = {
 		{"R", "B", "N", "G", "O", "V", "T", "P"},
@@ -3562,11 +3555,11 @@ CCampaignScreen::CCampaignButton::CCampaignButton(const JsonNode &config )
 
 	if (status != CCampaignScreen::DISABLED)
 	{
-		used |= LCLICK | HOVER;
+		addUsedEvents(LCLICK | HOVER);
 		image = new CPicture(config["image"].String());
 
 		hoverLabel = new CLabel(pos.w / 2, pos.h + 20, FONT_MEDIUM, CENTER, Colors::Jasmine, "");
-		CGuiHandler::moveChild(hoverLabel, this, parent);
+		parent->addChild(hoverLabel);
 	}
 
 	if (status == CCampaignScreen::COMPLETED)

+ 5 - 4
client/CSpellWindow.cpp

@@ -35,7 +35,7 @@ extern SDL_Surface * screen;
 SpellbookInteractiveArea::SpellbookInteractiveArea(const SDL_Rect & myRect, boost::function<void()> funcL,
 	const std::string & textR, boost::function<void()> funcHon, boost::function<void()> funcHoff, CPlayerInterface * _myInt)
 {
-	used = LCLICK | RCLICK | HOVER;
+	addUsedEvents(LCLICK | RCLICK | HOVER);
 	pos = myRect;
 	onLeft = funcL;
 	textOnRclick = textR;
@@ -216,6 +216,7 @@ CSpellWindow::CSpellWindow(const SDL_Rect & myRect, const CGHeroInstance * _myHe
 	currentPage = battleSpellsOnly ? LOCPLINT->spellbookSettings.spellbookLastPageBattle : LOCPLINT->spellbookSettings.spellbokLastPageAdvmap;
 	vstd::abetween(currentPage, 0, pagesWithinCurrentTab());
 	computeSpellsPerArea();
+	addUsedEvents(KEYBOARD);
 }
 
 CSpellWindow::~CSpellWindow()
@@ -460,7 +461,7 @@ void CSpellWindow::computeSpellsPerArea()
 
 void CSpellWindow::activate()
 {
-	activateKeys();
+	CIntObject::activate();
 	exitBtn->activate();
 	battleSpells->activate();
 	adventureSpells->activate();
@@ -483,7 +484,7 @@ void CSpellWindow::activate()
 
 void CSpellWindow::deactivate()
 {
-	deactivateKeys();
+	CIntObject::deactivate();
 	exitBtn->deactivate();
 	battleSpells->deactivate();
 	adventureSpells->deactivate();
@@ -586,7 +587,7 @@ CSpellWindow::SpellArea::SpellArea(SDL_Rect pos, CSpellWindow * owner)
 {
 	this->pos = pos;
 	this->owner = owner;
-	used = LCLICK | RCLICK | HOVER;
+	addUsedEvents(LCLICK | RCLICK | HOVER);
 
 	spellCost = mySpell = whichSchool = schoolLevel = -1;
 }

+ 5 - 4
client/Client.cpp

@@ -310,8 +310,6 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 	if(networkMode != GUEST)
 		myPlayers.insert(255); //neutral
 
-
-
 	CStopWatch tmh;
 	const_cast<CGameInfo*>(CGI)->state = new CGameState();
 	tlog0 <<"\tGamestate: "<<tmh.getDiff()<<std::endl;
@@ -712,8 +710,11 @@ void CServerHandler::callServer()
 	setThreadName(-1, "CServerHandler::callServer");
 	std::string logName = GVCMIDirs.UserPath + "/server_log.txt";
 	std::string comm = GameConstants::BIN_DIR + GameConstants::PATH_SEPARATOR + GameConstants::SERVER_NAME + " " + port + " > " + logName;
-	std::system(comm.c_str());
-	tlog0 << "Server finished\n";
+	int result = std::system(comm.c_str());
+	if (result == 0)
+		tlog1 << "Server closed correctly\n";
+	else
+		tlog0 << "Error: server failed to close correctly or crashed!\n";
 }
 
 CConnection * CServerHandler::justConnectToServer(const std::string &host, const std::string &port)

+ 37 - 135
client/GUIClasses.cpp

@@ -301,26 +301,11 @@ void CGarrisonSlot::clickLeft(tribool down, bool previousState)
 		if(refr) {hover(false);	hover(true); } //to refresh statusbar
 	}
 }
-void CGarrisonSlot::activate()
-{
-	if(!active) active=true;
-	else return;
-	activateLClick();
-	activateRClick();
-	activateHover();
-}
-void CGarrisonSlot::deactivate()
-{
-	if(active) active=false;
-	else return;
-	deactivateLClick();
-	deactivateRClick();
-	deactivateHover();
-}
+
 CGarrisonSlot::CGarrisonSlot(CGarrisonInt *Owner, int x, int y, int IID, int Upg, const CStackInstance * Creature)
 {
+	addUsedEvents(LCLICK | RCLICK | HOVER);
 	//assert(Creature == CGI->creh->creatures[Creature->idNumber]);
-	active = false;
 	upg = Upg;
 	ID = IID;
 	myStack = Creature;
@@ -340,11 +325,7 @@ CGarrisonSlot::CGarrisonSlot(CGarrisonInt *Owner, int x, int y, int IID, int Upg
 	}
 	owner = Owner;
 }
-CGarrisonSlot::~CGarrisonSlot()
-{
-	if(active)
-		deactivate();
-}
+
 void CGarrisonSlot::showAll(SDL_Surface * to)
 {
 	std::map<int,SDL_Surface*> &imgs = (owner->smallIcons ? graphics->smallImgs : graphics->bigImgs);
@@ -376,10 +357,7 @@ CGarrisonInt::~CGarrisonInt()
 
 void CGarrisonInt::addSplitBtn(CAdventureMapButton * button)
 {
-	if (button->parent)
-		GH.moveChild(button, button->parent, this);
-	else
-		addChild(button);
+	addChild(button);
 	button->recActions = defActions;
 	splitButtons.push_back(button);
 }
@@ -421,10 +399,10 @@ void CGarrisonInt::createSlots()
 void CGarrisonInt::deleteSlots()
 {
 	for (int i=0; i<slotsUp.size(); i++)
-		delChildNUll(slotsUp[i]);
+		vstd::clear_pointer(slotsUp[i]);
 
 	for (int i=0; i<slotsDown.size(); i++)
-		delChildNUll(slotsDown[i]);
+		vstd::clear_pointer(slotsDown[i]);
 }
 
 void CGarrisonInt::recreateSlots()
@@ -436,20 +414,8 @@ void CGarrisonInt::recreateSlots()
 	for(size_t i = 0; i<splitButtons.size(); i++)
 		splitButtons[i]->block(true);
 
-	bool wasActive = active;
-	if(active)
-	{
-		deactivate();
-	}
-
 	deleteSlots();
 	createSlots();
-
-	if(wasActive)
-	{
-		activate();
-		showAll(screen2);
-	}
 }
 
 void CGarrisonInt::splitClick()
@@ -677,14 +643,14 @@ void CInfoPopup::init(int x, int y)
 CComponent::CComponent(Etype Type, int Subtype, int Val):
 	image(nullptr)
 {
-	used |= RCLICK;
+	addUsedEvents(RCLICK);
 	init(Type,Subtype,Val);
 }
 
 CComponent::CComponent(const Component &c):
 	image(nullptr)
 {
-	used |= RCLICK;
+	addUsedEvents(RCLICK);
 
 	if(c.id == Component::EXPERIENCE)
 		init(experience,c.subtype,c.val);
@@ -700,7 +666,7 @@ CComponent::CComponent(const Component &c):
 CComponent::CComponent():
 	image(nullptr)
 {
-	used |= RCLICK;
+	addUsedEvents(RCLICK);
 }
 
 void CComponent::init(Etype Type, int Subtype, int Val)
@@ -825,7 +791,7 @@ std::string CComponent::getSubtitle()
 void CComponent::setSurface(std::string defName, int imgPos)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	delChildNUll(image);
+	vstd::clear_pointer(image);
 	image = new CAnimImage(defName, imgPos);
 }
 
@@ -852,14 +818,14 @@ void CSelectableComponent::init()
 CSelectableComponent::CSelectableComponent(const Component &c, boost::function<void()> OnSelect):
 	CComponent(c),onSelect(OnSelect)
 {
-	used |= LCLICK | KEYBOARD;
+	addUsedEvents(LCLICK | KEYBOARD);
 	init();
 }
 
 CSelectableComponent::CSelectableComponent(Etype Type, int Sub, int Val, boost::function<void()> OnSelect):
 	CComponent(Type,Sub,Val),onSelect(OnSelect)
 {
-	used |= LCLICK | KEYBOARD;
+	addUsedEvents(LCLICK | KEYBOARD);
 	init();
 }
 
@@ -1641,7 +1607,7 @@ void CRecruitmentWindow::showAll(SDL_Surface * to)
 CRecruitmentWindow::CRecruitmentWindow(const CGDwelling *Dwelling, int Level, const CArmedInstance *Dst, const boost::function<void(int,int)> &Recruit, int y_offset)
 :recruit(Recruit), dwelling(Dwelling), level(Level), dst(Dst)
 {
-	used = LCLICK | RCLICK;
+	addUsedEvents(LCLICK | RCLICK);
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 
 	which = 0;
@@ -1758,6 +1724,7 @@ CSplitWindow::CSplitWindow(int cid, int max, CGarrisonInt *Owner, int Last, int
 	std::string title = CGI->generaltexth->allTexts[256];
 	boost::algorithm::replace_first(title,"%s",CGI->creh->creatures[cid]->namePl);
 	printAtMiddle(title,150,34,FONT_BIG,Colors::Jasmine,bitmap);
+	addUsedEvents(LCLICK | KEYBOARD);
 }
 
 CSplitWindow::~CSplitWindow() //d-tor
@@ -1770,24 +1737,6 @@ CSplitWindow::~CSplitWindow() //d-tor
 	delete animRight;
 }
 
-void CSplitWindow::activate()
-{
-	activateLClick();
-	activateKeys();
-	ok->activate();
-	cancel->activate();
-	slider->activate();
-}
-
-void CSplitWindow::deactivate()
-{
-	deactivateLClick();
-	deactivateKeys();
-	ok->deactivate();
-	cancel->deactivate();
-	slider->deactivate();
-}
-
 void CSplitWindow::split()
 {
 	gar->splitStacks(a2);
@@ -1992,6 +1941,11 @@ void CLevelWindow::show(SDL_Surface * to)
 }
 
 void CMinorResDataBar::show(SDL_Surface * to)
+{
+
+}
+
+void CMinorResDataBar::showAll(SDL_Surface * to)
 {
 	blitAt(bg,pos.x,pos.y,to);
 	char buf[30];
@@ -2014,11 +1968,6 @@ void CMinorResDataBar::show(SDL_Surface * to)
 		,pos.x+545+(pos.w-545)/2,pos.y+pos.h/2,FONT_SMALL,Colors::Cornsilk,to);
 }
 
-void CMinorResDataBar::showAll(SDL_Surface * to)
-{
-	show(to);
-}
-
 CMinorResDataBar::CMinorResDataBar()
 {
 	bg = BitmapHandler::loadBitmap("Z2ESBAR.bmp");
@@ -2041,7 +1990,7 @@ CObjectListWindow::CItem::CItem(CObjectListWindow *_parent, size_t _id, std::str
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	border = new CPicture("TPGATES");
 	pos = border->pos;
-	used |= LCLICK;
+	addUsedEvents(LCLICK);
 	type |= REDRAW_PARENT;
 
 	text = new CLabel(pos.w/2, pos.h/2, FONT_SMALL, CENTER, Colors::Cornsilk, _text);
@@ -2192,7 +2141,7 @@ CTradeWindow::CTradeableItem::CTradeableItem( EType Type, int ID, bool Left, int
 	left = Left;
 	type = Type;
 	id = ID;
-	used = LCLICK | HOVER | RCLICK;
+	addUsedEvents(LCLICK | HOVER | RCLICK);
 	downSelection = false;
 	hlp = NULL;
 }
@@ -2661,10 +2610,8 @@ void CTradeWindow::removeItems(const std::set<CTradeableItem *> &toRemove)
 
 void CTradeWindow::removeItem(CTradeableItem * t)
 {
-	if(active)
-		t->deactivate();
 	items[t->left] -= t;
-	delChild(t);
+	delete t;
 
 	if(hRight == t)
 	{
@@ -2860,14 +2807,13 @@ CMarketplaceWindow::~CMarketplaceWindow()
 {
 	hLeft = hRight = NULL;
 	for(int i=0;i<items[1].size();i++)
-		delChild(items[1][i]);
+		delete items[1][i];
 	for(int i=0;i<items[0].size();i++)
-		delChild(items[0][i]);
+		delete items[0][i];
 
 	items[1].clear();
 	items[0].clear();
-	delChild(bg);
-	bg = NULL;
+	vstd::clear_pointer(bg);
 }
 
 
@@ -3933,7 +3879,7 @@ void CTavernWindow::HeroPortrait::clickRight(tribool down, bool previousState)
 CTavernWindow::HeroPortrait::HeroPortrait(int &sel, int id, int x, int y, const CGHeroInstance *H)
 : h(H), _sel(&sel), _id(id)
 {
-	used = LCLICK | RCLICK | HOVER;
+	addUsedEvents(LCLICK | RCLICK | HOVER);
 	h = H;
 	pos.x = x;
 	pos.y = y;
@@ -3970,16 +3916,6 @@ void CTavernWindow::HeroPortrait::hover( bool on )
 		GH.statusbar->clear();
 }
 
-void CInGameConsole::activate()
-{
-	activateKeys();
-}
-
-void CInGameConsole::deactivate()
-{
-	deactivateKeys();
-}
-
 void CInGameConsole::show(SDL_Surface * to)
 {
 	int number = 0;
@@ -4181,21 +4117,15 @@ void CInGameConsole::refreshEnteredText()
 
 CInGameConsole::CInGameConsole() : prevEntDisp(-1), defaultTimeout(10000), maxDisplayedTexts(10)
 {
+	addUsedEvents(KEYBOARD);
 }
 
-void CGarrisonWindow::close()
-{
-	GH.popIntTotally(this);
-}
-
-CGarrisonWindow::CGarrisonWindow( const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits )
+CGarrisonWindow::CGarrisonWindow( const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits ):
+    CWindowObject("GARRISON", PLAYER_COLORED)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	bg = new CPicture("GARRISON.bmp");
-	bg->colorizeAndConvert(LOCPLINT->playerID);
-	pos = bg->center();
 
-	garr = new CGarrisonInt(92, 127, 4, Point(0,96), bg->bg, Point(93,127), up, down, removableUnits);
+	garr = new CGarrisonInt(92, 127, 4, Point(0,96), background->bg, Point(93,127), up, down, removableUnits);
 	{
 		CAdventureMapButton *split = new CAdventureMapButton(CGI->generaltexth->tcommands[3],"",boost::bind(&CGarrisonInt::splitClick,garr),88,314,"IDV6432.DEF");
 		removeChild(split);
@@ -4220,7 +4150,7 @@ CGarrisonWindow::~CGarrisonWindow()
 
 void CGarrisonWindow::showAll(SDL_Surface * to)
 {
-	CIntObject::showAll(to);
+	CWindowObject::showAll(to);
 
 	blitAtLoc(graphics->flags->ourImages[garr->armedObjs[1]->getOwner()].bitmap,28,124,to);
 	blitAtLoc(graphics->portraitLarge[static_cast<const CGHeroInstance*>(garr->armedObjs[1])->portrait],29,222,to);
@@ -4253,14 +4183,6 @@ CArtPlace::CArtPlace(Point position, const CArtifactInstance * Art):
 	pos.w = pos.h = 44;
 }
 
-void CArtPlace::activate()
-{
-	if(!active)
-	{
-		LRClickableAreaWTextComp::activate();
-	}
-}
-
 void CArtPlace::clickLeft(tribool down, bool previousState)
 {
 	//LRClickableAreaWTextComp::clickLeft(down);
@@ -4481,14 +4403,6 @@ void CArtPlace::deselect ()
 	ourOwner->safeRedraw();
 }
 
-void CArtPlace::deactivate()
-{
-	if(active)
-	{
-		LRClickableAreaWTextComp::deactivate();
-	}
-}
-
 void CArtPlace::showAll(SDL_Surface * to)
 {
 	if (ourArt && !picked && ourArt == ourOwner->curHero->getArt(slotID, false)) //last condition is needed for disassembling -> artifact may be gone, but we don't know yet TODO: real, nice solution
@@ -4615,7 +4529,7 @@ void LRClickableAreaWTextComp::clickRight(tribool down, bool previousState)
 
 CHeroArea::CHeroArea(int x, int y, const CGHeroInstance * _hero):hero(_hero)
 {
-	used = LCLICK | RCLICK | HOVER;
+	addUsedEvents(LCLICK | RCLICK | HOVER);
 	pos.x += x;	pos.w = 58;
 	pos.y += y;	pos.h = 64;
 }
@@ -5543,7 +5457,7 @@ CTransformerWindow::CItem::CItem(CTransformerWindow * _parent, int _size, int _i
 	id(_id), size(_size), parent(_parent)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	used = LCLICK;
+	addUsedEvents(LCLICK);
 	left = true;
 	pos.w = 58;
 	pos.h = 64;
@@ -5687,7 +5601,7 @@ CUniversityWindow::CItem::CItem(CUniversityWindow * _parent, int _ID, int X, int
 	ID(_ID),
 	parent(_parent)
 {
-	used = LCLICK | RCLICK | HOVER;
+	addUsedEvents(LCLICK | RCLICK | HOVER);
 }
 
 CUniversityWindow::CUniversityWindow(const CGHeroInstance * _hero, const IMarket * _market):hero(_hero), market(_market)
@@ -6207,12 +6121,9 @@ void MoraleLuckBox::set(const IBonusBearer *node)
 		imageName = morale ? "IMRL30": "ILCK30";
 	else
 		imageName = morale ? "IMRL42" : "ILCK42";
-	if (image && active)
-		image->deactivate();
-	delChildNUll(image);
+
+	delete image;
 	image = new CAnimImage(imageName, bonusValue + 3);
-	if (active)
-		image->activate();
 	image->moveBy(Point(pos.w/2 - image->pos.w/2, pos.h/2 - image->pos.h/2));//center icon
 }
 
@@ -6305,16 +6216,6 @@ void CRClickPopup::clickRight(tribool down, bool previousState)
 	close();
 }
 
-void CRClickPopup::activate()
-{
-	activateRClick();
-}
-
-void CRClickPopup::deactivate()
-{
-	deactivateRClick();
-}
-
 void CRClickPopup::close()
 {
 	GH.popIntTotally(this);
@@ -6342,6 +6243,7 @@ void CRClickPopup::createAndPush(const CGObjectInstance *obj, const Point &p, EA
 
 CRClickPopup::CRClickPopup()
 {
+	addUsedEvents(RCLICK);
 }
 
 CRClickPopup::~CRClickPopup()

+ 4 - 18
client/GUIClasses.h

@@ -118,8 +118,6 @@ public:
 class CRClickPopup : public CIntObject
 {
 public:
-	virtual void activate();
-	virtual void deactivate();
 	virtual void close();
 	void clickRight(tribool down, bool previousState);
 
@@ -152,7 +150,7 @@ public:
 	void show(SDL_Surface * to);
 	CInfoPopup(SDL_Surface * Bitmap, int x, int y, bool Free=false); //c-tor
 	CInfoPopup(SDL_Surface * Bitmap, const Point &p, EAlignment alignment, bool Free=false); //c-tor
-	CInfoPopup(SDL_Surface *Bitmap = NULL, bool Free = false); //default c-tor
+	CInfoPopup(SDL_Surface * Bitmap = NULL, bool Free = false); //default c-tor
 
 	void init(int x, int y);
 	~CInfoPopup(); //d-tor
@@ -181,7 +179,7 @@ public:
 	std::string description; //r-click
 	std::string subtitle; //TODO: comment me
 
-	virtual void init(Etype Type, int Subtype, int Val);
+	void init(Etype Type, int Subtype, int Val);
 	CComponent(Etype Type, int Subtype, int Val); //c-tor
 	CComponent(const Component &c); //c-tor
 	CComponent(); //c-tor
@@ -221,7 +219,6 @@ public:
 	const CCreature *creature;
 	int count; //number of creatures
 	int upg; //0 - up garrison, 1 - down garrison
-	bool active; //TODO: comment me
 	bool highlight;
 
 	virtual void hover (bool on); //call-in
@@ -229,11 +226,8 @@ public:
 	bool our();
 	void clickRight(tribool down, bool previousState);
 	void clickLeft(tribool down, bool previousState);
-	void activate();
-	void deactivate();
 	void showAll(SDL_Surface * to);
 	CGarrisonSlot(CGarrisonInt *Owner, int x, int y, int IID, int Upg=0, const CStackInstance * Creature=NULL);
-	~CGarrisonSlot(); //d-tor
 };
 
 /// Class which manages slots of upper and lower garrison, splitting of units
@@ -400,10 +394,8 @@ public:
 
 	CSplitWindow(int cid, int max, CGarrisonInt *Owner, int Last = -1, int val=0); //c-tor; val - initial amount of second stack
 	~CSplitWindow(); //d-tor
-	void activate();
 	void split();
 	void close();
-	void deactivate();
 	void show(SDL_Surface * to);
 	void clickLeft(tribool down, bool previousState); //call-in
 	void keyPressed (const SDL_KeyboardEvent & key); //call-in
@@ -748,8 +740,6 @@ private:
 	int maxDisplayedTexts; //hiw many texts can be displayed simultaneously
 public:
 	std::string enteredText;
-	void activate();
-	void deactivate();
 	void show(SDL_Surface * to);
 	void print(const std::string &txt);
 	void keyPressed (const SDL_KeyboardEvent & key); //call-in
@@ -829,8 +819,6 @@ public:
 	void clickRight(tribool down, bool previousState);
 	void select ();
 	void deselect ();
-	void activate();
-	void deactivate();
 	void showAll(SDL_Surface * to);
 	bool fitsHere (const CArtifactInstance * art) const; //returns true if given artifact can be placed here
 
@@ -915,7 +903,7 @@ public:
 	virtual void updateGarrisons(){};
 };
 
-class CWindowWithGarrison : public CGarrisonHolder
+class CWindowWithGarrison : public virtual CGarrisonHolder
 {
 public:
 	CGarrisonInt *garr;
@@ -923,14 +911,12 @@ public:
 };
 
 /// Garrison window where you can take creatures out of the hero to place it on the garrison
-class CGarrisonWindow : public CWindowWithGarrison
+class CGarrisonWindow : public CWindowObject, public CWindowWithGarrison
 {
 public:
-	CPicture *bg; //background surface
 	CLabel *title;
 	CAdventureMapButton *quit;
 
-	void close();
 	void showAll(SDL_Surface * to);
 	CGarrisonWindow(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits); //c-tor
 	~CGarrisonWindow(); //d-tor

+ 1 - 11
client/UIFramework/CGuiHandler.cpp

@@ -125,10 +125,7 @@ void CGuiHandler::updateTime()
 	for (std::list<CIntObject*>::iterator i=hlp.begin(); i != hlp.end();i++)
 	{
 		if(!vstd::contains(timeinterested,*i)) continue;
-		if ((*i)->toNextTick>=0)
-			(*i)->toNextTick-=tv;
-		if ((*i)->toNextTick<0)
-			(*i)->tick();
+		(*i)->onTimer(tv);
 	}
 }
 
@@ -386,13 +383,6 @@ void CGuiHandler::breakEventHandling()
 	current = NULL;
 }
 
-CIntObject * CGuiHandler::moveChild(CIntObject *obj, CIntObject *from, CIntObject *to, bool adjustPos)
-{
-	from->removeChild(obj, adjustPos);
-	to->addChild(obj, adjustPos);
-	return obj;
-}
-
 void CGuiHandler::drawFPSCounter()
 {
 	const static SDL_Color yellow = {255, 255, 0, 0};

+ 0 - 1
client/UIFramework/CGuiHandler.h

@@ -91,7 +91,6 @@ public:
 	ui8 captureChildren; //all newly created objects will get their parents from stack and will be added to parents children list
 	std::list<CIntObject *> createdObj; //stack of objs being created
 	
-	static CIntObject * moveChild(CIntObject *obj, CIntObject *from, CIntObject *to, bool adjustPos = false);
 	static SDLKey arrowToNum(SDLKey key); //converts arrow key to according numpad key
 	static SDLKey numToDigit(SDLKey key);//converts numpad digit key to normal digit key
 	static bool isNumKey(SDLKey key, bool number = true); //checks if key is on numpad (numbers - check only for numpad digits)

+ 133 - 131
client/UIFramework/CIntObject.cpp

@@ -6,7 +6,7 @@
 void CIntObject::activateLClick()
 {
 	GH.lclickable.push_front(this);
-	active |= LCLICK;
+	active_m |= LCLICK;
 }
 
 void CIntObject::deactivateLClick()
@@ -14,17 +14,13 @@ void CIntObject::deactivateLClick()
 	std::list<CIntObject*>::iterator hlp = std::find(GH.lclickable.begin(),GH.lclickable.end(),this);
 	assert(hlp != GH.lclickable.end());
 	GH.lclickable.erase(hlp);
-	active &= ~LCLICK;
-}
-
-void CIntObject::clickLeft(tribool down, bool previousState)
-{
+	active_m &= ~LCLICK;
 }
 
 void CIntObject::activateRClick()
 {
 	GH.rclickable.push_front(this);
-	active |= RCLICK;
+	active_m |= RCLICK;
 }
 
 void CIntObject::deactivateRClick()
@@ -32,17 +28,13 @@ void CIntObject::deactivateRClick()
 	std::list<CIntObject*>::iterator hlp = std::find(GH.rclickable.begin(),GH.rclickable.end(),this);
 	assert(hlp != GH.rclickable.end());
 	GH.rclickable.erase(hlp);
-	active &= ~RCLICK;
-}
-
-void CIntObject::clickRight(tribool down, bool previousState)
-{
+	active_m &= ~RCLICK;
 }
 
 void CIntObject::activateHover()
 {
 	GH.hoverable.push_front(this);
-	active |= HOVER;
+	active_m |= HOVER;
 }
 
 void CIntObject::deactivateHover()
@@ -50,17 +42,13 @@ void CIntObject::deactivateHover()
 	std::list<CIntObject*>::iterator hlp = std::find(GH.hoverable.begin(),GH.hoverable.end(),this);
 	assert(hlp != GH.hoverable.end());
 	GH.hoverable.erase(hlp);
-	active &= ~HOVER;
-}
-
-void CIntObject::hover( bool on )
-{
+	active_m &= ~HOVER;
 }
 
 void CIntObject::activateKeys()
 {
 	GH.keyinterested.push_front(this);
-	active |= KEYBOARD;
+	active_m |= KEYBOARD;
 }
 
 void CIntObject::deactivateKeys()
@@ -68,17 +56,13 @@ void CIntObject::deactivateKeys()
 	std::list<CIntObject*>::iterator hlp = std::find(GH.keyinterested.begin(),GH.keyinterested.end(),this);
 	assert(hlp != GH.keyinterested.end());
 	GH.keyinterested.erase(hlp);
-	active &= ~KEYBOARD;
-}
-
-void CIntObject::keyPressed( const SDL_KeyboardEvent & key )
-{
+	active_m &= ~KEYBOARD;
 }
 
 void CIntObject::activateMouseMove()
 {
 	GH.motioninterested.push_front(this);
-	active |= MOVE;
+	active_m |= MOVE;
 }
 
 void CIntObject::deactivateMouseMove()
@@ -86,17 +70,41 @@ void CIntObject::deactivateMouseMove()
 	std::list<CIntObject*>::iterator hlp = std::find(GH.motioninterested.begin(),GH.motioninterested.end(),this);
 	assert(hlp != GH.motioninterested.end());
 	GH.motioninterested.erase(hlp);
-	active &= ~MOVE;
+	active_m &= ~MOVE;
+}
+
+void CIntObject::activateWheel()
+{
+	GH.wheelInterested.push_front(this);
+	active_m |= WHEEL;
+}
+
+void CIntObject::deactivateWheel()
+{
+	std::list<CIntObject*>::iterator hlp = std::find(GH.wheelInterested.begin(),GH.wheelInterested.end(),this);
+	assert(hlp != GH.wheelInterested.end());
+	GH.wheelInterested.erase(hlp);
+	active_m &= ~WHEEL;
+}
+
+void CIntObject::activateDClick()
+{
+	GH.doubleClickInterested.push_front(this);
+	active_m |= DOUBLECLICK;
 }
 
-void CIntObject::mouseMoved( const SDL_MouseMotionEvent & sEvent )
+void CIntObject::deactivateDClick()
 {
+	std::list<CIntObject*>::iterator hlp = std::find(GH.doubleClickInterested.begin(),GH.doubleClickInterested.end(),this);
+	assert(hlp != GH.doubleClickInterested.end());
+	GH.doubleClickInterested.erase(hlp);
+	active_m &= ~DOUBLECLICK;
 }
 
 void CIntObject::activateTimer()
 {
 	GH.timeinterested.push_back(this);
-	active |= TIME;
+	active_m |= TIME;
 }
 
 void CIntObject::deactivateTimer()
@@ -104,39 +112,46 @@ void CIntObject::deactivateTimer()
 	std::list<CIntObject*>::iterator hlp = std::find(GH.timeinterested.begin(),GH.timeinterested.end(),this);
 	assert(hlp != GH.timeinterested.end());
 	GH.timeinterested.erase(hlp);
-	active &= ~TIME;
-}
-
-void CIntObject::tick()
-{
+	active_m &= ~TIME;
 }
 
-CIntObject::CIntObject()
+CIntObject::CIntObject(int used_, Point pos_):
+	parent_m(nullptr),
+	active_m(0),
+	parent(parent_m),
+	active(active_m)
 {
 	pressedL = pressedR = hovered = captureAllKeys = strongInterest = false;
-	toNextTick = active = used = 0;
+	toNextTick = timerDelay = 0;
+	used = used_;
 
 	recActions = defActions = GH.defActionsDef;
 
-	pos.x = 0;
-	pos.y = 0;
+	pos.x = pos_.x;
+	pos.y = pos_.y;
 	pos.w = 0;
 	pos.h = 0;
 
 	if(GH.captureChildren)
-	{
-		assert(GH.createdObj.size());
-		parent = GH.createdObj.front();
-		parent->children.push_back(this);
+		GH.createdObj.front()->addChild(this, true);
+}
 
-		if(parent->defActions & SHARE_POS)
-		{
-			pos.x = parent->pos.x;
-			pos.y = parent->pos.y;
-		}
+void CIntObject::setTimer(int msToTrigger)
+{
+	if (!active & TIME )
+		activateTimer();
+	toNextTick = timerDelay = msToTrigger;
+	used |= TIME;
+}
+
+void CIntObject::onTimer(int timePassed)
+{
+	toNextTick -= timePassed;
+	if (toNextTick < 0)
+	{
+		toNextTick += timerDelay;
+		tick();
 	}
-	else
-		parent = NULL;
 }
 
 void CIntObject::show(SDL_Surface * to)
@@ -155,15 +170,23 @@ void CIntObject::showAll(SDL_Surface * to)
 			if(children[i]->recActions & SHOWALL)
 				children[i]->showAll(to);
 
-	}
+	}//FIXME: needed?
+	/*
 	else
-		show(to);
+		show(to);*/
 }
 
 void CIntObject::activate()
 {
-	assert(!active);
-	active |= GENERAL;
+	if (active_m)
+	{
+		if ((used | GENERAL) == active_m)
+			return;
+		else
+			deactivate(); //FIXME: better to avoid such possibility at all
+	}
+
+	active_m |= GENERAL;
 	activate(used);
 
 	if(defActions & ACTIVATE)
@@ -194,11 +217,13 @@ void CIntObject::activate(ui16 what)
 
 void CIntObject::deactivate()
 {
-	assert(active);
-	active &= ~ GENERAL;
-	deactivate(used);
+	if (!active_m)
+		return;
 
-	assert(!active);
+	active_m &= ~ GENERAL;
+	deactivate(active_m);
+
+	assert(!active_m);
 
 	if(defActions & DEACTIVATE)
 		for(size_t i = 0; i < children.size(); i++)
@@ -218,7 +243,7 @@ void CIntObject::deactivate(ui16 what)
 		deactivateMouseMove();
 	if(what & KEYBOARD)
 		deactivateKeys();
-	if(what & TIME)			// TIME is special
+	if(what & TIME)
 		deactivateTimer();
 	if(what & WHEEL)
 		deactivateWheel();
@@ -228,15 +253,20 @@ void CIntObject::deactivate(ui16 what)
 
 CIntObject::~CIntObject()
 {
-	assert(!active); //do not delete active obj
+	if (active_m)
+		deactivate();
 
 	if(defActions & DISPOSE)
-		for(size_t i = 0; i < children.size(); i++)
-			if(children[i]->recActions & DISPOSE)
-				delete children[i];
+	{
+		while (!children.empty())
+			if(children.front()->recActions & DISPOSE)
+				delete children.front();
+			else
+				removeChild(children.front());
+	}
 
-	if(parent && GH.createdObj.size()) //temporary object destroyed
-		parent->children -= this;
+	if(parent_m)
+		parent_m->removeChild(this);
 }
 
 void CIntObject::printAtLoc( const std::string & text, int x, int y, EFonts font, SDL_Color kolor/*=Colors::Cornsilk*/, SDL_Surface * dst/*=screen*/ )
@@ -274,6 +304,20 @@ void CIntObject::printToLoc( const std::string & text, int x, int y, EFonts font
 	CSDL_Ext::printTo(text, pos.x + x, pos.y + y, font, kolor, dst);
 }
 
+void CIntObject::addUsedEvents(ui16 newActions)
+{
+	if (active_m)
+		activate(newActions & ~used);
+	used |= newActions;
+}
+
+void CIntObject::removeUsedEvents(ui16 newActions)
+{
+	if (active_m)
+		deactivate(newActions & used);
+	used &= ~newActions;
+}
+
 void CIntObject::disable()
 {
 	if(active)
@@ -282,9 +326,9 @@ void CIntObject::disable()
 	recActions = DISPOSE;
 }
 
-void CIntObject::enable(bool activation)
+void CIntObject::enable()
 {
-	if(!active && activation)
+	if(!active_m && parent_m->active)
 		activate();
 
 	recActions = 255;
@@ -300,42 +344,6 @@ bool CIntObject::isItInLoc( const SDL_Rect &rect, const Point &p )
 	return isItIn(&rect, p.x - pos.x, p.y - pos.y);
 }
 
-void CIntObject::activateWheel()
-{
-	GH.wheelInterested.push_front(this);
-	active |= WHEEL;
-}
-
-void CIntObject::deactivateWheel()
-{
-	std::list<CIntObject*>::iterator hlp = std::find(GH.wheelInterested.begin(),GH.wheelInterested.end(),this);
-	assert(hlp != GH.wheelInterested.end());
-	GH.wheelInterested.erase(hlp);
-	active &= ~WHEEL;
-}
-
-void CIntObject::wheelScrolled(bool down, bool in)
-{
-}
-
-void CIntObject::activateDClick()
-{
-	GH.doubleClickInterested.push_front(this);
-	active |= DOUBLECLICK;
-}
-
-void CIntObject::deactivateDClick()
-{
-	std::list<CIntObject*>::iterator hlp = std::find(GH.doubleClickInterested.begin(),GH.doubleClickInterested.end(),this);
-	assert(hlp != GH.doubleClickInterested.end());
-	GH.doubleClickInterested.erase(hlp);
-	active &= ~DOUBLECLICK;
-}
-
-void CIntObject::onDoubleClick()
-{
-}
-
 void CIntObject::fitToScreen(int borderWidth, bool propagate)
 {
 	Point newPos = pos.topLeft();
@@ -361,48 +369,42 @@ void CIntObject::moveTo( const Point &p, bool propagate /*= true*/ )
 	moveBy(Point(p.x - pos.x, p.y - pos.y), propagate);
 }
 
-void CIntObject::delChild(CIntObject *child)
-{
-	children -= child;
-	delete child;
-}
-
 void CIntObject::addChild(CIntObject *child, bool adjustPosition /*= false*/)
 {
-	assert(!vstd::contains(children, child));
-	assert(child->parent == NULL);
+	if (vstd::contains(children, child))
+	{
+		tlog4<< "Warning: object already assigned to this parent!\n";
+		return;
+	}
+	if (child->parent_m)
+	{
+		tlog4<< "Warning: object already has parent!\n";
+		child->parent_m->removeChild(child, adjustPosition);
+	}
 	children.push_back(child);
-	child->parent = this;
+	child->parent_m = this;
 	if(adjustPosition)
 		child->pos += pos;
+
+	if (!active && child->active)
+		child->deactivate();
+	if (active && !child->active)
+		child->activate();
 }
 
 void CIntObject::removeChild(CIntObject *child, bool adjustPosition /*= false*/)
 {
+	if (!child)
+		return;
+
 	assert(vstd::contains(children, child));
-	assert(child->parent == this);
+	assert(child->parent_m == this);
 	children -= child;
-	child->parent = NULL;
+	child->parent_m = NULL;
 	if(adjustPosition)
 		child->pos -= pos;
 }
 
-void CIntObject::changeUsedEvents(ui16 what, bool enable, bool adjust /*= true*/)
-{
-	if(enable)
-	{
-		used |= what;
-		if(adjust && active)
-			activate(what);
-	}
-	else
-	{
-		used &= ~what;
-		if(adjust && active)
-			deactivate(what);
-	}
-}
-
 void CIntObject::drawBorderLoc(SDL_Surface * sur, const Rect &r, const int3 &color)
 {
 	CSDL_Ext::drawBorder(sur, r + pos, color);
@@ -410,9 +412,9 @@ void CIntObject::drawBorderLoc(SDL_Surface * sur, const Rect &r, const int3 &col
 
 void CIntObject::redraw()
 {
-	if (parent && (type & REDRAW_PARENT))
+	if (parent_m && (type & REDRAW_PARENT))
 	{
-		parent->redraw();
+		parent_m->redraw();
 	}
 	else
 	{
@@ -463,4 +465,4 @@ void CKeyShortcut::keyPressed(const SDL_KeyboardEvent & key)
 			clickLeft(false, prev);
 		}
 	}
-}
+}

+ 96 - 66
client/UIFramework/CIntObject.h

@@ -5,6 +5,8 @@
 #include "../FontBase.h"
 
 struct SDL_Surface;
+class CPicture;
+class CGuiHandler;
 
 /*
  * CIntObject.h, part of VCMI engine
@@ -64,110 +66,133 @@ public:
 	virtual ~IStatusBar(){}; //d-tor
 	virtual void print(const std::string & text)=0; //prints text and refreshes statusbar
 	virtual void clear()=0;//clears statusbar and refreshes
-	virtual void show(SDL_Surface * to)=0; //shows statusbar (with current text)
 	virtual std::string getCurrent()=0; //returns currently displayed text
 };
 
 // Base UI element
 class CIntObject : public IShowActivatable //interface object
 {
-public:
-	CIntObject *parent; //parent object
-	std::vector<CIntObject *> children;
-
-	Rect pos, //position of object on the screen
-		posRelative; //position of object in the parent (not used if no parent)
+	//activate or deactivate specific action (LCLICK, RCLICK...)
+	void activate(ui16 what);
+	void deactivate(ui16 what);
 
-	CIntObject();
-	virtual ~CIntObject(); //d-tor
+	ui16 used;//change via addUsed() or delUsed
 
 	//l-clicks handling
-	bool pressedL; //for determining if object is L-pressed
 	void activateLClick();
 	void deactivateLClick();
-	virtual void clickLeft(tribool down, bool previousState);
 
 	//r-clicks handling
-	bool pressedR; //for determining if object is R-pressed
 	void activateRClick();
 	void deactivateRClick();
-	virtual void clickRight(tribool down, bool previousState);
 
 	//hover handling
-	bool hovered;  //for determining if object is hovered
 	void activateHover();
 	void deactivateHover();
-	virtual void hover (bool on);
+
+	//double click
+	void activateDClick();
+	void deactivateDClick();
+
+	//mouse wheel
+	void activateWheel();
+	void deactivateWheel();
+
+	//time handling
+	int toNextTick;
+	int timerDelay;
+	void activateTimer();
+	void deactivateTimer();
+	void onTimer(int timePassed);
+
+	//non-const versions of fields to allow changing them in CIntObject
+	CIntObject *parent_m; //parent object
+	ui16 active_m;
+
+public:
+/*
+ * Functions and fields that supposed to be private but are not for now.
+ * Don't use them unless you really know what they are for
+ */
+	std::vector<CIntObject *> children;
 
 	//keyboard handling
-	bool captureAllKeys; //if true, only this object should get info about pressed keys
 	void activateKeys();
 	void deactivateKeys();
-	virtual void keyPressed(const SDL_KeyboardEvent & key);
-	virtual bool captureThisEvent(const SDL_KeyboardEvent & key); //allows refining captureAllKeys against specific events (eg. don't capture ENTER)
 
 	//mouse movement handling
-	bool strongInterest; //if true - report all mouse movements, if not - only when hovered
 	void activateMouseMove();
 	void deactivateMouseMove();
-	virtual void mouseMoved (const SDL_MouseMotionEvent & sEvent);
+
+/*
+ * Public interface
+ */
+
+	/// read-only parent access. May not be a "clean" solution but allows some compatibility
+	CIntObject * const & parent;
+
+	/// position of object on the screen. Please do not modify this anywhere but in constructor - use moveBy\moveTo instead
+	/*const*/ Rect pos;
+
+	CIntObject(int used=0, Point offset=Point());
+	virtual ~CIntObject(); //d-tor
+
+	//l-clicks handling
+	/*const*/ bool pressedL; //for determining if object is L-pressed
+	virtual void clickLeft(tribool down, bool previousState){}
+
+	//r-clicks handling
+	/*const*/ bool pressedR; //for determining if object is R-pressed
+	virtual void clickRight(tribool down, bool previousState){}
+
+	//hover handling
+	/*const*/ bool hovered;  //for determining if object is hovered
+	virtual void hover (bool on){}
+
+	//keyboard handling
+	bool captureAllKeys; //if true, only this object should get info about pressed keys
+	virtual void keyPressed(const SDL_KeyboardEvent & key){}
+	virtual bool captureThisEvent(const SDL_KeyboardEvent & key); //allows refining captureAllKeys against specific events (eg. don't capture ENTER)
+
+	//mouse movement handling
+	bool strongInterest; //if true - report all mouse movements, if not - only when hovered
+	virtual void mouseMoved (const SDL_MouseMotionEvent & sEvent){}
 
 	//time handling
-	int toNextTick;
-	void activateTimer();
-	void deactivateTimer();
-	virtual void tick();
+	void setTimer(int msToTrigger);//set timer delay and activate timer if needed.
+	virtual void tick(){}
 
 	//mouse wheel
-	void activateWheel();
-	void deactivateWheel();
-	virtual void wheelScrolled(bool down, bool in);
+	virtual void wheelScrolled(bool down, bool in){}
 
 	//double click
-	void activateDClick();
-	void deactivateDClick();
-	virtual void onDoubleClick();
+	virtual void onDoubleClick(){}
 
 	enum {LCLICK=1, RCLICK=2, HOVER=4, MOVE=8, KEYBOARD=16, TIME=32, GENERAL=64, WHEEL=128, DOUBLECLICK=256, ALL=0xffff};
-	ui16 active;
-	ui16 used;
+	const ui16 & active;
+	void addUsedEvents(ui16 newActions);
+	void removeUsedEvents(ui16 newActions);
 
 	enum {ACTIVATE=1, DEACTIVATE=2, UPDATE=4, SHOWALL=8, DISPOSE=16, SHARE_POS=32};
 	ui8 defActions; //which calls will be tried to be redirected to children
-	ui8 recActions; //which calls we allow te receive from parent
-
-	enum EAlignment {TOPLEFT, CENTER, BOTTOMRIGHT};
+	ui8 recActions; //which calls we allow to receive from parent
 
 	void disable(); //deactivates if needed, blocks all automatic activity, allows only disposal
-	void enable(bool activation = true); //activates if needed, all activity enabled (Warning: may not be symetric with disable if recActions was limited!)
+	void enable(); //activates if needed, all activity enabled (Warning: may not be symetric with disable if recActions was limited!)
 
 	// activate or deactivate object. Inactive object won't receive any input events (keyboard\mouse)
 	// usually used automatically by parent
 	void activate();
 	void deactivate();
 
-	//activate or deactivate specific action (LCLICK, RCLICK...)
-	void activate(ui16 what);
-	void deactivate(ui16 what);
-
 	//called each frame to update screen
 	void show(SDL_Surface * to);
 	//called on complete redraw only
 	void showAll(SDL_Surface * to);
-	//request complete redraw
+	//request complete redraw of this object
 	void redraw();
 
-	void drawBorderLoc(SDL_Surface * sur, const Rect &r, const int3 &color);
-	//functions for printing text. Use CLabel where possible instead
-	void printAtLoc(const std::string & text, int x, int y, EFonts font, SDL_Color color, SDL_Surface * dst);
-	void printToLoc(const std::string & text, int x, int y, EFonts font, SDL_Color color, SDL_Surface * dst);
-	void printAtMiddleLoc(const std::string & text, int x, int y, EFonts font, SDL_Color color, SDL_Surface * dst);
-	void printAtMiddleLoc(const std::string & text, const Point &p, EFonts font, SDL_Color color, SDL_Surface * dst);
-	void printAtMiddleWBLoc(const std::string & text, int x, int y, EFonts font, int charsPerLine, SDL_Color color, SDL_Surface * dst);
-
-	//image blitting. If possible use CPicture or CAnimImage instead
-	void blitAtLoc(SDL_Surface * src, int x, int y, SDL_Surface * dst);
-	void blitAtLoc(SDL_Surface * src, const Point &p, SDL_Surface * dst);
+	enum EAlignment {TOPLEFT, CENTER, BOTTOMRIGHT};
 
 	bool isItInLoc(const SDL_Rect &rect, int x, int y);
 	bool isItInLoc(const SDL_Rect &rect, const Point &p);
@@ -177,24 +202,29 @@ public:
 	void fitToScreen(int borderWidth, bool propagate = true); //moves window to fit into screen
 	void moveBy(const Point &p, bool propagate = true);
 	void moveTo(const Point &p, bool propagate = true);//move this to new position, coordinates are absolute (0,0 is topleft screen corner)
-	void changeUsedEvents(ui16 what, bool enable, bool adjust = true);
 
-	//add child without parent to this. Use CGuiHandler::moveChild() if child already have parent
 	void addChild(CIntObject *child, bool adjustPosition = false);
-	//remove child from this without deleting
 	void removeChild(CIntObject *child, bool adjustPosition = false);
-	void delChild(CIntObject *child); //removes from children list, deletes
-	template <typename T> void delChildNUll(T *&child, bool deactivateIfNeeded = false) //removes from children list, deletes and sets pointer to NULL
-	{
-		if(!child)
-			return;
+	//delChild - not needed, use normal "delete child" instead
+	//delChildNull - not needed, use "vstd::clear_pointer(child)" instead
+
+/*
+ * Functions that should be used only by specific GUI elements. Don't use them unless you really know why they are here
+ */
+	//wrappers for CSDL_Ext methods. This versions use coordinates relative to pos
+	void drawBorderLoc(SDL_Surface * sur, const Rect &r, const int3 &color);
+	//functions for printing text. Use CLabel where possible instead
+	void printAtLoc(const std::string & text, int x, int y, EFonts font, SDL_Color color, SDL_Surface * dst);
+	void printToLoc(const std::string & text, int x, int y, EFonts font, SDL_Color color, SDL_Surface * dst);
+	void printAtMiddleLoc(const std::string & text, int x, int y, EFonts font, SDL_Color color, SDL_Surface * dst);
+	void printAtMiddleLoc(const std::string & text, const Point &p, EFonts font, SDL_Color color, SDL_Surface * dst);
+	void printAtMiddleWBLoc(const std::string & text, int x, int y, EFonts font, int charsPerLine, SDL_Color color, SDL_Surface * dst);
 
-		if(deactivateIfNeeded && child->active)
-			child->deactivate();
+	//image blitting. If possible use CPicture or CAnimImage instead
+	void blitAtLoc(SDL_Surface * src, int x, int y, SDL_Surface * dst);
+	void blitAtLoc(SDL_Surface * src, const Point &p, SDL_Surface * dst);
 
-		delChild(child);
-		child = NULL;
-	}
+	friend class CGuiHandler;
 };
 
 /// Class for binding keys to left mouse button clicks
@@ -207,4 +237,4 @@ public:
 	CKeyShortcut(int key){assignedKeys.insert(key);}; //c-tor
 	CKeyShortcut(std::set<int> Keys):assignedKeys(Keys){}; //c-tor
 	virtual void keyPressed(const SDL_KeyboardEvent & key); //call-in
-};
+};

+ 74 - 57
client/UIFramework/CIntObjectClasses.cpp

@@ -216,7 +216,7 @@ void CButtonBase::update()
 void CButtonBase::addTextOverlay( const std::string &Text, EFonts font, SDL_Color color)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	delChild(text);
+	delete text;
 	text = new CLabel(pos.w/2, pos.h/2, font, CENTER, color, Text);
 	update();
 }
@@ -261,7 +261,7 @@ CAdventureMapButton::CAdventureMapButton ()
 {
 	hoverable = actOnDown = borderEnabled = soundDisabled = false;
 	borderColor.unused = 1; // represents a transparent color, used for HighlightableButton
-	used = LCLICK | RCLICK | HOVER | KEYBOARD;
+	addUsedEvents(LCLICK | RCLICK | HOVER | KEYBOARD);
 }
 
 CAdventureMapButton::CAdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, int x, int y,  const std::string &defName,int key, std::vector<std::string> * add, bool playerColoredButton )
@@ -360,7 +360,7 @@ void CAdventureMapButton::hover (bool on)
 void CAdventureMapButton::init(const CFunctionList<void()> &Callback, const std::map<int,std::string> &Name, const std::string &HelpBox, bool playerColoredButton, const std::string &defName, std::vector<std::string> * add, int x, int y, int key)
 {
 	currentImage = -1;
-	used = LCLICK | RCLICK | HOVER | KEYBOARD;
+	addUsedEvents(LCLICK | RCLICK | HOVER | KEYBOARD);
 	callback = Callback;
 	hoverable = actOnDown = borderEnabled = soundDisabled = false;
 	borderColor.unused = 1; // represents a transparent color, used for HighlightableButton
@@ -391,12 +391,8 @@ void CAdventureMapButton::setImage(CAnimation* anim, bool playerColoredButton, i
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 
-	if (image && active)
-		image->deactivate();
-	delChild(image);
+	delete image;
 	image = new CAnimImage(anim, getState(), 0, 0, 0, animFlags);
-	if (active)
-		image->activate();
 	if (playerColoredButton)
 		image->playerColored(LOCPLINT->playerID);
 
@@ -583,10 +579,7 @@ void CHighlightableButtonsGroup::block( ui8 on )
 void CSlider::sliderClicked()
 {
 	if(!(active & MOVE))
-	{
-		activateMouseMove();
-		used |= MOVE;
-	}
+		addUsedEvents(MOVE);
 }
 
 void CSlider::mouseMoved (const SDL_MouseMotionEvent & sEvent)
@@ -695,10 +688,7 @@ void CSlider::clickLeft(tribool down, bool previousState)
 		return;
 	}
 	if(active & MOVE)
-	{
-		deactivateMouseMove();
-		used &= ~MOVE;
-	}
+		removeUsedEvents(MOVE);
 }
 
 CSlider::~CSlider()
@@ -712,7 +702,7 @@ CSlider::CSlider(int x, int y, int totalw, boost::function<void(int)> Moved, int
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	setAmount(amount);
 
-	used = LCLICK;
+	addUsedEvents(LCLICK);
 	strongInterest = true;
 
 
@@ -860,8 +850,6 @@ void CObjectList::deleteItem(CIntObject* item)
 {
 	if (!item)
 		return;
-	if (active)
-		item->deactivate();
 	removeChild(item);
 	destroyObject(item);
 }
@@ -875,17 +863,7 @@ CIntObject* CObjectList::createItem(size_t index)
 
 	item->recActions = defActions;
 
-	//May happen if object was created before call to getObject()
-	if(item->parent != this)
-	{
-		if (item->parent)
-			CGuiHandler::moveChild(item, item->parent, this);
-		else
-			addChild(item);
-	}
-
-	if (item && active)
-		item->activate();
+	addChild(item);
 	return item;
 }
 
@@ -1085,6 +1063,11 @@ void CStatusBar::print(const std::string & text)
 	}
 }
 
+void CStatusBar::showAll(SDL_Surface * to)
+{
+	show(to);
+}
+
 void CStatusBar::show(SDL_Surface * to)
 {
 	SDL_Rect srcRect = genRect(pos.h,pos.w,0,0);
@@ -1098,24 +1081,6 @@ std::string CStatusBar::getCurrent()
 	return current;
 }
 
-void CList::activate()
-{
-	activateLClick();
-	activateRClick();
-	activateHover();
-	activateKeys();
-	activateMouseMove();
-};
-
-void CList::deactivate()
-{
-	deactivateLClick();
-	deactivateRClick();
-	deactivateHover();
-	deactivateKeys();
-	deactivateMouseMove();
-};
-
 void CList::clickLeft(tribool down, bool previousState)
 {
 };
@@ -1123,6 +1088,7 @@ void CList::clickLeft(tribool down, bool previousState)
 CList::CList(int Size)
 :SIZE(Size)
 {
+	addUsedEvents(LCLICK | RCLICK | HOVER | KEYBOARD | MOVE);
 }
 
 void CList::fixPos()
@@ -1149,7 +1115,7 @@ void CHoverableArea::hover (bool on)
 
 CHoverableArea::CHoverableArea()
 {
-	used |= HOVER;
+	addUsedEvents(HOVER);
 }
 
 CHoverableArea::~CHoverableArea()
@@ -1187,7 +1153,7 @@ LRClickableAreaWText::~LRClickableAreaWText()
 
 void LRClickableAreaWText::init()
 {
-	used = LCLICK | RCLICK | HOVER;
+	addUsedEvents(LCLICK | RCLICK | HOVER);
 }
 
 void CLabel::showAll(SDL_Surface * to)
@@ -1313,7 +1279,7 @@ void CTextBox::setBounds(int limitW, int limitH)
 
 void CTextBox::recalculateLines(const std::string &Txt)
 {
-	delChildNUll(slider, true);
+	vstd::clear_pointer(slider);
 	lines.clear();
 
 	const Font &f = *graphics->fonts[font];
@@ -1326,8 +1292,6 @@ void CTextBox::recalculateLines(const std::string &Txt)
 		lines = CMessage::breakText(Txt, pos.w - 32 - 10, font);
 		OBJ_CONSTRUCTION_CAPTURING_ALL;
 		slider = new CSlider(pos.w - 32, 0, pos.h, boost::bind(&CTextBox::sliderMoved, this, _1), lineCapacity, lines.size(), 0, false, sliderStyle);
-		if(active)
-			slider->activate();
 	}
 
 	maxH = lineHeight * lines.size();
@@ -1362,7 +1326,7 @@ CGStatusBar::CGStatusBar(CPicture *BG, EFonts Font /*= FONT_SMALL*/, EAlignment
 {
 	init();
 	bg = BG;
-	CGuiHandler::moveChild(bg, bg->parent, this);
+	addChild(bg);
 	pos = bg->pos;
 	calcOffset();
 }
@@ -1419,7 +1383,7 @@ CTextInput::CTextInput( const Rect &Pos, const Point &bgOffset, const std::strin
 	captureAllKeys = true;
 	OBJ_CONSTRUCTION;
 	bg = new CPicture(bgName, bgOffset.x, bgOffset.y);
-	used = LCLICK | KEYBOARD;
+	addUsedEvents(LCLICK | KEYBOARD);
 	giveFocus();
 }
 
@@ -1438,7 +1402,7 @@ CTextInput::CTextInput(const Rect &Pos, SDL_Surface *srf)
 	pos.w = bg->pos.w;
 	pos.h = bg->pos.h;
 	bg->pos = pos;
-	used = LCLICK | KEYBOARD;
+	addUsedEvents(LCLICK | KEYBOARD);
 	giveFocus();
 }
 
@@ -1544,4 +1508,57 @@ void CFocusable::moveFocus()
 			break;;
 		}
 	}
-}
+}
+
+CWindowObject::CWindowObject(std::string imageName, int options_, Point centerAt):
+    CIntObject(options_ & RCLICK_POPUP ? RCLICK : 0, Point()),
+    options(options_),
+    background(createBg(imageName, options & PLAYER_COLORED))
+{
+	assert(parent == nullptr); //Safe to remove, but windows should not have parent
+
+	if (background)
+		pos = background->center(centerAt);
+}
+
+CWindowObject::CWindowObject(std::string imageName, int options_):
+    CIntObject(options & RCLICK_POPUP ? RCLICK : 0, Point()),
+    options(options_),
+    background(createBg(imageName, options & PLAYER_COLORED))
+{
+	assert(parent == nullptr); //Safe to remove, but windows should not have parent
+
+	if (background)
+		pos = background->center();
+}
+
+CPicture * CWindowObject::createBg(std::string imageName, bool playerColored)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+
+	if (imageName.empty())
+		return nullptr;
+
+	auto image = new CPicture(imageName);
+	if (playerColored)
+		image->colorize(LOCPLINT->playerID);
+	return image;
+}
+
+void CWindowObject::showAll(SDL_Surface *to)
+{
+	CIntObject::showAll(to);
+	if ((options & BORDERED) && (pos.h != to->h || pos.w != to->w))
+		CMessage::drawBorder(LOCPLINT ? LOCPLINT->playerID : 1, to, pos.w+28, pos.h+29, pos.x-14, pos.y-15);
+}
+
+void CWindowObject::close()
+{
+	GH.popIntTotally(this);
+}
+
+void CWindowObject::clickRight(tribool down, bool previousState)
+{
+	if((!down || indeterminate(down)))
+		close();
+}

+ 37 - 4
client/UIFramework/CIntObjectClasses.h

@@ -298,7 +298,8 @@ public:
 	~CStatusBar(); //d-tor
 	void print(const std::string & text); //prints text and refreshes statusbar
 	void clear();//clears statusbar and refreshes
-	void show(SDL_Surface * to); //shows statusbar (with current text)
+	void showAll(SDL_Surface * to); //shows statusbar (with current text)
+	void show(SDL_Surface * to);
 	std::string getCurrent(); //getter for current
 };
 
@@ -430,8 +431,6 @@ public:
 
 	CList(int Size = 5); //c-tor
 	void clickLeft(tribool down, bool previousState);
-	void activate();
-	void deactivate();
 	virtual void mouseMoved (const SDL_MouseMotionEvent & sEvent)=0; //call-in
 	virtual void genList()=0;
 	virtual void select(int which)=0;
@@ -465,4 +464,38 @@ public:
 
 	virtual void clickLeft(tribool down, bool previousState);
 	virtual void clickRight(tribool down, bool previousState);
-};
+};
+
+/// Basic class for windows
+// TODO: status bar?
+class CWindowObject : public virtual CIntObject
+{
+	CPicture * createBg(std::string imageName, bool playerColored);
+
+	int options;
+
+protected:
+	CPicture * background;
+
+	//Simple function with call to GH.popInt
+	void close();
+	//Used only if RCLICK_POPUP was set
+	void clickRight(tribool down, bool previousState);
+	//To display border
+	void showAll(SDL_Surface *to);
+public:
+	enum EOptions
+	{
+		PLAYER_COLORED=1, //background will be player-colored
+		RCLICK_POPUP=2, // window will behave as right-click popup
+		BORDERED=4 // window will have border if current resolution is bigger than size of window
+	};
+
+	/*
+	 * imageName - name for background image, can be empty
+	 * options - EOpions enum
+	 * centerAt - position of window center. Default - center of the screen
+	*/
+	CWindowObject(std::string imageName, int options, Point centerAt);
+	CWindowObject(std::string imageName, int options);
+};

+ 1 - 1
client/mapHandler.cpp

@@ -565,7 +565,7 @@ void CMapHandler::terrainRect( int3 top_tile, ui8 anim, const std::vector< std::
 					ui8 dir;
 					std::vector<Cimage> * iv = NULL;
 					std::vector<CDefEssential *> Graphics::*flg = NULL;
-					SDL_Surface * tb; //surface to blitted
+					SDL_Surface * tb = nullptr; //surface to blitted
 
 					if(themp) //hero
 					{

+ 1 - 1
configure

@@ -15226,7 +15226,7 @@ fi
 
 # extra clang parameters
 if test "x${ax_cv_cxx_compiler_vendor}"  =  "xclang" ; then
-   CXXFLAGS="$CXXFLAGS -Wno-cast-align -Woverloaded-virtual"
+   CXXFLAGS="$CXXFLAGS -Wno-cast-align -Wno-overloaded-virtual"
 fi
 
 # extra Intel icc parameters

+ 1 - 1
configure.ac

@@ -38,7 +38,7 @@ fi
 
 # extra clang parameters
 if test "x${ax_cv_cxx_compiler_vendor}"  =  "xclang" ; then
-   CXXFLAGS="$CXXFLAGS -Wno-cast-align -Woverloaded-virtual"
+   CXXFLAGS="$CXXFLAGS -Wno-cast-align -Wno-overloaded-virtual"
 fi
 
 # extra Intel icc parameters

+ 2 - 2
lib/int3.h

@@ -30,9 +30,9 @@ public:
 		{return int3(x-i,y-i,z-i);}
 	inline int3 operator-() const //returns opposite position
 		{return int3(-x,-y,-z);}
-	inline double dist2d(const int3 other) const //distance (z coord is not used)
+	inline double dist2d(const int3 &other) const //distance (z coord is not used)
 		{return std::sqrt((double)(x-other.x)*(x-other.x) + (y-other.y)*(y-other.y));}
-	inline bool areNeighbours(const int3 other) const
+	inline bool areNeighbours(const int3 &other) const
 		{return dist2d(other) < 2. && z == other.z;}
 	inline void operator+=(const int3 & i)
 	{