1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

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

This commit is contained in:
Ivan Savenko 2014-07-15 10:14:49 +03:00
parent a69fcdd435
commit 731aedf3a1
67 changed files with 4023 additions and 3655 deletions

View File

@ -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"

View File

@ -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})

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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;}

View File

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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

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

View File

@ -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"

View File

@ -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"
/*

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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 );
};

View File

@ -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

View File

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

View File

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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;
}
};
};

View File

@ -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

View File

@ -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()));
}
}

View File

@ -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
client/widgets/Buttons.cpp Normal file
View File

@ -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
client/widgets/Buttons.h Normal file
View File

@ -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();
};

View File

@ -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"

View File

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

View File

@ -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"

View File

@ -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;
};

View File

@ -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)

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -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
client/widgets/Images.cpp Normal file
View File

@ -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
client/widgets/Images.h Normal file
View File

@ -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 );
};

View File

@ -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)
void CHoverableArea::hover (bool on)
{
for (unsigned i=0;i<components.size();i++)
{
CSelectableComponent * pom = dynamic_cast<CSelectableComponent*>(components[i]);
if (!pom)
continue;
pom->select(i==to);
}
redraw();
if (on)
GH.statusbar->setText(hoverText);
else if (GH.statusbar->getText()==hoverText)
GH.statusbar->clear();
}
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)
CHoverableArea::CHoverableArea()
{
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);
addUsedEvents(HOVER);
}
void CSelWindow::madeChoice()
CHoverableArea::~CHoverableArea()
{
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)
void LRClickableAreaWText::clickLeft(tribool down, bool previousState)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
type |= BLOCK_ADV_HOTKEYS;
ID = QueryID(-1);
for(auto & Button : Buttons)
if(!down && previousState && !text.empty())
{
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);
LOCPLINT->showInfoDialog(text);
}
}
void CInfoWindow::showAll(SDL_Surface * to)
void LRClickableAreaWText::clickRight(tribool down, bool previousState)
{
CSimpleWindow::show(to);
CIntObject::showAll(to);
if (!text.empty())
adventureInt->handleRightClick(text, down);
}
void CInfoWindow::showInfoDialog(const std::string &text, const std::vector<CComponent *> *components, bool DelComps, PlayerColor player)
LRClickableAreaWText::LRClickableAreaWText()
{
CInfoWindow * window = CInfoWindow::create(text, player, components, DelComps);
GH.pushInt(window);
init();
}
void CInfoWindow::showYesNoDialog(const std::string & text, const std::vector<CComponent*> *components, const CFunctionList<void( ) > &onYes, const CFunctionList<void()> &onNo, bool DelComps, PlayerColor player)
LRClickableAreaWText::LRClickableAreaWText(const Rect &Pos, const std::string &HoverText /*= ""*/, const std::string &ClickText /*= ""*/)
{
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);
init();
pos = Pos + pos;
hoverText = HoverText;
text = ClickText;
}
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()
LRClickableAreaWText::~LRClickableAreaWText()
{
}
void CRClickPopupInt::show(SDL_Surface * to)
void LRClickableAreaWText::init()
{
inner->show(to);
addUsedEvents(LCLICK | RCLICK | HOVER);
}
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;
}
}
void LRClickableAreaWTextComp::clickLeft(tribool down, bool previousState)
{
if((!down) && previousState)

View File

@ -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);
std::string hoverText;
CRClickPopup();
virtual ~CRClickPopup(); //d-tor
virtual void hover (bool on);
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);
CHoverableArea();
virtual ~CHoverableArea();
};
/// popup displayed on R-click
class CRClickPopupInt : 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:
IShowActivatable *inner;
bool delInner;
std::string text;
void show(SDL_Surface * to);
void showAll(SDL_Surface * to);
CRClickPopupInt(IShowActivatable *our, bool deleteInt); //c-tor
virtual ~CRClickPopupInt(); //d-tor
};
LRClickableAreaWText();
LRClickableAreaWText(const Rect &Pos, const std::string &HoverText = "", const std::string &ClickText = "");
virtual ~LRClickableAreaWText();
void init();
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
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);
};

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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;;
}
}
}

View File

@ -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);
};

View File

@ -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()));
}
}

View File

@ -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

View File

@ -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;

View File

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

View File

@ -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;

View File

@ -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
{

View File

@ -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"

View File

@ -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

View File

@ -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

View File

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

View File

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

View File

@ -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

View File

@ -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

View File

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

View File

@ -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"
/*

View File

@ -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
{

View File

@ -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();
}

View File

@ -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();
};

View File

@ -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"

View File

@ -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

View File

@ -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;
}
}

View File

@ -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
};