Browse Source

Split CIntObjectClasses into multiple smaller files. This should be the last change in files

Ivan Savenko 11 years ago
parent
commit
731aedf3a1
67 changed files with 4023 additions and 3655 deletions
  1. 1 0
      client/CMT.cpp
  2. 12 2
      client/CMakeLists.txt
  3. 5 4
      client/CMessage.cpp
  4. 3 1
      client/CPlayerInterface.cpp
  5. 3 2
      client/CPlayerInterface.h
  6. 6 2
      client/CPreGame.cpp
  7. 9 2
      client/CPreGame.h
  8. 3 0
      client/Client.cpp
  9. 5 1
      client/Client.h
  10. 0 1
      client/Graphics.cpp
  11. 1 0
      client/battle/CBattleAnimations.cpp
  12. 1 1
      client/battle/CBattleAnimations.h
  13. 1 1
      client/battle/CBattleInterface.cpp
  14. 1 3
      client/battle/CBattleInterface.h
  15. 4 1
      client/battle/CBattleInterfaceClasses.cpp
  16. 2 1
      client/battle/CCreatureAnimation.h
  17. 0 316
      client/gui/CAnimation.cpp
  18. 2 160
      client/gui/CAnimation.h
  19. 1 1
      client/gui/CCursorHandler.cpp
  20. 2 0
      client/gui/CGuiHandler.cpp
  21. 1 1
      client/gui/CGuiHandler.h
  22. 3 1
      client/gui/CIntObject.h
  23. 6 1
      client/gui/Geometries.cpp
  24. 3 5
      client/gui/Geometries.h
  25. 3 2
      client/gui/SDL_Extensions.h
  26. 5 37
      client/widgets/AdventureMapClasses.cpp
  27. 3 11
      client/widgets/AdventureMapClasses.h
  28. 732 0
      client/widgets/Buttons.cpp
  29. 175 0
      client/widgets/Buttons.h
  30. 3 1
      client/widgets/CArtifactHolder.cpp
  31. 2 1
      client/widgets/CArtifactHolder.h
  32. 1 1
      client/widgets/CComponent.cpp
  33. 2 14
      client/widgets/CComponent.h
  34. 12 1
      client/widgets/CGarrisonInt.cpp
  35. 1 1
      client/widgets/CGarrisonInt.h
  36. 0 2025
      client/widgets/CIntObjectClasses.cpp
  37. 0 560
      client/widgets/CIntObjectClasses.h
  38. 533 0
      client/widgets/Images.cpp
  39. 226 0
      client/widgets/Images.h
  40. 29 374
      client/widgets/MiscWidgets.cpp
  41. 42 101
      client/widgets/MiscWidgets.h
  42. 234 0
      client/widgets/ObjectLists.cpp
  43. 111 0
      client/widgets/ObjectLists.h
  44. 642 0
      client/widgets/TextControls.cpp
  45. 189 0
      client/widgets/TextControls.h
  46. 36 1
      client/windows/CAdvmapInterface.cpp
  47. 14 0
      client/windows/CAdvmapInterface.h
  48. 3 2
      client/windows/CCastleInterface.cpp
  49. 1 1
      client/windows/CCastleInterface.h
  50. 6 2
      client/windows/CCreatureWindow.cpp
  51. 3 1
      client/windows/CCreatureWindow.h
  52. 1 2
      client/windows/CHeroWindow.cpp
  53. 3 0
      client/windows/CHeroWindow.h
  54. 4 2
      client/windows/CKingdomInterface.cpp
  55. 3 0
      client/windows/CKingdomInterface.h
  56. 0 1
      client/windows/CQuestLog.cpp
  57. 4 2
      client/windows/CQuestLog.h
  58. 5 0
      client/windows/CSpellWindow.cpp
  59. 1 1
      client/windows/CSpellWindow.h
  60. 4 1
      client/windows/CTradeWindow.cpp
  61. 4 0
      client/windows/CTradeWindow.h
  62. 242 0
      client/windows/CWindowObject.cpp
  63. 65 0
      client/windows/CWindowObject.h
  64. 2 1
      client/windows/GUIClasses.cpp
  65. 9 2
      client/windows/GUIClasses.h
  66. 456 0
      client/windows/InfoWindows.cpp
  67. 137 0
      client/windows/InfoWindows.h

+ 1 - 0
client/CMT.cpp

@@ -39,6 +39,7 @@
 #include "../lib/GameConstants.h"
 #include "gui/CGuiHandler.h"
 #include "../lib/logging/CBasicLogConfigurator.h"
+#include "../lib/CondSh.h"
 
 #ifdef _WIN32
 #include "SDL_syswm.h"

+ 12 - 2
client/CMakeLists.txt

@@ -14,6 +14,7 @@ set(client_SRCS
 		battle/CBattleInterfaceClasses.cpp
 		battle/CCreatureAnimation.cpp
 
+		gui/CAnimation.cpp
 		gui/CCursorHandler.cpp
 		gui/CGuiHandler.cpp
 		gui/CIntObject.cpp
@@ -22,12 +23,14 @@ set(client_SRCS
 		gui/SDL_Extensions.cpp
 
 		widgets/AdventureMapClasses.cpp
-		widgets/CAnimation.cpp
+		widgets/Buttons.cpp
 		widgets/CArtifactHolder.cpp
 		widgets/CComponent.cpp
 		widgets/CGarrisonInt.cpp
-		widgets/CIntObjectClasses.cpp
+		widgets/Images.cpp
 		widgets/MiscWidgets.cpp
+		widgets/ObjectLists.cpp
+		widgets/TextControls.cpp
 
 		windows/CAdvmapInterface.cpp
 		windows/CCastleInterface.cpp
@@ -37,6 +40,8 @@ set(client_SRCS
 		windows/CQuestLog.cpp
 		windows/CSpellWindow.cpp
 		windows/CTradeWindow.cpp
+		windows/CWindowObject
+		windows/InfoWindows.cpp
 		windows/GUIClasses.cpp
 
 		CBitmapHandler.cpp
@@ -54,6 +59,11 @@ set(client_SRCS
 		NetPacksClient.cpp
 )
 
+set(client_HEADERS
+		gui/SDL_Pixels.h
+		gui/SDL_Compat.h
+)
+
 if(APPLE)
 	# OS X specific includes
 	include_directories(${SPARKLE_INCLUDE_DIR})

+ 5 - 4
client/CMessage.cpp

@@ -11,9 +11,7 @@
 #include "StdInc.h"
 #include "CMessage.h"
 
-#include "SDL_ttf.h"
 #include "CDefHandler.h"
-#include "widgets/CAnimation.h"
 #include "CGameInfo.h"
 #include "gui/SDL_Extensions.h"
 #include "../lib/CGeneralTextHandler.h"
@@ -21,8 +19,11 @@
 #include "windows/GUIClasses.h"
 #include "../lib/CConfigHandler.h"
 #include "CBitmapHandler.h"
-#include "widgets/CIntObjectClasses.h"
-#include "widgets/MiscWidgets.h"
+
+#include "widgets/CComponent.h"
+#include "windows/InfoWindows.h"
+#include "widgets/Buttons.h"
+#include "widgets/TextControls.h"
 
 const int BETWEEN_COMPS_ROWS = 10;
 const int BEFORE_COMPONENTS = 30;

+ 3 - 1
client/CPlayerInterface.cpp

@@ -13,6 +13,7 @@
 #include "CMessage.h"
 #include "CPlayerInterface.h"
 #include "gui/SDL_Extensions.h"
+#include "widgets/CComponent.h"
 #include "windows/CTradeWindow.h"
 #include "../lib/CConfigHandler.h"
 #include "battle/CCreatureAnimation.h"
@@ -37,8 +38,9 @@
 #include "../lib/CGameState.h"
 #include "../lib/GameConstants.h"
 #include "gui/CGuiHandler.h"
-#include "widgets/MiscWidgets.h"
+#include "windows/InfoWindows.h"
 #include "../lib/UnlockGuard.h"
+#include <SDL.h>
 
 #ifdef min
 #undef min

+ 3 - 2
client/CPlayerInterface.h

@@ -1,11 +1,12 @@
 #pragma once
 
 
-#include "../lib/CondSh.h"
+//#include "../lib/CondSh.h"
 #include "../lib/FunctionList.h"
 #include "../lib/CGameInterface.h"
+#include "../lib/NetPacksBase.h"
 #include "gui/CIntObject.h"
-#include "../lib/CGameState.h"
+//#include "../lib/CGameState.h"
 
 #ifdef __GNUC__
 #define sprintf_s snprintf

+ 6 - 2
client/CPreGame.cpp

@@ -9,7 +9,6 @@
 #include "gui/SDL_Extensions.h"
 #include "CGameInfo.h"
 #include "gui/CCursorHandler.h"
-#include "widgets/CAnimation.h"
 #include "CDefHandler.h"
 #include "../lib/CGeneralTextHandler.h"
 #include "../lib/CTownHandler.h"
@@ -38,8 +37,13 @@
 #include "../lib/CConfigHandler.h"
 #include "../lib/GameConstants.h"
 #include "gui/CGuiHandler.h"
-#include "widgets/CIntObjectClasses.h"
+#include "gui/CAnimation.h"
+#include "widgets/CComponent.h"
+#include "widgets/Buttons.h"
 #include "widgets/MiscWidgets.h"
+#include "widgets/ObjectLists.h"
+#include "widgets/TextControls.h"
+#include "windows/InfoWindows.h"
 #include "../lib/mapping/CMapService.h"
 #include "../lib/mapping/CMap.h"
 #include "../lib/CRandomGenerator.h"

+ 9 - 2
client/CPreGame.h

@@ -1,11 +1,11 @@
 #pragma once
 
-#include "../lib/filesystem/Filesystem.h"
+//#include "../lib/filesystem/Filesystem.h"
 #include "../lib/StartInfo.h"
 #include "../lib/FunctionList.h"
 #include "../lib/mapping/CMapInfo.h"
 #include "../lib/rmg/CMapGenerator.h"
-#include "widgets/CIntObjectClasses.h"
+#include "windows/CWindowObject.h"
 
 /*
  * CPreGame.h, part of VCMI engine
@@ -17,6 +17,7 @@
  *
  */
 
+class CMapInfo;
 class CMusicHandler;
 class CMapHeader;
 class CCampaignHeader;
@@ -31,6 +32,12 @@ class CMapGenOptions;
 class CRandomMapTab;
 struct CPackForSelectionScreen;
 struct PlayerInfo;
+class CMultiLineLabel;
+class CHighlightableButton;
+class CHighlightableButtonsGroup;
+class CTabbedInt;
+class CAdventureMapButton;
+class CSlider;
 
 namespace boost{ class thread; class recursive_mutex;}
 

+ 3 - 0
client/Client.cpp

@@ -1,4 +1,7 @@
 #include "StdInc.h"
+#include "Client.h"
+
+#include <SDL.h>
 
 #include "CMusicHandler.h"
 #include "../lib/mapping/CCampaignHandler.h"

+ 5 - 1
client/Client.h

@@ -2,8 +2,9 @@
 
 
 #include "../lib/IGameCallback.h"
-#include "../lib/CondSh.h"
+#include "../lib/BattleAction.h"
 #include "../lib/CStopWatch.h"
+#include "../lib/int3.h"
 
 /*
  * Client.h, part of VCMI engine
@@ -15,6 +16,9 @@
  *
  */
 
+class CPack;
+class CCampaignState;
+class CBattleCallback;
 class IGameEventsReceiver;
 class IBattleEventsReceiver;
 class CBattleGameInterface;

+ 0 - 1
client/Graphics.cpp

@@ -21,7 +21,6 @@
 #include "../lib/vcmi_endian.h"
 #include "../lib/GameConstants.h"
 #include "../lib/CStopWatch.h"
-#include "widgets/CAnimation.h"
 #include "../lib/mapObjects/CObjectClassesHandler.h"
 
 using namespace boost::assign;

+ 1 - 0
client/battle/CBattleAnimations.cpp

@@ -19,6 +19,7 @@
 #include "../../CCallback.h"
 #include "../../lib/BattleState.h"
 #include "../../lib/CTownHandler.h"
+#include "../../lib/mapObjects/CGTownInstance.h"
 
 /*
  * CBattleAnimations.cpp, part of VCMI engine

+ 1 - 1
client/battle/CBattleAnimations.h

@@ -1,7 +1,7 @@
 #pragma once
 
-#include "../widgets/CAnimation.h"
 #include "../../lib/BattleHex.h"
+#include "../widgets/Images.h"
 
 class CBattleInterface;
 class CStack;

+ 1 - 1
client/battle/CBattleInterface.cpp

@@ -17,7 +17,6 @@
 #include "../gui/CCursorHandler.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/SDL_Extensions.h"
-#include "../widgets/CAnimation.h"
 #include "../windows/CAdvmapInterface.h"
 #include "../windows/CCreatureWindow.h"
 #include "../windows/CSpellWindow.h"
@@ -31,6 +30,7 @@
 #include "../../lib/CRandomGenerator.h"
 #include "../../lib/CSpellHandler.h"
 #include "../../lib/CTownHandler.h"
+#include "../../lib/CGameState.h"
 #include "../../lib/mapping/CMap.h"
 #include "../../lib/NetPacks.h"
 #include "../../lib/UnlockGuard.h"

+ 1 - 3
client/battle/CBattleInterface.h

@@ -1,12 +1,10 @@
 #pragma once
 
 
-#include "../../lib/CCreatureSet.h"
+//#include "../../lib/CCreatureSet.h"
 #include "../../lib/ConstTransitivePtr.h" //may be reundant
 #include "../../lib/GameConstants.h"
 
-#include "../widgets/CAnimation.h"
-
 #include "CBattleAnimations.h"
 
 /*

+ 4 - 1
client/battle/CBattleInterfaceClasses.cpp

@@ -14,7 +14,8 @@
 #include "../gui/CCursorHandler.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/SDL_Extensions.h"
-#include "../widgets/CIntObjectClasses.h"
+#include "../widgets/Buttons.h"
+#include "../widgets/TextControls.h"
 #include "../windows/CCreatureWindow.h"
 #include "../windows/CSpellWindow.h"
 
@@ -22,10 +23,12 @@
 #include "../../lib/BattleState.h"
 #include "../../lib/CConfigHandler.h"
 #include "../../lib/CCreatureHandler.h"
+#include "../../lib/CGameState.h"
 #include "../../lib/CGeneralTextHandler.h"
 #include "../../lib/CTownHandler.h"
 #include "../../lib/NetPacks.h"
 #include "../../lib/StartInfo.h"
+#include "../../lib/CondSh.h"
 
 /*
  * CBattleInterfaceClasses.cpp, part of VCMI engine

+ 2 - 1
client/battle/CCreatureAnimation.h

@@ -1,7 +1,8 @@
 #pragma once
 
 #include "../../lib/FunctionList.h"
-#include "../widgets/CAnimation.h"
+#include "../gui/SDL_Extensions.h"
+#include "../widgets/Images.h"
 
 /*
  * CCreatureAnimation.h, part of VCMI engine

+ 0 - 316
client/widgets/CAnimation.cpp → client/gui/CAnimation.cpp

@@ -1222,319 +1222,3 @@ void CAnimation::getAnimInfo()
             logGlobal->errorStream()<<", "<<anim->images.begin()->second.size()<<" image loaded in group "<< anim->images.begin()->first;
 	}
 }
-
-CAnimImage::CAnimImage(std::string name, size_t Frame, size_t Group, int x, int y, ui8 Flags):
-	frame(Frame),
-	group(Group),
-	player(-1),
-	flags(Flags)
-{
-	pos.x += x;
-	pos.y += y;
-	anim = new CAnimation(name);
-	init();
-}
-
-CAnimImage::CAnimImage(CAnimation *Anim, size_t Frame, size_t Group, int x, int y, ui8 Flags):
-	anim(Anim),
-	frame(Frame),
-	group(Group),
-	player(-1),
-	flags(Flags)
-{
-	pos.x += x;
-	pos.y += y;
-	init();
-}
-
-size_t CAnimImage::size()
-{
-	return anim->size(group);
-}
-
-void CAnimImage::init()
-{
-	anim->load(frame, group);
-	if (flags & CShowableAnim::BASE)
-		anim->load(0,group);
-	
-	IImage *img = anim->getImage(frame, group);
-	if (img)
-	{
-		pos.w = img->width();
-		pos.h = img->height();
-	}
-}
-
-CAnimImage::~CAnimImage()
-{
-	anim->unload(frame, group);
-	if (flags & CShowableAnim::BASE)
-		anim->unload(0,group);
-	delete anim;
-}
-
-void CAnimImage::showAll(SDL_Surface * to)
-{
-	IImage *img;
-
-	if ( flags & CShowableAnim::BASE && frame != 0)
-		if ((img = anim->getImage(0, group)))
-			img->draw(to, pos.x, pos.y);
-
-	if ((img = anim->getImage(frame, group)))
-		img->draw(to, pos.x, pos.y);
-}
-
-void CAnimImage::setFrame(size_t Frame, size_t Group)
-{
-	if (frame == Frame && group==Group)
-		return;
-	if (anim->size(Group) > Frame)
-	{
-		anim->load(Frame, Group);
-		anim->unload(frame, group);
-		frame = Frame;
-		group = Group;
-		IImage *img = anim->getImage(frame, group);
-		if (img)
-		{
-			if (flags & CShowableAnim::PLAYER_COLORED)
-				img->playerColored(player);
-			pos.w = img->width();
-			pos.h = img->height();
-		}
-	}
-	else
-        logGlobal->errorStream() << "Error: accessing unavailable frame " << Group << ":" << Frame << " in CAnimation!";
-}
-
-void CAnimImage::playerColored(PlayerColor currPlayer)
-{
-	player = currPlayer;
-	flags |= CShowableAnim::PLAYER_COLORED;
-	anim->getImage(frame, group)->playerColored(player);
-	if (flags & CShowableAnim::BASE)
-			anim->getImage(0, group)->playerColored(player);
-}
-
-CShowableAnim::CShowableAnim(int x, int y, std::string name, ui8 Flags, ui32 Delay, size_t Group):
-	anim(name, Flags & USE_RLE),
-	group(Group),
-	frame(0),
-	first(0),
-	frameDelay(Delay),
-	value(0),
-	flags(Flags),
-	xOffset(0),
-	yOffset(0),
-	alpha(255)
-{
-	anim.loadGroup(group);
-	last = anim.size(group);
-
-	pos.w = anim.getImage(0, group)->width();
-	pos.h = anim.getImage(0, group)->height();
-	pos.x+= x;
-	pos.y+= y;
-}
-
-CShowableAnim::~CShowableAnim()
-{
-	anim.unloadGroup(group);
-}
-
-void CShowableAnim::setAlpha(ui32 alphaValue)
-{
-	alpha = std::min<ui32>(alphaValue, 255);
-}
-
-bool CShowableAnim::set(size_t Group, size_t from, size_t to)
-{
-	size_t max = anim.size(Group);
-
-	if (to < max)
-		max = to;
-
-	if (max < from || max == 0)
-		return false;
-
-	anim.load(Group);
-	anim.unload(group);
-	group = Group;
-	frame = first = from;
-	last = max;
-	value = 0;
-	return true;
-}
-
-bool CShowableAnim::set(size_t Group)
-{
-	if (anim.size(Group)== 0)
-		return false;
-	if (group != Group)
-	{
-		anim.loadGroup(Group);
-		anim.unloadGroup(group);
-		first = 0;
-		group = Group;
-		last = anim.size(Group);
-	}
-	frame = value = 0;
-	return true;
-}
-
-void CShowableAnim::reset()
-{
-	value = 0;
-	frame = first;
-
-	if (callback)
-		callback();
-}
-
-void CShowableAnim::clipRect(int posX, int posY, int width, int height)
-{
-	xOffset = posX;
-	yOffset = posY;
-	pos.w = width;
-	pos.h = height;
-}
-
-void CShowableAnim::show(SDL_Surface * to)
-{
-	if ( flags & BASE )// && frame != first) // FIXME: results in graphical glytch in Fortress, upgraded hydra's dwelling
-		blitImage(first, group, to);
-	blitImage(frame, group, to);
-
-	if ((flags & PLAY_ONCE) && frame + 1 == last)
-		return;
-
-	if ( ++value == frameDelay )
-	{
-		value = 0;
-		if ( ++frame >= last)
-			reset();
-	}
-}
-
-void CShowableAnim::showAll(SDL_Surface * to)
-{
-	if ( flags & BASE )// && frame != first)
-		blitImage(first, group, to);
-	blitImage(frame, group, to);
-}
-
-void CShowableAnim::blitImage(size_t frame, size_t group, SDL_Surface *to)
-{
-	assert(to);
-	Rect src( xOffset, yOffset, pos.w, pos.h);
-	IImage * img = anim.getImage(frame, group);
-	if (img)
-		img->draw(to, pos.x-xOffset, pos.y-yOffset, &src, alpha);
-}
-
-void CShowableAnim::rotate(bool on, bool vertical)
-{
-	ui8 flag = vertical? VERTICAL_FLIP:HORIZONTAL_FLIP;
-	if (on)
-		flags |= flag;
-	else
-		flags &= ~flag;
-}
-
-CCreatureAnim::CCreatureAnim(int x, int y, std::string name, Rect picPos, ui8 flags, EAnimType type):
-	CShowableAnim(x,y,name,flags,4,type)
-{
-	xOffset = picPos.x;
-	yOffset = picPos.y;
-	if (picPos.w)
-		pos.w = picPos.w;
-	if (picPos.h)
-		pos.h = picPos.h;
-};
-
-void CCreatureAnim::loopPreview(bool warMachine)
-{
-	std::vector<EAnimType> available;
-
-	static const EAnimType creaPreviewList[] = {HOLDING, HITTED, DEFENCE, ATTACK_FRONT, CAST_FRONT};
-	static const EAnimType machPreviewList[] = {HOLDING, MOVING, SHOOT_UP, SHOOT_FRONT, SHOOT_DOWN};
-	auto & previewList = warMachine ? machPreviewList : creaPreviewList;
-	
-	for (auto & elem : previewList)
-		if (anim.size(elem))
-			available.push_back(elem);
-
-	size_t rnd = CRandomGenerator::getDefault().nextInt(available.size() * 2 - 1);
-
-	if (rnd >= available.size())
-	{
-		EAnimType type;
-		if ( anim.size(MOVING) == 0 )//no moving animation present
-			type = HOLDING;
-		else
-			type = MOVING;
-
-		//display this anim for ~1 second (time is random, but it looks good)
-		for (size_t i=0; i< 12/anim.size(type) + 1; i++)
-			addLast(type);
-	}
-	else
-		addLast(available[rnd]);
-}
-
-void CCreatureAnim::addLast(EAnimType newType)
-{
-	if (type != MOVING && newType == MOVING)//starting moving - play init sequence
-	{
-		queue.push( MOVE_START );
-	}
-	else if (type == MOVING && newType != MOVING )//previous anim was moving - finish it
-	{
-		queue.push( MOVE_END );
-	}
-	if (newType == TURN_L || newType == TURN_R)
-		queue.push(newType);
-
-	queue.push(newType);
-}
-
-void CCreatureAnim::reset()
-{
-	//if we are in the middle of rotation - set flag
-	if (type == TURN_L && !queue.empty() && queue.front() == TURN_L)
-		rotate(true);
-	if (type == TURN_R && !queue.empty() && queue.front() == TURN_R)
-		rotate(false);
-
-	while (!queue.empty())
-	{
-		EAnimType at = queue.front();
-		queue.pop();
-		if (set(at))
-			return;
-	}
-	if  (callback)
-		callback();
-	while (!queue.empty())
-	{
-		EAnimType at = queue.front();
-		queue.pop();
-		if (set(at))
-			return;
-	}
-	set(HOLDING);
-}
-
-void CCreatureAnim::startPreview(bool warMachine)
-{
-	callback = boost::bind(&CCreatureAnim::loopPreview, this, warMachine);
-}
-
-void CCreatureAnim::clearAndSet(EAnimType type)
-{
-	while (!queue.empty())
-		queue.pop();
-	set(type);
-}

+ 2 - 160
client/widgets/CAnimation.h → client/gui/CAnimation.h

@@ -1,7 +1,8 @@
 #pragma once
 
 #include "../../lib/vcmi_endian.h"
-#include "../gui/CIntObject.h"
+#include "gui/Geometries.h"
+#include "../../lib/GameConstants.h"
 
 /*
  * CAnimation.h, part of VCMI engine
@@ -219,162 +220,3 @@ public:
 	//total count of frames in group (including not loaded)
 	size_t size(size_t group=0) const;
 };
-
-
-/// Class for displaying one image from animation
-class CAnimImage: public CIntObject
-{
-private:
-	CAnimation* anim;
-	//displayed frame/group
-	size_t frame;
-	size_t group;
-	PlayerColor player;
-	ui8 flags;
-
-	void init();
-
-public:
-	CAnimImage(std::string name, size_t Frame, size_t Group=0, int x=0, int y=0, ui8 Flags=0);
-	CAnimImage(CAnimation* anim, size_t Frame, size_t Group=0, int x=0, int y=0, ui8 Flags=0);
-	~CAnimImage();//d-tor
-
-	//size of animation
-	size_t size();
-
-	//change displayed frame on this one
-	void setFrame(size_t Frame, size_t Group=0);
-
-	//makes image player-colored
-	void playerColored(PlayerColor player);
-
-	void showAll(SDL_Surface * to);
-};
-
-/// Base class for displaying animation, used as superclass for different animations
-class CShowableAnim: public CIntObject
-{
-public:
-	enum EFlags
-	{
-		BASE=1,            //base frame will be blitted before current one
-		HORIZONTAL_FLIP=2, //TODO: will be displayed rotated
-		VERTICAL_FLIP=4,   //TODO: will be displayed rotated
-		USE_RLE=8,         //RLE-d version, support full alpha-channel for 8-bit images
-		PLAYER_COLORED=16, //TODO: all loaded images will be player-colored
-		PLAY_ONCE=32       //play animation only once and stop at last frame
-	};
-protected:
-	CAnimation anim;
-
-	size_t group, frame;//current frame
-
-	size_t first, last; //animation range
-
-	//TODO: replace with time delay(needed for battles)
-	ui32 frameDelay;//delay in frames of each image
-	ui32 value;//how many times current frame was showed
-
-	ui8 flags;//Flags from EFlags enum
-
-	//blit image with optional rotation, fitting into rect, etc
-	void blitImage(size_t frame, size_t group, SDL_Surface *to);
-
-	//For clipping in rect, offsets of picture coordinates
-	int xOffset, yOffset;
-
-	ui8 alpha;
-
-public:
-	//called when next animation sequence is required
-	std::function<void()> callback;
-
-	//Set per-surface alpha, 0 = transparent, 255 = opaque
-	void setAlpha(ui32 alphaValue);
-
-	CShowableAnim(int x, int y, std::string name, ui8 flags=0, ui32 Delay=4, size_t Group=0);
-	~CShowableAnim();
-
-	//set animation to group or part of group
-	bool set(size_t Group);
-	bool set(size_t Group, size_t from, size_t to=-1);
-
-	//set rotation flags
-	void rotate(bool on, bool vertical=false);
-
-	//move displayed part of picture (if picture is clipped to rect)
-	void clipRect(int posX, int posY, int width, int height);
-
-	//set frame to first, call callback
-	virtual void reset();
-
-	//show current frame and increase counter
-	void show(SDL_Surface * to);
-	void showAll(SDL_Surface * to);
-};
-
-/// Creature-dependend animations like attacking, moving,...
-class CCreatureAnim: public CShowableAnim
-{
-public:
-
-	enum EHeroAnimType
-	{
-		HERO_HOLDING = 0,
-		HERO_IDLE = 1, // idling movement that happens from time to time
-		HERO_DEFEAT = 2, // played when army loses stack or on friendly fire
-		HERO_VICTORY = 3, // when enemy stack killed or huge damage is dealt
-		HERO_CAST_SPELL = 4 // spellcasting
-	};
-
-	enum EAnimType // list of creature animations, numbers were taken from def files
-	{
-		MOVING=0,
-		MOUSEON=1,
-		HOLDING=2,
-		HITTED=3,
-		DEFENCE=4,
-		DEATH=5,
-		//DEATH2=6, //unused?
-		TURN_L=7,
-		TURN_R=8, //same
-		//TURN_L2=9, //identical to previous?
-		//TURN_R2=10,
-		ATTACK_UP=11,
-		ATTACK_FRONT=12,
-		ATTACK_DOWN=13,
-		SHOOT_UP=14,
-		SHOOT_FRONT=15,
-		SHOOT_DOWN=16,
-		CAST_UP=17,
-		CAST_FRONT=18,
-		CAST_DOWN=19,
-		MOVE_START=20,
-		MOVE_END=21,
-		DEAD = 22 // new group, used to show dead stacks. If empty - last frame from "DEATH" will be copied here
-
-	};
-
-private:
-	//queue of animations waiting to be displayed
-	std::queue<EAnimType> queue;
-
-	//this function is used as callback if preview flag was set during construction
-	void loopPreview(bool warMachine);
-
-public:
-	//change anim to next if queue is not empty, call callback othervice
-	void reset();
-
-	//add sequence to the end of queue
-	void addLast(EAnimType newType);
-
-	void startPreview(bool warMachine);
-
-	//clear queue and set animation to this sequence
-	void clearAndSet(EAnimType type);
-
-	CCreatureAnim(int x, int y, std::string name, Rect picPos,
-	              ui8 flags= USE_RLE, EAnimType = HOLDING );
-
-};

+ 1 - 1
client/gui/CCursorHandler.cpp

@@ -5,9 +5,9 @@
 
 #include "SDL_Extensions.h"
 #include "CGuiHandler.h"
+#include "widgets/Images.h"
 
 #include "../CMT.h"
-#include "../widgets/CAnimation.h"
 
 /*
  * CCursorHandler.cpp, part of VCMI engine

+ 2 - 0
client/gui/CGuiHandler.cpp

@@ -1,6 +1,8 @@
 #include "StdInc.h"
 #include "CGuiHandler.h"
 
+#include <SDL.h>
+
 #include "CIntObject.h"
 #include "CCursorHandler.h"
 

+ 1 - 1
client/gui/CGuiHandler.h

@@ -1,6 +1,6 @@
 #pragma once
 
-#include "../../lib/CStopWatch.h"
+//#include "../../lib/CStopWatch.h"
 #include "Geometries.h"
 #include "SDL_Extensions.h"
 

+ 3 - 1
client/gui/CIntObject.h

@@ -10,7 +10,7 @@
  
 #pragma once
 
-#include <SDL_events.h>
+//#include <SDL_events.h>
 #include "Geometries.h"
 #include "../Graphics.h"
 
@@ -18,6 +18,8 @@ struct SDL_Surface;
 class CPicture;
 class CGuiHandler;
 
+struct SDL_KeyboardEvent;
+
 using boost::logic::tribool;
 
 // Defines a activate/deactive method

+ 6 - 1
client/gui/Geometries.cpp

@@ -1,6 +1,11 @@
 #include "StdInc.h"
 #include "Geometries.h"
 #include "../CMT.h"
+#include <SDL_events.h>
+
+Point::Point(const SDL_MouseMotionEvent &a)
+	:x(a.x),y(a.y)
+{}
 
 Rect Rect::createCentered( int w, int h )
 {
@@ -15,4 +20,4 @@ Rect Rect::around(const Rect &r, int width /*= 1*/) /*creates rect around anothe
 Rect Rect::centerIn(const Rect &r)
 {
 	return Rect(r.x + (r.w - w) / 2, r.y + (r.h - h) / 2, w, h);
-}
+}

+ 3 - 5
client/gui/Geometries.h

@@ -1,7 +1,6 @@
 #pragma once
 
 #include <SDL_video.h>
-#include <SDL_events.h>
 #include "../../lib/int3.h"
 
 /*
@@ -21,6 +20,7 @@
 #undef min
 #endif
 
+struct SDL_MouseMotionEvent;
 
 // A point with x/y coordinate, used mostly for graphic rendering
 struct Point
@@ -38,9 +38,7 @@ struct Point
 	Point(const int3 &a)
 		:x(a.x),y(a.y)
 	{}
-	Point(const SDL_MouseMotionEvent &a)
-		:x(a.x),y(a.y)
-	{}
+	Point(const SDL_MouseMotionEvent &a);
 
 	template<typename T>
 	Point operator+(const T &b) const
@@ -265,4 +263,4 @@ struct Rect : public SDL_Rect
 		ret.h = y2 -ret.y;
 		return ret;
 	}
-};
+};

+ 3 - 2
client/gui/SDL_Extensions.h

@@ -16,10 +16,11 @@
 #endif
 
 #include <SDL_video.h>
-#include <SDL_ttf.h>
+#include <SDL_events.h>
 #include "../../lib/int3.h"
-#include "../Graphics.h"
+//#include "../Graphics.h"
 #include "Geometries.h"
+#include "../../lib/GameConstants.h"
 
 
 //A macro to force inlining some of our functions. Compiler (at least MSVC) is not so smart here-> without that displaying is MUCH slower

+ 5 - 37
client/widgets/AdventureMapClasses.cpp

@@ -1,8 +1,10 @@
 #include "StdInc.h"
 #include "AdventureMapClasses.h"
 
-#include "CAnimation.h"
+#include <SDL.h>
+
 #include "MiscWidgets.h"
+#include "CComponent.h"
 
 #include "../CGameInfo.h"
 #include "../CMusicHandler.h"
@@ -13,6 +15,7 @@
 #include "../gui/CGuiHandler.h"
 #include "../gui/SDL_Pixels.h"
 
+#include "../windows/InfoWindows.h"
 #include "../windows/CAdvmapInterface.h"
 #include "../windows/GUIClasses.h"
 
@@ -34,7 +37,7 @@
 #include "../../lib/StringConstants.h"
 
 /*
- * CAdventureMapClasses.h, part of VCMI engine
+ * CAdventureMapClasses.cpp, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
  *
@@ -1205,38 +1208,3 @@ CInGameConsole::CInGameConsole() : prevEntDisp(-1), defaultTimeout(10000), maxDi
 	addUsedEvents(KEYBOARD | TEXTINPUT);
 	#endif
 }
-
-CAdventureOptions::CAdventureOptions():
-	CWindowObject(PLAYER_COLORED, "ADVOPTS")
-{
-	OBJ_CONSTRUCTION_CAPTURING_ALL;
-
-	exit = new CAdventureMapButton("","",boost::bind(&CAdventureOptions::close, this), 204, 313, "IOK6432.DEF",SDLK_RETURN);
-	exit->assignedKeys.insert(SDLK_ESCAPE);
-
-	scenInfo = new CAdventureMapButton("","", boost::bind(&CAdventureOptions::close, this), 24, 198, "ADVINFO.DEF",SDLK_i);
-	scenInfo->callback += CAdventureOptions::showScenarioInfo;
-	//viewWorld = new CAdventureMapButton("","",boost::bind(&CGuiHandler::popIntTotally, &GH, this), 204, 313, "IOK6432.DEF",SDLK_RETURN);
-
-	puzzle = new CAdventureMapButton("","", boost::bind(&CAdventureOptions::close, this), 24, 81, "ADVPUZ.DEF");
-	puzzle->callback += boost::bind(&CPlayerInterface::showPuzzleMap, LOCPLINT);
-
-	dig = new CAdventureMapButton("","", boost::bind(&CAdventureOptions::close, this), 24, 139, "ADVDIG.DEF");
-	if(const CGHeroInstance *h = adventureInt->curHero())
-		dig->callback += boost::bind(&CPlayerInterface::tryDiggging, LOCPLINT, h);
-	else
-		dig->block(true);
-}
-
-void CAdventureOptions::showScenarioInfo()
-{
-	auto campState = LOCPLINT->cb->getStartInfo()->campState;
-	if(campState)
-	{
-		GH.pushInt(new CBonusSelection(campState));
-	}
-	else
-	{
-		GH.pushInt(new CScenarioInfo(LOCPLINT->cb->getMapHeader(), LOCPLINT->cb->getStartInfo()));
-	}
-}

+ 3 - 11
client/widgets/AdventureMapClasses.h

@@ -1,6 +1,7 @@
 #pragma once
 
-#include "CIntObjectClasses.h"
+#include "ObjectLists.h"
+#include "../../lib/FunctionList.h"
 
 class CArmedInstance;
 class CShowableAnim;
@@ -8,6 +9,7 @@ class CGGarrison;
 class CGObjectInstance;
 class CGHeroInstance;
 class CGTownInstance;
+class CAdventureMapButton;
 struct Component;
 struct InfoAboutArmy;
 struct InfoAboutHero;
@@ -339,13 +341,3 @@ public:
 
 	CInGameConsole(); //c-tor
 };
-
-/// Adventure options dialogue where you can view the world, dig, play the replay of the last turn,...
-class CAdventureOptions : public CWindowObject
-{
-public:
-	CAdventureMapButton *exit, *viewWorld, *puzzle, *dig, *scenInfo, *replay;
-
-	CAdventureOptions();
-	static void showScenarioInfo();
-};

+ 732 - 0
client/widgets/Buttons.cpp

@@ -0,0 +1,732 @@
+#include "StdInc.h"
+#include "Buttons.h"
+
+#include "Images.h"
+#include "TextControls.h"
+
+#include "../CMusicHandler.h"
+#include "../CGameInfo.h"
+#include "../CPlayerInterface.h"
+#include "../battle/CBattleInterface.h"
+#include "../battle/CBattleInterfaceClasses.h"
+#include "../gui/CAnimation.h"
+#include "../gui/CGuiHandler.h"
+#include "../windows/InfoWindows.h"
+#include "../../lib/CConfigHandler.h"
+
+/*
+ * Buttons.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+CButtonBase::CButtonBase()
+{
+	swappedImages = keepFrame = false;
+	bitmapOffset = 0;
+	state=NORMAL;
+	image = nullptr;
+	overlay = nullptr;
+}
+
+CButtonBase::~CButtonBase()
+{
+
+}
+
+void CButtonBase::update()
+{
+	if (overlay)
+	{
+		if (state == PRESSED)
+			overlay->moveTo(overlay->pos.centerIn(pos).topLeft() + Point(1,1));
+		else
+			overlay->moveTo(overlay->pos.centerIn(pos).topLeft());
+	}
+
+	int newPos = (int)state + bitmapOffset;
+	if (newPos < 0)
+		newPos = 0;
+
+	if (state == HIGHLIGHTED && image->size() < 4)
+		newPos = image->size()-1;
+
+	if (swappedImages)
+	{
+		if (newPos == 0) newPos = 1;
+		else if (newPos == 1) newPos = 0;
+	}
+
+	if (!keepFrame)
+		image->setFrame(newPos);
+
+	if (active)
+		redraw();
+}
+
+void CButtonBase::addTextOverlay( const std::string &Text, EFonts font, SDL_Color color)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	addOverlay(new CLabel(pos.w/2, pos.h/2, font, CENTER, color, Text));
+	update();
+}
+
+void CButtonBase::addOverlay(CIntObject *newOverlay)
+{
+	delete overlay;
+	overlay = newOverlay;
+	addChild(newOverlay);
+	overlay->moveTo(overlay->pos.centerIn(pos).topLeft());
+	update();
+}
+
+void CButtonBase::setOffset(int newOffset)
+{
+	if (bitmapOffset == newOffset)
+		return;
+	bitmapOffset = newOffset;
+	update();
+}
+
+void CButtonBase::setState(ButtonState newState)
+{
+	if (state == newState)
+		return;
+	state = newState;
+	update();
+}
+
+CButtonBase::ButtonState CButtonBase::getState()
+{
+	return state;
+}
+
+bool CButtonBase::isBlocked()
+{
+	return state == BLOCKED;
+}
+
+bool CButtonBase::isHighlighted()
+{
+	return state == HIGHLIGHTED;
+}
+
+void CButtonBase::block(bool on)
+{
+	setState(on?BLOCKED:NORMAL);
+}
+
+CAdventureMapButton::CAdventureMapButton ()
+{
+	hoverable = actOnDown = borderEnabled = soundDisabled = false;
+	CSDL_Ext::colorSetAlpha(borderColor,1);// represents a transparent color, used for HighlightableButton
+	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 )
+{
+	std::map<int,std::string> pom;
+	pom[0] = Name;
+	init(Callback, pom, HelpBox, playerColoredButton, defName, add, x, y, key);
+}
+
+CAdventureMapButton::CAdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, config::ButtonInfo *info, int key/*=0*/ )
+{
+	std::map<int,std::string> pom;
+	pom[0] = Name;
+	init(Callback, pom, HelpBox, info->playerColoured, info->defName, &info->additionalDefs, info->x, info->y, key);
+}
+
+CAdventureMapButton::CAdventureMapButton( const std::pair<std::string, std::string> &help, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key/*=0*/, std::vector<std::string> * add /*= nullptr*/, bool playerColoredButton /*= false */ )
+{
+	std::map<int,std::string> pom;
+	pom[0] = help.first;
+	init(Callback, pom, help.second, playerColoredButton, defName, add, x, y, key);
+}
+
+void CAdventureMapButton::onButtonClicked()
+{
+	// debug logging to figure out pressed button (and as result - player actions) in case of crash
+	logAnim->traceStream() << "Button clicked at " << pos.x << "x" << pos.y;
+	CIntObject * parent = this->parent;
+	std::string prefix = "Parent is";
+	while (parent)
+	{
+		logAnim->traceStream() << prefix << typeid(*parent).name() << " at " << parent->pos.x << "x" << parent->pos.y;
+		parent = parent->parent;
+		prefix = '\t' + prefix;
+	}
+	callback();
+}
+
+void CAdventureMapButton::clickLeft(tribool down, bool previousState)
+{
+	if(isBlocked())
+		return;
+
+	if (down)
+	{
+		if (!soundDisabled)
+			CCS->soundh->playSound(soundBase::button);
+		setState(PRESSED);
+	}
+	else if(hoverable && hovered)
+		setState(HIGHLIGHTED);
+	else
+		setState(NORMAL);
+
+	if (actOnDown && down)
+	{
+		onButtonClicked();
+	}
+	else if (!actOnDown && previousState && (down==false))
+	{
+		onButtonClicked();
+	}
+}
+
+void CAdventureMapButton::clickRight(tribool down, bool previousState)
+{
+	if(down && helpBox.size()) //there is no point to show window with nothing inside...
+		CRClickPopup::createAndPush(helpBox);
+}
+
+void CAdventureMapButton::hover (bool on)
+{
+	if(hoverable)
+	{
+		if(on)
+			setState(HIGHLIGHTED);
+		else
+			setState(NORMAL);
+	}
+
+	if(pressedL && on)
+		setState(PRESSED);
+
+	std::string *name = (vstd::contains(hoverTexts,getState()))
+		? (&hoverTexts[getState()])
+		: (vstd::contains(hoverTexts,0) ? (&hoverTexts[0]) : nullptr);
+	if(name && name->size() && !isBlocked()) //if there is no name, there is nohing to display also
+	{
+		if (LOCPLINT && LOCPLINT->battleInt) //for battle buttons
+		{
+			if(on && LOCPLINT->battleInt->console->alterTxt == "")
+			{
+				LOCPLINT->battleInt->console->alterTxt = *name;
+				LOCPLINT->battleInt->console->whoSetAlter = 1;
+			}
+			else if (LOCPLINT->battleInt->console->alterTxt == *name)
+			{
+				LOCPLINT->battleInt->console->alterTxt = "";
+				LOCPLINT->battleInt->console->whoSetAlter = 0;
+			}
+		}
+		else if(GH.statusbar) //for other buttons
+		{
+			if (on)
+				GH.statusbar->setText(*name);
+			else if ( GH.statusbar->getText()==(*name) )
+				GH.statusbar->clear();
+		}
+	}
+}
+
+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;
+	addUsedEvents(LCLICK | RCLICK | HOVER | KEYBOARD);
+	callback = Callback;
+	hoverable = actOnDown = borderEnabled = soundDisabled = false;
+	CSDL_Ext::colorSetAlpha(borderColor,1);// represents a transparent color, used for HighlightableButton
+	hoverTexts = Name;
+	helpBox=HelpBox;
+
+	if (key != SDLK_UNKNOWN)
+		assignedKeys.insert(key);
+
+	pos.x += x;
+	pos.y += y;
+
+	if (!defName.empty())
+		imageNames.push_back(defName);
+	if (add)
+		for (auto & elem : *add)
+			imageNames.push_back(elem);
+	setIndex(0, playerColoredButton);
+}
+
+void CAdventureMapButton::setIndex(size_t index, bool playerColoredButton)
+{
+	if (index == currentImage || index>=imageNames.size())
+		return;
+	currentImage = index;
+	setImage(new CAnimation(imageNames[index]), playerColoredButton);
+}
+
+void CAdventureMapButton::setImage(CAnimation* anim, bool playerColoredButton, int animFlags)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+
+	delete image;
+	image = new CAnimImage(anim, getState(), 0, 0, 0, animFlags);
+	if (playerColoredButton)
+		image->playerColored(LOCPLINT->playerID);
+
+	pos.w = image->pos.w;
+	pos.h = image->pos.h;
+}
+
+void CAdventureMapButton::setPlayerColor(PlayerColor player)
+{
+	if (image)
+		image->playerColored(player);
+}
+
+void CAdventureMapButton::showAll(SDL_Surface * to)
+{
+	CIntObject::showAll(to);
+	
+	#ifdef VCMI_SDL1
+	if (borderEnabled && borderColor.unused == 0)
+		CSDL_Ext::drawBorder(to, pos.x-1, pos.y-1, pos.w+2, pos.h+2, int3(borderColor.r, borderColor.g, borderColor.b));	
+	#else
+	if (borderEnabled && borderColor.a == 0)
+		CSDL_Ext::drawBorder(to, pos.x-1, pos.y-1, pos.w+2, pos.h+2, int3(borderColor.r, borderColor.g, borderColor.b));	
+	#endif // 0
+}
+
+void CHighlightableButton::select(bool on)
+{
+	selected = on;
+	if (on)
+	{
+		borderEnabled = true;
+		setState(HIGHLIGHTED);
+		callback();
+	}
+	else
+	{
+		borderEnabled = false;
+		setState(NORMAL);
+		callback2();
+	}
+
+	if(hoverTexts.size()>1)
+	{
+		hover(false);
+		hover(true);
+	}
+}
+
+void CHighlightableButton::clickLeft(tribool down, bool previousState)
+{
+	if(isBlocked())
+		return;
+
+	if (down && !(onlyOn && isHighlighted()))
+	{
+		CCS->soundh->playSound(soundBase::button);
+		setState(PRESSED);
+	}
+
+	if(previousState)//mouse up
+	{
+		if(down == false && getState() == PRESSED)
+			select(!selected);
+		else
+			setState(selected?HIGHLIGHTED:NORMAL);
+	}
+}
+
+CHighlightableButton::CHighlightableButton( const CFunctionList<void()> &onSelect, const CFunctionList<void()> &onDeselect, 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)
+: onlyOn(false), selected(false), callback2(onDeselect)
+{
+	init(onSelect,Name,HelpBox,playerColoredButton,defName,add,x,y,key);
+}
+
+CHighlightableButton::CHighlightableButton( const std::pair<std::string, std::string> &help, const CFunctionList<void()> &onSelect, int x, int y, const std::string &defName, int myid, int key/*=0*/, std::vector<std::string> * add /*= nullptr*/, bool playerColoredButton /*= false */ )
+: onlyOn(false), selected(false) // TODO: callback2(???)
+{
+	ID = myid;
+	std::map<int,std::string> pom;
+	pom[0] = help.first;
+	init(onSelect, pom, help.second, playerColoredButton, defName, add, x, y, key);
+}
+
+CHighlightableButton::CHighlightableButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &onSelect, int x, int y, const std::string &defName, int myid, int key/*=0*/, std::vector<std::string> * add /*= nullptr*/, bool playerColoredButton /*= false */ )
+: onlyOn(false), selected(false) // TODO: callback2(???)
+{
+	ID = myid;
+	std::map<int,std::string> pom;
+	pom[0] = Name;
+	init(onSelect, pom,HelpBox, playerColoredButton, defName, add, x, y, key);
+}
+
+void CHighlightableButtonsGroup::addButton(CHighlightableButton* bt)
+{
+	if (bt->parent)
+		bt->parent->removeChild(bt);
+	addChild(bt);
+	bt->recActions = defActions;//FIXME: not needed?
+
+	bt->callback += boost::bind(&CHighlightableButtonsGroup::selectionChanged,this,bt->ID);
+	bt->onlyOn = true;
+	buttons.push_back(bt);
+}
+
+void CHighlightableButtonsGroup::addButton(const std::map<int,std::string> &tooltip, const std::string &HelpBox, const std::string &defName, int x, int y, int uid, const CFunctionList<void()> &OnSelect, int key)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	CHighlightableButton *bt = new CHighlightableButton(OnSelect, 0, tooltip, HelpBox, false, defName, nullptr, x, y, key);
+	if(musicLike)
+	{
+		bt->setOffset(buttons.size()-3);
+	}
+	bt->ID = uid;
+	bt->callback += boost::bind(&CHighlightableButtonsGroup::selectionChanged,this,bt->ID);
+	bt->onlyOn = true;
+	buttons.push_back(bt);
+}
+
+CHighlightableButtonsGroup::CHighlightableButtonsGroup(const CFunctionList<void(int)> &OnChange, bool musicLikeButtons)
+: onChange(OnChange), musicLike(musicLikeButtons)
+{}
+
+CHighlightableButtonsGroup::~CHighlightableButtonsGroup()
+{
+
+}
+
+void CHighlightableButtonsGroup::select(int id, bool mode)
+{
+	assert(!buttons.empty());
+
+	CHighlightableButton *bt = buttons.front();
+	if(mode)
+	{
+		for(auto btn : buttons)
+			if (btn->ID == id)
+				bt = btn;
+	}
+	else
+	{
+		bt = buttons[id];
+	}
+	bt->select(true);
+	selectionChanged(bt->ID);
+}
+
+void CHighlightableButtonsGroup::selectionChanged(int to)
+{
+	for(auto & elem : buttons)
+		if(elem->ID!=to && elem->isHighlighted())
+			elem->select(false);
+	onChange(to);
+	if (parent)
+		parent->redraw();
+}
+
+void CHighlightableButtonsGroup::show(SDL_Surface * to)
+{
+	if (musicLike)
+	{
+		for(auto & elem : buttons)
+			if(elem->isHighlighted())
+				elem->show(to);
+	}
+	else
+		CIntObject::show(to);
+}
+
+void CHighlightableButtonsGroup::showAll(SDL_Surface * to)
+{
+	if (musicLike)
+	{
+		for(auto & elem : buttons)
+			if(elem->isHighlighted())
+				elem->showAll(to);
+	}
+	else
+		CIntObject::showAll(to);
+}
+
+void CHighlightableButtonsGroup::block( ui8 on )
+{
+	for(auto & elem : buttons)
+	{
+		elem->block(on);
+	}
+}
+
+void CSlider::sliderClicked()
+{
+	if(!(active & MOVE))
+		addUsedEvents(MOVE);
+}
+
+void CSlider::mouseMoved (const SDL_MouseMotionEvent & sEvent)
+{
+	double v = 0;
+	if(horizontal)
+	{
+		if(	std::abs(sEvent.y-(pos.y+pos.h/2)) > pos.h/2+40  ||  std::abs(sEvent.x-(pos.x+pos.w/2)) > pos.w/2  )
+			return;
+		v = sEvent.x - pos.x - 24;
+		v *= positions;
+		v /= (pos.w - 48);
+	}
+	else
+	{
+		if(std::abs(sEvent.x-(pos.x+pos.w/2)) > pos.w/2+40  ||  std::abs(sEvent.y-(pos.y+pos.h/2)) > pos.h/2  )
+			return;
+		v = sEvent.y - pos.y - 24;
+		v *= positions;
+		v /= (pos.h - 48);
+	}
+	v += 0.5;
+	if(v!=value)
+	{
+		moveTo(v);
+		redrawSlider();
+	}
+}
+
+void CSlider::redrawSlider()
+{
+	//slider->show(screenBuf);
+}
+
+void CSlider::moveLeft()
+{
+	moveTo(value-1);
+}
+
+void CSlider::moveRight()
+{
+	moveTo(value+1);
+}
+
+void CSlider::moveTo(int to)
+{
+	vstd::amax(to, 0);
+	vstd::amin(to, positions);
+
+	//same, old position?
+	if(value == to)
+		return;
+
+	value = to;
+	if(horizontal)
+	{
+		if(positions)
+		{
+			double part = static_cast<double>(to) / positions;
+			part*=(pos.w-48);
+			int newPos = part + pos.x + 16 - slider->pos.x;
+			slider->moveBy(Point(newPos, 0));
+		}
+		else
+			slider->moveTo(Point(pos.x+16, pos.y));
+	}
+	else
+	{
+		if(positions)
+		{
+			double part = static_cast<double>(to) / positions;
+			part*=(pos.h-48);
+			int newPos = part + pos.y + 16 - slider->pos.y;
+			slider->moveBy(Point(0, newPos));
+		}
+		else
+			slider->moveTo(Point(pos.x, pos.y+16));
+	}
+
+	if(moved)
+		moved(to);
+}
+
+void CSlider::clickLeft(tribool down, bool previousState)
+{
+	if(down && !slider->isBlocked())
+	{
+		double pw = 0;
+		double rw = 0;
+		if(horizontal)
+		{
+			pw = GH.current->motion.x-pos.x-25;
+			rw = pw / static_cast<double>(pos.w - 48);
+		}
+		else
+		{
+			pw = GH.current->motion.y-pos.y-24;
+			rw = pw / (pos.h-48);
+		}
+		if(pw < -8  ||  pw > (horizontal ? pos.w : pos.h) - 40)
+			return;
+		// 		if (rw>1) return;
+		// 		if (rw<0) return;
+		slider->clickLeft(true, slider->pressedL);
+		moveTo(rw * positions  +  0.5);
+		return;
+	}
+	if(active & MOVE)
+		removeUsedEvents(MOVE);
+}
+
+CSlider::~CSlider()
+{
+
+}
+
+CSlider::CSlider(int x, int y, int totalw, std::function<void(int)> Moved, int Capacity, int Amount, int Value, bool Horizontal, int style):
+    capacity(Capacity),
+    amount(Amount),
+    scrollStep(1),
+    horizontal(Horizontal),
+    moved(Moved)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	setAmount(amount);
+
+	addUsedEvents(LCLICK | KEYBOARD | WHEEL);
+	strongInterest = true;
+
+
+	left = new CAdventureMapButton();
+	right = new CAdventureMapButton();
+	slider = new CAdventureMapButton();
+
+	pos.x += x;
+	pos.y += y;
+
+	if(horizontal)
+	{
+		left->pos.y = slider->pos.y = right->pos.y = pos.y;
+		left->pos.x = pos.x;
+		right->pos.x = pos.x + totalw - 16;
+	}
+	else
+	{
+		left->pos.x = slider->pos.x = right->pos.x = pos.x;
+		left->pos.y = pos.y;
+		right->pos.y = pos.y + totalw - 16;
+	}
+
+	left->callback = boost::bind(&CSlider::moveLeft,this);
+	right->callback = boost::bind(&CSlider::moveRight,this);
+	slider->callback = boost::bind(&CSlider::sliderClicked,this);
+	left->pos.w = left->pos.h = right->pos.w = right->pos.h = slider->pos.w = slider->pos.h = 16;
+	if(horizontal)
+	{
+		pos.h = 16;
+		pos.w = totalw;
+	}
+	else
+	{
+		pos.w = 16;
+		pos.h = totalw;
+	}
+
+	if(style == 0)
+	{
+		std::string name = horizontal?"IGPCRDIV.DEF":"OVBUTN2.DEF";
+		//NOTE: this images do not have "blocked" frames. They should be implemented somehow (e.g. palette transform or something...)
+
+		//use source def to create custom animations. Format "name.def:123" will load this frame from def file
+		auto animLeft = new CAnimation();
+		animLeft->setCustom(name + ":0", 0);
+		animLeft->setCustom(name + ":1", 1);
+		left->setImage(animLeft);
+
+		auto animRight = new CAnimation();
+		animRight->setCustom(name + ":2", 0);
+		animRight->setCustom(name + ":3", 1);
+		right->setImage(animRight);
+
+		auto animSlider = new CAnimation();
+		animSlider->setCustom(name + ":4", 0);
+		slider->setImage(animSlider);
+	}
+	else
+	{
+		left->setImage(new CAnimation(horizontal ? "SCNRBLF.DEF" : "SCNRBUP.DEF"));
+		right->setImage(new CAnimation(horizontal ? "SCNRBRT.DEF" : "SCNRBDN.DEF"));
+		slider->setImage(new CAnimation("SCNRBSL.DEF"));
+	}
+	slider->actOnDown = true;
+	slider->soundDisabled = true;
+	left->soundDisabled = true;
+	right->soundDisabled = true;
+
+	value = -1;
+	moveTo(Value);
+}
+
+void CSlider::block( bool on )
+{
+	left->block(on);
+	right->block(on);
+	slider->block(on);
+}
+
+void CSlider::setAmount( int to )
+{
+	amount = to;
+	positions = to - capacity;
+	vstd::amax(positions, 0);
+}
+
+void CSlider::showAll(SDL_Surface * to)
+{
+	CSDL_Ext::fillRectBlack(to, &pos);
+	CIntObject::showAll(to);
+}
+
+void CSlider::wheelScrolled(bool down, bool in)
+{
+	moveTo(value + 3 * (down ? +scrollStep : -scrollStep));
+}
+
+void CSlider::keyPressed(const SDL_KeyboardEvent & key)
+{
+	if(key.state != SDL_PRESSED) return;
+
+	int moveDest = 0;
+	switch(key.keysym.sym)
+	{
+	case SDLK_UP:
+	case SDLK_LEFT:
+		moveDest = value - scrollStep;
+		break;
+	case SDLK_DOWN:
+	case SDLK_RIGHT:
+		moveDest = value + scrollStep;
+		break;
+	case SDLK_PAGEUP:
+		moveDest = value - capacity + scrollStep;
+		break;
+	case SDLK_PAGEDOWN:
+		moveDest = value + capacity - scrollStep;
+		break;
+	case SDLK_HOME:
+		moveDest = 0;
+		break;
+	case SDLK_END:
+		moveDest = amount - capacity;
+		break;
+	default:
+		return;
+	}
+
+	moveTo(moveDest);
+}
+
+void CSlider::moveToMax()
+{
+	moveTo(amount);
+}

+ 175 - 0
client/widgets/Buttons.h

@@ -0,0 +1,175 @@
+#pragma once
+
+#include "../gui/CIntObject.h"
+#include "../gui/SDL_Extensions.h"
+
+#include "../../lib/FunctionList.h"
+
+struct SDL_Surface;
+struct Rect;
+class CAnimImage;
+class CLabel;
+class CAnimation;
+class CDefHandler;
+
+namespace config
+{
+	struct ButtonInfo;
+}
+
+/*
+ * Buttons.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+/// Base class for buttons.
+class CButtonBase : public CKeyShortcut
+{
+public:
+	enum ButtonState
+	{
+		NORMAL=0,
+		PRESSED=1,
+		BLOCKED=2,
+		HIGHLIGHTED=3
+	};
+private:
+	int bitmapOffset; // base offset of visible bitmap from animation
+	ButtonState state;//current state of button from enum
+
+public:
+	bool swappedImages,//fix for some buttons: normal and pressed image are swapped
+		keepFrame; // don't change visual representation
+
+	void addOverlay(CIntObject * newOverlay);
+	void addTextOverlay(const std::string &Text, EFonts font, SDL_Color color = Colors::WHITE);
+
+	void update();//to refresh button after image or text change
+
+	void setOffset(int newOffset);
+	void setState(ButtonState newState);
+	ButtonState getState();
+
+	//just to make code clearer
+	void block(bool on);
+	bool isBlocked();
+	bool isHighlighted();
+
+	CAnimImage * image; //image for this button
+	CIntObject * overlay;//object-overlay
+
+	CButtonBase(); //c-tor
+	virtual ~CButtonBase(); //d-tor
+};
+
+/// Typical Heroes 3 button which can be inactive or active and can 
+/// hold further information if you right-click it
+class CAdventureMapButton : public CButtonBase
+{
+	std::vector<std::string> imageNames;//store list of images that can be used by this button
+	size_t currentImage;
+
+	void onButtonClicked(); // calls callback
+public:
+	std::map<int, std::string> hoverTexts; //text for statusbar
+	std::string helpBox; //for right-click help
+	CFunctionList<void()> callback;
+	bool actOnDown,//runs when mouse is pressed down over it, not when up
+		hoverable,//if true, button will be highlighted when hovered
+		borderEnabled,
+		soundDisabled;
+	SDL_Color borderColor;
+
+	void clickRight(tribool down, bool previousState);
+	virtual void clickLeft(tribool down, bool previousState);
+	void hover (bool on);
+
+	CAdventureMapButton(); //c-tor
+	CAdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key=0, std::vector<std::string> * add = nullptr, bool playerColoredButton = false );//c-tor
+	CAdventureMapButton( const std::pair<std::string, std::string> &help, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key=0, std::vector<std::string> * add = nullptr, bool playerColoredButton = false );//c-tor
+	CAdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, config::ButtonInfo *info, int key=0);//c-tor
+
+	void 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 );
+
+	void setIndex(size_t index, bool playerColoredButton=false);
+	void setImage(CAnimation* anim, bool playerColoredButton=false, int animFlags=0);
+	void setPlayerColor(PlayerColor player);
+	void showAll(SDL_Surface * to);
+};
+
+/// A button which can be selected/deselected
+class CHighlightableButton 
+	: public CAdventureMapButton
+{
+public:
+	CHighlightableButton(const CFunctionList<void()> &onSelect, const CFunctionList<void()> &onDeselect, 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=0);
+	CHighlightableButton(const std::pair<std::string, std::string> &help, const CFunctionList<void()> &onSelect, int x, int y, const std::string &defName, int myid, int key=0, std::vector<std::string> * add = nullptr, bool playerColoredButton = false );//c-tor
+	CHighlightableButton(const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &onSelect, int x, int y, const std::string &defName, int myid, int key=0, std::vector<std::string> * add = nullptr, bool playerColoredButton = false );//c-tor
+	bool onlyOn;//button can not be de-selected
+	bool selected;//state of highlightable button
+	int ID; //for identification
+	CFunctionList<void()> callback2; //when de-selecting
+	void select(bool on);
+	void clickLeft(tribool down, bool previousState);
+};
+
+/// A group of buttons where one button can be selected
+class CHighlightableButtonsGroup : public CIntObject
+{
+public:
+	CFunctionList<void(int)> onChange; //called when changing selected button with new button's id
+	std::vector<CHighlightableButton*> buttons;
+	bool musicLike; //determines the behaviour of this group
+
+	//void addButton(const std::map<int,std::string> &tooltip, const std::string &HelpBox, const std::string &defName, int x, int y, int uid);
+	void addButton(CHighlightableButton* bt);//add existing button, it'll be deleted by CHighlightableButtonsGroup destructor
+	void addButton(const std::map<int,std::string> &tooltip, const std::string &HelpBox, const std::string &defName, int x, int y, int uid, const CFunctionList<void()> &OnSelect=0, int key=0); //creates new button
+	CHighlightableButtonsGroup(const CFunctionList<void(int)> & OnChange, bool musicLikeButtons = false);
+	~CHighlightableButtonsGroup();
+	void select(int id, bool mode); //mode==0: id is serial; mode==1: id is unique button id
+	void selectionChanged(int to);
+	void show(SDL_Surface * to);
+	void showAll(SDL_Surface * to);
+	void block(ui8 on);
+};
+
+/// A typical slider which can be orientated horizontally/vertically.
+class CSlider : public CIntObject
+{
+public:
+	CAdventureMapButton *left, *right, *slider; //if vertical then left=up
+	int capacity;//how many elements can be active at same time (e.g. hero list = 5)
+	int amount; //total amount of elements (e.g. hero list = 0-8)
+	int positions; //number of highest position (0 if there is only one)
+	int value; //first active element
+	int scrollStep; // how many elements will be scrolled via one click, default = 1
+	bool horizontal;
+	bool wheelScrolling;
+	bool keyScrolling;
+
+	std::function<void(int)> moved;
+
+	void redrawSlider(); 
+	void sliderClicked();
+	void moveLeft();
+	void moveRight();
+	void moveTo(int to);
+	void block(bool on);
+	void setAmount(int to);
+
+	void keyPressed(const SDL_KeyboardEvent & key);
+	void wheelScrolled(bool down, bool in);
+	void clickLeft(tribool down, bool previousState);
+	void mouseMoved (const SDL_MouseMotionEvent & sEvent);
+	void showAll(SDL_Surface * to);	
+
+	CSlider(int x, int y, int totalw, std::function<void(int)> Moved, int Capacity, int Amount, 
+		int Value=0, bool Horizontal=true, int style = 0); //style 0 - brown, 1 - blue
+	~CSlider();
+	void moveToMax();
+};

+ 3 - 1
client/widgets/CArtifactHolder.cpp

@@ -4,7 +4,9 @@
 #include "../gui/CGuiHandler.h"
 #include "../gui/CCursorHandler.h"
 
-#include "CAnimation.h"
+#include "Buttons.h"
+#include "CComponent.h"
+
 #include "../windows/CHeroWindow.h"
 #include "../windows/CSpellWindow.h"
 #include "../windows/GUIClasses.h"

+ 2 - 1
client/widgets/CArtifactHolder.h

@@ -1,6 +1,7 @@
 #pragma once
 
-#include "CComponent.h"
+//#include "CComponent.h"
+#include "MiscWidgets.h"
 
 /*
  * CArtifactHolder.h, part of VCMI engine

+ 1 - 1
client/widgets/CComponent.cpp

@@ -4,9 +4,9 @@
 #include "../gui/CGuiHandler.h"
 #include "../gui/CCursorHandler.h"
 
-#include "CAnimation.h"
 #include "../CMessage.h"
 #include "../CGameInfo.h"
+#include "../widgets/Images.h"
 #include "../windows/CAdvmapInterface.h"
 
 #include "../../lib/CArtHandler.h"

+ 2 - 14
client/widgets/CComponent.h

@@ -1,6 +1,6 @@
 #pragma once
 
-#include "CIntObjectClasses.h"
+#include "../gui/CIntObject.h"
 
 /*
  * CComponent.h, part of VCMI engine
@@ -13,6 +13,7 @@
  */
 
 struct Component;
+class CAnimImage;
 
 /// common popup window component
 class CComponent : public virtual CIntObject
@@ -109,16 +110,3 @@ public:
 	/// onSelect - optional function that will be called every time on selection change
 	CComponentBox(std::vector<CSelectableComponent *> components, Rect position, std::function<void(int newID)> onSelect = nullptr);
 };
-
-/// Can interact on left and right mouse clicks
-class LRClickableAreaWTextComp: public LRClickableAreaWText
-{
-public:
-	int baseType;
-	int bonusValue, type;
-	virtual void clickLeft(tribool down, bool previousState);
-	virtual void clickRight(tribool down, bool previousState);
-
-	LRClickableAreaWTextComp(const Rect &Pos = Rect(0,0,0,0), int BaseType = -1);
-	CComponent * createComponent() const;
-};

+ 12 - 1
client/widgets/CGarrisonInt.cpp

@@ -3,9 +3,10 @@
 
 #include "../gui/CGuiHandler.h"
 
-#include "CAnimation.h"
 #include "../CGameInfo.h"
 #include "../CPlayerInterface.h"
+#include "../widgets/Buttons.h"
+#include "../widgets/TextControls.h"
 #include "../windows/CCreatureWindow.h"
 #include "../windows/GUIClasses.h"
 
@@ -17,6 +18,16 @@
 
 #include "../../lib/CGameState.h"
 
+/*
+ * CGarrisonInt.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
 void CGarrisonSlot::setHighlight(bool on)
 {
 	if (on)

+ 1 - 1
client/widgets/CGarrisonInt.h

@@ -1,6 +1,6 @@
 #pragma once
 
-#include "CIntObjectClasses.h"
+#include "../windows/CWindowObject.h"
 
 /*
  * CGarrisonInt.h, part of VCMI engine

+ 0 - 2025
client/widgets/CIntObjectClasses.cpp

@@ -1,2025 +0,0 @@
-#include "StdInc.h"
-#include "CIntObjectClasses.h"
-
-#include "CAnimation.h"
-#include "MiscWidgets.h"
-
-#include "../gui/SDL_Pixels.h"
-#include "../gui/SDL_Extensions.h"
-#include "../gui/CGuiHandler.h"
-#include "../gui/CCursorHandler.h"
-
-#include "../battle/CBattleInterface.h"
-#include "../battle/CBattleInterfaceClasses.h"
-
-#include "../CBitmapHandler.h"
-#include "../Graphics.h"
-#include "../CGameInfo.h"
-#include "../CPlayerInterface.h"
-#include "../CMessage.h"
-#include "../CMusicHandler.h"
-#include "../windows/CAdvmapInterface.h"
-
-#include "../../CCallback.h"
-
-#include "../../lib/CConfigHandler.h"
-#include "../../lib/CGeneralTextHandler.h" //for Unicode related stuff
-
-CPicture::CPicture( SDL_Surface *BG, int x, int y, bool Free )
-{
-	init();
-	bg = BG;
-	freeSurf = Free;
-	pos.x += x;
-	pos.y += y;
-	pos.w = BG->w;
-	pos.h = BG->h;
-}
-
-CPicture::CPicture( const std::string &bmpname, int x, int y )
-{
-	init();
-	bg = BitmapHandler::loadBitmap(bmpname);
-	freeSurf = true;;
-	pos.x += x;
-	pos.y += y;
-	if(bg)
-	{
-		pos.w = bg->w;
-		pos.h = bg->h;
-	}
-	else
-	{
-		pos.w = pos.h = 0;
-	}
-}
-
-CPicture::CPicture(const Rect &r, const SDL_Color &color, bool screenFormat /*= false*/)
-{
-	init();
-	createSimpleRect(r, screenFormat, SDL_MapRGB(bg->format, color.r, color.g,color.b));
-}
-
-CPicture::CPicture(const Rect &r, ui32 color, bool screenFormat /*= false*/)
-{
-	init();
-	createSimpleRect(r, screenFormat, color);
-}
-
-CPicture::CPicture(SDL_Surface *BG, const Rect &SrcRect, int x /*= 0*/, int y /*= 0*/, bool free /*= false*/)
-{
-	needRefresh = false;
-	srcRect = new Rect(SrcRect);
-	pos.x += x;
-	pos.y += y;
-	pos.w = srcRect->w;
-	pos.h = srcRect->h;
-	bg = BG;
-	freeSurf = free;
-}
-
-void CPicture::setSurface(SDL_Surface *to)
-{
-	bg = to;
-	if (srcRect)
-	{
-		pos.w = srcRect->w;
-		pos.h = srcRect->h;
-	}
-	else
-	{
-		pos.w = bg->w;
-		pos.h = bg->h;
-	}
-}
-
-CPicture::~CPicture()
-{
-	if(freeSurf)
-		SDL_FreeSurface(bg);
-	delete srcRect;
-}
-
-void CPicture::init()
-{
-	needRefresh = false;
-	srcRect = nullptr;
-}
-
-void CPicture::show(SDL_Surface * to)
-{
-	if (needRefresh)
-		showAll(to);
-}
-
-void CPicture::showAll(SDL_Surface * to)
-{
-	if(bg)
-	{
-		if(srcRect)
-		{
-			SDL_Rect srcRectCpy = *srcRect;
-			SDL_Rect dstRect = srcRectCpy;
-			dstRect.x = pos.x;
-			dstRect.y = pos.y;
-
-			CSDL_Ext::blitSurface(bg, &srcRectCpy, to, &dstRect);
-		}
-		else
-			blitAt(bg, pos, to);
-	}
-}
-
-void CPicture::convertToScreenBPP()
-{
-	SDL_Surface *hlp = bg;
-	bg = SDL_ConvertSurface(hlp,screen->format,0);
-	CSDL_Ext::setDefaultColorKey(bg);	
-	SDL_FreeSurface(hlp);
-}
-
-void CPicture::setAlpha(int value)
-{	
-	#ifdef VCMI_SDL1
-	SDL_SetAlpha(bg, SDL_SRCALPHA, value);	
-	#else
-	SDL_SetSurfaceAlphaMod(bg,value);
-	#endif // 0
-}
-
-void CPicture::scaleTo(Point size)
-{
-	SDL_Surface * scaled = CSDL_Ext::scaleSurface(bg, size.x, size.y);
-
-	if(freeSurf)
-		SDL_FreeSurface(bg);
-
-	setSurface(scaled);
-	freeSurf = false;
-}
-
-void CPicture::createSimpleRect(const Rect &r, bool screenFormat, ui32 color)
-{
-	pos += r;
-	pos.w = r.w;
-	pos.h = r.h;
-	if(screenFormat)
-		bg = CSDL_Ext::newSurface(r.w, r.h);
-	else
-		bg = SDL_CreateRGBSurface(SDL_SWSURFACE, r.w, r.h, 8, 0, 0, 0, 0);
-
-	SDL_FillRect(bg, nullptr, color);
-	freeSurf = true;
-}
-
-void CPicture::colorizeAndConvert(PlayerColor player)
-{
-	assert(bg);
-	colorize(player);
-	convertToScreenBPP();
-}
-
-void CPicture::colorize(PlayerColor player)
-{
-	assert(bg);
-	graphics->blueToPlayersAdv(bg, player);
-}
-
-CFilledTexture::CFilledTexture(std::string imageName, Rect position):
-    CIntObject(0, position.topLeft()),
-    texture(BitmapHandler::loadBitmap(imageName))
-{
-	pos.w = position.w;
-	pos.h = position.h;
-}
-
-CFilledTexture::~CFilledTexture()
-{
-	SDL_FreeSurface(texture);
-}
-
-void CFilledTexture::showAll(SDL_Surface *to)
-{
-	CSDL_Ext::CClipRectGuard guard(to, pos);
-	CSDL_Ext::fillTexture(to, texture);
-}
-
-CButtonBase::CButtonBase()
-{
-	swappedImages = keepFrame = false;
-	bitmapOffset = 0;
-	state=NORMAL;
-	image = nullptr;
-	overlay = nullptr;
-}
-
-CButtonBase::~CButtonBase()
-{
-
-}
-
-void CButtonBase::update()
-{
-	if (overlay)
-	{
-		if (state == PRESSED)
-			overlay->moveTo(overlay->pos.centerIn(pos).topLeft() + Point(1,1));
-		else
-			overlay->moveTo(overlay->pos.centerIn(pos).topLeft());
-	}
-
-	int newPos = (int)state + bitmapOffset;
-	if (newPos < 0)
-		newPos = 0;
-
-	if (state == HIGHLIGHTED && image->size() < 4)
-		newPos = image->size()-1;
-
-	if (swappedImages)
-	{
-		if (newPos == 0) newPos = 1;
-		else if (newPos == 1) newPos = 0;
-	}
-
-	if (!keepFrame)
-		image->setFrame(newPos);
-
-	if (active)
-		redraw();
-}
-
-void CButtonBase::addTextOverlay( const std::string &Text, EFonts font, SDL_Color color)
-{
-	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	addOverlay(new CLabel(pos.w/2, pos.h/2, font, CENTER, color, Text));
-	update();
-}
-
-void CButtonBase::addOverlay(CIntObject *newOverlay)
-{
-	delete overlay;
-	overlay = newOverlay;
-	addChild(newOverlay);
-	overlay->moveTo(overlay->pos.centerIn(pos).topLeft());
-	update();
-}
-
-void CButtonBase::setOffset(int newOffset)
-{
-	if (bitmapOffset == newOffset)
-		return;
-	bitmapOffset = newOffset;
-	update();
-}
-
-void CButtonBase::setState(ButtonState newState)
-{
-	if (state == newState)
-		return;
-	state = newState;
-	update();
-}
-
-CButtonBase::ButtonState CButtonBase::getState()
-{
-	return state;
-}
-
-bool CButtonBase::isBlocked()
-{
-	return state == BLOCKED;
-}
-
-bool CButtonBase::isHighlighted()
-{
-	return state == HIGHLIGHTED;
-}
-
-void CButtonBase::block(bool on)
-{
-	setState(on?BLOCKED:NORMAL);
-}
-
-CAdventureMapButton::CAdventureMapButton ()
-{
-	hoverable = actOnDown = borderEnabled = soundDisabled = false;
-	CSDL_Ext::colorSetAlpha(borderColor,1);// represents a transparent color, used for HighlightableButton
-	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 )
-{
-	std::map<int,std::string> pom;
-	pom[0] = Name;
-	init(Callback, pom, HelpBox, playerColoredButton, defName, add, x, y, key);
-}
-
-CAdventureMapButton::CAdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, config::ButtonInfo *info, int key/*=0*/ )
-{
-	std::map<int,std::string> pom;
-	pom[0] = Name;
-	init(Callback, pom, HelpBox, info->playerColoured, info->defName, &info->additionalDefs, info->x, info->y, key);
-}
-
-CAdventureMapButton::CAdventureMapButton( const std::pair<std::string, std::string> &help, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key/*=0*/, std::vector<std::string> * add /*= nullptr*/, bool playerColoredButton /*= false */ )
-{
-	std::map<int,std::string> pom;
-	pom[0] = help.first;
-	init(Callback, pom, help.second, playerColoredButton, defName, add, x, y, key);
-}
-
-void CAdventureMapButton::onButtonClicked()
-{
-	// debug logging to figure out pressed button (and as result - player actions) in case of crash
-	logAnim->traceStream() << "Button clicked at " << pos.x << "x" << pos.y;
-	CIntObject * parent = this->parent;
-	std::string prefix = "Parent is";
-	while (parent)
-	{
-		logAnim->traceStream() << prefix << typeid(*parent).name() << " at " << parent->pos.x << "x" << parent->pos.y;
-		parent = parent->parent;
-		prefix = '\t' + prefix;
-	}
-	callback();
-}
-
-void CAdventureMapButton::clickLeft(tribool down, bool previousState)
-{
-	if(isBlocked())
-		return;
-
-	if (down)
-	{
-		if (!soundDisabled)
-			CCS->soundh->playSound(soundBase::button);
-		setState(PRESSED);
-	}
-	else if(hoverable && hovered)
-		setState(HIGHLIGHTED);
-	else
-		setState(NORMAL);
-
-	if (actOnDown && down)
-	{
-		onButtonClicked();
-	}
-	else if (!actOnDown && previousState && (down==false))
-	{
-		onButtonClicked();
-	}
-}
-
-void CAdventureMapButton::clickRight(tribool down, bool previousState)
-{
-	if(down && helpBox.size()) //there is no point to show window with nothing inside...
-		CRClickPopup::createAndPush(helpBox);
-}
-
-void CAdventureMapButton::hover (bool on)
-{
-	if(hoverable)
-	{
-		if(on)
-			setState(HIGHLIGHTED);
-		else
-			setState(NORMAL);
-	}
-
-	if(pressedL && on)
-		setState(PRESSED);
-
-	std::string *name = (vstd::contains(hoverTexts,getState()))
-		? (&hoverTexts[getState()])
-		: (vstd::contains(hoverTexts,0) ? (&hoverTexts[0]) : nullptr);
-	if(name && name->size() && !isBlocked()) //if there is no name, there is nohing to display also
-	{
-		if (LOCPLINT && LOCPLINT->battleInt) //for battle buttons
-		{
-			if(on && LOCPLINT->battleInt->console->alterTxt == "")
-			{
-				LOCPLINT->battleInt->console->alterTxt = *name;
-				LOCPLINT->battleInt->console->whoSetAlter = 1;
-			}
-			else if (LOCPLINT->battleInt->console->alterTxt == *name)
-			{
-				LOCPLINT->battleInt->console->alterTxt = "";
-				LOCPLINT->battleInt->console->whoSetAlter = 0;
-			}
-		}
-		else if(GH.statusbar) //for other buttons
-		{
-			if (on)
-				GH.statusbar->setText(*name);
-			else if ( GH.statusbar->getText()==(*name) )
-				GH.statusbar->clear();
-		}
-	}
-}
-
-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;
-	addUsedEvents(LCLICK | RCLICK | HOVER | KEYBOARD);
-	callback = Callback;
-	hoverable = actOnDown = borderEnabled = soundDisabled = false;
-	CSDL_Ext::colorSetAlpha(borderColor,1);// represents a transparent color, used for HighlightableButton
-	hoverTexts = Name;
-	helpBox=HelpBox;
-
-	if (key != SDLK_UNKNOWN)
-		assignedKeys.insert(key);
-
-	pos.x += x;
-	pos.y += y;
-
-	if (!defName.empty())
-		imageNames.push_back(defName);
-	if (add)
-		for (auto & elem : *add)
-			imageNames.push_back(elem);
-	setIndex(0, playerColoredButton);
-}
-
-void CAdventureMapButton::setIndex(size_t index, bool playerColoredButton)
-{
-	if (index == currentImage || index>=imageNames.size())
-		return;
-	currentImage = index;
-	setImage(new CAnimation(imageNames[index]), playerColoredButton);
-}
-
-void CAdventureMapButton::setImage(CAnimation* anim, bool playerColoredButton, int animFlags)
-{
-	OBJ_CONSTRUCTION_CAPTURING_ALL;
-
-	delete image;
-	image = new CAnimImage(anim, getState(), 0, 0, 0, animFlags);
-	if (playerColoredButton)
-		image->playerColored(LOCPLINT->playerID);
-
-	pos.w = image->pos.w;
-	pos.h = image->pos.h;
-}
-
-void CAdventureMapButton::setPlayerColor(PlayerColor player)
-{
-	if (image)
-		image->playerColored(player);
-}
-
-void CAdventureMapButton::showAll(SDL_Surface * to)
-{
-	CIntObject::showAll(to);
-	
-	#ifdef VCMI_SDL1
-	if (borderEnabled && borderColor.unused == 0)
-		CSDL_Ext::drawBorder(to, pos.x-1, pos.y-1, pos.w+2, pos.h+2, int3(borderColor.r, borderColor.g, borderColor.b));	
-	#else
-	if (borderEnabled && borderColor.a == 0)
-		CSDL_Ext::drawBorder(to, pos.x-1, pos.y-1, pos.w+2, pos.h+2, int3(borderColor.r, borderColor.g, borderColor.b));	
-	#endif // 0
-}
-
-void CHighlightableButton::select(bool on)
-{
-	selected = on;
-	if (on)
-	{
-		borderEnabled = true;
-		setState(HIGHLIGHTED);
-		callback();
-	}
-	else
-	{
-		borderEnabled = false;
-		setState(NORMAL);
-		callback2();
-	}
-
-	if(hoverTexts.size()>1)
-	{
-		hover(false);
-		hover(true);
-	}
-}
-
-void CHighlightableButton::clickLeft(tribool down, bool previousState)
-{
-	if(isBlocked())
-		return;
-
-	if (down && !(onlyOn && isHighlighted()))
-	{
-		CCS->soundh->playSound(soundBase::button);
-		setState(PRESSED);
-	}
-
-	if(previousState)//mouse up
-	{
-		if(down == false && getState() == PRESSED)
-			select(!selected);
-		else
-			setState(selected?HIGHLIGHTED:NORMAL);
-	}
-}
-
-CHighlightableButton::CHighlightableButton( const CFunctionList<void()> &onSelect, const CFunctionList<void()> &onDeselect, 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)
-: onlyOn(false), selected(false), callback2(onDeselect)
-{
-	init(onSelect,Name,HelpBox,playerColoredButton,defName,add,x,y,key);
-}
-
-CHighlightableButton::CHighlightableButton( const std::pair<std::string, std::string> &help, const CFunctionList<void()> &onSelect, int x, int y, const std::string &defName, int myid, int key/*=0*/, std::vector<std::string> * add /*= nullptr*/, bool playerColoredButton /*= false */ )
-: onlyOn(false), selected(false) // TODO: callback2(???)
-{
-	ID = myid;
-	std::map<int,std::string> pom;
-	pom[0] = help.first;
-	init(onSelect, pom, help.second, playerColoredButton, defName, add, x, y, key);
-}
-
-CHighlightableButton::CHighlightableButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &onSelect, int x, int y, const std::string &defName, int myid, int key/*=0*/, std::vector<std::string> * add /*= nullptr*/, bool playerColoredButton /*= false */ )
-: onlyOn(false), selected(false) // TODO: callback2(???)
-{
-	ID = myid;
-	std::map<int,std::string> pom;
-	pom[0] = Name;
-	init(onSelect, pom,HelpBox, playerColoredButton, defName, add, x, y, key);
-}
-
-void CHighlightableButtonsGroup::addButton(CHighlightableButton* bt)
-{
-	if (bt->parent)
-		bt->parent->removeChild(bt);
-	addChild(bt);
-	bt->recActions = defActions;//FIXME: not needed?
-
-	bt->callback += boost::bind(&CHighlightableButtonsGroup::selectionChanged,this,bt->ID);
-	bt->onlyOn = true;
-	buttons.push_back(bt);
-}
-
-void CHighlightableButtonsGroup::addButton(const std::map<int,std::string> &tooltip, const std::string &HelpBox, const std::string &defName, int x, int y, int uid, const CFunctionList<void()> &OnSelect, int key)
-{
-	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	CHighlightableButton *bt = new CHighlightableButton(OnSelect, 0, tooltip, HelpBox, false, defName, nullptr, x, y, key);
-	if(musicLike)
-	{
-		bt->setOffset(buttons.size()-3);
-	}
-	bt->ID = uid;
-	bt->callback += boost::bind(&CHighlightableButtonsGroup::selectionChanged,this,bt->ID);
-	bt->onlyOn = true;
-	buttons.push_back(bt);
-}
-
-CHighlightableButtonsGroup::CHighlightableButtonsGroup(const CFunctionList<void(int)> &OnChange, bool musicLikeButtons)
-: onChange(OnChange), musicLike(musicLikeButtons)
-{}
-
-CHighlightableButtonsGroup::~CHighlightableButtonsGroup()
-{
-
-}
-
-void CHighlightableButtonsGroup::select(int id, bool mode)
-{
-	assert(!buttons.empty());
-
-	CHighlightableButton *bt = buttons.front();
-	if(mode)
-	{
-		for(auto btn : buttons)
-			if (btn->ID == id)
-				bt = btn;
-	}
-	else
-	{
-		bt = buttons[id];
-	}
-	bt->select(true);
-	selectionChanged(bt->ID);
-}
-
-void CHighlightableButtonsGroup::selectionChanged(int to)
-{
-	for(auto & elem : buttons)
-		if(elem->ID!=to && elem->isHighlighted())
-			elem->select(false);
-	onChange(to);
-	if (parent)
-		parent->redraw();
-}
-
-void CHighlightableButtonsGroup::show(SDL_Surface * to)
-{
-	if (musicLike)
-	{
-		for(auto & elem : buttons)
-			if(elem->isHighlighted())
-				elem->show(to);
-	}
-	else
-		CIntObject::show(to);
-}
-
-void CHighlightableButtonsGroup::showAll(SDL_Surface * to)
-{
-	if (musicLike)
-	{
-		for(auto & elem : buttons)
-			if(elem->isHighlighted())
-				elem->showAll(to);
-	}
-	else
-		CIntObject::showAll(to);
-}
-
-void CHighlightableButtonsGroup::block( ui8 on )
-{
-	for(auto & elem : buttons)
-	{
-		elem->block(on);
-	}
-}
-
-void CSlider::sliderClicked()
-{
-	if(!(active & MOVE))
-		addUsedEvents(MOVE);
-}
-
-void CSlider::mouseMoved (const SDL_MouseMotionEvent & sEvent)
-{
-	double v = 0;
-	if(horizontal)
-	{
-		if(	std::abs(sEvent.y-(pos.y+pos.h/2)) > pos.h/2+40  ||  std::abs(sEvent.x-(pos.x+pos.w/2)) > pos.w/2  )
-			return;
-		v = sEvent.x - pos.x - 24;
-		v *= positions;
-		v /= (pos.w - 48);
-	}
-	else
-	{
-		if(std::abs(sEvent.x-(pos.x+pos.w/2)) > pos.w/2+40  ||  std::abs(sEvent.y-(pos.y+pos.h/2)) > pos.h/2  )
-			return;
-		v = sEvent.y - pos.y - 24;
-		v *= positions;
-		v /= (pos.h - 48);
-	}
-	v += 0.5;
-	if(v!=value)
-	{
-		moveTo(v);
-		redrawSlider();
-	}
-}
-
-void CSlider::redrawSlider()
-{
-	//slider->show(screenBuf);
-}
-
-void CSlider::moveLeft()
-{
-	moveTo(value-1);
-}
-
-void CSlider::moveRight()
-{
-	moveTo(value+1);
-}
-
-void CSlider::moveTo(int to)
-{
-	vstd::amax(to, 0);
-	vstd::amin(to, positions);
-
-	//same, old position?
-	if(value == to)
-		return;
-
-	value = to;
-	if(horizontal)
-	{
-		if(positions)
-		{
-			double part = static_cast<double>(to) / positions;
-			part*=(pos.w-48);
-			int newPos = part + pos.x + 16 - slider->pos.x;
-			slider->moveBy(Point(newPos, 0));
-		}
-		else
-			slider->moveTo(Point(pos.x+16, pos.y));
-	}
-	else
-	{
-		if(positions)
-		{
-			double part = static_cast<double>(to) / positions;
-			part*=(pos.h-48);
-			int newPos = part + pos.y + 16 - slider->pos.y;
-			slider->moveBy(Point(0, newPos));
-		}
-		else
-			slider->moveTo(Point(pos.x, pos.y+16));
-	}
-
-	if(moved)
-		moved(to);
-}
-
-void CSlider::clickLeft(tribool down, bool previousState)
-{
-	if(down && !slider->isBlocked())
-	{
-		double pw = 0;
-		double rw = 0;
-		if(horizontal)
-		{
-			pw = GH.current->motion.x-pos.x-25;
-			rw = pw / static_cast<double>(pos.w - 48);
-		}
-		else
-		{
-			pw = GH.current->motion.y-pos.y-24;
-			rw = pw / (pos.h-48);
-		}
-		if(pw < -8  ||  pw > (horizontal ? pos.w : pos.h) - 40)
-			return;
-		// 		if (rw>1) return;
-		// 		if (rw<0) return;
-		slider->clickLeft(true, slider->pressedL);
-		moveTo(rw * positions  +  0.5);
-		return;
-	}
-	if(active & MOVE)
-		removeUsedEvents(MOVE);
-}
-
-CSlider::~CSlider()
-{
-
-}
-
-CSlider::CSlider(int x, int y, int totalw, std::function<void(int)> Moved, int Capacity, int Amount, int Value, bool Horizontal, int style):
-    capacity(Capacity),
-    amount(Amount),
-    scrollStep(1),
-    horizontal(Horizontal),
-    moved(Moved)
-{
-	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	setAmount(amount);
-
-	addUsedEvents(LCLICK | KEYBOARD | WHEEL);
-	strongInterest = true;
-
-
-	left = new CAdventureMapButton();
-	right = new CAdventureMapButton();
-	slider = new CAdventureMapButton();
-
-	pos.x += x;
-	pos.y += y;
-
-	if(horizontal)
-	{
-		left->pos.y = slider->pos.y = right->pos.y = pos.y;
-		left->pos.x = pos.x;
-		right->pos.x = pos.x + totalw - 16;
-	}
-	else
-	{
-		left->pos.x = slider->pos.x = right->pos.x = pos.x;
-		left->pos.y = pos.y;
-		right->pos.y = pos.y + totalw - 16;
-	}
-
-	left->callback = boost::bind(&CSlider::moveLeft,this);
-	right->callback = boost::bind(&CSlider::moveRight,this);
-	slider->callback = boost::bind(&CSlider::sliderClicked,this);
-	left->pos.w = left->pos.h = right->pos.w = right->pos.h = slider->pos.w = slider->pos.h = 16;
-	if(horizontal)
-	{
-		pos.h = 16;
-		pos.w = totalw;
-	}
-	else
-	{
-		pos.w = 16;
-		pos.h = totalw;
-	}
-
-	if(style == 0)
-	{
-		std::string name = horizontal?"IGPCRDIV.DEF":"OVBUTN2.DEF";
-		//NOTE: this images do not have "blocked" frames. They should be implemented somehow (e.g. palette transform or something...)
-
-		//use source def to create custom animations. Format "name.def:123" will load this frame from def file
-		auto animLeft = new CAnimation();
-		animLeft->setCustom(name + ":0", 0);
-		animLeft->setCustom(name + ":1", 1);
-		left->setImage(animLeft);
-
-		auto animRight = new CAnimation();
-		animRight->setCustom(name + ":2", 0);
-		animRight->setCustom(name + ":3", 1);
-		right->setImage(animRight);
-
-		auto animSlider = new CAnimation();
-		animSlider->setCustom(name + ":4", 0);
-		slider->setImage(animSlider);
-	}
-	else
-	{
-		left->setImage(new CAnimation(horizontal ? "SCNRBLF.DEF" : "SCNRBUP.DEF"));
-		right->setImage(new CAnimation(horizontal ? "SCNRBRT.DEF" : "SCNRBDN.DEF"));
-		slider->setImage(new CAnimation("SCNRBSL.DEF"));
-	}
-	slider->actOnDown = true;
-	slider->soundDisabled = true;
-	left->soundDisabled = true;
-	right->soundDisabled = true;
-
-	value = -1;
-	moveTo(Value);
-}
-
-void CSlider::block( bool on )
-{
-	left->block(on);
-	right->block(on);
-	slider->block(on);
-}
-
-void CSlider::setAmount( int to )
-{
-	amount = to;
-	positions = to - capacity;
-	vstd::amax(positions, 0);
-}
-
-void CSlider::showAll(SDL_Surface * to)
-{
-	CSDL_Ext::fillRectBlack(to, &pos);
-	CIntObject::showAll(to);
-}
-
-void CSlider::wheelScrolled(bool down, bool in)
-{
-	moveTo(value + 3 * (down ? +scrollStep : -scrollStep));
-}
-
-void CSlider::keyPressed(const SDL_KeyboardEvent & key)
-{
-	if(key.state != SDL_PRESSED) return;
-
-	int moveDest = 0;
-	switch(key.keysym.sym)
-	{
-	case SDLK_UP:
-	case SDLK_LEFT:
-		moveDest = value - scrollStep;
-		break;
-	case SDLK_DOWN:
-	case SDLK_RIGHT:
-		moveDest = value + scrollStep;
-		break;
-	case SDLK_PAGEUP:
-		moveDest = value - capacity + scrollStep;
-		break;
-	case SDLK_PAGEDOWN:
-		moveDest = value + capacity - scrollStep;
-		break;
-	case SDLK_HOME:
-		moveDest = 0;
-		break;
-	case SDLK_END:
-		moveDest = amount - capacity;
-		break;
-	default:
-		return;
-	}
-
-	moveTo(moveDest);
-}
-
-void CSlider::moveToMax()
-{
-	moveTo(amount);
-}
-
-static void intDeleter(CIntObject* object)
-{
-	delete object;
-}
-
-CObjectList::CObjectList(CreateFunc create, DestroyFunc destroy):
-createObject(create),
-destroyObject(destroy)
-{
-	if (!destroyObject)
-		destroyObject = intDeleter;
-}
-
-void CObjectList::deleteItem(CIntObject* item)
-{
-	if (!item)
-		return;
-	removeChild(item);
-	destroyObject(item);
-}
-
-CIntObject* CObjectList::createItem(size_t index)
-{
-	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	CIntObject * item = createObject(index);
-	if (item == nullptr)
-		item = new CIntObject();
-
-	item->recActions = defActions;
-
-	addChild(item);
-	return item;
-}
-
-CTabbedInt::CTabbedInt(CreateFunc create, DestroyFunc destroy, Point position, size_t ActiveID):
-CObjectList(create, destroy),
-activeTab(nullptr),
-activeID(ActiveID)
-{
-	pos += position;
-	reset();
-}
-
-void CTabbedInt::setActive(size_t which)
-{
-	if (which != activeID)
-	{
-		activeID = which;
-		reset();
-	}
-}
-
-void CTabbedInt::reset()
-{
-	deleteItem(activeTab);
-	activeTab = createItem(activeID);
-	activeTab->moveTo(pos.topLeft());
-
-	if (active)
-		redraw();
-}
-
-CIntObject * CTabbedInt::getItem()
-{
-	return activeTab;
-}
-
-CListBox::CListBox(CreateFunc create, DestroyFunc destroy, Point Pos, Point ItemOffset, size_t VisibleSize,
-				   size_t TotalSize, size_t InitialPos, int Slider, Rect SliderPos):
-	CObjectList(create, destroy),
-	first(InitialPos),
-	totalSize(TotalSize),
-	itemOffset(ItemOffset),
-    slider(nullptr)
-{
-	pos += Pos;
-	items.resize(VisibleSize, nullptr);
-
-	if (Slider & 1)
-	{
-		OBJ_CONSTRUCTION_CAPTURING_ALL;
-		slider = new CSlider(SliderPos.x, SliderPos.y, SliderPos.w, boost::bind(&CListBox::moveToPos, this, _1),
-			VisibleSize, TotalSize, InitialPos, Slider & 2, Slider & 4);
-	}
-	reset();
-}
-
-// Used to move active items after changing list position
-void CListBox::updatePositions()
-{
-	Point itemPos = pos.topLeft();
-	for (auto & elem : items)
-	{
-		(elem)->moveTo(itemPos);
-		itemPos += itemOffset;
-	}
-	if (active)
-	{
-		redraw();
-		if (slider)
-			slider->moveTo(first);
-	}
-}
-
-void CListBox::reset()
-{
-	size_t current = first;
-	for (auto & elem : items)
-	{
-		deleteItem(elem);
-		elem = createItem(current++);
-	}
-	updatePositions();
-}
-
-void CListBox::resize(size_t newSize)
-{
-	totalSize = newSize;
-	if (slider)
-		slider->setAmount(totalSize);
-	reset();
-}
-
-size_t CListBox::size()
-{
-	return totalSize;
-}
-
-CIntObject * CListBox::getItem(size_t which)
-{
-	if (which < first || which > first + items.size() || which > totalSize)
-		return nullptr;
-
-	size_t i=first;
-	for (auto iter = items.begin(); iter != items.end(); iter++, i++)
-		if( i == which)
-			return *iter;
-	return nullptr;
-}
-
-size_t CListBox::getIndexOf(CIntObject *item)
-{
-	size_t i=first;
-	for (auto iter = items.begin(); iter != items.end(); iter++, i++)
-		if(*iter == item)
-			return i;
-	return size_t(-1);
-}
-
-void CListBox::scrollTo(size_t which)
-{
-	//scroll up
-	if (first > which)
-		moveToPos(which);
-	//scroll down
-	else if (first + items.size() <= which && which < totalSize)
-		moveToPos(which - items.size() + 1);
-}
-
-void CListBox::moveToPos(size_t which)
-{
-	//Calculate new position
-	size_t maxPossible;
-	if (totalSize > items.size())
-		maxPossible = totalSize - items.size();
-	else
-		maxPossible = 0;
-
-	size_t newPos = std::min(which, maxPossible);
-
-	//If move distance is 1 (most of calls from Slider) - use faster shifts instead of resetting all items
-	if (first - newPos == 1)
-		moveToPrev();
-	else if (newPos - first == 1)
-		moveToNext();
-	else if (newPos != first)
-	{
-		first = newPos;
-		reset();
-	}
-}
-
-void CListBox::moveToNext()
-{
-	//Remove front item and insert new one to end
-	if (first + items.size() < totalSize)
-	{
-		first++;
-		deleteItem(items.front());
-		items.pop_front();
-		items.push_back(createItem(first+items.size()));
-		updatePositions();
-	}
-}
-
-void CListBox::moveToPrev()
-{
-	//Remove last item and insert new one at start
-	if (first)
-	{
-		first--;
-		deleteItem(items.back());
-		items.pop_back();
-		items.push_front(createItem(first));
-		updatePositions();
-	}
-}
-
-size_t CListBox::getPos()
-{
-	return first;
-}
-
-const std::list<CIntObject *> &CListBox::getItems()
-{
-	return items;
-}
-
-void CSimpleWindow::show(SDL_Surface * to)
-{
-	if(bitmap)
-		blitAt(bitmap,pos.x,pos.y,to);
-}
-CSimpleWindow::~CSimpleWindow()
-{
-	if (bitmap)
-	{
-		SDL_FreeSurface(bitmap);
-		bitmap=nullptr;
-	}
-}
-
-void CHoverableArea::hover (bool on)
-{
-	if (on)
-		GH.statusbar->setText(hoverText);
-	else if (GH.statusbar->getText()==hoverText)
-		GH.statusbar->clear();
-}
-
-CHoverableArea::CHoverableArea()
-{
-	addUsedEvents(HOVER);
-}
-
-CHoverableArea::~CHoverableArea()
-{
-}
-
-void LRClickableAreaWText::clickLeft(tribool down, bool previousState)
-{
-	if(!down && previousState && !text.empty())
-	{
-		LOCPLINT->showInfoDialog(text);
-	}
-}
-void LRClickableAreaWText::clickRight(tribool down, bool previousState)
-{
-	if (!text.empty())
-		adventureInt->handleRightClick(text, down);
-}
-
-LRClickableAreaWText::LRClickableAreaWText()
-{
-	init();
-}
-
-LRClickableAreaWText::LRClickableAreaWText(const Rect &Pos, const std::string &HoverText /*= ""*/, const std::string &ClickText /*= ""*/)
-{
-	init();
-	pos = Pos + pos;
-	hoverText = HoverText;
-	text = ClickText;
-}
-
-LRClickableAreaWText::~LRClickableAreaWText()
-{
-}
-
-void LRClickableAreaWText::init()
-{
-	addUsedEvents(LCLICK | RCLICK | HOVER);
-}
-
-std::string CLabel::visibleText()
-{
-	return text;
-}
-
-void CLabel::showAll(SDL_Surface * to)
-{
-	CIntObject::showAll(to);
-
-	if(!visibleText().empty())
-		blitLine(to, pos, visibleText());
-
-}
-
-CLabel::CLabel(int x, int y, EFonts Font /*= FONT_SMALL*/, EAlignment Align, const SDL_Color &Color /*= Colors::WHITE*/, const std::string &Text /*= ""*/)
-:CTextContainer(Align, Font, Color), text(Text)
-{
-	type |= REDRAW_PARENT;
-	autoRedraw = true;
-	pos.x += x;
-	pos.y += y;
-	pos.w = pos.h = 0;
-	bg = nullptr;
-
-	if (alignment == TOPLEFT) // causes issues for MIDDLE
-	{
-		pos.w = graphics->fonts[font]->getStringWidth(visibleText().c_str());
-		pos.h = graphics->fonts[font]->getLineHeight();
-	}
-}
-
-Point CLabel::getBorderSize()
-{
-	return Point(0, 0);
-}
-
-std::string CLabel::getText()
-{
-	return text;
-}
-
-void CLabel::setText(const std::string &Txt)
-{
-	text = Txt;
-	if(autoRedraw)
-	{
-		if(bg || !parent)
-			redraw();
-		else
-			parent->redraw();
-	}
-}
-
-CMultiLineLabel::CMultiLineLabel(Rect position, EFonts Font, EAlignment Align, const SDL_Color &Color, const std::string &Text):
-    CLabel(position.x, position.y, Font, Align, Color, Text),
-    visibleSize(0, 0, position.w, position.h)
-{
-	pos.w = position.w;
-	pos.h = position.h;
-	splitText(Text);
-}
-
-void CMultiLineLabel::setVisibleSize(Rect visibleSize)
-{
-	this->visibleSize = visibleSize;
-	redraw();
-}
-
-void CMultiLineLabel::scrollTextBy(int distance)
-{
-	scrollTextTo(visibleSize.y + distance);
-}
-
-void CMultiLineLabel::scrollTextTo(int distance)
-{
-	Rect size = visibleSize;
-	size.y = distance;
-	setVisibleSize(size);
-}
-
-void CMultiLineLabel::setText(const std::string &Txt)
-{
-	splitText(Txt);
-	CLabel::setText(Txt);
-}
-
-void CTextContainer::blitLine(SDL_Surface *to, Rect destRect, std::string what)
-{
-	const IFont * f = graphics->fonts[font];
-	Point where = destRect.topLeft();
-
-	// input is rect in which given text should be placed
-	// calculate proper position for top-left corner of the text
-	if (alignment == TOPLEFT)
-	{
-		where.x += getBorderSize().x;
-		where.y += getBorderSize().y;
-	}
-
-	if (alignment == CENTER)
-	{
-		where.x += (int(destRect.w) - int(f->getStringWidth(what))) / 2;
-		where.y += (int(destRect.h) - int(f->getLineHeight())) / 2;
-	}
-
-	if (alignment == BOTTOMRIGHT)
-	{
-		where.x += getBorderSize().x + destRect.w - f->getStringWidth(what);
-		where.y += getBorderSize().y + destRect.h - f->getLineHeight();
-	}
-
-	size_t begin = 0;
-	std::string delimeters = "{}";
-	size_t currDelimeter = 0;
-
-	do
-	{
-		size_t end = what.find_first_of(delimeters[currDelimeter % 2], begin);
-		if (begin != end)
-		{
-			std::string toPrint = what.substr(begin, end - begin);
-
-			if (currDelimeter % 2) // Enclosed in {} text - set to yellow
-				f->renderTextLeft(to, toPrint, Colors::YELLOW, where);
-			else // Non-enclosed text, use default color
-				f->renderTextLeft(to, toPrint, color, where);
-			begin = end;
-
-			where.x += f->getStringWidth(toPrint);
-		}
-		currDelimeter++;
-	}
-	while (begin++ != std::string::npos);
-}
-
-CTextContainer::CTextContainer(EAlignment alignment, EFonts font, SDL_Color color):
-	alignment(alignment),
-	font(font),
-	color(color)
-{}
-
-void CMultiLineLabel::showAll(SDL_Surface * to)
-{
-	CIntObject::showAll(to);
-
-	const IFont * f = graphics->fonts[font];
-
-	// calculate which lines should be visible
-	int totalLines = lines.size();
-	int beginLine  = visibleSize.y;
-	int endLine    = getTextLocation().h + visibleSize.y;
-
-	if (beginLine < 0)
-		beginLine = 0;
-	else
-		beginLine /= f->getLineHeight();
-
-	if (endLine < 0)
-		endLine = 0;
-	else
-		endLine /= f->getLineHeight();
-	endLine++;
-
-	// and where they should be displayed
-	Point lineStart = getTextLocation().topLeft() - visibleSize + Point(0, beginLine * f->getLineHeight());
-	Point lineSize  = Point(getTextLocation().w, f->getLineHeight());
-
-	CSDL_Ext::CClipRectGuard guard(to, getTextLocation()); // to properly trim text that is too big to fit
-
-	for (int i = beginLine; i < std::min(totalLines, endLine); i++)
-	{
-		if (!lines[i].empty()) //non-empty line
-			blitLine(to, Rect(lineStart, lineSize), lines[i]);
-
-		lineStart.y += f->getLineHeight();
-	}
-}
-
-void CMultiLineLabel::splitText(const std::string &Txt)
-{
-	lines.clear();
-
-	const IFont * f = graphics->fonts[font];
-	int lineHeight =  f->getLineHeight();
-
-	lines = CMessage::breakText(Txt, pos.w, font);
-
-	 textSize.y = lineHeight * lines.size();
-	 textSize.x = 0;
-	for(const std::string &line : lines)
-		vstd::amax( textSize.x, f->getStringWidth(line.c_str()));
-	redraw();
-}
-
-Rect CMultiLineLabel::getTextLocation()
-{
-	// this method is needed for vertical alignment alignment of text
-	// when height of available text is smaller than height of widget
-	// in this case - we should add proper offset to display text at required position
-	if (pos.h <= textSize.y)
-		return pos;
-
-	Point textSize(pos.w, graphics->fonts[font]->getLineHeight() * lines.size());
-	Point textOffset(pos.w - textSize.x, pos.h - textSize.y);
-
-	switch(alignment)
-	{
-	case TOPLEFT:     return Rect(pos.topLeft(), textSize);
-	case CENTER:      return Rect(pos.topLeft() + textOffset / 2, textSize);
-	case BOTTOMRIGHT: return Rect(pos.topLeft() + textOffset, textSize);
-	}
-	assert(0);
-	return Rect();
-}
-
-CLabelGroup::CLabelGroup(EFonts Font, EAlignment Align, const SDL_Color &Color):
-	font(Font), align(Align), color(Color)
-{}
-
-void CLabelGroup::add(int x, int y, const std::string &text)
-{
-	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	new CLabel(x, y, font, align, color, text);
-}
-
-CTextBox::CTextBox(std::string Text, const Rect &rect, int SliderStyle, EFonts Font /*= FONT_SMALL*/, EAlignment Align /*= TOPLEFT*/, const SDL_Color &Color /*= Colors::WHITE*/):
-    sliderStyle(SliderStyle),
-    slider(nullptr)
-{
-	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	label = new CMultiLineLabel(rect, Font, Align, Color);
-
-	type |= REDRAW_PARENT;
-	pos.x += rect.x;
-	pos.y += rect.y;
-	pos.h = rect.h;
-	pos.w = rect.w;
-
-	assert(pos.w >= 40); //we need some space
-	setText(Text);
-}
-
-void CTextBox::sliderMoved(int to)
-{
-	label->scrollTextTo(to);
-}
-
-void CTextBox::resize(Point newSize)
-{
-	pos.w = newSize.x;
-	pos.h = newSize.y;
-	label->pos.w = pos.w;
-	label->pos.h = pos.h;
-	if (slider)
-		vstd::clear_pointer(slider); // will be recreated if needed later
-
-	setText(label->getText()); // force refresh
-}
-
-void CTextBox::setText(const std::string &text)
-{
-	label->setText(text);
-	if (label->textSize.y <= label->pos.h && slider)
-	{
-		// slider is no longer needed
-		vstd::clear_pointer(slider);
-		label->pos.w = pos.w;
-		label->setText(text);
-	}
-	else if (label->textSize.y > label->pos.h && !slider)
-	{
-		// create slider and update widget
-		label->pos.w = pos.w - 32;
-		label->setText(text);
-
-		OBJ_CONSTRUCTION_CAPTURING_ALL;
-		slider = new CSlider(pos.w - 32, 0, pos.h, boost::bind(&CTextBox::sliderMoved, this, _1),
-		                     label->pos.h, label->textSize.y, 0, false, sliderStyle);
-		slider->scrollStep = graphics->fonts[label->font]->getLineHeight();
-	}
-}
-
-void CGStatusBar::setText(const std::string & Text)
-{
-	if(!textLock)
-		CLabel::setText(Text);
-}
-
-void CGStatusBar::clear()
-{
-	setText("");
-}
-
-CGStatusBar::CGStatusBar(CPicture *BG, EFonts Font /*= FONT_SMALL*/, EAlignment Align /*= CENTER*/, const SDL_Color &Color /*= Colors::WHITE*/)
-: CLabel(BG->pos.x, BG->pos.y, Font, Align, Color, "")
-{
-	init();
-	bg = BG;
-	addChild(bg);
-	pos = bg->pos;
-	getBorderSize();
-    textLock = false;
-}
-
-CGStatusBar::CGStatusBar(int x, int y, std::string name/*="ADROLLVR.bmp"*/, int maxw/*=-1*/)
-: CLabel(x, y, FONT_SMALL, CENTER)
-{
-	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	init();
-	bg = new CPicture(name);
-	pos = bg->pos;
-	if((unsigned int)maxw < pos.w)
-	{
-		vstd::amin(pos.w, maxw);
-		bg->srcRect = new Rect(0, 0, maxw, pos.h);
-	}
-    textLock = false;
-}
-
-CGStatusBar::~CGStatusBar()
-{
-	GH.statusbar = oldStatusBar;
-}
-
-void CGStatusBar::show(SDL_Surface * to)
-{
-    showAll(to);
-}
-
-void CGStatusBar::init()
-{
-	oldStatusBar = GH.statusbar;
-	GH.statusbar = this;
-}
-
-Point CGStatusBar::getBorderSize()
-{
-	//Width of borders where text should not be printed
-	static const Point borderSize(5,1);
-
-	switch(alignment)
-	{
-	case TOPLEFT:     return Point(borderSize.x, borderSize.y);
-	case CENTER:      return Point(pos.w/2, pos.h/2);
-	case BOTTOMRIGHT: return Point(pos.w - borderSize.x, pos.h - borderSize.y);
-	}
-	assert(0);
-	return Point();
-}
-
-void CGStatusBar::lock(bool shouldLock)
-{
-    textLock = shouldLock;
-}
-
-CTextInput::CTextInput(const Rect &Pos, EFonts font, const CFunctionList<void(const std::string &)> &CB):
-    CLabel(Pos.x, Pos.y, font, CENTER),
-    cb(CB)
-{
-	type |= REDRAW_PARENT;
-	focus = false;
-	pos.h = Pos.h;
-	pos.w = Pos.w;
-	captureAllKeys = true;
-	bg = nullptr;
-	addUsedEvents(LCLICK | KEYBOARD | TEXTINPUT);
-	giveFocus();
-}
-
-CTextInput::CTextInput( const Rect &Pos, const Point &bgOffset, const std::string &bgName, const CFunctionList<void(const std::string &)> &CB )
-:cb(CB)
-{
-	focus = false;
-	pos += Pos;
-	captureAllKeys = true;
-	OBJ_CONSTRUCTION;
-	bg = new CPicture(bgName, bgOffset.x, bgOffset.y);
-	addUsedEvents(LCLICK | KEYBOARD | TEXTINPUT);
-	giveFocus();
-}
-
-CTextInput::CTextInput(const Rect &Pos, SDL_Surface *srf)
-{
-	focus = false;
-	pos += Pos;
-	captureAllKeys = true;
-	OBJ_CONSTRUCTION;
-	bg = new CPicture(Pos, 0, true);
-	Rect hlp = Pos;
-	if(srf)
-		CSDL_Ext::blitSurface(srf, &hlp, *bg, nullptr);
-	else
-		SDL_FillRect(*bg, nullptr, 0);
-	pos.w = bg->pos.w;
-	pos.h = bg->pos.h;
-	bg->pos = pos;
-	addUsedEvents(LCLICK | KEYBOARD | TEXTINPUT);
-	giveFocus();
-}
-
-void CTextInput::focusGot()
-{
-	CSDL_Ext::startTextInput(&pos);	
-}
-
-void CTextInput::focusLost()
-{
-	CSDL_Ext::stopTextInput();
-}
-
-
-std::string CTextInput::visibleText()
-{
-	return focus ? text + newText + "_" : text;
-}
-
-void CTextInput::clickLeft( tribool down, bool previousState )
-{
-	if(down && !focus)
-		giveFocus();
-}
-
-void CTextInput::keyPressed( const SDL_KeyboardEvent & key )
-{
-
-	if(!focus || key.state != SDL_PRESSED)
-		return;
-
-	if(key.keysym.sym == SDLK_TAB)
-	{
-		moveFocus();
-		GH.breakEventHandling();
-		return;
-	}
-
-	bool redrawNeeded = false;
-	#ifdef VCMI_SDL1
-	std::string oldText = text;
-	#endif // 0	
-	switch(key.keysym.sym)
-	{
-	case SDLK_DELETE: // have index > ' ' so it won't be filtered out by default section
-		return;
-	case SDLK_BACKSPACE:
-		if(!newText.empty())
-		{
-			Unicode::trimRight(newText);
-			redrawNeeded = true;
-		}
-		else if(!text.empty())
-		{
-			Unicode::trimRight(text);
-			redrawNeeded = true;
-		}			
-		break;
-	default:
-		#ifdef VCMI_SDL1
-		if (key.keysym.unicode < ' ')
-			return;
-		else
-		{
-			text += key.keysym.unicode; //TODO 16-/>8
-			redrawNeeded = true;
-		}			
-		#endif // 0
-		break;
-	}
-	#ifdef VCMI_SDL1
-	filters(text, oldText);
-	#endif // 0
-	if (redrawNeeded)
-	{
-		redraw();
-		cb(text);
-	}	
-}
-
-void CTextInput::setText( const std::string &nText, bool callCb )
-{
-	CLabel::setText(nText);
-	if(callCb)
-		cb(text);
-}
-
-bool CTextInput::captureThisEvent(const SDL_KeyboardEvent & key)
-{
-	if(key.keysym.sym == SDLK_RETURN || key.keysym.sym == SDLK_KP_ENTER)
-		return false;
-	
-	#ifdef VCMI_SDL1
-	//this should allow all non-printable keys to go through (for example arrows)
-	if (key.keysym.unicode < ' ')
-		return false;
-
-	return true;
-	#else
-	return false;
-	#endif
-}
-
-#ifndef VCMI_SDL1
-void CTextInput::textInputed(const SDL_TextInputEvent & event)
-{
-	if(!focus)
-		return;
-	std::string oldText = text;
-	
-	text += event.text;	
-	
-	filters(text,oldText);
-	if (text != oldText)
-	{
-		redraw();
-		cb(text);
-	}	
-	newText = "";
-}
-
-void CTextInput::textEdited(const SDL_TextEditingEvent & event)
-{
-	if(!focus)
-		return;
-		
-	newText = event.text;
-	redraw();
-	cb(text+newText);	
-}
-
-#endif
-
-
-void CTextInput::filenameFilter(std::string & text, const std::string &)
-{
-	static const std::string forbiddenChars = "<>:\"/\\|?*\r\n"; //if we are entering a filename, some special characters won't be allowed
-	size_t pos;
-	while ((pos = text.find_first_of(forbiddenChars)) != std::string::npos)
-		text.erase(pos, 1);
-}
-
-void CTextInput::numberFilter(std::string & text, const std::string & oldText, int minValue, int maxValue)
-{
-	assert(minValue < maxValue);
-
-	if (text.empty())
-		text = "0";
-
-	size_t pos = 0;
-	if (text[0] == '-') //allow '-' sign as first symbol only
-		pos++;
-
-	while (pos < text.size())
-	{
-		if (text[pos] < '0' || text[pos] > '9')
-		{
-			text = oldText;
-			return; //new text is not number.
-		}
-		pos++;
-	}
-	try
-	{
-		int value = boost::lexical_cast<int>(text);
-		if (value < minValue)
-			text = boost::lexical_cast<std::string>(minValue);
-		else if (value > maxValue)
-			text = boost::lexical_cast<std::string>(maxValue);
-	}
-	catch(boost::bad_lexical_cast &)
-	{
-		//Should never happen. Unless I missed some cases
-        logGlobal->warnStream() << "Warning: failed to convert "<< text << " to number!";
-		text = oldText;
-	}
-}
-
-CFocusable::CFocusable()
-{
-	focusables.push_back(this);
-}
-
-CFocusable::~CFocusable()
-{
-	if(inputWithFocus == this)
-	{
-		focusLost();
-		inputWithFocus = nullptr;
-	}	
-
-	focusables -= this;
-}
-void CFocusable::giveFocus()
-{
-	if(inputWithFocus)
-	{
-		inputWithFocus->focus = false;
-		inputWithFocus->focusLost();
-		inputWithFocus->redraw();
-	}
-
-	focus = true;
-	inputWithFocus = this;
-	focusGot();
-	redraw();	
-}
-
-void CFocusable::moveFocus()
-{
-	auto i = vstd::find(focusables, this),
-		ourIt = i;
-	for(i++; i != ourIt; i++)
-	{
-		if(i == focusables.end())
-			i = focusables.begin();
-
-		if((*i)->active)
-		{
-			(*i)->giveFocus();
-			break;;
-		}
-	}
-}
-
-CWindowObject::CWindowObject(int options_, std::string imageName, Point centerAt):
-    CIntObject(getUsedEvents(options_), Point()),
-    shadow(nullptr),
-    options(options_),
-    background(createBg(imageName, options & PLAYER_COLORED))
-{
-	assert(parent == nullptr); //Safe to remove, but windows should not have parent
-
-	if (options & RCLICK_POPUP)
-		CCS->curh->hide();
-
-	if (background)
-		pos = background->center(centerAt);
-	else
-		center(centerAt);
-
-	if (!(options & SHADOW_DISABLED))
-		setShadow(true);
-}
-
-CWindowObject::CWindowObject(int options_, std::string imageName):
-    CIntObject(getUsedEvents(options_), Point()),
-    shadow(nullptr),
-    options(options_),
-    background(createBg(imageName, options & PLAYER_COLORED))
-{
-	assert(parent == nullptr); //Safe to remove, but windows should not have parent
-
-	if (options & RCLICK_POPUP)
-		CCS->curh->hide();
-
-	if (background)
-		pos = background->center();
-	else
-		center(Point(screen->w/2, screen->h/2));
-
-	if (!(options & SHADOW_DISABLED))
-		setShadow(true);
-}
-
-CWindowObject::~CWindowObject()
-{
-	setShadow(false);
-}
-
-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::setBackground(std::string filename)
-{
-	OBJ_CONSTRUCTION_CAPTURING_ALL;
-
-	delete background;
-	background = createBg(filename, options & PLAYER_COLORED);
-
-	if (background)
-		pos = background->center(Point(pos.w/2 + pos.x, pos.h/2 + pos.y));
-
-	updateShadow();
-}
-
-int CWindowObject::getUsedEvents(int options)
-{
-	if (options & RCLICK_POPUP)
-		return RCLICK;
-	return 0;
-}
-
-void CWindowObject::updateShadow()
-{
-	setShadow(false);
-	if (!(options & SHADOW_DISABLED))
-		setShadow(true);
-}
-
-void CWindowObject::setShadow(bool on)
-{
-	//size of shadow
-	static const int size = 8;
-
-	if (on == bool(shadow))
-		return;
-
-	vstd::clear_pointer(shadow);
-
-	//object too small to cast shadow
-	if (pos.h <= size || pos.w <= size)
-		return;
-
-	if (on)
-	{
-
-		//helper to set last row
-		auto blitAlphaRow = [](SDL_Surface *surf, size_t row)
-		{
-			Uint8 * ptr = (Uint8*)surf->pixels + surf->pitch * (row);
-
-			for (size_t i=0; i< surf->w; i++)
-			{
-				Channels::px<4>::a.set(ptr, 128);
-				ptr+=4;
-			}
-		};
-
-		// helper to set last column
-		auto blitAlphaCol = [](SDL_Surface *surf, size_t col)
-		{
-			Uint8 * ptr = (Uint8*)surf->pixels + 4 * (col);
-
-			for (size_t i=0; i< surf->h; i++)
-			{
-				Channels::px<4>::a.set(ptr, 128);
-				ptr+= surf->pitch;
-			}
-		};
-
-		static SDL_Surface * shadowCornerTempl = nullptr;
-		static SDL_Surface * shadowBottomTempl = nullptr;
-		static SDL_Surface * shadowRightTempl = nullptr;
-
-		//one-time initialization
-		if (!shadowCornerTempl)
-		{
-			//create "template" surfaces
-			shadowCornerTempl = CSDL_Ext::createSurfaceWithBpp<4>(size, size);
-			shadowBottomTempl = CSDL_Ext::createSurfaceWithBpp<4>(1, size);
-			shadowRightTempl  = CSDL_Ext::createSurfaceWithBpp<4>(size, 1);
-
-			Uint32 shadowColor = SDL_MapRGBA(shadowCornerTempl->format, 0, 0, 0, 192);
-
-			//fill with shadow body color
-			SDL_FillRect(shadowCornerTempl, nullptr, shadowColor);
-			SDL_FillRect(shadowBottomTempl, nullptr, shadowColor);
-			SDL_FillRect(shadowRightTempl,  nullptr, shadowColor);
-
-			//fill last row and column with more transparent color
-			blitAlphaCol(shadowRightTempl , size-1);
-			blitAlphaCol(shadowCornerTempl, size-1);
-			blitAlphaRow(shadowBottomTempl, size-1);
-			blitAlphaRow(shadowCornerTempl, size-1);
-		}
-
-		OBJ_CONSTRUCTION_CAPTURING_ALL;
-
-		//FIXME: do something with this points
-		Point shadowStart;
-		if (options & BORDERED)
-			shadowStart = Point(size - 14, size - 14);
-		else
-			shadowStart = Point(size, size);
-
-		Point shadowPos;
-		if (options & BORDERED)
-			shadowPos = Point(pos.w + 14, pos.h + 14);
-		else
-			shadowPos = Point(pos.w, pos.h);
-
-		Point fullsize;
-		if (options & BORDERED)
-			fullsize = Point(pos.w + 28, pos.h + 29);
-		else
-			fullsize = Point(pos.w, pos.h);
-
-		//create base 8x8 piece of shadow
-		SDL_Surface * shadowCorner = CSDL_Ext::copySurface(shadowCornerTempl);
-		SDL_Surface * shadowBottom = CSDL_Ext::scaleSurfaceFast(shadowBottomTempl, fullsize.x - size, size);
-		SDL_Surface * shadowRight  = CSDL_Ext::scaleSurfaceFast(shadowRightTempl,  size, fullsize.y - size);
-
-		blitAlphaCol(shadowBottom, 0);
-		blitAlphaRow(shadowRight, 0);
-
-		//generate "shadow" object with these 3 pieces in it
-		shadow = new CIntObject;
-		shadow->addChild(new CPicture(shadowCorner, shadowPos.x, shadowPos.y));
-		shadow->addChild(new CPicture(shadowRight,  shadowPos.x, shadowStart.y));
-		shadow->addChild(new CPicture(shadowBottom, shadowStart.x, shadowPos.y));
-	}
-}
-
-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 : PlayerColor(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)
-{
-	close();
-	CCS->curh->show();
-}

+ 0 - 560
client/widgets/CIntObjectClasses.h

@@ -1,560 +0,0 @@
-#pragma once
-
-#include "../gui/CIntObject.h"
-#include "../gui/SDL_Extensions.h"
-
-#include "../../lib/FunctionList.h"
-
-struct SDL_Surface;
-struct Rect;
-class CAnimImage;
-class CLabel;
-class CAnimation;
-class CDefHandler;
-
-/*
- * CPicture.h, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
-
-// Window GUI class
-class CSimpleWindow : public CIntObject
-{
-public:
-	SDL_Surface * bitmap; //background
-	virtual void show(SDL_Surface * to);
-	CSimpleWindow():bitmap(nullptr){}; //c-tor
-	virtual ~CSimpleWindow(); //d-tor
-};
-
-// Image class
-class CPicture : public CIntObject
-{
-	void setSurface(SDL_Surface *to);
-public: 
-	SDL_Surface * bg;
-	Rect * srcRect; //if nullptr then whole surface will be used
-	bool freeSurf; //whether surface will be freed upon CPicture destruction
-	bool needRefresh;//Surface needs to be displayed each frame
-
-	operator SDL_Surface*()
-	{
-		return bg;
-	}
-
-	CPicture(const Rect & r, const SDL_Color & color, bool screenFormat = false); //rect filled with given color
-	CPicture(const Rect & r, ui32 color, bool screenFormat = false); //rect filled with given color
-	CPicture(SDL_Surface * BG, int x = 0, int y=0, bool Free = true); //wrap existing SDL_Surface
-	CPicture(const std::string &bmpname, int x=0, int y=0);
-	CPicture(SDL_Surface *BG, const Rect &SrcRext, int x = 0, int y = 0, bool free = false); //wrap subrect of given surface
-	~CPicture();
-	void init();
-
-	//set alpha value for whole surface. Note: may be messed up if surface is shared
-	// 0=transparent, 255=opaque
-	void setAlpha(int value);
-
-	void scaleTo(Point size);
-	void createSimpleRect(const Rect &r, bool screenFormat, ui32 color);
-	void show(SDL_Surface * to);
-	void showAll(SDL_Surface * to);
-	void convertToScreenBPP();
-	void colorizeAndConvert(PlayerColor player);
-	void colorize(PlayerColor player);
-};
-
-/// area filled with specific texture
-class CFilledTexture : CIntObject
-{
-	SDL_Surface * texture;
-
-public:
-	CFilledTexture(std::string imageName, Rect position);
-	~CFilledTexture();
-	void showAll(SDL_Surface *to);
-};
-
-namespace config{struct ButtonInfo;}
-
-/// Base class for buttons.
-class CButtonBase : public CKeyShortcut
-{
-public:
-	enum ButtonState
-	{
-		NORMAL=0,
-		PRESSED=1,
-		BLOCKED=2,
-		HIGHLIGHTED=3
-	};
-private:
-	int bitmapOffset; // base offset of visible bitmap from animation
-	ButtonState state;//current state of button from enum
-
-public:
-	bool swappedImages,//fix for some buttons: normal and pressed image are swapped
-		keepFrame; // don't change visual representation
-
-	void addOverlay(CIntObject * newOverlay);
-	void addTextOverlay(const std::string &Text, EFonts font, SDL_Color color = Colors::WHITE);
-
-	void update();//to refresh button after image or text change
-
-	void setOffset(int newOffset);
-	void setState(ButtonState newState);
-	ButtonState getState();
-
-	//just to make code clearer
-	void block(bool on);
-	bool isBlocked();
-	bool isHighlighted();
-
-	CAnimImage * image; //image for this button
-	CIntObject * overlay;//object-overlay
-
-	CButtonBase(); //c-tor
-	virtual ~CButtonBase(); //d-tor
-};
-
-/// Typical Heroes 3 button which can be inactive or active and can 
-/// hold further information if you right-click it
-class CAdventureMapButton : public CButtonBase
-{
-	std::vector<std::string> imageNames;//store list of images that can be used by this button
-	size_t currentImage;
-
-	void onButtonClicked(); // calls callback
-public:
-	std::map<int, std::string> hoverTexts; //text for statusbar
-	std::string helpBox; //for right-click help
-	CFunctionList<void()> callback;
-	bool actOnDown,//runs when mouse is pressed down over it, not when up
-		hoverable,//if true, button will be highlighted when hovered
-		borderEnabled,
-		soundDisabled;
-	SDL_Color borderColor;
-
-	void clickRight(tribool down, bool previousState);
-	virtual void clickLeft(tribool down, bool previousState);
-	void hover (bool on);
-
-	CAdventureMapButton(); //c-tor
-	CAdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key=0, std::vector<std::string> * add = nullptr, bool playerColoredButton = false );//c-tor
-	CAdventureMapButton( const std::pair<std::string, std::string> &help, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key=0, std::vector<std::string> * add = nullptr, bool playerColoredButton = false );//c-tor
-	CAdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, config::ButtonInfo *info, int key=0);//c-tor
-
-	void 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 );
-
-	void setIndex(size_t index, bool playerColoredButton=false);
-	void setImage(CAnimation* anim, bool playerColoredButton=false, int animFlags=0);
-	void setPlayerColor(PlayerColor player);
-	void showAll(SDL_Surface * to);
-};
-
-/// A button which can be selected/deselected
-class CHighlightableButton 
-	: public CAdventureMapButton
-{
-public:
-	CHighlightableButton(const CFunctionList<void()> &onSelect, const CFunctionList<void()> &onDeselect, 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=0);
-	CHighlightableButton(const std::pair<std::string, std::string> &help, const CFunctionList<void()> &onSelect, int x, int y, const std::string &defName, int myid, int key=0, std::vector<std::string> * add = nullptr, bool playerColoredButton = false );//c-tor
-	CHighlightableButton(const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &onSelect, int x, int y, const std::string &defName, int myid, int key=0, std::vector<std::string> * add = nullptr, bool playerColoredButton = false );//c-tor
-	bool onlyOn;//button can not be de-selected
-	bool selected;//state of highlightable button
-	int ID; //for identification
-	CFunctionList<void()> callback2; //when de-selecting
-	void select(bool on);
-	void clickLeft(tribool down, bool previousState);
-};
-
-/// A group of buttons where one button can be selected
-class CHighlightableButtonsGroup : public CIntObject
-{
-public:
-	CFunctionList<void(int)> onChange; //called when changing selected button with new button's id
-	std::vector<CHighlightableButton*> buttons;
-	bool musicLike; //determines the behaviour of this group
-
-	//void addButton(const std::map<int,std::string> &tooltip, const std::string &HelpBox, const std::string &defName, int x, int y, int uid);
-	void addButton(CHighlightableButton* bt);//add existing button, it'll be deleted by CHighlightableButtonsGroup destructor
-	void addButton(const std::map<int,std::string> &tooltip, const std::string &HelpBox, const std::string &defName, int x, int y, int uid, const CFunctionList<void()> &OnSelect=0, int key=0); //creates new button
-	CHighlightableButtonsGroup(const CFunctionList<void(int)> & OnChange, bool musicLikeButtons = false);
-	~CHighlightableButtonsGroup();
-	void select(int id, bool mode); //mode==0: id is serial; mode==1: id is unique button id
-	void selectionChanged(int to);
-	void show(SDL_Surface * to);
-	void showAll(SDL_Surface * to);
-	void block(ui8 on);
-};
-
-/// A typical slider which can be orientated horizontally/vertically.
-class CSlider : public CIntObject
-{
-public:
-	CAdventureMapButton *left, *right, *slider; //if vertical then left=up
-	int capacity;//how many elements can be active at same time (e.g. hero list = 5)
-	int amount; //total amount of elements (e.g. hero list = 0-8)
-	int positions; //number of highest position (0 if there is only one)
-	int value; //first active element
-	int scrollStep; // how many elements will be scrolled via one click, default = 1
-	bool horizontal;
-	bool wheelScrolling;
-	bool keyScrolling;
-
-	std::function<void(int)> moved;
-
-	void redrawSlider(); 
-	void sliderClicked();
-	void moveLeft();
-	void moveRight();
-	void moveTo(int to);
-	void block(bool on);
-	void setAmount(int to);
-
-	void keyPressed(const SDL_KeyboardEvent & key);
-	void wheelScrolled(bool down, bool in);
-	void clickLeft(tribool down, bool previousState);
-	void mouseMoved (const SDL_MouseMotionEvent & sEvent);
-	void showAll(SDL_Surface * to);	
-
-	CSlider(int x, int y, int totalw, std::function<void(int)> Moved, int Capacity, int Amount, 
-		int Value=0, bool Horizontal=true, int style = 0); //style 0 - brown, 1 - blue
-	~CSlider();
-	void moveToMax();
-};
-
-/// Used as base for Tabs and List classes
-class CObjectList : public CIntObject
-{
-public:
-	typedef std::function<CIntObject* (size_t)> CreateFunc;
-	typedef std::function<void(CIntObject *)> DestroyFunc;
-
-private:
-	CreateFunc createObject;
-	DestroyFunc destroyObject;
-
-protected:
-	//Internal methods for safe creation of items (Children capturing and activation/deactivation if needed)
-	void deleteItem(CIntObject* item);
-	CIntObject* createItem(size_t index);
-
-	CObjectList(CreateFunc create, DestroyFunc destroy = DestroyFunc());//Protected constructor
-};
-
-/// Window element with multiple tabs
-class CTabbedInt : public CObjectList
-{
-private:
-	CIntObject * activeTab;
-	size_t activeID;
-
-public:
-	//CreateFunc, DestroyFunc - see CObjectList
-	//Pos - position of object, all tabs will be moved to this position
-	//ActiveID - ID of initially active tab
-	CTabbedInt(CreateFunc create, DestroyFunc destroy = DestroyFunc(), Point position=Point(), size_t ActiveID=0);
-
-	void setActive(size_t which);
-	//recreate active tab
-	void reset();
-
-	//return currently active item
-	CIntObject * getItem();
-};
-
-/// List of IntObjects with optional slider
-class CListBox : public CObjectList
-{
-private:
-	std::list< CIntObject* > items;
-	size_t first;
-	size_t totalSize;
-
-	Point itemOffset;
-	CSlider * slider;
-
-	void updatePositions();
-public:
-	//CreateFunc, DestroyFunc - see CObjectList
-	//Pos - position of first item
-	//ItemOffset - distance between items in the list
-	//VisibleSize - maximal number of displayable at once items
-	//TotalSize
-	//Slider - slider style, bit field: 1 = present(disabled), 2=horisontal(vertical), 4=blue(brown)
-	//SliderPos - position of slider, if present
-	CListBox(CreateFunc create, DestroyFunc destroy, Point Pos, Point ItemOffset, size_t VisibleSize,
-		size_t TotalSize, size_t InitialPos=0, int Slider=0, Rect SliderPos=Rect() );
-
-	//recreate all visible items
-	void reset();
-
-	//change or get total amount of items in the list
-	void resize(size_t newSize);
-	size_t size();
-
-	//return item with index which or null if not present
-	CIntObject * getItem(size_t which);
-
-	//return currently active items
-	const std::list< CIntObject * > & getItems();
-
-	//get index of this item. -1 if not found
-	size_t getIndexOf(CIntObject * item);
-
-	//scroll list to make item which visible
-	void scrollTo(size_t which);
-
-	//scroll list to specified position
-	void moveToPos(size_t which);
-	void moveToNext();
-	void moveToPrev();
-
-	size_t getPos();
-};
-
-/// Small helper class to manage group of similar labels
-class CLabelGroup : public CIntObject
-{
-	std::list<CLabel*> labels;
-	EFonts font;
-	EAlignment align;
-	SDL_Color color;
-public:
-	CLabelGroup(EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE);
-	void add(int x=0, int y=0, const std::string &text =  "");
-};
-
-/// Base class for all text-related widgets.
-/// Controls text blitting-related options
-class CTextContainer : public virtual CIntObject
-{
-protected:
-	/// returns size of border, for left- or right-aligned text
-	virtual Point getBorderSize() = 0;
-	/// do actual blitting of line. Text "what" will be placed at "where" and aligned according to alignment
-	void blitLine(SDL_Surface * to, Rect where, std::string what);
-
-	CTextContainer(EAlignment alignment, EFonts font, SDL_Color color);
-
-public:
-	EAlignment alignment;
-	EFonts font;
-	SDL_Color color; // default font color. Can be overridden by placing "{}" into the string
-};
-
-/// Label which shows text
-class CLabel : public CTextContainer
-{
-protected:
-	Point getBorderSize() override;
-	virtual std::string visibleText();
-
-	CPicture *bg;
-public:
-
-	std::string text;
-	bool autoRedraw;  //whether control will redraw itself on setTxt
-
-	std::string getText();
-	virtual void setText(const std::string &Txt);
-
-	CLabel(int x=0, int y=0, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT,
-	       const SDL_Color &Color = Colors::WHITE, const std::string &Text =  "");
-	void showAll(SDL_Surface * to); //shows statusbar (with current text)
-};
-
-/// Multi-line label that can display multiple lines of text
-/// If text is too big to fit into requested area remaining part will not be visible
-class CMultiLineLabel : public CLabel
-{
-	// text to blit, split into lines that are no longer than widget width
-	std::vector<std::string> lines;
-
-	// area of text that actually will be printed, default is widget size
-	Rect visibleSize;
-
-	void splitText(const std::string &Txt);
-	Rect getTextLocation();
-public:
-	// total size of text, x = longest line of text, y = total height of lines
-	Point textSize;
-
-	CMultiLineLabel(Rect position, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE, const std::string &Text =  "");
-
-	void setText(const std::string &Txt);
-	void showAll(SDL_Surface * to);
-
-	void setVisibleSize(Rect visibleSize);
-	// scrolls text visible in widget. Positive value will move text up
-	void scrollTextTo(int distance);
-	void scrollTextBy(int distance);
-};
-
-/// a multi-line label that tries to fit text with given available width and height;
-/// if not possible, it creates a slider for scrolling text
-class CTextBox : public CIntObject
-{
-	int sliderStyle;
-public:
-	CMultiLineLabel * label;
-	CSlider *slider;
-
-	CTextBox(std::string Text, const Rect &rect, int SliderStyle, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE);
-
-	void resize(Point newSize);
-	void setText(const std::string &Txt);
-	void sliderMoved(int to);
-};
-
-/// Status bar which is shown at the bottom of the in-game screens
-class CGStatusBar : public CLabel
-{
-	bool textLock; //Used for blocking changes to the text
-	void init();
-
-	CGStatusBar *oldStatusBar;
-protected:
-	Point getBorderSize() override;
-
-public:
-
-	void clear();//clears statusbar and refreshes
-	void setText(const std::string & Text) override; //prints text and refreshes statusbar
-
-	void show(SDL_Surface * to); //shows statusbar (with current text)
-
-	CGStatusBar(CPicture *BG, EFonts Font = FONT_SMALL, EAlignment Align = CENTER, const SDL_Color &Color = Colors::WHITE); //given CPicture will be captured by created sbar and it's pos will be used as pos for sbar
-	CGStatusBar(int x, int y, std::string name, int maxw=-1);
-	~CGStatusBar();
-
-	void lock(bool shouldLock); //If true, current text cannot be changed until lock(false) is called
-};
-
-/// UIElement which can get input focus
-class CFocusable : public virtual CIntObject
-{
-protected:
-	virtual void focusGot(){};
-	virtual void focusLost(){};
-public:
-	bool focus; //only one focusable control can have focus at one moment
-
-	void giveFocus(); //captures focus
-	void moveFocus(); //moves focus to next active control (may be used for tab switching)
-
-	static std::list<CFocusable*> focusables; //all existing objs
-	static CFocusable *inputWithFocus; //who has focus now
-	CFocusable();
-	~CFocusable();
-};
-
-/// Text input box where players can enter text
-class CTextInput : public CLabel, public CFocusable
-{
-	std::string newText;
-protected:
-	std::string visibleText() override;
-
-	void focusGot() override;
-	void focusLost() override;
-public:
-	CFunctionList<void(const std::string &)> cb;
-	CFunctionList<void(std::string &, const std::string &)> filters;
-	void setText(const std::string &nText, bool callCb = false);
-
-	CTextInput(const Rect &Pos, EFonts font, const CFunctionList<void(const std::string &)> &CB);
-	CTextInput(const Rect &Pos, const Point &bgOffset, const std::string &bgName, const CFunctionList<void(const std::string &)> &CB);
-	CTextInput(const Rect &Pos, SDL_Surface *srf = nullptr);
-
-	void clickLeft(tribool down, bool previousState) override;
-	void keyPressed(const SDL_KeyboardEvent & key) override;
-	bool captureThisEvent(const SDL_KeyboardEvent & key) override;
-	
-#ifndef VCMI_SDL1
-	void textInputed(const SDL_TextInputEvent & event) override;
-	void textEdited(const SDL_TextEditingEvent & event) override;
-	
-	
-#endif // VCMI_SDL1	
-
-	//Filter that will block all characters not allowed in filenames
-	static void filenameFilter(std::string &text, const std::string & oldText);
-	//Filter that will allow only input of numbers in range min-max (min-max are allowed)
-	//min-max should be set via something like boost::bind
-	static void numberFilter(std::string &text, const std::string & oldText, int minValue, int maxValue);
-};
-
-/// Shows a text by moving the mouse cursor over the object
-class CHoverableArea: public virtual CIntObject
-{
-public:
-	std::string hoverText;
-
-	virtual void hover (bool on);
-
-	CHoverableArea();
-	virtual ~CHoverableArea();
-};
-
-/// Can interact on left and right mouse clicks, plus it shows a text when by hovering over it
-class LRClickableAreaWText: public CHoverableArea
-{
-public:
-	std::string text;
-
-	LRClickableAreaWText();
-	LRClickableAreaWText(const Rect &Pos, const std::string &HoverText = "", const std::string &ClickText = "");
-	virtual ~LRClickableAreaWText();
-	void init();
-
-	virtual void clickLeft(tribool down, bool previousState);
-	virtual void clickRight(tribool down, bool previousState);
-};
-
-/// Basic class for windows
-class CWindowObject : public CIntObject
-{
-	CPicture * createBg(std::string imageName, bool playerColored);
-	int getUsedEvents(int options);
-
-	CIntObject *shadow;
-	void setShadow(bool on);
-
-	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);
-	//change or set background image
-	void setBackground(std::string filename);
-	void updateShadow();
-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
-		SHADOW_DISABLED=8 //this window won't display any shadow
-	};
-
-	/*
-	 * options - EOpions enum
-	 * imageName - name for background image, can be empty
-	 * centerAt - position of window center. Default - center of the screen
-	*/
-	CWindowObject(int options, std::string imageName, Point centerAt);
-	CWindowObject(int options, std::string imageName = "");
-	~CWindowObject();
-};

+ 533 - 0
client/widgets/Images.cpp

@@ -0,0 +1,533 @@
+#include "StdInc.h"
+#include "Images.h"
+
+#include "MiscWidgets.h"
+
+#include "../gui/CAnimation.h"
+#include "../gui/SDL_Pixels.h"
+#include "../gui/SDL_Extensions.h"
+#include "../gui/CGuiHandler.h"
+#include "../gui/CCursorHandler.h"
+
+#include "../battle/CBattleInterface.h"
+#include "../battle/CBattleInterfaceClasses.h"
+
+#include "../CBitmapHandler.h"
+#include "../Graphics.h"
+#include "../CGameInfo.h"
+#include "../CPlayerInterface.h"
+#include "../CMessage.h"
+#include "../CMusicHandler.h"
+#include "../windows/CAdvmapInterface.h"
+
+#include "../../CCallback.h"
+
+#include "../../lib/CConfigHandler.h"
+#include "../../lib/CGeneralTextHandler.h" //for Unicode related stuff
+#include "../../lib/CRandomGenerator.h"
+
+/*
+ * Images.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+CPicture::CPicture( SDL_Surface *BG, int x, int y, bool Free )
+{
+	init();
+	bg = BG;
+	freeSurf = Free;
+	pos.x += x;
+	pos.y += y;
+	pos.w = BG->w;
+	pos.h = BG->h;
+}
+
+CPicture::CPicture( const std::string &bmpname, int x, int y )
+{
+	init();
+	bg = BitmapHandler::loadBitmap(bmpname);
+	freeSurf = true;;
+	pos.x += x;
+	pos.y += y;
+	if(bg)
+	{
+		pos.w = bg->w;
+		pos.h = bg->h;
+	}
+	else
+	{
+		pos.w = pos.h = 0;
+	}
+}
+
+CPicture::CPicture(const Rect &r, const SDL_Color &color, bool screenFormat /*= false*/)
+{
+	init();
+	createSimpleRect(r, screenFormat, SDL_MapRGB(bg->format, color.r, color.g,color.b));
+}
+
+CPicture::CPicture(const Rect &r, ui32 color, bool screenFormat /*= false*/)
+{
+	init();
+	createSimpleRect(r, screenFormat, color);
+}
+
+CPicture::CPicture(SDL_Surface *BG, const Rect &SrcRect, int x /*= 0*/, int y /*= 0*/, bool free /*= false*/)
+{
+	needRefresh = false;
+	srcRect = new Rect(SrcRect);
+	pos.x += x;
+	pos.y += y;
+	pos.w = srcRect->w;
+	pos.h = srcRect->h;
+	bg = BG;
+	freeSurf = free;
+}
+
+void CPicture::setSurface(SDL_Surface *to)
+{
+	bg = to;
+	if (srcRect)
+	{
+		pos.w = srcRect->w;
+		pos.h = srcRect->h;
+	}
+	else
+	{
+		pos.w = bg->w;
+		pos.h = bg->h;
+	}
+}
+
+CPicture::~CPicture()
+{
+	if(freeSurf)
+		SDL_FreeSurface(bg);
+	delete srcRect;
+}
+
+void CPicture::init()
+{
+	needRefresh = false;
+	srcRect = nullptr;
+}
+
+void CPicture::show(SDL_Surface * to)
+{
+	if (needRefresh)
+		showAll(to);
+}
+
+void CPicture::showAll(SDL_Surface * to)
+{
+	if(bg)
+	{
+		if(srcRect)
+		{
+			SDL_Rect srcRectCpy = *srcRect;
+			SDL_Rect dstRect = srcRectCpy;
+			dstRect.x = pos.x;
+			dstRect.y = pos.y;
+
+			CSDL_Ext::blitSurface(bg, &srcRectCpy, to, &dstRect);
+		}
+		else
+			blitAt(bg, pos, to);
+	}
+}
+
+void CPicture::convertToScreenBPP()
+{
+	SDL_Surface *hlp = bg;
+	bg = SDL_ConvertSurface(hlp,screen->format,0);
+	CSDL_Ext::setDefaultColorKey(bg);	
+	SDL_FreeSurface(hlp);
+}
+
+void CPicture::setAlpha(int value)
+{	
+	#ifdef VCMI_SDL1
+	SDL_SetAlpha(bg, SDL_SRCALPHA, value);	
+	#else
+	SDL_SetSurfaceAlphaMod(bg,value);
+	#endif // 0
+}
+
+void CPicture::scaleTo(Point size)
+{
+	SDL_Surface * scaled = CSDL_Ext::scaleSurface(bg, size.x, size.y);
+
+	if(freeSurf)
+		SDL_FreeSurface(bg);
+
+	setSurface(scaled);
+	freeSurf = false;
+}
+
+void CPicture::createSimpleRect(const Rect &r, bool screenFormat, ui32 color)
+{
+	pos += r;
+	pos.w = r.w;
+	pos.h = r.h;
+	if(screenFormat)
+		bg = CSDL_Ext::newSurface(r.w, r.h);
+	else
+		bg = SDL_CreateRGBSurface(SDL_SWSURFACE, r.w, r.h, 8, 0, 0, 0, 0);
+
+	SDL_FillRect(bg, nullptr, color);
+	freeSurf = true;
+}
+
+void CPicture::colorizeAndConvert(PlayerColor player)
+{
+	assert(bg);
+	colorize(player);
+	convertToScreenBPP();
+}
+
+void CPicture::colorize(PlayerColor player)
+{
+	assert(bg);
+	graphics->blueToPlayersAdv(bg, player);
+}
+
+CFilledTexture::CFilledTexture(std::string imageName, Rect position):
+    CIntObject(0, position.topLeft()),
+    texture(BitmapHandler::loadBitmap(imageName))
+{
+	pos.w = position.w;
+	pos.h = position.h;
+}
+
+CFilledTexture::~CFilledTexture()
+{
+	SDL_FreeSurface(texture);
+}
+
+void CFilledTexture::showAll(SDL_Surface *to)
+{
+	CSDL_Ext::CClipRectGuard guard(to, pos);
+	CSDL_Ext::fillTexture(to, texture);
+}
+
+CAnimImage::CAnimImage(std::string name, size_t Frame, size_t Group, int x, int y, ui8 Flags):
+	frame(Frame),
+	group(Group),
+	player(-1),
+	flags(Flags)
+{
+	pos.x += x;
+	pos.y += y;
+	anim = new CAnimation(name);
+	init();
+}
+
+CAnimImage::CAnimImage(CAnimation *Anim, size_t Frame, size_t Group, int x, int y, ui8 Flags):
+	anim(Anim),
+	frame(Frame),
+	group(Group),
+	player(-1),
+	flags(Flags)
+{
+	pos.x += x;
+	pos.y += y;
+	init();
+}
+
+size_t CAnimImage::size()
+{
+	return anim->size(group);
+}
+
+void CAnimImage::init()
+{
+	anim->load(frame, group);
+	if (flags & CShowableAnim::BASE)
+		anim->load(0,group);
+
+	IImage *img = anim->getImage(frame, group);
+	if (img)
+	{
+		pos.w = img->width();
+		pos.h = img->height();
+	}
+}
+
+CAnimImage::~CAnimImage()
+{
+	anim->unload(frame, group);
+	if (flags & CShowableAnim::BASE)
+		anim->unload(0,group);
+	delete anim;
+}
+
+void CAnimImage::showAll(SDL_Surface * to)
+{
+	IImage *img;
+
+	if ( flags & CShowableAnim::BASE && frame != 0)
+		if ((img = anim->getImage(0, group)))
+			img->draw(to, pos.x, pos.y);
+
+	if ((img = anim->getImage(frame, group)))
+		img->draw(to, pos.x, pos.y);
+}
+
+void CAnimImage::setFrame(size_t Frame, size_t Group)
+{
+	if (frame == Frame && group==Group)
+		return;
+	if (anim->size(Group) > Frame)
+	{
+		anim->load(Frame, Group);
+		anim->unload(frame, group);
+		frame = Frame;
+		group = Group;
+		IImage *img = anim->getImage(frame, group);
+		if (img)
+		{
+			if (flags & CShowableAnim::PLAYER_COLORED)
+				img->playerColored(player);
+			pos.w = img->width();
+			pos.h = img->height();
+		}
+	}
+	else
+		logGlobal->errorStream() << "Error: accessing unavailable frame " << Group << ":" << Frame << " in CAnimation!";
+}
+
+void CAnimImage::playerColored(PlayerColor currPlayer)
+{
+	player = currPlayer;
+	flags |= CShowableAnim::PLAYER_COLORED;
+	anim->getImage(frame, group)->playerColored(player);
+	if (flags & CShowableAnim::BASE)
+			anim->getImage(0, group)->playerColored(player);
+}
+
+CShowableAnim::CShowableAnim(int x, int y, std::string name, ui8 Flags, ui32 Delay, size_t Group):
+	anim(new CAnimation(name, Flags & USE_RLE)),
+	group(Group),
+	frame(0),
+	first(0),
+	frameDelay(Delay),
+	value(0),
+	flags(Flags),
+	xOffset(0),
+	yOffset(0),
+	alpha(255)
+{
+	anim->loadGroup(group);
+	last = anim->size(group);
+
+	pos.w = anim->getImage(0, group)->width();
+	pos.h = anim->getImage(0, group)->height();
+	pos.x+= x;
+	pos.y+= y;
+}
+
+CShowableAnim::~CShowableAnim()
+{
+	anim->unloadGroup(group);
+	delete anim;
+}
+
+void CShowableAnim::setAlpha(ui32 alphaValue)
+{
+	alpha = std::min<ui32>(alphaValue, 255);
+}
+
+bool CShowableAnim::set(size_t Group, size_t from, size_t to)
+{
+	size_t max = anim->size(Group);
+
+	if (to < max)
+		max = to;
+
+	if (max < from || max == 0)
+		return false;
+
+	anim->load(Group);
+	anim->unload(group);
+	group = Group;
+	frame = first = from;
+	last = max;
+	value = 0;
+	return true;
+}
+
+bool CShowableAnim::set(size_t Group)
+{
+	if (anim->size(Group)== 0)
+		return false;
+	if (group != Group)
+	{
+		anim->loadGroup(Group);
+		anim->unloadGroup(group);
+		first = 0;
+		group = Group;
+		last = anim->size(Group);
+	}
+	frame = value = 0;
+	return true;
+}
+
+void CShowableAnim::reset()
+{
+	value = 0;
+	frame = first;
+
+	if (callback)
+		callback();
+}
+
+void CShowableAnim::clipRect(int posX, int posY, int width, int height)
+{
+	xOffset = posX;
+	yOffset = posY;
+	pos.w = width;
+	pos.h = height;
+}
+
+void CShowableAnim::show(SDL_Surface * to)
+{
+	if ( flags & BASE )// && frame != first) // FIXME: results in graphical glytch in Fortress, upgraded hydra's dwelling
+		blitImage(first, group, to);
+	blitImage(frame, group, to);
+
+	if ((flags & PLAY_ONCE) && frame + 1 == last)
+		return;
+
+	if ( ++value == frameDelay )
+	{
+		value = 0;
+		if ( ++frame >= last)
+			reset();
+	}
+}
+
+void CShowableAnim::showAll(SDL_Surface * to)
+{
+	if ( flags & BASE )// && frame != first)
+		blitImage(first, group, to);
+	blitImage(frame, group, to);
+}
+
+void CShowableAnim::blitImage(size_t frame, size_t group, SDL_Surface *to)
+{
+	assert(to);
+	Rect src( xOffset, yOffset, pos.w, pos.h);
+	IImage * img = anim->getImage(frame, group);
+	if (img)
+		img->draw(to, pos.x-xOffset, pos.y-yOffset, &src, alpha);
+}
+
+void CShowableAnim::rotate(bool on, bool vertical)
+{
+	ui8 flag = vertical? VERTICAL_FLIP:HORIZONTAL_FLIP;
+	if (on)
+		flags |= flag;
+	else
+		flags &= ~flag;
+}
+
+CCreatureAnim::CCreatureAnim(int x, int y, std::string name, Rect picPos, ui8 flags, EAnimType type):
+	CShowableAnim(x,y,name,flags,4,type)
+{
+	xOffset = picPos.x;
+	yOffset = picPos.y;
+	if (picPos.w)
+		pos.w = picPos.w;
+	if (picPos.h)
+		pos.h = picPos.h;
+};
+
+void CCreatureAnim::loopPreview(bool warMachine)
+{
+	std::vector<EAnimType> available;
+
+	static const EAnimType creaPreviewList[] = {HOLDING, HITTED, DEFENCE, ATTACK_FRONT, CAST_FRONT};
+	static const EAnimType machPreviewList[] = {HOLDING, MOVING, SHOOT_UP, SHOOT_FRONT, SHOOT_DOWN};
+	auto & previewList = warMachine ? machPreviewList : creaPreviewList;
+
+	for (auto & elem : previewList)
+		if (anim->size(elem))
+			available.push_back(elem);
+
+	size_t rnd = CRandomGenerator::getDefault().nextInt(available.size() * 2 - 1);
+
+	if (rnd >= available.size())
+	{
+		EAnimType type;
+		if ( anim->size(MOVING) == 0 )//no moving animation present
+			type = HOLDING;
+		else
+			type = MOVING;
+
+		//display this anim for ~1 second (time is random, but it looks good)
+		for (size_t i=0; i< 12/anim->size(type) + 1; i++)
+			addLast(type);
+	}
+	else
+		addLast(available[rnd]);
+}
+
+void CCreatureAnim::addLast(EAnimType newType)
+{
+	if (type != MOVING && newType == MOVING)//starting moving - play init sequence
+	{
+		queue.push( MOVE_START );
+	}
+	else if (type == MOVING && newType != MOVING )//previous anim was moving - finish it
+	{
+		queue.push( MOVE_END );
+	}
+	if (newType == TURN_L || newType == TURN_R)
+		queue.push(newType);
+
+	queue.push(newType);
+}
+
+void CCreatureAnim::reset()
+{
+	//if we are in the middle of rotation - set flag
+	if (type == TURN_L && !queue.empty() && queue.front() == TURN_L)
+		rotate(true);
+	if (type == TURN_R && !queue.empty() && queue.front() == TURN_R)
+		rotate(false);
+
+	while (!queue.empty())
+	{
+		EAnimType at = queue.front();
+		queue.pop();
+		if (set(at))
+			return;
+	}
+	if  (callback)
+		callback();
+	while (!queue.empty())
+	{
+		EAnimType at = queue.front();
+		queue.pop();
+		if (set(at))
+			return;
+	}
+	set(HOLDING);
+}
+
+void CCreatureAnim::startPreview(bool warMachine)
+{
+	callback = boost::bind(&CCreatureAnim::loopPreview, this, warMachine);
+}
+
+void CCreatureAnim::clearAndSet(EAnimType type)
+{
+	while (!queue.empty())
+		queue.pop();
+	set(type);
+}

+ 226 - 0
client/widgets/Images.h

@@ -0,0 +1,226 @@
+#pragma once
+
+#include "../gui/CIntObject.h"
+#include "../gui/SDL_Extensions.h"
+
+struct SDL_Surface;
+struct Rect;
+class CAnimImage;
+class CLabel;
+class CAnimation;
+class CDefHandler;
+
+/*
+ * Images.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+// Image class
+class CPicture : public CIntObject
+{
+	void setSurface(SDL_Surface *to);
+public: 
+	SDL_Surface * bg;
+	Rect * srcRect; //if nullptr then whole surface will be used
+	bool freeSurf; //whether surface will be freed upon CPicture destruction
+	bool needRefresh;//Surface needs to be displayed each frame
+
+	operator SDL_Surface*()
+	{
+		return bg;
+	}
+
+	CPicture(const Rect & r, const SDL_Color & color, bool screenFormat = false); //rect filled with given color
+	CPicture(const Rect & r, ui32 color, bool screenFormat = false); //rect filled with given color
+	CPicture(SDL_Surface * BG, int x = 0, int y=0, bool Free = true); //wrap existing SDL_Surface
+	CPicture(const std::string &bmpname, int x=0, int y=0);
+	CPicture(SDL_Surface *BG, const Rect &SrcRext, int x = 0, int y = 0, bool free = false); //wrap subrect of given surface
+	~CPicture();
+	void init();
+
+	//set alpha value for whole surface. Note: may be messed up if surface is shared
+	// 0=transparent, 255=opaque
+	void setAlpha(int value);
+
+	void scaleTo(Point size);
+	void createSimpleRect(const Rect &r, bool screenFormat, ui32 color);
+	void show(SDL_Surface * to);
+	void showAll(SDL_Surface * to);
+	void convertToScreenBPP();
+	void colorizeAndConvert(PlayerColor player);
+	void colorize(PlayerColor player);
+};
+
+/// area filled with specific texture
+class CFilledTexture : CIntObject
+{
+	SDL_Surface * texture;
+
+public:
+	CFilledTexture(std::string imageName, Rect position);
+	~CFilledTexture();
+	void showAll(SDL_Surface *to);
+};
+
+/// Class for displaying one image from animation
+class CAnimImage: public CIntObject
+{
+private:
+	CAnimation* anim;
+	//displayed frame/group
+	size_t frame;
+	size_t group;
+	PlayerColor player;
+	ui8 flags;
+
+	void init();
+
+public:
+	CAnimImage(std::string name, size_t Frame, size_t Group=0, int x=0, int y=0, ui8 Flags=0);
+	CAnimImage(CAnimation* anim, size_t Frame, size_t Group=0, int x=0, int y=0, ui8 Flags=0);
+	~CAnimImage();//d-tor
+
+	//size of animation
+	size_t size();
+
+	//change displayed frame on this one
+	void setFrame(size_t Frame, size_t Group=0);
+
+	//makes image player-colored
+	void playerColored(PlayerColor player);
+
+	void showAll(SDL_Surface * to);
+};
+
+/// Base class for displaying animation, used as superclass for different animations
+class CShowableAnim: public CIntObject
+{
+public:
+	enum EFlags
+	{
+		BASE=1,            //base frame will be blitted before current one
+		HORIZONTAL_FLIP=2, //TODO: will be displayed rotated
+		VERTICAL_FLIP=4,   //TODO: will be displayed rotated
+		USE_RLE=8,         //RLE-d version, support full alpha-channel for 8-bit images
+		PLAYER_COLORED=16, //TODO: all loaded images will be player-colored
+		PLAY_ONCE=32       //play animation only once and stop at last frame
+	};
+protected:
+	CAnimation * anim;
+
+	size_t group, frame;//current frame
+
+	size_t first, last; //animation range
+
+	//TODO: replace with time delay(needed for battles)
+	ui32 frameDelay;//delay in frames of each image
+	ui32 value;//how many times current frame was showed
+
+	ui8 flags;//Flags from EFlags enum
+
+	//blit image with optional rotation, fitting into rect, etc
+	void blitImage(size_t frame, size_t group, SDL_Surface *to);
+
+	//For clipping in rect, offsets of picture coordinates
+	int xOffset, yOffset;
+
+	ui8 alpha;
+
+public:
+	//called when next animation sequence is required
+	std::function<void()> callback;
+
+	//Set per-surface alpha, 0 = transparent, 255 = opaque
+	void setAlpha(ui32 alphaValue);
+
+	CShowableAnim(int x, int y, std::string name, ui8 flags=0, ui32 Delay=4, size_t Group=0);
+	~CShowableAnim();
+
+	//set animation to group or part of group
+	bool set(size_t Group);
+	bool set(size_t Group, size_t from, size_t to=-1);
+
+	//set rotation flags
+	void rotate(bool on, bool vertical=false);
+
+	//move displayed part of picture (if picture is clipped to rect)
+	void clipRect(int posX, int posY, int width, int height);
+
+	//set frame to first, call callback
+	virtual void reset();
+
+	//show current frame and increase counter
+	void show(SDL_Surface * to);
+	void showAll(SDL_Surface * to);
+};
+
+/// Creature-dependend animations like attacking, moving,...
+class CCreatureAnim: public CShowableAnim
+{
+public:
+
+	enum EHeroAnimType
+	{
+		HERO_HOLDING = 0,
+		HERO_IDLE = 1, // idling movement that happens from time to time
+		HERO_DEFEAT = 2, // played when army loses stack or on friendly fire
+		HERO_VICTORY = 3, // when enemy stack killed or huge damage is dealt
+		HERO_CAST_SPELL = 4 // spellcasting
+	};
+
+	enum EAnimType // list of creature animations, numbers were taken from def files
+	{
+		MOVING=0,
+		MOUSEON=1,
+		HOLDING=2,
+		HITTED=3,
+		DEFENCE=4,
+		DEATH=5,
+		//DEATH2=6, //unused?
+		TURN_L=7,
+		TURN_R=8, //same
+		//TURN_L2=9, //identical to previous?
+		//TURN_R2=10,
+		ATTACK_UP=11,
+		ATTACK_FRONT=12,
+		ATTACK_DOWN=13,
+		SHOOT_UP=14,
+		SHOOT_FRONT=15,
+		SHOOT_DOWN=16,
+		CAST_UP=17,
+		CAST_FRONT=18,
+		CAST_DOWN=19,
+		MOVE_START=20,
+		MOVE_END=21,
+		DEAD = 22 // new group, used to show dead stacks. If empty - last frame from "DEATH" will be copied here
+
+	};
+
+private:
+	//queue of animations waiting to be displayed
+	std::queue<EAnimType> queue;
+
+	//this function is used as callback if preview flag was set during construction
+	void loopPreview(bool warMachine);
+
+public:
+	//change anim to next if queue is not empty, call callback othervice
+	void reset();
+
+	//add sequence to the end of queue
+	void addLast(EAnimType newType);
+
+	void startPreview(bool warMachine);
+
+	//clear queue and set animation to this sequence
+	void clearAndSet(EAnimType type);
+
+	CCreatureAnim(int x, int y, std::string name, Rect picPos,
+				  ui8 flags= USE_RLE, EAnimType = HOLDING );
+
+};

+ 29 - 374
client/widgets/MiscWidgets.cpp

@@ -1,6 +1,8 @@
 #include "StdInc.h"
 #include "MiscWidgets.h"
 
+#include "CComponent.h"
+
 #include "../gui/CGuiHandler.h"
 #include "../gui/CCursorHandler.h"
 
@@ -10,12 +12,15 @@
 #include "../CGameInfo.h"
 #include "../windows/CAdvmapInterface.h"
 #include "../windows/CCastleInterface.h"
+#include "../windows/InfoWindows.h"
 
 #include "../../CCallback.h"
 
 #include "../../lib/mapObjects/CGHeroInstance.h"
+#include "../../lib/mapObjects/CGTownInstance.h"
 #include "../../lib/CGeneralTextHandler.h"
 #include "../../lib/CModHandler.h"
+#include "../../lib/CGameState.h"
 
 /*
  * MiscWidgets.cpp, part of VCMI engine
@@ -27,408 +32,58 @@
  *
  */
 
-void CSelWindow::selectionChange(unsigned to)
-{
-	for (unsigned i=0;i<components.size();i++)
-	{
-		CSelectableComponent * pom = dynamic_cast<CSelectableComponent*>(components[i]);
-		if (!pom)
-			continue;
-		pom->select(i==to);
-	}
-	redraw();
-}
-
-CSelWindow::CSelWindow(const std::string &Text, PlayerColor player, int charperline, const std::vector<CSelectableComponent*> &comps, const std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, QueryID askID)
-{
-	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	ID = askID;
-	for(int i=0;i<Buttons.size();i++)
-	{
-		buttons.push_back(new CAdventureMapButton("","",Buttons[i].second,0,0,Buttons[i].first));
-		if(!i  &&  askID.getNum() >= 0)
-			buttons.back()->callback += boost::bind(&CSelWindow::madeChoice,this);
-		buttons[i]->callback += boost::bind(&CInfoWindow::close,this); //each button will close the window apart from call-defined actions
-	}
-
-	text = new CTextBox(Text, Rect(0, 0, 250, 100), 0, FONT_MEDIUM, CENTER, Colors::WHITE);
-
-	buttons.front()->assignedKeys.insert(SDLK_RETURN); //first button - reacts on enter
-	buttons.back()->assignedKeys.insert(SDLK_ESCAPE); //last button - reacts on escape
-
-	if(buttons.size() > 1  &&  askID.getNum() >= 0) //cancel button functionality
-		buttons.back()->callback += boost::bind(&CCallback::selectionMade,LOCPLINT->cb.get(),0,askID);
-
-	for(int i=0;i<comps.size();i++)
-	{
-		comps[i]->recActions = 255;
-		addChild(comps[i]);
-		components.push_back(comps[i]);
-		comps[i]->onSelect = boost::bind(&CSelWindow::selectionChange,this,i);
-		if(i<9)
-			comps[i]->assignedKeys.insert(SDLK_1+i);
-	}
-	CMessage::drawIWindow(this, Text, player);
-}
-
-void CSelWindow::madeChoice()
-{
-	if(ID.getNum() < 0)
-		return;
-	int ret = -1;
-	for (int i=0;i<components.size();i++)
-	{
-		if(dynamic_cast<CSelectableComponent*>(components[i])->selected)
-		{
-			ret = i;
-		}
-	}
-	LOCPLINT->cb->selectionMade(ret+1,ID);
-}
-
-CInfoWindow::CInfoWindow(std::string Text, PlayerColor player, const TCompsInfo &comps, const TButtonsInfo &Buttons, bool delComps)
-{
-	OBJ_CONSTRUCTION_CAPTURING_ALL;
-
-	type |= BLOCK_ADV_HOTKEYS;
-	ID = QueryID(-1);
-	for(auto & Button : Buttons)
-	{
-		CAdventureMapButton *button = new CAdventureMapButton("","",boost::bind(&CInfoWindow::close,this),0,0,Button.first);
-		button->borderColor = Colors::METALLIC_GOLD;
-		button->borderEnabled = true;
-		button->callback.add(Button.second); //each button will close the window apart from call-defined actions
-		buttons.push_back(button);
-	}
-
-	text = new CTextBox(Text, Rect(0, 0, 250, 100), 0, FONT_MEDIUM, CENTER, Colors::WHITE);
-	if(!text->slider)
-	{
-		text->resize(text->label->textSize);
-	}
-
-	if(buttons.size())
-	{
-		buttons.front()->assignedKeys.insert(SDLK_RETURN); //first button - reacts on enter
-		buttons.back()->assignedKeys.insert(SDLK_ESCAPE); //last button - reacts on escape
-	}
-
-	for(auto & comp : comps)
-	{
-		comp->recActions = 0xff;
-		addChild(comp);
-		comp->recActions &= ~(SHOWALL | UPDATE);
-		components.push_back(comp);
-	}
-	setDelComps(delComps);
-	CMessage::drawIWindow(this,Text,player);
-}
-
-CInfoWindow::CInfoWindow()
-{
-	ID = QueryID(-1);
-	setDelComps(false);
-	text = nullptr;
-}
-
-void CInfoWindow::close()
-{
-	GH.popIntTotally(this);
-	if(LOCPLINT)
-		LOCPLINT->showingDialog->setn(false);
-}
-
-void CInfoWindow::show(SDL_Surface * to)
-{
-	CIntObject::show(to);
-}
-
-CInfoWindow::~CInfoWindow()
-{
-	if(!delComps)
-	{
-		for (auto & elem : components)
-			removeChild(elem);
-	}
-}
-
-void CInfoWindow::showAll(SDL_Surface * to)
-{
-	CSimpleWindow::show(to);
-	CIntObject::showAll(to);
-}
-
-void CInfoWindow::showInfoDialog(const std::string &text, const std::vector<CComponent *> *components, bool DelComps, PlayerColor player)
-{
-	CInfoWindow * window = CInfoWindow::create(text, player, components, DelComps);
-	GH.pushInt(window);
-}
-
-void CInfoWindow::showYesNoDialog(const std::string & text, const std::vector<CComponent*> *components, const CFunctionList<void( ) > &onYes, const CFunctionList<void()> &onNo, bool DelComps, PlayerColor player)
-{
-	assert(!LOCPLINT || LOCPLINT->showingDialog->get());
-	std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
-	pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));
-	pom.push_back(std::pair<std::string,CFunctionList<void()> >("ICANCEL.DEF",0));
-	CInfoWindow * temp = new CInfoWindow(text, player, components ? *components : std::vector<CComponent*>(), pom, DelComps);
-	for(auto & elem : onYes.funcs)
-		temp->buttons[0]->callback += elem;
-	for(auto & elem : onNo.funcs)
-		temp->buttons[1]->callback += elem;
-
-	GH.pushInt(temp);
-}
-
-void CInfoWindow::showOkDialog(const std::string & text, const std::vector<CComponent*> *components, const boost::function<void()> & onOk, bool delComps, PlayerColor player)
-{
-	std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
-	pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));
-	CInfoWindow * temp = new CInfoWindow(text, player, *components, pom, delComps);
-	temp->buttons[0]->callback += onOk;
-
-	GH.pushInt(temp);
-}
-
-CInfoWindow * CInfoWindow::create(const std::string &text, PlayerColor playerID /*= 1*/, const std::vector<CComponent*> *components /*= nullptr*/, bool DelComps)
-{
-	std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
-	pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));
-	CInfoWindow * ret = new CInfoWindow(text, playerID, components ? *components : std::vector<CComponent*>(), pom, DelComps);
-	return ret;
-}
-
-std::string CInfoWindow::genText(std::string title, std::string description)
-{
-	return std::string("{") + title + "}" + "\n\n" + description;
-}
-
-void CInfoWindow::setDelComps(bool DelComps)
-{
-	delComps = DelComps;
-	for(CComponent *comp : components)
-	{
-		if(delComps)
-			comp->recActions |= DISPOSE;
-		else
-			comp->recActions &= ~DISPOSE;
-	}
-}
-
-CInfoPopup::CInfoPopup(SDL_Surface * Bitmap, int x, int y, bool Free)
- :free(Free),bitmap(Bitmap)
-{
-	init(x, y);
-}
-
-
-CInfoPopup::CInfoPopup(SDL_Surface * Bitmap, const Point &p, EAlignment alignment, bool Free/*=false*/)
- : free(Free),bitmap(Bitmap)
-{
-	switch(alignment)
-	{
-	case BOTTOMRIGHT:
-		init(p.x - Bitmap->w, p.y - Bitmap->h);
-		break;
-	case CENTER:
-		init(p.x - Bitmap->w/2, p.y - Bitmap->h/2);
-		break;
-	case TOPLEFT:
-		init(p.x, p.y);
-		break;
-	default:
-		assert(0); //not implemented
-	}
-}
-
-CInfoPopup::CInfoPopup(SDL_Surface *Bitmap, bool Free)
-{
-	CCS->curh->hide();
-
-	free=Free;
-	bitmap=Bitmap;
-
-	if(bitmap)
-	{
-		pos.x = screen->w/2 - bitmap->w/2;
-		pos.y = screen->h/2 - bitmap->h/2;
-		pos.h = bitmap->h;
-		pos.w = bitmap->w;
-	}
-}
-
-void CInfoPopup::close()
-{
-	if(free)
-		SDL_FreeSurface(bitmap);
-	GH.popIntTotally(this);
-}
-
-void CInfoPopup::show(SDL_Surface * to)
-{
-	blitAt(bitmap,pos.x,pos.y,to);
-}
-
-CInfoPopup::~CInfoPopup()
-{
-	CCS->curh->show();
-}
-
-void CInfoPopup::init(int x, int y)
-{
-	CCS->curh->hide();
-
-	pos.x = x;
-	pos.y = y;
-	pos.h = bitmap->h;
-	pos.w = bitmap->w;
-
-	// Put the window back on screen if necessary
-	vstd::amax(pos.x, 0);
-	vstd::amax(pos.y, 0);
-	vstd::amin(pos.x, screen->w - bitmap->w);
-	vstd::amin(pos.y, screen->h - bitmap->h);
-}
-
-
-void CRClickPopup::clickRight(tribool down, bool previousState)
-{
-	if(down)
-		return;
-	close();
-}
-
-void CRClickPopup::close()
+void CHoverableArea::hover (bool on)
 {
-	GH.popIntTotally(this);
+	if (on)
+		GH.statusbar->setText(hoverText);
+	else if (GH.statusbar->getText()==hoverText)
+		GH.statusbar->clear();
 }
 
-void CRClickPopup::createAndPush(const std::string &txt, const CInfoWindow::TCompsInfo &comps)
+CHoverableArea::CHoverableArea()
 {
-	PlayerColor player = LOCPLINT ? LOCPLINT->playerID : PlayerColor(1); //if no player, then use blue
-
-	CSimpleWindow * temp = new CInfoWindow(txt, player, comps);
-	temp->center(Point(GH.current->motion)); //center on mouse
-	temp->fitToScreen(10);
-	auto  rcpi = new CRClickPopupInt(temp,true);
-	GH.pushInt(rcpi);
+	addUsedEvents(HOVER);
 }
 
-void CRClickPopup::createAndPush(const std::string &txt, CComponent * component)
+CHoverableArea::~CHoverableArea()
 {
-	CInfoWindow::TCompsInfo intComps;
-	intComps.push_back(component);
-
-	createAndPush(txt, intComps);
 }
 
-void CRClickPopup::createAndPush(const CGObjectInstance *obj, const Point &p, EAlignment alignment /*= BOTTOMRIGHT*/)
+void LRClickableAreaWText::clickLeft(tribool down, bool previousState)
 {
-	CIntObject *iWin = createInfoWin(p, obj); //try get custom infowindow for this obj
-	if(iWin)
-		GH.pushInt(iWin);
-	else
+	if(!down && previousState && !text.empty())
 	{
-		if (adventureInt->curHero())
-			CRClickPopup::createAndPush(obj->getHoverText(adventureInt->curHero()));
-		else
-			CRClickPopup::createAndPush(obj->getHoverText(LOCPLINT->playerID));
+		LOCPLINT->showInfoDialog(text);
 	}
 }
-
-CRClickPopup::CRClickPopup()
-{
-	addUsedEvents(RCLICK);
-}
-
-CRClickPopup::~CRClickPopup()
-{
-}
-
-void CRClickPopupInt::show(SDL_Surface * to)
-{
-	inner->show(to);
-}
-
-CRClickPopupInt::CRClickPopupInt( IShowActivatable *our, bool deleteInt )
+void LRClickableAreaWText::clickRight(tribool down, bool previousState)
 {
-	CCS->curh->hide();
-	inner = our;
-	delInner = deleteInt;
+	if (!text.empty())
+		adventureInt->handleRightClick(text, down);
 }
 
-CRClickPopupInt::~CRClickPopupInt()
+LRClickableAreaWText::LRClickableAreaWText()
 {
-	if(delInner)
-		delete inner;
-
-	CCS->curh->show();
+	init();
 }
 
-void CRClickPopupInt::showAll(SDL_Surface * to)
+LRClickableAreaWText::LRClickableAreaWText(const Rect &Pos, const std::string &HoverText /*= ""*/, const std::string &ClickText /*= ""*/)
 {
-	inner->showAll(to);
+	init();
+	pos = Pos + pos;
+	hoverText = HoverText;
+	text = ClickText;
 }
 
-Point CInfoBoxPopup::toScreen(Point p)
+LRClickableAreaWText::~LRClickableAreaWText()
 {
-	vstd::abetween(p.x, adventureInt->terrain.pos.x + 100, adventureInt->terrain.pos.x + adventureInt->terrain.pos.w - 100);
-	vstd::abetween(p.y, adventureInt->terrain.pos.y + 100, adventureInt->terrain.pos.y + adventureInt->terrain.pos.h - 100);
-
-	return p;
 }
 
-CInfoBoxPopup::CInfoBoxPopup(Point position, const CGTownInstance * town):
-	CWindowObject(RCLICK_POPUP | PLAYER_COLORED, "TOWNQVBK", toScreen(position))
+void LRClickableAreaWText::init()
 {
-	InfoAboutTown iah;
-	LOCPLINT->cb->getTownInfo(town, iah);
-
-	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	new CTownTooltip(Point(9, 10), iah);
-}
-
-CInfoBoxPopup::CInfoBoxPopup(Point position, const CGHeroInstance * hero):
-	CWindowObject(RCLICK_POPUP | PLAYER_COLORED, "HEROQVBK", toScreen(position))
-{
-	InfoAboutHero iah;
-	LOCPLINT->cb->getHeroInfo(hero, iah);
-
-	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	new CHeroTooltip(Point(9, 10), iah);
-}
-
-CInfoBoxPopup::CInfoBoxPopup(Point position, const CGGarrison * garr):
-	CWindowObject(RCLICK_POPUP | PLAYER_COLORED, "TOWNQVBK", toScreen(position))
-{
-	InfoAboutTown iah;
-	LOCPLINT->cb->getTownInfo(garr, iah);
-
-	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	new CArmyTooltip(Point(9, 10), iah);
-}
-
-CIntObject * CRClickPopup::createInfoWin(Point position, const CGObjectInstance * specific) //specific=0 => draws info about selected town/hero
-{
-	if(!specific)
-		specific = adventureInt->selection;
-
-	assert(specific);
-
-	switch(specific->ID)
-	{
-	case Obj::HERO:
-		return new CInfoBoxPopup(position, dynamic_cast<const CGHeroInstance *>(specific));
-	case Obj::TOWN:
-		return new CInfoBoxPopup(position, dynamic_cast<const CGTownInstance *>(specific));
-	case Obj::GARRISON:
-	case Obj::GARRISON2:
-		return new CInfoBoxPopup(position, dynamic_cast<const CGGarrison *>(specific));
-	default:
-		return nullptr;
-	}
+	addUsedEvents(LCLICK | RCLICK | HOVER);
 }
 
-
 void LRClickableAreaWTextComp::clickLeft(tribool down, bool previousState)
 {
 	if((!down) && previousState)

+ 42 - 101
client/widgets/MiscWidgets.h

@@ -1,6 +1,6 @@
 #pragma once
 
-#include "CComponent.h"
+#include "../gui/CIntObject.h"
 
 /*
  * MiscWidgets.h, part of VCMI engine
@@ -19,105 +19,33 @@ class CSelectableComponent;
 class InfoAboutArmy;
 class CArmedInstance;
 class IBonusBearer;
+class CAnimImage;
 
-/// text + comp. + ok button
-class CInfoWindow : public CSimpleWindow
-{ //window able to delete its components when closed
-	bool delComps; //whether comps will be deleted
-
-public:
-	typedef std::vector<std::pair<std::string,CFunctionList<void()> > > TButtonsInfo;
-	typedef std::vector<CComponent*> TCompsInfo;
-	QueryID ID; //for identification
-	CTextBox *text;
-	std::vector<CAdventureMapButton *> buttons;
-	std::vector<CComponent*> components;
-	CSlider *slider;
-
-	void setDelComps(bool DelComps);
-	virtual void close();
-
-	void show(SDL_Surface * to);
-	void showAll(SDL_Surface * to);
-	void sliderMoved(int to);
-
-	CInfoWindow(std::string Text, PlayerColor player, const TCompsInfo &comps = TCompsInfo(), const TButtonsInfo &Buttons = TButtonsInfo(), bool delComps = true); //c-tor
-	CInfoWindow(); //c-tor
-	~CInfoWindow(); //d-tor
-
-	//use only before the game starts! (showYesNoDialog in LOCPLINT must be used then)
-	static void showInfoDialog( const std::string & text, const std::vector<CComponent*> *components, bool DelComps = true, PlayerColor player = PlayerColor(1));
-	static void showOkDialog(const std::string & text, const std::vector<CComponent*> *components, const boost::function<void()> & onOk, bool delComps = true, PlayerColor player = PlayerColor(1));
-	static void showYesNoDialog( const std::string & text, const std::vector<CComponent*> *components, const CFunctionList<void( ) > &onYes, const CFunctionList<void()> &onNo, bool DelComps = true, PlayerColor player = PlayerColor(1));
-	static CInfoWindow *create(const std::string &text, PlayerColor playerID = PlayerColor(1), const std::vector<CComponent*> *components = nullptr, bool DelComps = false);
-
-	/// create text from title and description: {title}\n\n description
-	static std::string genText(std::string title, std::string description);
-};
-
-/// popup displayed on R-click
-class CRClickPopup : public CIntObject
+/// Shows a text by moving the mouse cursor over the object
+class CHoverableArea: public virtual CIntObject
 {
 public:
-	virtual void close();
-	void clickRight(tribool down, bool previousState);
-
-	CRClickPopup();
-	virtual ~CRClickPopup(); //d-tor
-
-	static CIntObject* createInfoWin(Point position, const CGObjectInstance * specific);
-	static void createAndPush(const std::string &txt, const CInfoWindow::TCompsInfo &comps = CInfoWindow::TCompsInfo());
-	static void createAndPush(const std::string &txt, CComponent * component);
-	static void createAndPush(const CGObjectInstance *obj, const Point &p, EAlignment alignment = BOTTOMRIGHT);
-};
+	std::string hoverText;
 
-/// popup displayed on R-click
-class CRClickPopupInt : public CRClickPopup
-{
-public:
-	IShowActivatable *inner;
-	bool delInner;
+	virtual void hover (bool on);
 
-	void show(SDL_Surface * to);
-	void showAll(SDL_Surface * to);
-	CRClickPopupInt(IShowActivatable *our, bool deleteInt); //c-tor
-	virtual ~CRClickPopupInt(); //d-tor
+	CHoverableArea();
+	virtual ~CHoverableArea();
 };
 
-class CInfoPopup : public CRClickPopup
+/// Can interact on left and right mouse clicks, plus it shows a text when by hovering over it
+class LRClickableAreaWText: public CHoverableArea
 {
 public:
-	bool free; //TODO: comment me
-	SDL_Surface * bitmap; //popup background
-	void close();
-	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 = nullptr, bool Free = false); //default c-tor
-
-	void init(int x, int y);
-	~CInfoPopup(); //d-tor
-};
+	std::string text;
 
-/// popup on adventure map for town\hero objects
-class CInfoBoxPopup : public CWindowObject
-{
-	Point toScreen(Point pos);
-public:
-	CInfoBoxPopup(Point position, const CGTownInstance * town);
-	CInfoBoxPopup(Point position, const CGHeroInstance * hero);
-	CInfoBoxPopup(Point position, const CGGarrison * garr);
-};
+	LRClickableAreaWText();
+	LRClickableAreaWText(const Rect &Pos, const std::string &HoverText = "", const std::string &ClickText = "");
+	virtual ~LRClickableAreaWText();
+	void init();
 
-/// component selection window
-class CSelWindow : public CInfoWindow
-{ //warning - this window deletes its components by closing!
-public:
-	void selectionChange(unsigned to);
-	void madeChoice(); //looks for selected component and calls callback
-	CSelWindow(const std::string& text, PlayerColor player, int charperline ,const std::vector<CSelectableComponent*> &comps, const std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, QueryID askID); //c-tor
-	CSelWindow(){}; //c-tor
-	//notification - this class inherits important destructor from CInfoWindow
+	virtual void clickLeft(tribool down, bool previousState);
+	virtual void clickRight(tribool down, bool previousState);
 };
 
 /// base class for hero/town/garrison tooltips
@@ -173,18 +101,6 @@ public:
 	~CMinorResDataBar(); //d-tor
 };
 
-class MoraleLuckBox : public LRClickableAreaWTextComp
-{
-	CAnimImage *image;
-public:
-	bool morale; //true if morale, false if luck
-	bool small;
-
-	void set(const IBonusBearer *node);
-
-	MoraleLuckBox(bool Morale, const Rect &r, bool Small=false);
-};
-
 /// Opens hero window by left-clicking on it
 class CHeroArea: public CIntObject
 {
@@ -198,6 +114,19 @@ public:
 	void hover(bool on);
 };
 
+/// Can interact on left and right mouse clicks
+class LRClickableAreaWTextComp: public LRClickableAreaWText
+{
+public:
+	int baseType;
+	int bonusValue, type;
+	virtual void clickLeft(tribool down, bool previousState);
+	virtual void clickRight(tribool down, bool previousState);
+
+	LRClickableAreaWTextComp(const Rect &Pos = Rect(0,0,0,0), int BaseType = -1);
+	CComponent * createComponent() const;
+};
+
 /// Opens town screen by left-clicking on it
 class LRClickableAreaOpenTown: public LRClickableAreaWTextComp
 {
@@ -207,3 +136,15 @@ public:
 	void clickRight(tribool down, bool previousState);
 	LRClickableAreaOpenTown();
 };
+
+class MoraleLuckBox : public LRClickableAreaWTextComp
+{
+	CAnimImage *image;
+public:
+	bool morale; //true if morale, false if luck
+	bool small;
+
+	void set(const IBonusBearer *node);
+
+	MoraleLuckBox(bool Morale, const Rect &r, bool Small=false);
+};

+ 234 - 0
client/widgets/ObjectLists.cpp

@@ -0,0 +1,234 @@
+#include "StdInc.h"
+#include "ObjectLists.h"
+
+#include "../gui/CGuiHandler.h"
+#include "Buttons.h"
+
+/*
+ * ObjectLists.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+
+static void intDeleter(CIntObject* object)
+{
+	delete object;
+}
+
+CObjectList::CObjectList(CreateFunc create, DestroyFunc destroy):
+createObject(create),
+destroyObject(destroy)
+{
+	if (!destroyObject)
+		destroyObject = intDeleter;
+}
+
+void CObjectList::deleteItem(CIntObject* item)
+{
+	if (!item)
+		return;
+	removeChild(item);
+	destroyObject(item);
+}
+
+CIntObject* CObjectList::createItem(size_t index)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	CIntObject * item = createObject(index);
+	if (item == nullptr)
+		item = new CIntObject();
+
+	item->recActions = defActions;
+
+	addChild(item);
+	return item;
+}
+
+CTabbedInt::CTabbedInt(CreateFunc create, DestroyFunc destroy, Point position, size_t ActiveID):
+CObjectList(create, destroy),
+activeTab(nullptr),
+activeID(ActiveID)
+{
+	pos += position;
+	reset();
+}
+
+void CTabbedInt::setActive(size_t which)
+{
+	if (which != activeID)
+	{
+		activeID = which;
+		reset();
+	}
+}
+
+void CTabbedInt::reset()
+{
+	deleteItem(activeTab);
+	activeTab = createItem(activeID);
+	activeTab->moveTo(pos.topLeft());
+
+	if (active)
+		redraw();
+}
+
+CIntObject * CTabbedInt::getItem()
+{
+	return activeTab;
+}
+
+CListBox::CListBox(CreateFunc create, DestroyFunc destroy, Point Pos, Point ItemOffset, size_t VisibleSize,
+				   size_t TotalSize, size_t InitialPos, int Slider, Rect SliderPos):
+	CObjectList(create, destroy),
+	first(InitialPos),
+	totalSize(TotalSize),
+	itemOffset(ItemOffset),
+    slider(nullptr)
+{
+	pos += Pos;
+	items.resize(VisibleSize, nullptr);
+
+	if (Slider & 1)
+	{
+		OBJ_CONSTRUCTION_CAPTURING_ALL;
+		slider = new CSlider(SliderPos.x, SliderPos.y, SliderPos.w, boost::bind(&CListBox::moveToPos, this, _1),
+			VisibleSize, TotalSize, InitialPos, Slider & 2, Slider & 4);
+	}
+	reset();
+}
+
+// Used to move active items after changing list position
+void CListBox::updatePositions()
+{
+	Point itemPos = pos.topLeft();
+	for (auto & elem : items)
+	{
+		(elem)->moveTo(itemPos);
+		itemPos += itemOffset;
+	}
+	if (active)
+	{
+		redraw();
+		if (slider)
+			slider->moveTo(first);
+	}
+}
+
+void CListBox::reset()
+{
+	size_t current = first;
+	for (auto & elem : items)
+	{
+		deleteItem(elem);
+		elem = createItem(current++);
+	}
+	updatePositions();
+}
+
+void CListBox::resize(size_t newSize)
+{
+	totalSize = newSize;
+	if (slider)
+		slider->setAmount(totalSize);
+	reset();
+}
+
+size_t CListBox::size()
+{
+	return totalSize;
+}
+
+CIntObject * CListBox::getItem(size_t which)
+{
+	if (which < first || which > first + items.size() || which > totalSize)
+		return nullptr;
+
+	size_t i=first;
+	for (auto iter = items.begin(); iter != items.end(); iter++, i++)
+		if( i == which)
+			return *iter;
+	return nullptr;
+}
+
+size_t CListBox::getIndexOf(CIntObject *item)
+{
+	size_t i=first;
+	for (auto iter = items.begin(); iter != items.end(); iter++, i++)
+		if(*iter == item)
+			return i;
+	return size_t(-1);
+}
+
+void CListBox::scrollTo(size_t which)
+{
+	//scroll up
+	if (first > which)
+		moveToPos(which);
+	//scroll down
+	else if (first + items.size() <= which && which < totalSize)
+		moveToPos(which - items.size() + 1);
+}
+
+void CListBox::moveToPos(size_t which)
+{
+	//Calculate new position
+	size_t maxPossible;
+	if (totalSize > items.size())
+		maxPossible = totalSize - items.size();
+	else
+		maxPossible = 0;
+
+	size_t newPos = std::min(which, maxPossible);
+
+	//If move distance is 1 (most of calls from Slider) - use faster shifts instead of resetting all items
+	if (first - newPos == 1)
+		moveToPrev();
+	else if (newPos - first == 1)
+		moveToNext();
+	else if (newPos != first)
+	{
+		first = newPos;
+		reset();
+	}
+}
+
+void CListBox::moveToNext()
+{
+	//Remove front item and insert new one to end
+	if (first + items.size() < totalSize)
+	{
+		first++;
+		deleteItem(items.front());
+		items.pop_front();
+		items.push_back(createItem(first+items.size()));
+		updatePositions();
+	}
+}
+
+void CListBox::moveToPrev()
+{
+	//Remove last item and insert new one at start
+	if (first)
+	{
+		first--;
+		deleteItem(items.back());
+		items.pop_back();
+		items.push_front(createItem(first));
+		updatePositions();
+	}
+}
+
+size_t CListBox::getPos()
+{
+	return first;
+}
+
+const std::list<CIntObject *> &CListBox::getItems()
+{
+	return items;
+}

+ 111 - 0
client/widgets/ObjectLists.h

@@ -0,0 +1,111 @@
+#pragma once
+
+#include "../gui/CIntObject.h"
+
+struct SDL_Surface;
+struct Rect;
+class CAnimImage;
+class CSlider;
+class CLabel;
+class CAnimation;
+class CDefHandler;
+
+/*
+ * ObjectLists.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+/// Used as base for Tabs and List classes
+class CObjectList : public CIntObject
+{
+public:
+	typedef std::function<CIntObject* (size_t)> CreateFunc;
+	typedef std::function<void(CIntObject *)> DestroyFunc;
+
+private:
+	CreateFunc createObject;
+	DestroyFunc destroyObject;
+
+protected:
+	//Internal methods for safe creation of items (Children capturing and activation/deactivation if needed)
+	void deleteItem(CIntObject* item);
+	CIntObject* createItem(size_t index);
+
+	CObjectList(CreateFunc create, DestroyFunc destroy = DestroyFunc());//Protected constructor
+};
+
+/// Window element with multiple tabs
+class CTabbedInt : public CObjectList
+{
+private:
+	CIntObject * activeTab;
+	size_t activeID;
+
+public:
+	//CreateFunc, DestroyFunc - see CObjectList
+	//Pos - position of object, all tabs will be moved to this position
+	//ActiveID - ID of initially active tab
+	CTabbedInt(CreateFunc create, DestroyFunc destroy = DestroyFunc(), Point position=Point(), size_t ActiveID=0);
+
+	void setActive(size_t which);
+	//recreate active tab
+	void reset();
+
+	//return currently active item
+	CIntObject * getItem();
+};
+
+/// List of IntObjects with optional slider
+class CListBox : public CObjectList
+{
+private:
+	std::list< CIntObject* > items;
+	size_t first;
+	size_t totalSize;
+
+	Point itemOffset;
+	CSlider * slider;
+
+	void updatePositions();
+public:
+	//CreateFunc, DestroyFunc - see CObjectList
+	//Pos - position of first item
+	//ItemOffset - distance between items in the list
+	//VisibleSize - maximal number of displayable at once items
+	//TotalSize
+	//Slider - slider style, bit field: 1 = present(disabled), 2=horisontal(vertical), 4=blue(brown)
+	//SliderPos - position of slider, if present
+	CListBox(CreateFunc create, DestroyFunc destroy, Point Pos, Point ItemOffset, size_t VisibleSize,
+		size_t TotalSize, size_t InitialPos=0, int Slider=0, Rect SliderPos=Rect() );
+
+	//recreate all visible items
+	void reset();
+
+	//change or get total amount of items in the list
+	void resize(size_t newSize);
+	size_t size();
+
+	//return item with index which or null if not present
+	CIntObject * getItem(size_t which);
+
+	//return currently active items
+	const std::list< CIntObject * > & getItems();
+
+	//get index of this item. -1 if not found
+	size_t getIndexOf(CIntObject * item);
+
+	//scroll list to make item which visible
+	void scrollTo(size_t which);
+
+	//scroll list to specified position
+	void moveToPos(size_t which);
+	void moveToNext();
+	void moveToPrev();
+
+	size_t getPos();
+};

+ 642 - 0
client/widgets/TextControls.cpp

@@ -0,0 +1,642 @@
+#include "StdInc.h"
+#include "TextControls.h"
+
+#include "Buttons.h"
+#include "Images.h"
+
+#include "../CMessage.h"
+#include "../gui/CGuiHandler.h"
+
+#include "../../lib/CGeneralTextHandler.h" //for Unicode related stuff
+
+/*
+ * TextControls.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+std::string CLabel::visibleText()
+{
+	return text;
+}
+
+void CLabel::showAll(SDL_Surface * to)
+{
+	CIntObject::showAll(to);
+
+	if(!visibleText().empty())
+		blitLine(to, pos, visibleText());
+
+}
+
+CLabel::CLabel(int x, int y, EFonts Font /*= FONT_SMALL*/, EAlignment Align, const SDL_Color &Color /*= Colors::WHITE*/, const std::string &Text /*= ""*/)
+:CTextContainer(Align, Font, Color), text(Text)
+{
+	type |= REDRAW_PARENT;
+	autoRedraw = true;
+	pos.x += x;
+	pos.y += y;
+	pos.w = pos.h = 0;
+	bg = nullptr;
+
+	if (alignment == TOPLEFT) // causes issues for MIDDLE
+	{
+		pos.w = graphics->fonts[font]->getStringWidth(visibleText().c_str());
+		pos.h = graphics->fonts[font]->getLineHeight();
+	}
+}
+
+Point CLabel::getBorderSize()
+{
+	return Point(0, 0);
+}
+
+std::string CLabel::getText()
+{
+	return text;
+}
+
+void CLabel::setText(const std::string &Txt)
+{
+	text = Txt;
+	if(autoRedraw)
+	{
+		if(bg || !parent)
+			redraw();
+		else
+			parent->redraw();
+	}
+}
+
+CMultiLineLabel::CMultiLineLabel(Rect position, EFonts Font, EAlignment Align, const SDL_Color &Color, const std::string &Text):
+    CLabel(position.x, position.y, Font, Align, Color, Text),
+    visibleSize(0, 0, position.w, position.h)
+{
+	pos.w = position.w;
+	pos.h = position.h;
+	splitText(Text);
+}
+
+void CMultiLineLabel::setVisibleSize(Rect visibleSize)
+{
+	this->visibleSize = visibleSize;
+	redraw();
+}
+
+void CMultiLineLabel::scrollTextBy(int distance)
+{
+	scrollTextTo(visibleSize.y + distance);
+}
+
+void CMultiLineLabel::scrollTextTo(int distance)
+{
+	Rect size = visibleSize;
+	size.y = distance;
+	setVisibleSize(size);
+}
+
+void CMultiLineLabel::setText(const std::string &Txt)
+{
+	splitText(Txt);
+	CLabel::setText(Txt);
+}
+
+void CTextContainer::blitLine(SDL_Surface *to, Rect destRect, std::string what)
+{
+	const IFont * f = graphics->fonts[font];
+	Point where = destRect.topLeft();
+
+	// input is rect in which given text should be placed
+	// calculate proper position for top-left corner of the text
+	if (alignment == TOPLEFT)
+	{
+		where.x += getBorderSize().x;
+		where.y += getBorderSize().y;
+	}
+
+	if (alignment == CENTER)
+	{
+		where.x += (int(destRect.w) - int(f->getStringWidth(what))) / 2;
+		where.y += (int(destRect.h) - int(f->getLineHeight())) / 2;
+	}
+
+	if (alignment == BOTTOMRIGHT)
+	{
+		where.x += getBorderSize().x + destRect.w - f->getStringWidth(what);
+		where.y += getBorderSize().y + destRect.h - f->getLineHeight();
+	}
+
+	size_t begin = 0;
+	std::string delimeters = "{}";
+	size_t currDelimeter = 0;
+
+	do
+	{
+		size_t end = what.find_first_of(delimeters[currDelimeter % 2], begin);
+		if (begin != end)
+		{
+			std::string toPrint = what.substr(begin, end - begin);
+
+			if (currDelimeter % 2) // Enclosed in {} text - set to yellow
+				f->renderTextLeft(to, toPrint, Colors::YELLOW, where);
+			else // Non-enclosed text, use default color
+				f->renderTextLeft(to, toPrint, color, where);
+			begin = end;
+
+			where.x += f->getStringWidth(toPrint);
+		}
+		currDelimeter++;
+	}
+	while (begin++ != std::string::npos);
+}
+
+CTextContainer::CTextContainer(EAlignment alignment, EFonts font, SDL_Color color):
+	alignment(alignment),
+	font(font),
+	color(color)
+{}
+
+void CMultiLineLabel::showAll(SDL_Surface * to)
+{
+	CIntObject::showAll(to);
+
+	const IFont * f = graphics->fonts[font];
+
+	// calculate which lines should be visible
+	int totalLines = lines.size();
+	int beginLine  = visibleSize.y;
+	int endLine    = getTextLocation().h + visibleSize.y;
+
+	if (beginLine < 0)
+		beginLine = 0;
+	else
+		beginLine /= f->getLineHeight();
+
+	if (endLine < 0)
+		endLine = 0;
+	else
+		endLine /= f->getLineHeight();
+	endLine++;
+
+	// and where they should be displayed
+	Point lineStart = getTextLocation().topLeft() - visibleSize + Point(0, beginLine * f->getLineHeight());
+	Point lineSize  = Point(getTextLocation().w, f->getLineHeight());
+
+	CSDL_Ext::CClipRectGuard guard(to, getTextLocation()); // to properly trim text that is too big to fit
+
+	for (int i = beginLine; i < std::min(totalLines, endLine); i++)
+	{
+		if (!lines[i].empty()) //non-empty line
+			blitLine(to, Rect(lineStart, lineSize), lines[i]);
+
+		lineStart.y += f->getLineHeight();
+	}
+}
+
+void CMultiLineLabel::splitText(const std::string &Txt)
+{
+	lines.clear();
+
+	const IFont * f = graphics->fonts[font];
+	int lineHeight =  f->getLineHeight();
+
+	lines = CMessage::breakText(Txt, pos.w, font);
+
+	 textSize.y = lineHeight * lines.size();
+	 textSize.x = 0;
+	for(const std::string &line : lines)
+		vstd::amax( textSize.x, f->getStringWidth(line.c_str()));
+	redraw();
+}
+
+Rect CMultiLineLabel::getTextLocation()
+{
+	// this method is needed for vertical alignment alignment of text
+	// when height of available text is smaller than height of widget
+	// in this case - we should add proper offset to display text at required position
+	if (pos.h <= textSize.y)
+		return pos;
+
+	Point textSize(pos.w, graphics->fonts[font]->getLineHeight() * lines.size());
+	Point textOffset(pos.w - textSize.x, pos.h - textSize.y);
+
+	switch(alignment)
+	{
+	case TOPLEFT:     return Rect(pos.topLeft(), textSize);
+	case CENTER:      return Rect(pos.topLeft() + textOffset / 2, textSize);
+	case BOTTOMRIGHT: return Rect(pos.topLeft() + textOffset, textSize);
+	}
+	assert(0);
+	return Rect();
+}
+
+CLabelGroup::CLabelGroup(EFonts Font, EAlignment Align, const SDL_Color &Color):
+	font(Font), align(Align), color(Color)
+{}
+
+void CLabelGroup::add(int x, int y, const std::string &text)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	new CLabel(x, y, font, align, color, text);
+}
+
+CTextBox::CTextBox(std::string Text, const Rect &rect, int SliderStyle, EFonts Font /*= FONT_SMALL*/, EAlignment Align /*= TOPLEFT*/, const SDL_Color &Color /*= Colors::WHITE*/):
+    sliderStyle(SliderStyle),
+    slider(nullptr)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	label = new CMultiLineLabel(rect, Font, Align, Color);
+
+	type |= REDRAW_PARENT;
+	pos.x += rect.x;
+	pos.y += rect.y;
+	pos.h = rect.h;
+	pos.w = rect.w;
+
+	assert(pos.w >= 40); //we need some space
+	setText(Text);
+}
+
+void CTextBox::sliderMoved(int to)
+{
+	label->scrollTextTo(to);
+}
+
+void CTextBox::resize(Point newSize)
+{
+	pos.w = newSize.x;
+	pos.h = newSize.y;
+	label->pos.w = pos.w;
+	label->pos.h = pos.h;
+	if (slider)
+		vstd::clear_pointer(slider); // will be recreated if needed later
+
+	setText(label->getText()); // force refresh
+}
+
+void CTextBox::setText(const std::string &text)
+{
+	label->setText(text);
+	if (label->textSize.y <= label->pos.h && slider)
+	{
+		// slider is no longer needed
+		vstd::clear_pointer(slider);
+		label->pos.w = pos.w;
+		label->setText(text);
+	}
+	else if (label->textSize.y > label->pos.h && !slider)
+	{
+		// create slider and update widget
+		label->pos.w = pos.w - 32;
+		label->setText(text);
+
+		OBJ_CONSTRUCTION_CAPTURING_ALL;
+		slider = new CSlider(pos.w - 32, 0, pos.h, boost::bind(&CTextBox::sliderMoved, this, _1),
+		                     label->pos.h, label->textSize.y, 0, false, sliderStyle);
+		slider->scrollStep = graphics->fonts[label->font]->getLineHeight();
+	}
+}
+
+void CGStatusBar::setText(const std::string & Text)
+{
+	if(!textLock)
+		CLabel::setText(Text);
+}
+
+void CGStatusBar::clear()
+{
+	setText("");
+}
+
+CGStatusBar::CGStatusBar(CPicture *BG, EFonts Font /*= FONT_SMALL*/, EAlignment Align /*= CENTER*/, const SDL_Color &Color /*= Colors::WHITE*/)
+: CLabel(BG->pos.x, BG->pos.y, Font, Align, Color, "")
+{
+	init();
+	bg = BG;
+	addChild(bg);
+	pos = bg->pos;
+	getBorderSize();
+    textLock = false;
+}
+
+CGStatusBar::CGStatusBar(int x, int y, std::string name/*="ADROLLVR.bmp"*/, int maxw/*=-1*/)
+: CLabel(x, y, FONT_SMALL, CENTER)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	init();
+	bg = new CPicture(name);
+	pos = bg->pos;
+	if((unsigned int)maxw < pos.w)
+	{
+		vstd::amin(pos.w, maxw);
+		bg->srcRect = new Rect(0, 0, maxw, pos.h);
+	}
+    textLock = false;
+}
+
+CGStatusBar::~CGStatusBar()
+{
+	GH.statusbar = oldStatusBar;
+}
+
+void CGStatusBar::show(SDL_Surface * to)
+{
+    showAll(to);
+}
+
+void CGStatusBar::init()
+{
+	oldStatusBar = GH.statusbar;
+	GH.statusbar = this;
+}
+
+Point CGStatusBar::getBorderSize()
+{
+	//Width of borders where text should not be printed
+	static const Point borderSize(5,1);
+
+	switch(alignment)
+	{
+	case TOPLEFT:     return Point(borderSize.x, borderSize.y);
+	case CENTER:      return Point(pos.w/2, pos.h/2);
+	case BOTTOMRIGHT: return Point(pos.w - borderSize.x, pos.h - borderSize.y);
+	}
+	assert(0);
+	return Point();
+}
+
+void CGStatusBar::lock(bool shouldLock)
+{
+    textLock = shouldLock;
+}
+
+CTextInput::CTextInput(const Rect &Pos, EFonts font, const CFunctionList<void(const std::string &)> &CB):
+    CLabel(Pos.x, Pos.y, font, CENTER),
+    cb(CB)
+{
+	type |= REDRAW_PARENT;
+	focus = false;
+	pos.h = Pos.h;
+	pos.w = Pos.w;
+	captureAllKeys = true;
+	bg = nullptr;
+	addUsedEvents(LCLICK | KEYBOARD | TEXTINPUT);
+	giveFocus();
+}
+
+CTextInput::CTextInput( const Rect &Pos, const Point &bgOffset, const std::string &bgName, const CFunctionList<void(const std::string &)> &CB )
+:cb(CB)
+{
+	focus = false;
+	pos += Pos;
+	captureAllKeys = true;
+	OBJ_CONSTRUCTION;
+	bg = new CPicture(bgName, bgOffset.x, bgOffset.y);
+	addUsedEvents(LCLICK | KEYBOARD | TEXTINPUT);
+	giveFocus();
+}
+
+CTextInput::CTextInput(const Rect &Pos, SDL_Surface *srf)
+{
+	focus = false;
+	pos += Pos;
+	captureAllKeys = true;
+	OBJ_CONSTRUCTION;
+	bg = new CPicture(Pos, 0, true);
+	Rect hlp = Pos;
+	if(srf)
+		CSDL_Ext::blitSurface(srf, &hlp, *bg, nullptr);
+	else
+		SDL_FillRect(*bg, nullptr, 0);
+	pos.w = bg->pos.w;
+	pos.h = bg->pos.h;
+	bg->pos = pos;
+	addUsedEvents(LCLICK | KEYBOARD | TEXTINPUT);
+	giveFocus();
+}
+
+void CTextInput::focusGot()
+{
+	CSDL_Ext::startTextInput(&pos);	
+}
+
+void CTextInput::focusLost()
+{
+	CSDL_Ext::stopTextInput();
+}
+
+
+std::string CTextInput::visibleText()
+{
+	return focus ? text + newText + "_" : text;
+}
+
+void CTextInput::clickLeft( tribool down, bool previousState )
+{
+	if(down && !focus)
+		giveFocus();
+}
+
+void CTextInput::keyPressed( const SDL_KeyboardEvent & key )
+{
+
+	if(!focus || key.state != SDL_PRESSED)
+		return;
+
+	if(key.keysym.sym == SDLK_TAB)
+	{
+		moveFocus();
+		GH.breakEventHandling();
+		return;
+	}
+
+	bool redrawNeeded = false;
+	#ifdef VCMI_SDL1
+	std::string oldText = text;
+	#endif // 0	
+	switch(key.keysym.sym)
+	{
+	case SDLK_DELETE: // have index > ' ' so it won't be filtered out by default section
+		return;
+	case SDLK_BACKSPACE:
+		if(!newText.empty())
+		{
+			Unicode::trimRight(newText);
+			redrawNeeded = true;
+		}
+		else if(!text.empty())
+		{
+			Unicode::trimRight(text);
+			redrawNeeded = true;
+		}			
+		break;
+	default:
+		#ifdef VCMI_SDL1
+		if (key.keysym.unicode < ' ')
+			return;
+		else
+		{
+			text += key.keysym.unicode; //TODO 16-/>8
+			redrawNeeded = true;
+		}			
+		#endif // 0
+		break;
+	}
+	#ifdef VCMI_SDL1
+	filters(text, oldText);
+	#endif // 0
+	if (redrawNeeded)
+	{
+		redraw();
+		cb(text);
+	}	
+}
+
+void CTextInput::setText( const std::string &nText, bool callCb )
+{
+	CLabel::setText(nText);
+	if(callCb)
+		cb(text);
+}
+
+bool CTextInput::captureThisEvent(const SDL_KeyboardEvent & key)
+{
+	if(key.keysym.sym == SDLK_RETURN || key.keysym.sym == SDLK_KP_ENTER)
+		return false;
+	
+	#ifdef VCMI_SDL1
+	//this should allow all non-printable keys to go through (for example arrows)
+	if (key.keysym.unicode < ' ')
+		return false;
+
+	return true;
+	#else
+	return false;
+	#endif
+}
+
+#ifndef VCMI_SDL1
+void CTextInput::textInputed(const SDL_TextInputEvent & event)
+{
+	if(!focus)
+		return;
+	std::string oldText = text;
+	
+	text += event.text;	
+	
+	filters(text,oldText);
+	if (text != oldText)
+	{
+		redraw();
+		cb(text);
+	}	
+	newText = "";
+}
+
+void CTextInput::textEdited(const SDL_TextEditingEvent & event)
+{
+	if(!focus)
+		return;
+		
+	newText = event.text;
+	redraw();
+	cb(text+newText);	
+}
+
+#endif
+
+
+void CTextInput::filenameFilter(std::string & text, const std::string &)
+{
+	static const std::string forbiddenChars = "<>:\"/\\|?*\r\n"; //if we are entering a filename, some special characters won't be allowed
+	size_t pos;
+	while ((pos = text.find_first_of(forbiddenChars)) != std::string::npos)
+		text.erase(pos, 1);
+}
+
+void CTextInput::numberFilter(std::string & text, const std::string & oldText, int minValue, int maxValue)
+{
+	assert(minValue < maxValue);
+
+	if (text.empty())
+		text = "0";
+
+	size_t pos = 0;
+	if (text[0] == '-') //allow '-' sign as first symbol only
+		pos++;
+
+	while (pos < text.size())
+	{
+		if (text[pos] < '0' || text[pos] > '9')
+		{
+			text = oldText;
+			return; //new text is not number.
+		}
+		pos++;
+	}
+	try
+	{
+		int value = boost::lexical_cast<int>(text);
+		if (value < minValue)
+			text = boost::lexical_cast<std::string>(minValue);
+		else if (value > maxValue)
+			text = boost::lexical_cast<std::string>(maxValue);
+	}
+	catch(boost::bad_lexical_cast &)
+	{
+		//Should never happen. Unless I missed some cases
+        logGlobal->warnStream() << "Warning: failed to convert "<< text << " to number!";
+		text = oldText;
+	}
+}
+
+CFocusable::CFocusable()
+{
+	focusables.push_back(this);
+}
+
+CFocusable::~CFocusable()
+{
+	if(inputWithFocus == this)
+	{
+		focusLost();
+		inputWithFocus = nullptr;
+	}	
+
+	focusables -= this;
+}
+void CFocusable::giveFocus()
+{
+	if(inputWithFocus)
+	{
+		inputWithFocus->focus = false;
+		inputWithFocus->focusLost();
+		inputWithFocus->redraw();
+	}
+
+	focus = true;
+	inputWithFocus = this;
+	focusGot();
+	redraw();	
+}
+
+void CFocusable::moveFocus()
+{
+	auto i = vstd::find(focusables, this),
+		ourIt = i;
+	for(i++; i != ourIt; i++)
+	{
+		if(i == focusables.end())
+			i = focusables.begin();
+
+		if((*i)->active)
+		{
+			(*i)->giveFocus();
+			break;;
+		}
+	}
+}

+ 189 - 0
client/widgets/TextControls.h

@@ -0,0 +1,189 @@
+#pragma once
+
+#include "../gui/CIntObject.h"
+#include "../gui/SDL_Extensions.h"
+#include "../../lib/FunctionList.h"
+
+/*
+ * TextControls.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+class CSlider;
+
+/// Base class for all text-related widgets.
+/// Controls text blitting-related options
+class CTextContainer : public virtual CIntObject
+{
+protected:
+	/// returns size of border, for left- or right-aligned text
+	virtual Point getBorderSize() = 0;
+	/// do actual blitting of line. Text "what" will be placed at "where" and aligned according to alignment
+	void blitLine(SDL_Surface * to, Rect where, std::string what);
+
+	CTextContainer(EAlignment alignment, EFonts font, SDL_Color color);
+
+public:
+	EAlignment alignment;
+	EFonts font;
+	SDL_Color color; // default font color. Can be overridden by placing "{}" into the string
+};
+
+/// Label which shows text
+class CLabel : public CTextContainer
+{
+protected:
+	Point getBorderSize() override;
+	virtual std::string visibleText();
+
+	CPicture *bg;
+public:
+
+	std::string text;
+	bool autoRedraw;  //whether control will redraw itself on setTxt
+
+	std::string getText();
+	virtual void setText(const std::string &Txt);
+
+	CLabel(int x=0, int y=0, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT,
+	       const SDL_Color &Color = Colors::WHITE, const std::string &Text =  "");
+	void showAll(SDL_Surface * to); //shows statusbar (with current text)
+};
+
+/// Small helper class to manage group of similar labels
+class CLabelGroup : public CIntObject
+{
+	std::list<CLabel*> labels;
+	EFonts font;
+	EAlignment align;
+	SDL_Color color;
+public:
+	CLabelGroup(EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE);
+	void add(int x=0, int y=0, const std::string &text =  "");
+};
+
+/// Multi-line label that can display multiple lines of text
+/// If text is too big to fit into requested area remaining part will not be visible
+class CMultiLineLabel : public CLabel
+{
+	// text to blit, split into lines that are no longer than widget width
+	std::vector<std::string> lines;
+
+	// area of text that actually will be printed, default is widget size
+	Rect visibleSize;
+
+	void splitText(const std::string &Txt);
+	Rect getTextLocation();
+public:
+	// total size of text, x = longest line of text, y = total height of lines
+	Point textSize;
+
+	CMultiLineLabel(Rect position, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE, const std::string &Text =  "");
+
+	void setText(const std::string &Txt);
+	void showAll(SDL_Surface * to);
+
+	void setVisibleSize(Rect visibleSize);
+	// scrolls text visible in widget. Positive value will move text up
+	void scrollTextTo(int distance);
+	void scrollTextBy(int distance);
+};
+
+/// a multi-line label that tries to fit text with given available width and height;
+/// if not possible, it creates a slider for scrolling text
+class CTextBox : public CIntObject
+{
+	int sliderStyle;
+public:
+	CMultiLineLabel * label;
+	CSlider *slider;
+
+	CTextBox(std::string Text, const Rect &rect, int SliderStyle, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = Colors::WHITE);
+
+	void resize(Point newSize);
+	void setText(const std::string &Txt);
+	void sliderMoved(int to);
+};
+
+/// Status bar which is shown at the bottom of the in-game screens
+class CGStatusBar : public CLabel
+{
+	bool textLock; //Used for blocking changes to the text
+	void init();
+
+	CGStatusBar *oldStatusBar;
+protected:
+	Point getBorderSize() override;
+
+public:
+
+	void clear();//clears statusbar and refreshes
+	void setText(const std::string & Text) override; //prints text and refreshes statusbar
+
+	void show(SDL_Surface * to); //shows statusbar (with current text)
+
+	CGStatusBar(CPicture *BG, EFonts Font = FONT_SMALL, EAlignment Align = CENTER, const SDL_Color &Color = Colors::WHITE); //given CPicture will be captured by created sbar and it's pos will be used as pos for sbar
+	CGStatusBar(int x, int y, std::string name, int maxw=-1);
+	~CGStatusBar();
+
+	void lock(bool shouldLock); //If true, current text cannot be changed until lock(false) is called
+};
+
+/// UIElement which can get input focus
+class CFocusable : public virtual CIntObject
+{
+protected:
+	virtual void focusGot(){};
+	virtual void focusLost(){};
+public:
+	bool focus; //only one focusable control can have focus at one moment
+
+	void giveFocus(); //captures focus
+	void moveFocus(); //moves focus to next active control (may be used for tab switching)
+
+	static std::list<CFocusable*> focusables; //all existing objs
+	static CFocusable *inputWithFocus; //who has focus now
+	CFocusable();
+	~CFocusable();
+};
+
+/// Text input box where players can enter text
+class CTextInput : public CLabel, public CFocusable
+{
+	std::string newText;
+protected:
+	std::string visibleText() override;
+
+	void focusGot() override;
+	void focusLost() override;
+public:
+	CFunctionList<void(const std::string &)> cb;
+	CFunctionList<void(std::string &, const std::string &)> filters;
+	void setText(const std::string &nText, bool callCb = false);
+
+	CTextInput(const Rect &Pos, EFonts font, const CFunctionList<void(const std::string &)> &CB);
+	CTextInput(const Rect &Pos, const Point &bgOffset, const std::string &bgName, const CFunctionList<void(const std::string &)> &CB);
+	CTextInput(const Rect &Pos, SDL_Surface *srf = nullptr);
+
+	void clickLeft(tribool down, bool previousState) override;
+	void keyPressed(const SDL_KeyboardEvent & key) override;
+	bool captureThisEvent(const SDL_KeyboardEvent & key) override;
+	
+#ifndef VCMI_SDL1
+	void textInputed(const SDL_TextInputEvent & event) override;
+	void textEdited(const SDL_TextEditingEvent & event) override;
+	
+	
+#endif // VCMI_SDL1	
+
+	//Filter that will block all characters not allowed in filenames
+	static void filenameFilter(std::string &text, const std::string & oldText);
+	//Filter that will allow only input of numbers in range min-max (min-max are allowed)
+	//min-max should be set via something like boost::bind
+	static void numberFilter(std::string &text, const std::string & oldText, int minValue, int maxValue);
+};

+ 36 - 1
client/windows/CAdvmapInterface.cpp

@@ -21,8 +21,8 @@
 #include "../gui/CCursorHandler.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/SDL_Extensions.h"
-#include "../widgets/CIntObjectClasses.h"
 #include "../widgets/MiscWidgets.h"
+#include "../windows/InfoWindows.h"
 
 #include "../../CCallback.h"
 
@@ -1530,3 +1530,38 @@ void CAdvMapInt::adjustActiveness(bool aiTurnStart)
 	if(wasActive) 
 		activate();
 }
+
+CAdventureOptions::CAdventureOptions():
+	CWindowObject(PLAYER_COLORED, "ADVOPTS")
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+
+	exit = new CAdventureMapButton("","",boost::bind(&CAdventureOptions::close, this), 204, 313, "IOK6432.DEF",SDLK_RETURN);
+	exit->assignedKeys.insert(SDLK_ESCAPE);
+
+	scenInfo = new CAdventureMapButton("","", boost::bind(&CAdventureOptions::close, this), 24, 198, "ADVINFO.DEF",SDLK_i);
+	scenInfo->callback += CAdventureOptions::showScenarioInfo;
+	//viewWorld = new CAdventureMapButton("","",boost::bind(&CGuiHandler::popIntTotally, &GH, this), 204, 313, "IOK6432.DEF",SDLK_RETURN);
+
+	puzzle = new CAdventureMapButton("","", boost::bind(&CAdventureOptions::close, this), 24, 81, "ADVPUZ.DEF");
+	puzzle->callback += boost::bind(&CPlayerInterface::showPuzzleMap, LOCPLINT);
+
+	dig = new CAdventureMapButton("","", boost::bind(&CAdventureOptions::close, this), 24, 139, "ADVDIG.DEF");
+	if(const CGHeroInstance *h = adventureInt->curHero())
+		dig->callback += boost::bind(&CPlayerInterface::tryDiggging, LOCPLINT, h);
+	else
+		dig->block(true);
+}
+
+void CAdventureOptions::showScenarioInfo()
+{
+	auto campState = LOCPLINT->cb->getStartInfo()->campState;
+	if(campState)
+	{
+		GH.pushInt(new CBonusSelection(campState));
+	}
+	else
+	{
+		GH.pushInt(new CScenarioInfo(LOCPLINT->cb->getMapHeader(), LOCPLINT->cb->getStartInfo()));
+	}
+}

+ 14 - 0
client/windows/CAdvmapInterface.h

@@ -1,6 +1,10 @@
 #pragma once
 
 #include "../widgets/AdventureMapClasses.h"
+#include "CWindowObject.h"
+
+#include "../widgets/TextControls.h"
+#include "../widgets/Buttons.h"
 
 class CDefHandler;
 class CCallback;
@@ -24,6 +28,16 @@ class IShipyard;
  *
  */
 
+/// Adventure options dialogue where you can view the world, dig, play the replay of the last turn,...
+class CAdventureOptions : public CWindowObject
+{
+public:
+	CAdventureMapButton *exit, *viewWorld, *puzzle, *dig, *scenInfo, *replay;
+
+	CAdventureOptions();
+	static void showScenarioInfo();
+};
+
 /// Holds information about which tiles of the terrain are shown/not shown at the screen
 class CTerrainRect
 	:  public CIntObject

+ 3 - 2
client/windows/CCastleInterface.cpp

@@ -16,9 +16,9 @@
 
 #include "../gui/CGuiHandler.h"
 #include "../gui/SDL_Extensions.h"
-#include "../widgets/CAnimation.h"
-#include "../widgets/CIntObjectClasses.h"
+#include "../windows/InfoWindows.h"
 #include "../widgets/MiscWidgets.h"
+#include "../widgets/CComponent.h"
 
 #include "../../CCallback.h"
 #include "../../lib/CArtHandler.h"
@@ -30,6 +30,7 @@
 #include "../../lib/CTownHandler.h"
 #include "../../lib/GameConstants.h"
 #include "../../lib/mapObjects/CGHeroInstance.h"
+#include "../../lib/mapObjects/CGTownInstance.h"
 
 using namespace boost::assign;
 

+ 1 - 1
client/windows/CCastleInterface.h

@@ -1,7 +1,7 @@
 #pragma once
 
-#include "../widgets/CAnimation.h"
 #include "../widgets/CGarrisonInt.h"
+#include "../widgets/Images.h"
 
 class CAdventureMapButton;
 class CBuilding;

+ 6 - 2
client/windows/CCreatureWindow.cpp

@@ -3,9 +3,12 @@
 
 #include "../CGameInfo.h"
 #include "../CPlayerInterface.h"
+#include "../widgets/Buttons.h"
+#include "../widgets/CComponent.h"
+#include "../widgets/Images.h"
+#include "../widgets/TextControls.h"
+#include "../widgets/ObjectLists.h"
 #include "../gui/CGuiHandler.h"
-#include "../widgets/CIntObjectClasses.h"
-#include "../widgets/CAnimation.h"
 
 #include "../../CCallback.h"
 #include "../../lib/BattleState.h"
@@ -14,6 +17,7 @@
 #include "../../lib/CModHandler.h"
 #include "../../lib/CHeroHandler.h"
 #include "../../lib/CSpellHandler.h"
+#include "../../lib/CGameState.h"
 
 using namespace CSDL_Ext;
 

+ 3 - 1
client/windows/CCreatureWindow.h

@@ -2,6 +2,7 @@
 
 #include "../../lib/HeroBonus.h"
 #include "../widgets/MiscWidgets.h"
+#include "CWindowObject.h"
 
 /*
  * CCreatureWindow.h, part of VCMI engine
@@ -18,7 +19,8 @@ class CCommanderInstance;
 class CStackInstance;
 class CStack;
 struct UpgradeInfo;
-class LRClickableAreaWTextComp;
+class CTabbedInt;
+class CAdventureMapButton;
 
 class CClickableObject : public LRClickableAreaWText
 {

+ 1 - 2
client/windows/CHeroWindow.cpp

@@ -17,9 +17,8 @@
 
 #include "../gui/SDL_Extensions.h"
 #include "../gui/CGuiHandler.h"
-#include "../widgets/CAnimation.h"
-#include "../widgets/CIntObjectClasses.h"
 #include "../widgets/MiscWidgets.h"
+#include "../widgets/CComponent.h"
 
 #include "../../CCallback.h"
 

+ 3 - 0
client/windows/CHeroWindow.h

@@ -25,6 +25,9 @@ class LRClickableAreaWText;
 class LRClickableAreaWTextComp;
 class CArtifactsOfHero;
 class MoraleLuckBox;
+class CHighlightableButton;
+class CHighlightableButtonsGroup;
+class CGStatusBar;
 
 /// Button which switches hero selection
 class CHeroSwitcher : public CIntObject

+ 4 - 2
client/windows/CKingdomInterface.cpp

@@ -8,9 +8,9 @@
 #include "../CMT.h"
 #include "../CPlayerInterface.h"
 #include "../gui/CGuiHandler.h"
-#include "../widgets/CAnimation.h"
-#include "../widgets/CIntObjectClasses.h"
+#include "../widgets/CComponent.h"
 #include "../widgets/MiscWidgets.h"
+#include "../windows/InfoWindows.h"
 
 #include "../../CCallback.h"
 
@@ -21,6 +21,8 @@
 #include "../../lib/CModHandler.h"
 #include "../../lib/CTownHandler.h"
 #include "../../lib/mapObjects/CGHeroInstance.h"
+#include "../../lib/mapObjects/CGTownInstance.h"
+#include "../../lib/mapObjects/MiscObjects.h"
 
 /*
  * CKingdomInterface.cpp, part of VCMI engine

+ 3 - 0
client/windows/CKingdomInterface.h

@@ -15,6 +15,9 @@ class LRClickableAreaOpenTown;
 class CComponent;
 class CHeroArea;
 class MoraleLuckBox;
+class CListBox;
+class CTabbedInt;
+class CGStatusBar;
 
 /*
  * CKingdomInterface.h, part of VCMI engine

+ 0 - 1
client/windows/CQuestLog.cpp

@@ -11,7 +11,6 @@
 
 #include "../gui/CGuiHandler.h"
 #include "../gui/SDL_Extensions.h"
-#include "../widgets/CIntObjectClasses.h"
 
 #include "../../CCallback.h"
 #include "../../lib/CArtHandler.h"

+ 4 - 2
client/windows/CQuestLog.h

@@ -1,8 +1,10 @@
 #pragma once
 
-#include "../widgets/CIntObjectClasses.h"
-#include "../widgets/CAnimation.h"
 #include "../widgets/AdventureMapClasses.h"
+#include "../widgets/TextControls.h"
+#include "../widgets/MiscWidgets.h"
+#include "../widgets/Images.h"
+#include "CWindowObject.h"
 
 /*
  * CQuestLog.h, part of VCMI engine

+ 5 - 0
client/windows/CSpellWindow.cpp

@@ -3,6 +3,7 @@
 
 #include "CAdvmapInterface.h"
 #include "GUIClasses.h"
+#include "InfoWindows.h"
 
 #include "../CBitmapHandler.h"
 #include "../CDefHandler.h"
@@ -14,9 +15,11 @@
 #include "../Graphics.h"
 
 #include "../battle/CBattleInterface.h"
+#include "../gui/CAnimation.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/SDL_Extensions.h"
 #include "../widgets/MiscWidgets.h"
+#include "../widgets/CComponent.h"
 
 #include "../../CCallback.h"
 
@@ -26,6 +29,8 @@
 #include "../../lib/CHeroHandler.h"
 #include "../../lib/CSpellHandler.h"
 #include "../../lib/GameConstants.h"
+#include "../../lib/CGameState.h"
+#include "../../lib/mapObjects/CGTownInstance.h"
 
 /*
  * CSpellWindow.cpp, part of VCMI engine

+ 1 - 1
client/windows/CSpellWindow.h

@@ -1,6 +1,6 @@
 #pragma once
 
-#include "../widgets/CIntObjectClasses.h"
+#include "CWindowObject.h"
 
 /*
  * CSpellWindow.h, part of VCMI engine

+ 4 - 1
client/windows/CTradeWindow.cpp

@@ -5,7 +5,7 @@
 
 #include "../gui/CGuiHandler.h"
 #include "../gui/CCursorHandler.h"
-#include "../widgets/CAnimation.h"
+#include "../widgets/Images.h"
 
 #include "../CGameInfo.h"
 #include "../CPlayerInterface.h"
@@ -17,7 +17,10 @@
 #include "../../lib/CCreatureHandler.h"
 #include "../../lib/CGeneralTextHandler.h"
 #include "../../lib/CHeroHandler.h"
+#include "../../lib/CGameState.h"
 #include "../../lib/mapObjects/CGHeroInstance.h"
+#include "../../lib/mapObjects/CGTownInstance.h"
+#include "../../lib/mapObjects/CGMarket.h"
 
 
 /*

+ 4 - 0
client/windows/CTradeWindow.h

@@ -1,6 +1,8 @@
 #pragma once
 
 #include "../widgets/CArtifactHolder.h"
+#include "CWindowObject.h"
+#include "../../lib/FunctionList.h"
 
 /*
  * CTradeWindow.h, part of VCMI engine
@@ -13,6 +15,8 @@
  */
 
 class IMarket;
+class CSlider;
+class CTextBox;
 
 class CTradeWindow : public CWindowObject, public CWindowWithArtifacts //base for markets and altar of sacrifice
 {

+ 242 - 0
client/windows/CWindowObject.cpp

@@ -0,0 +1,242 @@
+#include "StdInc.h"
+#include "CWindowObject.h"
+
+#include "../widgets/MiscWidgets.h"
+
+#include "../gui/SDL_Pixels.h"
+#include "../gui/SDL_Extensions.h"
+#include "../gui/CGuiHandler.h"
+#include "../gui/CCursorHandler.h"
+
+#include "../battle/CBattleInterface.h"
+#include "../battle/CBattleInterfaceClasses.h"
+
+#include "../CBitmapHandler.h"
+#include "../Graphics.h"
+#include "../CGameInfo.h"
+#include "../CPlayerInterface.h"
+#include "../CMessage.h"
+#include "../CMusicHandler.h"
+#include "../windows/CAdvmapInterface.h"
+
+#include "../../CCallback.h"
+
+#include "../../lib/CConfigHandler.h"
+#include "../../lib/CGeneralTextHandler.h" //for Unicode related stuff
+
+/*
+ * CWindowObject.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+CWindowObject::CWindowObject(int options_, std::string imageName, Point centerAt):
+    CIntObject(getUsedEvents(options_), Point()),
+    shadow(nullptr),
+    options(options_),
+    background(createBg(imageName, options & PLAYER_COLORED))
+{
+	assert(parent == nullptr); //Safe to remove, but windows should not have parent
+
+	if (options & RCLICK_POPUP)
+		CCS->curh->hide();
+
+	if (background)
+		pos = background->center(centerAt);
+	else
+		center(centerAt);
+
+	if (!(options & SHADOW_DISABLED))
+		setShadow(true);
+}
+
+CWindowObject::CWindowObject(int options_, std::string imageName):
+    CIntObject(getUsedEvents(options_), Point()),
+    shadow(nullptr),
+    options(options_),
+    background(createBg(imageName, options & PLAYER_COLORED))
+{
+	assert(parent == nullptr); //Safe to remove, but windows should not have parent
+
+	if (options & RCLICK_POPUP)
+		CCS->curh->hide();
+
+	if (background)
+		pos = background->center();
+	else
+		center(Point(screen->w/2, screen->h/2));
+
+	if (!(options & SHADOW_DISABLED))
+		setShadow(true);
+}
+
+CWindowObject::~CWindowObject()
+{
+	setShadow(false);
+}
+
+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::setBackground(std::string filename)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+
+	delete background;
+	background = createBg(filename, options & PLAYER_COLORED);
+
+	if (background)
+		pos = background->center(Point(pos.w/2 + pos.x, pos.h/2 + pos.y));
+
+	updateShadow();
+}
+
+int CWindowObject::getUsedEvents(int options)
+{
+	if (options & RCLICK_POPUP)
+		return RCLICK;
+	return 0;
+}
+
+void CWindowObject::updateShadow()
+{
+	setShadow(false);
+	if (!(options & SHADOW_DISABLED))
+		setShadow(true);
+}
+
+void CWindowObject::setShadow(bool on)
+{
+	//size of shadow
+	static const int size = 8;
+
+	if (on == bool(shadow))
+		return;
+
+	vstd::clear_pointer(shadow);
+
+	//object too small to cast shadow
+	if (pos.h <= size || pos.w <= size)
+		return;
+
+	if (on)
+	{
+
+		//helper to set last row
+		auto blitAlphaRow = [](SDL_Surface *surf, size_t row)
+		{
+			Uint8 * ptr = (Uint8*)surf->pixels + surf->pitch * (row);
+
+			for (size_t i=0; i< surf->w; i++)
+			{
+				Channels::px<4>::a.set(ptr, 128);
+				ptr+=4;
+			}
+		};
+
+		// helper to set last column
+		auto blitAlphaCol = [](SDL_Surface *surf, size_t col)
+		{
+			Uint8 * ptr = (Uint8*)surf->pixels + 4 * (col);
+
+			for (size_t i=0; i< surf->h; i++)
+			{
+				Channels::px<4>::a.set(ptr, 128);
+				ptr+= surf->pitch;
+			}
+		};
+
+		static SDL_Surface * shadowCornerTempl = nullptr;
+		static SDL_Surface * shadowBottomTempl = nullptr;
+		static SDL_Surface * shadowRightTempl = nullptr;
+
+		//one-time initialization
+		if (!shadowCornerTempl)
+		{
+			//create "template" surfaces
+			shadowCornerTempl = CSDL_Ext::createSurfaceWithBpp<4>(size, size);
+			shadowBottomTempl = CSDL_Ext::createSurfaceWithBpp<4>(1, size);
+			shadowRightTempl  = CSDL_Ext::createSurfaceWithBpp<4>(size, 1);
+
+			Uint32 shadowColor = SDL_MapRGBA(shadowCornerTempl->format, 0, 0, 0, 192);
+
+			//fill with shadow body color
+			SDL_FillRect(shadowCornerTempl, nullptr, shadowColor);
+			SDL_FillRect(shadowBottomTempl, nullptr, shadowColor);
+			SDL_FillRect(shadowRightTempl,  nullptr, shadowColor);
+
+			//fill last row and column with more transparent color
+			blitAlphaCol(shadowRightTempl , size-1);
+			blitAlphaCol(shadowCornerTempl, size-1);
+			blitAlphaRow(shadowBottomTempl, size-1);
+			blitAlphaRow(shadowCornerTempl, size-1);
+		}
+
+		OBJ_CONSTRUCTION_CAPTURING_ALL;
+
+		//FIXME: do something with this points
+		Point shadowStart;
+		if (options & BORDERED)
+			shadowStart = Point(size - 14, size - 14);
+		else
+			shadowStart = Point(size, size);
+
+		Point shadowPos;
+		if (options & BORDERED)
+			shadowPos = Point(pos.w + 14, pos.h + 14);
+		else
+			shadowPos = Point(pos.w, pos.h);
+
+		Point fullsize;
+		if (options & BORDERED)
+			fullsize = Point(pos.w + 28, pos.h + 29);
+		else
+			fullsize = Point(pos.w, pos.h);
+
+		//create base 8x8 piece of shadow
+		SDL_Surface * shadowCorner = CSDL_Ext::copySurface(shadowCornerTempl);
+		SDL_Surface * shadowBottom = CSDL_Ext::scaleSurfaceFast(shadowBottomTempl, fullsize.x - size, size);
+		SDL_Surface * shadowRight  = CSDL_Ext::scaleSurfaceFast(shadowRightTempl,  size, fullsize.y - size);
+
+		blitAlphaCol(shadowBottom, 0);
+		blitAlphaRow(shadowRight, 0);
+
+		//generate "shadow" object with these 3 pieces in it
+		shadow = new CIntObject;
+		shadow->addChild(new CPicture(shadowCorner, shadowPos.x, shadowPos.y));
+		shadow->addChild(new CPicture(shadowRight,  shadowPos.x, shadowStart.y));
+		shadow->addChild(new CPicture(shadowBottom, shadowStart.x, shadowPos.y));
+	}
+}
+
+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 : PlayerColor(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)
+{
+	close();
+	CCS->curh->show();
+}

+ 65 - 0
client/windows/CWindowObject.h

@@ -0,0 +1,65 @@
+#pragma once
+
+#include "../gui/CIntObject.h"
+//#include "../gui/SDL_Extensions.h"
+
+//#include "../../lib/FunctionList.h"
+
+struct SDL_Surface;
+struct Rect;
+class CAnimImage;
+class CLabel;
+class CAnimation;
+class CDefHandler;
+
+/*
+ * CWindowObject.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+/// Basic class for windows
+class CWindowObject : public CIntObject
+{
+	CPicture * createBg(std::string imageName, bool playerColored);
+	int getUsedEvents(int options);
+
+	CIntObject *shadow;
+	void setShadow(bool on);
+
+	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);
+	//change or set background image
+	void setBackground(std::string filename);
+	void updateShadow();
+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
+		SHADOW_DISABLED=8 //this window won't display any shadow
+	};
+
+	/*
+	 * options - EOpions enum
+	 * imageName - name for background image, can be empty
+	 * centerAt - position of window center. Default - center of the screen
+	*/
+	CWindowObject(int options, std::string imageName, Point centerAt);
+	CWindowObject(int options, std::string imageName = "");
+	~CWindowObject();
+};

+ 2 - 1
client/windows/GUIClasses.cpp

@@ -26,8 +26,9 @@
 #include "../gui/SDL_Extensions.h"
 #include "../gui/CCursorHandler.h"
 
-#include "../widgets/CAnimation.h"
+#include "../widgets/CComponent.h"
 #include "../widgets/MiscWidgets.h"
+#include "../windows/InfoWindows.h"
 
 #include "../../CCallback.h"
 

+ 9 - 2
client/windows/GUIClasses.h

@@ -5,7 +5,8 @@
 #include "../lib/CConfigHandler.h"
 #include "../widgets/CArtifactHolder.h"
 #include "../widgets/CGarrisonInt.h"
-#include "../widgets/CAnimation.h"
+#include "../widgets/Images.h"
+#include "../windows/CWindowObject.h"
 
 /*
  * GUIClasses.h, part of VCMI engine
@@ -23,8 +24,14 @@ class CCreaturePic;
 class MoraleLuckBox;
 class CHeroArea;
 class CMinorResDataBar;
-
+class CSlider;
 class CComponentBox;
+class CTextInput;
+class CListBox;
+class CLabelGroup;
+class CHighlightableButton;
+class CHighlightableButtonsGroup;
+class CGStatusBar;
 
 /// Recruitment window where you can recruit creatures
 class CRecruitmentWindow : public CWindowObject

+ 456 - 0
client/windows/InfoWindows.cpp

@@ -0,0 +1,456 @@
+#include "StdInc.h"
+#include "InfoWindows.h"
+
+#include "../CBitmapHandler.h"
+#include "../Graphics.h"
+#include "../CGameInfo.h"
+#include "../CPlayerInterface.h"
+#include "../CMessage.h"
+#include "../CMusicHandler.h"
+
+#include "../windows/CAdvmapInterface.h"
+#include "../widgets/CComponent.h"
+#include "../widgets/MiscWidgets.h"
+
+#include "../gui/SDL_Pixels.h"
+#include "../gui/SDL_Extensions.h"
+#include "../gui/CGuiHandler.h"
+#include "../gui/CCursorHandler.h"
+
+#include "../battle/CBattleInterface.h"
+#include "../battle/CBattleInterfaceClasses.h"
+
+#include "../../CCallback.h"
+
+#include "../../lib/CGameState.h"
+#include "../../lib/CConfigHandler.h"
+#include "../../lib/CondSh.h"
+#include "../../lib/CGeneralTextHandler.h" //for Unicode related stuff
+#include "../../lib/mapObjects/CGHeroInstance.h"
+#include "../../lib/mapObjects/CGTownInstance.h"
+#include "../../lib/mapObjects/MiscObjects.h"
+
+/*
+ * InfoWindows.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+void CSimpleWindow::show(SDL_Surface * to)
+{
+	if(bitmap)
+		blitAt(bitmap,pos.x,pos.y,to);
+}
+CSimpleWindow::~CSimpleWindow()
+{
+	if (bitmap)
+	{
+		SDL_FreeSurface(bitmap);
+		bitmap=nullptr;
+	}
+}
+
+void CSelWindow::selectionChange(unsigned to)
+{
+	for (unsigned i=0;i<components.size();i++)
+	{
+		CSelectableComponent * pom = dynamic_cast<CSelectableComponent*>(components[i]);
+		if (!pom)
+			continue;
+		pom->select(i==to);
+	}
+	redraw();
+}
+
+CSelWindow::CSelWindow(const std::string &Text, PlayerColor player, int charperline, const std::vector<CSelectableComponent*> &comps, const std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, QueryID askID)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	ID = askID;
+	for(int i=0;i<Buttons.size();i++)
+	{
+		buttons.push_back(new CAdventureMapButton("","",Buttons[i].second,0,0,Buttons[i].first));
+		if(!i  &&  askID.getNum() >= 0)
+			buttons.back()->callback += boost::bind(&CSelWindow::madeChoice,this);
+		buttons[i]->callback += boost::bind(&CInfoWindow::close,this); //each button will close the window apart from call-defined actions
+	}
+
+	text = new CTextBox(Text, Rect(0, 0, 250, 100), 0, FONT_MEDIUM, CENTER, Colors::WHITE);
+
+	buttons.front()->assignedKeys.insert(SDLK_RETURN); //first button - reacts on enter
+	buttons.back()->assignedKeys.insert(SDLK_ESCAPE); //last button - reacts on escape
+
+	if(buttons.size() > 1  &&  askID.getNum() >= 0) //cancel button functionality
+		buttons.back()->callback += boost::bind(&CCallback::selectionMade,LOCPLINT->cb.get(),0,askID);
+
+	for(int i=0;i<comps.size();i++)
+	{
+		comps[i]->recActions = 255;
+		addChild(comps[i]);
+		components.push_back(comps[i]);
+		comps[i]->onSelect = boost::bind(&CSelWindow::selectionChange,this,i);
+		if(i<9)
+			comps[i]->assignedKeys.insert(SDLK_1+i);
+	}
+	CMessage::drawIWindow(this, Text, player);
+}
+
+void CSelWindow::madeChoice()
+{
+	if(ID.getNum() < 0)
+		return;
+	int ret = -1;
+	for (int i=0;i<components.size();i++)
+	{
+		if(dynamic_cast<CSelectableComponent*>(components[i])->selected)
+		{
+			ret = i;
+		}
+	}
+	LOCPLINT->cb->selectionMade(ret+1,ID);
+}
+
+CInfoWindow::CInfoWindow(std::string Text, PlayerColor player, const TCompsInfo &comps, const TButtonsInfo &Buttons, bool delComps)
+{
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+
+	type |= BLOCK_ADV_HOTKEYS;
+	ID = QueryID(-1);
+	for(auto & Button : Buttons)
+	{
+		CAdventureMapButton *button = new CAdventureMapButton("","",boost::bind(&CInfoWindow::close,this),0,0,Button.first);
+		button->borderColor = Colors::METALLIC_GOLD;
+		button->borderEnabled = true;
+		button->callback.add(Button.second); //each button will close the window apart from call-defined actions
+		buttons.push_back(button);
+	}
+
+	text = new CTextBox(Text, Rect(0, 0, 250, 100), 0, FONT_MEDIUM, CENTER, Colors::WHITE);
+	if(!text->slider)
+	{
+		text->resize(text->label->textSize);
+	}
+
+	if(buttons.size())
+	{
+		buttons.front()->assignedKeys.insert(SDLK_RETURN); //first button - reacts on enter
+		buttons.back()->assignedKeys.insert(SDLK_ESCAPE); //last button - reacts on escape
+	}
+
+	for(auto & comp : comps)
+	{
+		comp->recActions = 0xff;
+		addChild(comp);
+		comp->recActions &= ~(SHOWALL | UPDATE);
+		components.push_back(comp);
+	}
+	setDelComps(delComps);
+	CMessage::drawIWindow(this,Text,player);
+}
+
+CInfoWindow::CInfoWindow()
+{
+	ID = QueryID(-1);
+	setDelComps(false);
+	text = nullptr;
+}
+
+void CInfoWindow::close()
+{
+	GH.popIntTotally(this);
+	if(LOCPLINT)
+		LOCPLINT->showingDialog->setn(false);
+}
+
+void CInfoWindow::show(SDL_Surface * to)
+{
+	CIntObject::show(to);
+}
+
+CInfoWindow::~CInfoWindow()
+{
+	if(!delComps)
+	{
+		for (auto & elem : components)
+			removeChild(elem);
+	}
+}
+
+void CInfoWindow::showAll(SDL_Surface * to)
+{
+	CSimpleWindow::show(to);
+	CIntObject::showAll(to);
+}
+
+void CInfoWindow::showInfoDialog(const std::string &text, const std::vector<CComponent *> *components, bool DelComps, PlayerColor player)
+{
+	CInfoWindow * window = CInfoWindow::create(text, player, components, DelComps);
+	GH.pushInt(window);
+}
+
+void CInfoWindow::showYesNoDialog(const std::string & text, const std::vector<CComponent*> *components, const CFunctionList<void( ) > &onYes, const CFunctionList<void()> &onNo, bool DelComps, PlayerColor player)
+{
+	assert(!LOCPLINT || LOCPLINT->showingDialog->get());
+	std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
+	pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));
+	pom.push_back(std::pair<std::string,CFunctionList<void()> >("ICANCEL.DEF",0));
+	CInfoWindow * temp = new CInfoWindow(text, player, components ? *components : std::vector<CComponent*>(), pom, DelComps);
+	for(auto & elem : onYes.funcs)
+		temp->buttons[0]->callback += elem;
+	for(auto & elem : onNo.funcs)
+		temp->buttons[1]->callback += elem;
+
+	GH.pushInt(temp);
+}
+
+void CInfoWindow::showOkDialog(const std::string & text, const std::vector<CComponent*> *components, const boost::function<void()> & onOk, bool delComps, PlayerColor player)
+{
+	std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
+	pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));
+	CInfoWindow * temp = new CInfoWindow(text, player, *components, pom, delComps);
+	temp->buttons[0]->callback += onOk;
+
+	GH.pushInt(temp);
+}
+
+CInfoWindow * CInfoWindow::create(const std::string &text, PlayerColor playerID /*= 1*/, const std::vector<CComponent*> *components /*= nullptr*/, bool DelComps)
+{
+	std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
+	pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));
+	CInfoWindow * ret = new CInfoWindow(text, playerID, components ? *components : std::vector<CComponent*>(), pom, DelComps);
+	return ret;
+}
+
+std::string CInfoWindow::genText(std::string title, std::string description)
+{
+	return std::string("{") + title + "}" + "\n\n" + description;
+}
+
+void CInfoWindow::setDelComps(bool DelComps)
+{
+	delComps = DelComps;
+	for(CComponent *comp : components)
+	{
+		if(delComps)
+			comp->recActions |= DISPOSE;
+		else
+			comp->recActions &= ~DISPOSE;
+	}
+}
+
+CInfoPopup::CInfoPopup(SDL_Surface * Bitmap, int x, int y, bool Free)
+ :free(Free),bitmap(Bitmap)
+{
+	init(x, y);
+}
+
+
+CInfoPopup::CInfoPopup(SDL_Surface * Bitmap, const Point &p, EAlignment alignment, bool Free/*=false*/)
+ : free(Free),bitmap(Bitmap)
+{
+	switch(alignment)
+	{
+	case BOTTOMRIGHT:
+		init(p.x - Bitmap->w, p.y - Bitmap->h);
+		break;
+	case CENTER:
+		init(p.x - Bitmap->w/2, p.y - Bitmap->h/2);
+		break;
+	case TOPLEFT:
+		init(p.x, p.y);
+		break;
+	default:
+		assert(0); //not implemented
+	}
+}
+
+CInfoPopup::CInfoPopup(SDL_Surface *Bitmap, bool Free)
+{
+	CCS->curh->hide();
+
+	free=Free;
+	bitmap=Bitmap;
+
+	if(bitmap)
+	{
+		pos.x = screen->w/2 - bitmap->w/2;
+		pos.y = screen->h/2 - bitmap->h/2;
+		pos.h = bitmap->h;
+		pos.w = bitmap->w;
+	}
+}
+
+void CInfoPopup::close()
+{
+	if(free)
+		SDL_FreeSurface(bitmap);
+	GH.popIntTotally(this);
+}
+
+void CInfoPopup::show(SDL_Surface * to)
+{
+	blitAt(bitmap,pos.x,pos.y,to);
+}
+
+CInfoPopup::~CInfoPopup()
+{
+	CCS->curh->show();
+}
+
+void CInfoPopup::init(int x, int y)
+{
+	CCS->curh->hide();
+
+	pos.x = x;
+	pos.y = y;
+	pos.h = bitmap->h;
+	pos.w = bitmap->w;
+
+	// Put the window back on screen if necessary
+	vstd::amax(pos.x, 0);
+	vstd::amax(pos.y, 0);
+	vstd::amin(pos.x, screen->w - bitmap->w);
+	vstd::amin(pos.y, screen->h - bitmap->h);
+}
+
+
+void CRClickPopup::clickRight(tribool down, bool previousState)
+{
+	if(down)
+		return;
+	close();
+}
+
+void CRClickPopup::close()
+{
+	GH.popIntTotally(this);
+}
+
+void CRClickPopup::createAndPush(const std::string &txt, const CInfoWindow::TCompsInfo &comps)
+{
+	PlayerColor player = LOCPLINT ? LOCPLINT->playerID : PlayerColor(1); //if no player, then use blue
+
+	CSimpleWindow * temp = new CInfoWindow(txt, player, comps);
+	temp->center(Point(GH.current->motion)); //center on mouse
+	temp->fitToScreen(10);
+	auto  rcpi = new CRClickPopupInt(temp,true);
+	GH.pushInt(rcpi);
+}
+
+void CRClickPopup::createAndPush(const std::string &txt, CComponent * component)
+{
+	CInfoWindow::TCompsInfo intComps;
+	intComps.push_back(component);
+
+	createAndPush(txt, intComps);
+}
+
+void CRClickPopup::createAndPush(const CGObjectInstance *obj, const Point &p, EAlignment alignment /*= BOTTOMRIGHT*/)
+{
+	CIntObject *iWin = createInfoWin(p, obj); //try get custom infowindow for this obj
+	if(iWin)
+		GH.pushInt(iWin);
+	else
+	{
+		if (adventureInt->curHero())
+			CRClickPopup::createAndPush(obj->getHoverText(adventureInt->curHero()));
+		else
+			CRClickPopup::createAndPush(obj->getHoverText(LOCPLINT->playerID));
+	}
+}
+
+CRClickPopup::CRClickPopup()
+{
+	addUsedEvents(RCLICK);
+}
+
+CRClickPopup::~CRClickPopup()
+{
+}
+
+void CRClickPopupInt::show(SDL_Surface * to)
+{
+	inner->show(to);
+}
+
+CRClickPopupInt::CRClickPopupInt( IShowActivatable *our, bool deleteInt )
+{
+	CCS->curh->hide();
+	inner = our;
+	delInner = deleteInt;
+}
+
+CRClickPopupInt::~CRClickPopupInt()
+{
+	if(delInner)
+		delete inner;
+
+	CCS->curh->show();
+}
+
+void CRClickPopupInt::showAll(SDL_Surface * to)
+{
+	inner->showAll(to);
+}
+
+Point CInfoBoxPopup::toScreen(Point p)
+{
+	vstd::abetween(p.x, adventureInt->terrain.pos.x + 100, adventureInt->terrain.pos.x + adventureInt->terrain.pos.w - 100);
+	vstd::abetween(p.y, adventureInt->terrain.pos.y + 100, adventureInt->terrain.pos.y + adventureInt->terrain.pos.h - 100);
+
+	return p;
+}
+
+CInfoBoxPopup::CInfoBoxPopup(Point position, const CGTownInstance * town):
+	CWindowObject(RCLICK_POPUP | PLAYER_COLORED, "TOWNQVBK", toScreen(position))
+{
+	InfoAboutTown iah;
+	LOCPLINT->cb->getTownInfo(town, iah);
+
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	new CTownTooltip(Point(9, 10), iah);
+}
+
+CInfoBoxPopup::CInfoBoxPopup(Point position, const CGHeroInstance * hero):
+	CWindowObject(RCLICK_POPUP | PLAYER_COLORED, "HEROQVBK", toScreen(position))
+{
+	InfoAboutHero iah;
+	LOCPLINT->cb->getHeroInfo(hero, iah);
+
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	new CHeroTooltip(Point(9, 10), iah);
+}
+
+CInfoBoxPopup::CInfoBoxPopup(Point position, const CGGarrison * garr):
+	CWindowObject(RCLICK_POPUP | PLAYER_COLORED, "TOWNQVBK", toScreen(position))
+{
+	InfoAboutTown iah;
+	LOCPLINT->cb->getTownInfo(garr, iah);
+
+	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	new CArmyTooltip(Point(9, 10), iah);
+}
+
+CIntObject * CRClickPopup::createInfoWin(Point position, const CGObjectInstance * specific) //specific=0 => draws info about selected town/hero
+{
+	if(!specific)
+		specific = adventureInt->selection;
+
+	assert(specific);
+
+	switch(specific->ID)
+	{
+	case Obj::HERO:
+		return new CInfoBoxPopup(position, dynamic_cast<const CGHeroInstance *>(specific));
+	case Obj::TOWN:
+		return new CInfoBoxPopup(position, dynamic_cast<const CGTownInstance *>(specific));
+	case Obj::GARRISON:
+	case Obj::GARRISON2:
+		return new CInfoBoxPopup(position, dynamic_cast<const CGGarrison *>(specific));
+	default:
+		return nullptr;
+	}
+}

+ 137 - 0
client/windows/InfoWindows.h

@@ -0,0 +1,137 @@
+#pragma once
+
+#include "CWindowObject.h"
+//#include "../gui/SDL_Extensions.h"
+#include "../../lib/FunctionList.h"
+
+struct SDL_Surface;
+struct Rect;
+class CAnimImage;
+class CLabel;
+class CAnimation;
+class CDefHandler;
+class CComponent;
+class CSelectableComponent;
+class CGGarrison;
+class CTextBox;
+class CAdventureMapButton;
+class CSlider;
+
+/*
+ * InfoWindows.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+// Window GUI class
+class CSimpleWindow : public CIntObject
+{
+public:
+	SDL_Surface * bitmap; //background
+	virtual void show(SDL_Surface * to);
+	CSimpleWindow():bitmap(nullptr){}; //c-tor
+	virtual ~CSimpleWindow(); //d-tor
+};
+
+/// text + comp. + ok button
+class CInfoWindow : public CSimpleWindow
+{ //window able to delete its components when closed
+	bool delComps; //whether comps will be deleted
+
+public:
+	typedef std::vector<std::pair<std::string,CFunctionList<void()> > > TButtonsInfo;
+	typedef std::vector<CComponent*> TCompsInfo;
+	QueryID ID; //for identification
+	CTextBox *text;
+	std::vector<CAdventureMapButton *> buttons;
+	std::vector<CComponent*> components;
+	CSlider *slider;
+
+	void setDelComps(bool DelComps);
+	virtual void close();
+
+	void show(SDL_Surface * to);
+	void showAll(SDL_Surface * to);
+	void sliderMoved(int to);
+
+	CInfoWindow(std::string Text, PlayerColor player, const TCompsInfo &comps = TCompsInfo(), const TButtonsInfo &Buttons = TButtonsInfo(), bool delComps = true); //c-tor
+	CInfoWindow(); //c-tor
+	~CInfoWindow(); //d-tor
+
+	//use only before the game starts! (showYesNoDialog in LOCPLINT must be used then)
+	static void showInfoDialog( const std::string & text, const std::vector<CComponent*> *components, bool DelComps = true, PlayerColor player = PlayerColor(1));
+	static void showOkDialog(const std::string & text, const std::vector<CComponent*> *components, const boost::function<void()> & onOk, bool delComps = true, PlayerColor player = PlayerColor(1));
+	static void showYesNoDialog( const std::string & text, const std::vector<CComponent*> *components, const CFunctionList<void( ) > &onYes, const CFunctionList<void()> &onNo, bool DelComps = true, PlayerColor player = PlayerColor(1));
+	static CInfoWindow *create(const std::string &text, PlayerColor playerID = PlayerColor(1), const std::vector<CComponent*> *components = nullptr, bool DelComps = false);
+
+	/// create text from title and description: {title}\n\n description
+	static std::string genText(std::string title, std::string description);
+};
+
+/// popup displayed on R-click
+class CRClickPopup : public CIntObject
+{
+public:
+	virtual void close();
+	void clickRight(tribool down, bool previousState);
+
+	CRClickPopup();
+	virtual ~CRClickPopup(); //d-tor
+
+	static CIntObject* createInfoWin(Point position, const CGObjectInstance * specific);
+	static void createAndPush(const std::string &txt, const CInfoWindow::TCompsInfo &comps = CInfoWindow::TCompsInfo());
+	static void createAndPush(const std::string &txt, CComponent * component);
+	static void createAndPush(const CGObjectInstance *obj, const Point &p, EAlignment alignment = BOTTOMRIGHT);
+};
+
+/// popup displayed on R-click
+class CRClickPopupInt : public CRClickPopup
+{
+public:
+	IShowActivatable *inner;
+	bool delInner;
+
+	void show(SDL_Surface * to);
+	void showAll(SDL_Surface * to);
+	CRClickPopupInt(IShowActivatable *our, bool deleteInt); //c-tor
+	virtual ~CRClickPopupInt(); //d-tor
+};
+
+class CInfoPopup : public CRClickPopup
+{
+public:
+	bool free; //TODO: comment me
+	SDL_Surface * bitmap; //popup background
+	void close();
+	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 = nullptr, bool Free = false); //default c-tor
+
+	void init(int x, int y);
+	~CInfoPopup(); //d-tor
+};
+
+/// popup on adventure map for town\hero objects
+class CInfoBoxPopup : public CWindowObject
+{
+	Point toScreen(Point pos);
+public:
+	CInfoBoxPopup(Point position, const CGTownInstance * town);
+	CInfoBoxPopup(Point position, const CGHeroInstance * hero);
+	CInfoBoxPopup(Point position, const CGGarrison * garr);
+};
+
+/// component selection window
+class CSelWindow : public CInfoWindow
+{ //warning - this window deletes its components by closing!
+public:
+	void selectionChange(unsigned to);
+	void madeChoice(); //looks for selected component and calls callback
+	CSelWindow(const std::string& text, PlayerColor player, int charperline ,const std::vector<CSelectableComponent*> &comps, const std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, QueryID askID); //c-tor
+	CSelWindow(){}; //c-tor
+	//notification - this class inherits important destructor from CInfoWindow
+};