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

Merged GUI refactoring into develop, fixed conflicts

This commit is contained in:
Ivan Savenko 2014-08-09 15:00:45 +03:00
commit b1285bc506
119 changed files with 13087 additions and 12229 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,8 @@
{
"basepath" : "buttons/",
"images" :
[
{ "frame" : 0, "file" : "commanderNormal.png"},
{ "frame" : 1, "file" : "commanderPressed.png"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,8 @@
{
"basepath" : "buttons/",
"images" :
[
{ "frame" : 0, "file" : "resolutionNormal.png"},
{ "frame" : 1, "file" : "resolutionPressed.png"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,8 @@
{
"basepath" : "stackWindow/",
"images" :
[
{ "frame" : 0, "file" : "cancel-normal.png"},
{ "frame" : 1, "file" : "cancel-pressed.png"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,17 @@
{
"basepath" : "stackWindow/",
"images" :
[
{ "frame" : 0, "file" : "level-0.png"},
{ "frame" : 1, "file" : "level-1.png"},
{ "frame" : 2, "file" : "level-2.png"},
{ "frame" : 3, "file" : "level-3.png"},
{ "frame" : 4, "file" : "level-4.png"},
{ "frame" : 5, "file" : "level-5.png"},
{ "frame" : 6, "file" : "level-6.png"},
{ "frame" : 7, "file" : "level-7.png"},
{ "frame" : 8, "file" : "level-8.png"},
{ "frame" : 9, "file" : "level-9.png"},
{ "frame" : 10,"file" : "level-10.png"}
]
}

View File

@ -0,0 +1,7 @@
{
"images" :
[
{ "frame" : 0, "file" : "SECSK32:69"},
{ "frame" : 1, "file" : "SECSK32:28"}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,8 @@
{
"basepath" : "stackWindow/",
"images" :
[
{ "frame" : 0, "file" : "upgrade-normal.png"},
{ "frame" : 1, "file" : "upgrade-pressed.png"}
]
}

View File

@ -15,6 +15,7 @@ For building from source see project wiki at http://wiki.vcmi.eu/
## Copyright and license ## Copyright and license
VCMI Project is released under GPL version 2 or later VCMI Project source code is licensed under GPL version 2 or later.
VCMI Project assets are licensed under CC-BY-SA 4.0. Assets sources and information about contributors are available under following link: [https://github.com/vcmi/vcmi-assets]
Copyright (C) 2007-2014 VCMI Team (check AUTHORS file for the contributors list) Copyright (C) 2007-2014 VCMI Team (check AUTHORS file for the contributors list)

View File

@ -1,935 +0,0 @@
#include "StdInc.h"
#include "CCreatureWindow.h"
#include "../lib/CCreatureSet.h"
#include "CGameInfo.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/BattleState.h"
#include "../CCallback.h"
#include <SDL.h>
#include "gui/SDL_Extensions.h"
#include "CBitmapHandler.h"
#include "CDefHandler.h"
#include "Graphics.h"
#include "CPlayerInterface.h"
#include "../lib/CConfigHandler.h"
#include "CAnimation.h"
#include "../lib/CGameState.h"
#include "../lib/BattleState.h"
#include "../lib/CSpellHandler.h"
#include "../lib/CArtHandler.h"
#include "../lib/NetPacksBase.h" //ArtifactLocation
#include "../lib/CModHandler.h"
#include "../lib/IBonusTypeHandler.h"
#include "gui/CGuiHandler.h"
#include "gui/CIntObjectClasses.h"
using namespace CSDL_Ext;
class CCreatureArtifactInstance;
class CSelectableSkill;
/*
* CCreatureWindow.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
*
*/
CCreatureWindow::CCreatureWindow (const CStack &stack, CreWinType Type):
CWindowObject(PLAYER_COLORED | (Type == OTHER ? RCLICK_POPUP : 0 ) ),
type(Type)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
if (stack.base)
init(stack.base, &stack, dynamic_cast<const CGHeroInstance*>(stack.base->armyObj));
else
{
auto s = new CStackInstance(stack.type, 1); //TODO: war machines and summons should be regular stacks
init(s, &stack, nullptr);
delete s;
}
}
CCreatureWindow::CCreatureWindow (const CStackInstance &stack, CreWinType Type):
CWindowObject(PLAYER_COLORED | (Type == OTHER ? RCLICK_POPUP : 0 ) ),
type(Type)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
init(&stack, &stack, dynamic_cast<const CGHeroInstance*>(stack.armyObj));
}
CCreatureWindow::CCreatureWindow(CreatureID Cid, CreWinType Type, int creatureCount):
CWindowObject(PLAYER_COLORED | (Type == OTHER ? RCLICK_POPUP : 0 ) ),
type(Type)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
auto stack = new CStackInstance(Cid, creatureCount); //TODO: simplify?
init(stack, CGI->creh->creatures[Cid], nullptr);
delete stack;
}
CCreatureWindow::CCreatureWindow(const CStackInstance &st, CreWinType Type, std::function<void()> Upg, std::function<void()> Dsm, UpgradeInfo *ui):
CWindowObject(PLAYER_COLORED | (Type == OTHER ? RCLICK_POPUP : 0 ) ),
type(Type),
dismiss(nullptr),
upgrade(nullptr),
ok(nullptr),
dsm(Dsm)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
init(&st, &st,dynamic_cast<const CGHeroInstance*>(st.armyObj));
//print abilities text - if r-click popup
if(type)
{
if(Upg && ui)
{
TResources upgradeCost = ui->cost[0] * st.count;
for(TResources::nziterator i(upgradeCost); i.valid(); i++)
{
BLOCK_CAPTURING;
upgResCost.push_back(new CComponent(CComponent::resource, i->resType, i->resVal));
}
if(LOCPLINT->cb->getResourceAmount().canAfford(upgradeCost))
{
CFunctionList<void()> fs;
fs += Upg;
fs += std::bind(&CCreatureWindow::close,this);
CFunctionList<void()> cfl;
cfl += std::bind(&CPlayerInterface::showYesNoDialog,
LOCPLINT, CGI->generaltexth->allTexts[207], fs, nullptr, false, upgResCost);
upgrade = new CAdventureMapButton("",CGI->generaltexth->zelp[446].second,cfl,385, 148,"IVIEWCR.DEF",SDLK_u);
}
else
{
upgrade = new CAdventureMapButton("",CGI->generaltexth->zelp[446].second,std::function<void()>(),385, 148,"IVIEWCR.DEF");
upgrade->callback.funcs.clear();
upgrade->setOffset(2);
}
}
if(Dsm)
{
CFunctionList<void()> fs[2];
//on dismiss confirmed
fs[0] += Dsm; //dismiss
fs[0] += std::bind(&CCreatureWindow::close,this);//close this window
CFunctionList<void()> cfl;
cfl = std::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],fs[0],fs[1],false,std::vector<CComponent*>());
dismiss = new CAdventureMapButton("",CGI->generaltexth->zelp[445].second,cfl,333, 148,"IVIEWCR2.DEF",SDLK_d);
}
}
}
CCreatureWindow::CCreatureWindow (const CCommanderInstance * Commander, const CStack * stack):
CWindowObject(PLAYER_COLORED),
commander (Commander)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
if (stack)
{
type = COMMANDER_BATTLE;
init(commander, stack, dynamic_cast<const CGHeroInstance*>(commander->armyObj));
}
else
{
type = COMMANDER;
init(commander, commander, dynamic_cast<const CGHeroInstance*>(commander->armyObj));
}
std::function<void()> Dsm;
CFunctionList<void()> fs[2];
//on dismiss confirmed
fs[0] += Dsm; //dismiss
fs[0] += std::bind(&CCreatureWindow::close,this);//close this window
CFunctionList<void()> cfl;
cfl = std::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],fs[0],fs[1],false,std::vector<CComponent*>());
if (type < COMMANDER_LEVEL_UP) //can dismiss only in regular window
dismiss = new CAdventureMapButton("",CGI->generaltexth->zelp[445].second, cfl, 333, 148,"IVIEWCR2.DEF", SDLK_d);
}
CCreatureWindow::CCreatureWindow (std::vector<ui32> &skills, const CCommanderInstance * Commander, std::function<void(ui32)> callback):
CWindowObject(PLAYER_COLORED),
type(COMMANDER_LEVEL_UP),
commander (Commander),
selectedOption (0), //choose something before drawing
upgradeOptions(skills), //copy skills to choose from
levelUp (callback)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
init(commander, commander, dynamic_cast<const CGHeroInstance*>(commander->armyObj));
std::function<void()> Dsm;
CFunctionList<void()> fs[2];
//on dismiss confirmed
fs[0] += Dsm; //dismiss
fs[0] += std::bind(&CCreatureWindow::close,this);//close this window
CFunctionList<void()> cfl;
cfl = std::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],fs[0],fs[1],false,std::vector<CComponent*>());
if (type < COMMANDER_LEVEL_UP) //can dismiss only in regular window
dismiss = new CAdventureMapButton("",CGI->generaltexth->zelp[445].second, cfl, 333, 148,"IVIEWCR2.DEF", SDLK_d);
}
void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode *StackNode, const CGHeroInstance *HeroOwner)
{
creatureArtifact = nullptr; //may be set later
artifactImage = nullptr;
spellEffectsPics = nullptr;
stack = Stack;
c = stack->type;
if(!StackNode)
stackNode = c;
else
stackNode = StackNode;
const CStack *battleStack = dynamic_cast<const CStack*>(stackNode); //only during battle
heroOwner = HeroOwner;
if (battleStack)
count = boost::lexical_cast<std::string>(battleStack->count);
else if (Stack->count)
count = boost::lexical_cast<std::string>(Stack->count);
if (type < COMMANDER)
commander = nullptr;
bool creArt = false;
displayedArtifact = ArtifactPosition::CREATURE_SLOT; // 0
//Basic graphics - need to calculate size
int commanderOffset = 0;
if (type >= COMMANDER)
commanderOffset = 74;
if (commander) //secondary skills
{
creArt = true;
for (int i = ECommander::ATTACK; i <= ECommander::SPELL_POWER; ++i)
{
if (commander->secondarySkills[i] || vstd::contains(upgradeOptions, i))
{
std::string file = skillToFile(i);
skillPictures.push_back(new CPicture(file, 0,0));
}
}
if (type == COMMANDER_LEVEL_UP)
{
for (auto option : upgradeOptions)
{
ui32 index = selectableSkills.size();
auto selectableSkill = new CSelectableSkill();
selectableSkill->callback = std::bind(&CCreatureWindow::selectSkill, this, index);
if (option < 100)
{
selectableSkill->pos = skillPictures[index]->pos; //resize
selectableSkills.push_back (selectableSkill);
}
else
{
selectableSkill->pos = Rect (95, 256, 55, 55); //TODO: scroll
const Bonus *b = CGI->creh->skillRequirements[option-100].first;
bonusItems.push_back (new CBonusItem (genRect(0, 0, 251, 57), stack->bonusToString(b, false), stack->bonusToString(b, true), stack->bonusToGraphics(b)));
selectableBonuses.push_back (selectableSkill); //insert these before other bonuses
}
}
}
}
BonusList bl, blTemp;
blTemp = (*(stackNode->getBonuses(Selector::durationType(Bonus::PERMANENT).And(Selector::anyRange()))));
while (blTemp.size())
{
Bonus * b = blTemp.front();
bl.push_back (new Bonus(*b));
bl.back()->val = blTemp.valOfBonuses(Selector::typeSubtype(b->type, b->subtype)); //merge multiple bonuses into one
blTemp.remove_if (Selector::typeSubtype(b->type, b->subtype)); //remove used bonuses
}
std::string text, img;
for(Bonus* b : bl)
{
text = stack->bonusToString(b, false);
img = stack->bonusToGraphics(b);
if (text.size() || img.size()) //if it's possible to give any description or image for this kind of bonus
{
bonusItems.push_back (new CBonusItem(genRect(0, 0, 251, 57), text, stack->bonusToString(b, true), img));
}
}
//handle Magic resistance separately :/
const IBonusBearer *temp = stack;
if (battleStack)
{
temp = battleStack;
}
int magicResistance = temp->magicResistance();
if (magicResistance)
{
Bonus b;
b.type = Bonus::MAGIC_RESISTANCE;
text = VLC->getBth()->bonusToString(&b,temp,false);
const std::string description = VLC->getBth()->bonusToString(&b,temp,true);
bonusItems.push_back (new CBonusItem(genRect(0, 0, 251, 57), text, description, stack->bonusToGraphics(&b)));
}
bonusRows = std::min ((int)((bonusItems.size() + 1) / 2), (screen->h - 230) / 60);
if (type >= COMMANDER)
vstd::amin(bonusRows, 3);
else
vstd::amin(bonusRows, 4);
vstd::amax(bonusRows, 1);
if (type >= COMMANDER)
{
setBackground("CommWin" + boost::lexical_cast<std::string>(bonusRows) + ".pcx");
for (int i = 0; i < skillPictures.size(); ++i)
{
skillPictures[i]->moveTo (Point (pos.x + 37 + i * 84, pos.y + 224));
}
for (int i = 0; i < selectableSkills.size(); ++i)
{
if (upgradeOptions[i] < skillPictures.size()) // it's secondary skill
{
selectableSkills[i]->pos = skillPictures[upgradeOptions[i]]->pos; //dirty workaround
}
else
break;
}
//print commander level
new CLabel(488, 62, FONT_MEDIUM, CENTER, Colors::YELLOW,
boost::lexical_cast<std::string>((ui16)(commander->level)));
new CLabel(488, 82, FONT_SMALL, CENTER, Colors::WHITE,
boost::lexical_cast<std::string>(stack->experience));
}
else
setBackground("CreWin" + boost::lexical_cast<std::string>(bonusRows) + ".pcx"); //1 to 4 rows for now
//Buttons
ok = new CAdventureMapButton("",CGI->generaltexth->zelp[445].second, std::bind(&CCreatureWindow::close,this), 489, 148, "hsbtns.def", SDLK_RETURN);
ok->assignedKeys.insert(SDLK_ESCAPE);
if (type <= BATTLE) //in battle or info window
{
upgrade = nullptr;
dismiss = nullptr;
}
anim = new CCreaturePic(22, 48, c);
//Stats
morale = new MoraleLuckBox(true, genRect(42, 42, 335, 100));
morale->set(stackNode);
luck = new MoraleLuckBox(false, genRect(42, 42, 387, 100));
luck->set(stackNode);
new CAnimImage("PSKIL42", 4, 0, 387, 51); //exp icon - Print it always?
if (type) //not in fort window
{
if (CGI->modh->modules.STACK_EXP && type < COMMANDER)
{
int rank = std::min(stack->getExpRank(), 10); //hopefully nobody adds more
new CLabel(488, 82, FONT_SMALL, CENTER, Colors::WHITE, boost::lexical_cast<std::string>(stack->experience));
new CLabel(488, 62, FONT_MEDIUM, CENTER, Colors::YELLOW,
CGI->generaltexth->zcrexp[rank] + " [" + boost::lexical_cast<std::string>(rank) + "]");
if (type > BATTLE) //we need it only on adv. map
{
int tier = stack->type->level;
if (!vstd::iswithin(tier, 1, 7))
tier = 0;
int number;
std::string expText = CGI->generaltexth->zcrexp[324];
boost::replace_first (expText, "%s", c->namePl);
boost::replace_first (expText, "%s", CGI->generaltexth->zcrexp[rank]);
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(rank));
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(stack->experience));
number = CGI->creh->expRanks[tier][rank] - stack->experience;
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number));
number = CGI->creh->maxExpPerBattle[tier]; //percent
boost::replace_first (expText, "%i%", boost::lexical_cast<std::string>(number));
number *= CGI->creh->expRanks[tier].back() / 100; //actual amount
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number));
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(stack->count)); //Number of Creatures in stack
int expmin = std::max(CGI->creh->expRanks[tier][std::max(rank-1, 0)], (ui32)1);
number = (stack->count * (stack->experience - expmin)) / expmin; //Maximum New Recruits without losing current Rank
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number)); //TODO
boost::replace_first (expText, "%.2f", boost::lexical_cast<std::string>(1)); //TODO Experience Multiplier
number = CGI->creh->expAfterUpgrade;
boost::replace_first (expText, "%.2f", boost::lexical_cast<std::string>(number) + "%"); //Upgrade Multiplier
expmin = CGI->creh->expRanks[tier][9];
int expmax = CGI->creh->expRanks[tier][10];
number = expmax - expmin;
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number)); //Experience after Rank 10
number = (stack->count * (expmax - expmin)) / expmin;
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number)); //Maximum New Recruits to remain at Rank 10 if at Maximum Experience
expArea = new LRClickableAreaWTextComp(Rect(334, 49, 160, 44),CComponent::experience);
expArea->text = expText;
expArea->bonusValue = 0; //TDO: some specific value or no number at all
}
}
if (CGI->modh->modules.STACK_ARTIFACT)
{
creArt = true;
}
}
if (creArt) //stack or commander artifacts
{
setArt (stack->getArt(ArtifactPosition::CREATURE_SLOT));
if (type > BATTLE && type < COMMANDER_BATTLE) //artifact buttons inactive in battle
{
//TODO: disable buttons if no artifact is equipped
leftArtRoll = new CAdventureMapButton(std::string(), std::string(), std::bind (&CCreatureWindow::scrollArt, this, -1), 437, 98, "hsbtns3.def", SDLK_LEFT);
rightArtRoll = new CAdventureMapButton(std::string(), std::string(), std::bind (&CCreatureWindow::scrollArt, this, +1), 516, 98, "hsbtns5.def", SDLK_RIGHT);
if (heroOwner)
passArtToHero = new CAdventureMapButton(std::string(), std::string(), std::bind (&CCreatureWindow::passArtifactToHero, this), 437, 148, "OVBUTN1.DEF", SDLK_HOME);
}
}
if (battleStack) //only during battle
{
spellEffectsPics = new CAnimation("SpellInt.def");
//spell effects
int printed=0; //how many effect pics have been printed
std::vector<si32> spells = battleStack->activeSpells();
for(si32 effect : spells)
{
const si32 imageIndex = effect+1; //there is "null" frame with index 0 in SpellInt.def
std::string spellText;
spellEffectsPics->load(imageIndex);
IImage * effectIcon = spellEffectsPics->getImage(imageIndex,0,false); //todo: better way to determine presence of icon
spellEffectsPics->unload(imageIndex);
if (effectIcon != nullptr) //not all effects have graphics (for eg. Acid Breath)
{
spellText = CGI->generaltexth->allTexts[610]; //"%s, duration: %d rounds."
boost::replace_first (spellText, "%s", CGI->spellh->objects[effect]->name);
int duration = battleStack->getBonusLocalFirst(Selector::source(Bonus::SPELL_EFFECT,effect))->turnsRemain;
boost::replace_first (spellText, "%d", boost::lexical_cast<std::string>(duration));
new CAnimImage("SpellInt.def", imageIndex, 0, 20 + 52 * printed, 184);
spellEffects.push_back(new LRClickableAreaWText(Rect(20 + 52 * printed, 184, 50, 38), spellText, spellText));
if (++printed >= 10) //we can fit only 10 effects
break;
}
}
//print current health
printLine (5, CGI->generaltexth->allTexts[200], battleStack->firstHPleft);
}
if (bonusItems.size() > (bonusRows << 1)) //only after graphics are created
{
slider = new CSlider(528, 231 + commanderOffset, bonusRows*60, std::bind (&CCreatureWindow::sliderMoved, this, _1),
bonusRows, (bonusItems.size() + 1) >> 1, 0, false, 0);
}
else //slider automatically places bonus Items
recreateSkillList (0);
showAll(screen2);
//AUIDAT.DEF
}
void CCreatureWindow::printLine(int nr, const std::string &text, int baseVal, int val/*=-1*/, bool range/*=false*/)
{
new CLabel(162, 48 + nr*19, FONT_SMALL, TOPLEFT, Colors::WHITE, text);
std::string hlp;
if(range && baseVal != val)
hlp = boost::str(boost::format("%d - %d") % baseVal % val);
else if(baseVal != val && val>=0)
hlp = boost::str(boost::format("%d (%d)") % baseVal % val);
else
hlp = boost::lexical_cast<std::string>(baseVal);
new CLabel(325, 64 + nr*19, FONT_SMALL, BOTTOMRIGHT, Colors::WHITE, hlp);
}
void CCreatureWindow::recreateSkillList(int Pos)
{
int commanderOffset = 0;
if (type >= COMMANDER)
commanderOffset = 74;
int n = 0, i = 0, j = 0;
int numSkills = std::min ((bonusRows + Pos) << 1, (int)bonusItems.size());
for (n = 0; n < Pos << 1; ++n)
{
bonusItems[n]->visible = false;
if (n < selectableBonuses.size())
selectableBonuses[n]->deactivate(); //we assume that bonuses are at front of the list
}
for (n = Pos << 1; n < numSkills; ++n)
{
int offsetx = 257*j - (bonusRows == 4 ? 1 : 0);
int offsety = 60*i + (bonusRows > 1 ? 1 : 0) + commanderOffset; //lack of precision :/
bonusItems[n]->moveTo (Point(pos.x + offsetx + 10, pos.y + offsety + 230), true);
bonusItems[n]->visible = true;
if (n < selectableBonuses.size())
{
selectableBonuses[n]->moveTo (Point(bonusItems[n]->pos.x + 12, bonusItems[n]->pos.y + 2)); //for some reason bonusItems have dimensions 0?
//selectableBonuses[n]->pos = bonusItems[n]->bonusGraphics->pos;
selectableBonuses[n]->activate();
}
if (++j > 1) //next line
{
++i;
j = 0;
}
}
for (n = numSkills; n < bonusItems.size(); ++n)
{
bonusItems[n]->visible = false;
if (n < selectableBonuses.size())
selectableBonuses[n]->deactivate();
}
}
void CCreatureWindow::showAll(SDL_Surface * to)
{
CIntObject::showAll(to);
printAtMiddleLoc((type >= COMMANDER ? c->nameSing : c->namePl), 180, 30, FONT_SMALL, Colors::YELLOW, to); //creature name
printLine(0, CGI->generaltexth->primarySkillNames[0], c->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), stackNode->Attack());
printLine(1, CGI->generaltexth->primarySkillNames[1], c->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), stackNode->Defense());
if (stackNode->valOfBonuses(Bonus::SHOTS) && stackNode->hasBonusOfType(Bonus::SHOOTER))
{//only for shooting units - important with wog exp shooters
if (type == BATTLE)
printLine(2, CGI->generaltexth->allTexts[198], stackNode->valOfBonuses(Bonus::SHOTS), dynamic_cast<const CStack*>(stackNode)->shots);
else
printLine(2, CGI->generaltexth->allTexts[198], stackNode->valOfBonuses(Bonus::SHOTS));
}
if (stackNode->valOfBonuses(Bonus::CASTS))
{
printAtMiddleLoc(CGI->generaltexth->allTexts[399], 356, 62, FONT_SMALL, Colors::WHITE, to);
std::string casts;
if (type == BATTLE)
casts = boost::lexical_cast<std::string>((ui16)dynamic_cast<const CStack*>(stackNode)->casts); //ui8 is converted to char :(
else
casts = boost::lexical_cast<std::string>(stackNode->valOfBonuses(Bonus::CASTS));
printAtMiddleLoc(casts, 356, 82, FONT_SMALL, Colors::WHITE, to);
}
//TODO
int dmgMultiply = 1;
if(heroOwner && stackNode->hasBonusOfType(Bonus::SIEGE_WEAPON))
dmgMultiply += heroOwner->Attack();
printLine(3, CGI->generaltexth->allTexts[199], stackNode->getMinDamage() * dmgMultiply, stackNode->getMaxDamage() * dmgMultiply, true);
printLine(4, CGI->generaltexth->allTexts[388], c->valOfBonuses(Bonus::STACK_HEALTH), stackNode->valOfBonuses(Bonus::STACK_HEALTH));
printLine(6, CGI->generaltexth->zelp[441].first, c->Speed(), stackNode->Speed());
for(CBonusItem* b : bonusItems)
b->showAll (to);
for(auto s : selectableSkills)
s->showAll (to);
for (int i = 0; i < skillPictures.size(); i++)
{
skillPictures[i]->bg = BitmapHandler::loadBitmap (skillToFile(i));
skillPictures[i]->showAll (to);
}
if (upgradeOptions.size() && (type == COMMANDER_LEVEL_UP && upgradeOptions[selectedOption] >= 100)) //add frame to selected skill
{
int index = selectedOption - selectableSkills.size(); //this is screwed
CSDL_Ext::drawBorder(to, Rect::around(selectableBonuses[index]->pos), int3(Colors::METALLIC_GOLD.r, Colors::METALLIC_GOLD.g, Colors::METALLIC_GOLD.b));
}
}
void CCreatureWindow::show(SDL_Surface * to)
{
CIntObject::show(to);
if (!count.empty()) //army stack
graphics->fonts[FONT_TIMES]->renderTextRight(to, count, Colors::WHITE, Point(pos.x + 114, pos.y + 174));
}
void CCreatureWindow::close()
{
if (upgradeOptions.size()) //a skill for commander was chosen
levelUp (selectedOption); //callback value is vector index
GH.popIntTotally(this);
}
void CCreatureWindow::sliderMoved(int newpos)
{
recreateSkillList(newpos); //move components
redraw();
}
std::string CCreatureWindow::skillToFile (int skill)
{
std::string file = "zvs/Lib1.res/_";
switch (skill)
{
case ECommander::ATTACK:
file += "AT";
break;
case ECommander::DEFENSE:
file += "DF";
break;
case ECommander::HEALTH:
file += "HP";
break;
case ECommander::DAMAGE:
file += "DM";
break;
case ECommander::SPEED:
file += "SP";
break;
case ECommander::SPELL_POWER:
file += "MP";
break;
}
std::string sufix = boost::lexical_cast<std::string>((int)(commander->secondarySkills[skill])); //casting ui8 causes ascii char conversion
if (type == COMMANDER_LEVEL_UP)
{
if (upgradeOptions.size() && upgradeOptions[selectedOption] == skill)//that one specific skill is selected
sufix += "="; //level-up highlight
else if (!vstd::contains(upgradeOptions, skill))
sufix = "no"; //not available - no number
}
file += sufix += ".bmp";
return file;
}
void CCreatureWindow::setArt(const CArtifactInstance *art)
{
creatureArtifact = art;
if (creatureArtifact)
{
if (artifactImage == nullptr)
artifactImage = new CAnimImage("ARTIFACT", creatureArtifact->artType->iconIndex, 0, 466, 100);
else
artifactImage->setFrame(creatureArtifact->artType->iconIndex);
}
else
artifactImage = nullptr;
redraw();
}
void CCreatureWindow::scrollArt(int dir)
{
//TODO: get next artifact
int size = stack->artifactsWorn.size();
displayedArtifact = size ? static_cast<ArtifactPosition>((displayedArtifact + dir) % size)
: static_cast<ArtifactPosition>(ArtifactPosition::CREATURE_SLOT);
setArt (stack->getArt(displayedArtifact));
}
void CCreatureWindow::passArtifactToHero()
{
const CGHeroInstance * h = dynamic_cast<const CGHeroInstance *>(stack->armyObj);
if (h && creatureArtifact)
{
LOCPLINT->cb->swapArtifacts (ArtifactLocation (stack, displayedArtifact), ArtifactLocation(h, creatureArtifact->firstBackpackSlot(h)));
}
else
logGlobal->warnStream() << "Pass artifact to hero should be disabled, no hero or no artifact!";
//redraw is handled via CArtifactHolder interface
}
void CCreatureWindow::artifactRemoved (const ArtifactLocation &artLoc)
{
//align artifacts to remove holes
for (auto al : stack->artifactsWorn)
{
ArtifactPosition freeSlot = al.second.artifact->firstAvailableSlot(stack);
if (freeSlot < al.first)
LOCPLINT->cb->swapArtifacts (ArtifactLocation(stack, al.first), ArtifactLocation(stack, freeSlot));
}
int size = stack->artifactsWorn.size();
displayedArtifact = size ? static_cast<ArtifactPosition>(displayedArtifact % size)
: static_cast<ArtifactPosition>(ArtifactPosition::CREATURE_SLOT); //0
setArt (stack->getArt(displayedArtifact));
}
void CCreatureWindow::artifactMoved (const ArtifactLocation &artLoc, const ArtifactLocation &destLoc)
{
artifactRemoved (artLoc); //same code
}
void CCreatureWindow::selectSkill (ui32 which)
{
selectedOption = which;
redraw();
}
CCreatureWindow::~CCreatureWindow()
{
for (auto & elem : upgResCost)
delete elem;
bonusItems.clear();
if(spellEffectsPics!=nullptr)
delete spellEffectsPics;
}
CBonusItem::CBonusItem()
{
}
CBonusItem::CBonusItem(const Rect &Pos, const std::string &Name, const std::string &Description, const std::string &graphicsName)
{
OBJ_CONSTRUCTION;
visible = false;
name = Name;
description = Description;
if (graphicsName.size())
bonusGraphics = new CPicture(graphicsName, 26, 232);
else
bonusGraphics = nullptr;
removeUsedEvents(ALL); //no actions atm
}
void CBonusItem::showAll (SDL_Surface * to)
{
if (visible)
{
graphics->fonts[FONT_SMALL]->renderTextLeft(to, name, Colors::YELLOW, Point(pos.x + 72, pos.y + 6));
graphics->fonts[FONT_SMALL]->renderTextLeft(to, description, Colors::WHITE, Point(pos.x + 72, pos.y + 30));
if (bonusGraphics && bonusGraphics->bg)
blitAtLoc(bonusGraphics->bg, 12, 2, to);
}
}
CBonusItem::~CBonusItem()
{
//delete bonusGraphics; //automatic destruction
}
void CSelectableSkill::clickLeft(tribool down, bool previousState)
{
if (down)
callback();
}
void CCreInfoWindow::show(SDL_Surface * to)
{
CIntObject::show(to);
creatureCount->showAll(to);
}
CCreInfoWindow::CCreInfoWindow(const CStackInstance &stack, bool LClicked, std::function<void()> upgradeFunc, std::function<void()> dismissFunc, UpgradeInfo *upgradeInfo):
CWindowObject(PLAYER_COLORED | (LClicked ? 0 : RCLICK_POPUP), "CRSTKPU")
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
init(stack.type, &stack, dynamic_cast<const CGHeroInstance*>(stack.armyObj), stack.count, LClicked);
//additional buttons if opened with left click
if(LClicked)
{
std::function<void()> closeFunc = std::bind(&CCreInfoWindow::close,this);
if(upgradeFunc && upgradeInfo)
{
TResources upgradeCost = upgradeInfo->cost[0] * stack.count;
for(TResources::nziterator i(upgradeCost); i.valid(); i++)
{
BLOCK_CAPTURING;
upgResCost.push_back(new CComponent(CComponent::resource, i->resType, i->resVal));
}
CFunctionList<void()> onUpgrade;
onUpgrade += upgradeFunc;
onUpgrade += closeFunc;
std::function<void()> dialog = std::bind(&CPlayerInterface::showYesNoDialog,
LOCPLINT,
CGI->generaltexth->allTexts[207],
onUpgrade, 0, false,
std::ref(upgResCost));
upgrade = new CAdventureMapButton("", CGI->generaltexth->zelp[446].second, dialog, 76, 237, "IVIEWCR", SDLK_u);
upgrade->block(!LOCPLINT->cb->getResourceAmount().canAfford(upgradeCost));
}
if(dismissFunc)
{
CFunctionList<void()> onDismiss;
onDismiss += dismissFunc;
onDismiss += closeFunc;
std::function<void()> dialog = std::bind(&CPlayerInterface::showYesNoDialog,
LOCPLINT,
CGI->generaltexth->allTexts[12],
onDismiss, 0, true, std::vector<CComponent*>());
dismiss = new CAdventureMapButton("", CGI->generaltexth->zelp[445].second, dialog, 21, 237, "IVIEWCR2",SDLK_d);
}
}
}
CCreInfoWindow::CCreInfoWindow(int creatureID, bool LClicked, int creatureCount):
CWindowObject(PLAYER_COLORED | (LClicked ? 0 : RCLICK_POPUP), "CRSTKPU")
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
const CCreature *creature = CGI->creh->creatures[creatureID];
init(creature, nullptr, nullptr, creatureCount, LClicked);
}
CCreInfoWindow::CCreInfoWindow(const CStack &stack, bool LClicked):
CWindowObject(PLAYER_COLORED | (LClicked ? 0 : RCLICK_POPUP), "CRSTKPU")
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
init(stack.getCreature(), &stack, stack.getMyHero(), stack.count, LClicked);
}
CCreInfoWindow::~CCreInfoWindow()
{
for(CComponent* object : upgResCost)
delete object;
}
void CCreInfoWindow::printLine(int position, const std::string &text, int baseVal, int val/*=-1*/, bool range/*=false*/)
{
infoTexts[position].first = new CLabel(155, 48 + position*19, FONT_SMALL, TOPLEFT, Colors::WHITE, text);
std::string valueStr;
if(range && baseVal != val)
valueStr = boost::str(boost::format("%d - %d") % baseVal % val);
else if(baseVal != val && val>=0)
valueStr = boost::str(boost::format("%d (%d)") % baseVal % val);
else
valueStr = boost::lexical_cast<std::string>(baseVal);
infoTexts[position].second = new CLabel(276, 63 + position*19, FONT_SMALL, BOTTOMRIGHT, Colors::WHITE, valueStr);
}
void CCreInfoWindow::init(const CCreature *creature, const CBonusSystemNode *stackNode, const CGHeroInstance *heroOwner, int count, bool LClicked)
{
removeUsedEvents(ALL);
if (!LClicked)
addUsedEvents(RCLICK);
if(!stackNode)
stackNode = creature;
animation = new CCreaturePic(21, 48, creature);
std::string countStr = boost::lexical_cast<std::string>(count);
creatureCount = new CLabel(114, 174, FONT_TIMES, BOTTOMRIGHT, Colors::WHITE, countStr);
creatureName = new CLabel(149, 30, FONT_SMALL, CENTER, Colors::YELLOW, creature->namePl);
printLine(0, CGI->generaltexth->primarySkillNames[0], creature->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), stackNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK));
printLine(1, CGI->generaltexth->primarySkillNames[1], creature->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), stackNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE));
if(stackNode->valOfBonuses(Bonus::SHOTS))
printLine(2, CGI->generaltexth->allTexts[198], stackNode->valOfBonuses(Bonus::SHOTS));
//TODO
int dmgMultiply = 1;
if(heroOwner && stackNode->hasBonusOfType(Bonus::SIEGE_WEAPON))
dmgMultiply += heroOwner->Attack();
printLine(3, CGI->generaltexth->allTexts[199], stackNode->getMinDamage() * dmgMultiply, stackNode->getMaxDamage() * dmgMultiply, true);
printLine(4, CGI->generaltexth->allTexts[388], creature->valOfBonuses(Bonus::STACK_HEALTH), stackNode->valOfBonuses(Bonus::STACK_HEALTH));
printLine(6, CGI->generaltexth->zelp[441].first, creature->valOfBonuses(Bonus::STACKS_SPEED), stackNode->valOfBonuses(Bonus::STACKS_SPEED));
//setting morale
morale = new MoraleLuckBox(true, genRect(42, 42, 22, 186));
morale->set(stackNode);
//setting luck
luck = new MoraleLuckBox(false, genRect(42, 42, 75, 186));
luck->set(stackNode);
if(!LClicked)
{
abilityText = new CLabel(17, 231, FONT_SMALL, TOPLEFT, Colors::WHITE, creature->abilityText);
}
else
{
abilityText = nullptr;
ok = new CAdventureMapButton("", CGI->generaltexth->zelp[445].second,
std::bind(&CCreInfoWindow::close,this), 216, 237, "IOKAY.DEF", SDLK_RETURN);
ok->assignedKeys.insert(SDLK_ESCAPE);
}
//if we are displying window fo r stack in battle, there are several more things that we need to display
if(const CStack *battleStack = dynamic_cast<const CStack*>(stackNode))
{
//print at most 3 spell effects
std::vector<si32> spells = battleStack->activeSpells();
for (size_t i=0; i< std::min(spells.size(), size_t(3)); i++)
effects.push_back(new CAnimImage("SpellInt", spells[i]+1, 0, 127 + 52*i, 186));
//print current health
printLine(5, CGI->generaltexth->allTexts[200], battleStack->firstHPleft);
}
}
CIntObject * createCreWindow(
const CStack *s, bool lclick/* = false*/)
{
auto c = dynamic_cast<const CCommanderInstance *>(s->base);
if (c)
{
return new CCreatureWindow (c, s);
}
else
{
if(settings["general"]["classicCreatureWindow"].Bool())
return new CCreInfoWindow(*s, lclick);
else
return new CCreatureWindow(*s, LOCPLINT->battleInt ? CCreatureWindow::BATTLE : CCreatureWindow::OTHER);
}
}
CIntObject * createCreWindow(CreatureID Cid, CCreatureWindow::CreWinType Type, int creatureCount)
{
if(settings["general"]["classicCreatureWindow"].Bool())
return new CCreInfoWindow(Cid, Type, creatureCount);
else
return new CCreatureWindow(Cid, Type, creatureCount);
}
CIntObject * createCreWindow(const CStackInstance *s, CCreatureWindow::CreWinType type, std::function<void()> Upg, std::function<void()> Dsm, UpgradeInfo *ui)
{
if(settings["general"]["classicCreatureWindow"].Bool())
return new CCreInfoWindow(*s, type==CCreatureWindow::HERO, Upg, Dsm, ui);
else
return new CCreatureWindow(*s, type, Upg, Dsm, ui);
}

View File

@ -1,163 +0,0 @@
#pragma once
#include "gui/CIntObject.h"
#include "../lib/HeroBonus.h"
#include "GUIClasses.h"
/*
* CCreatureWindow.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
*
*/
struct Bonus;
class CCreature;
class CStackInstance;
class CCommanderInstance;
class CStack;
struct ArtifactLocation;
class CCreatureArtifactInstance;
class CAdventureMapButton;
class CBonusItem;
class CGHeroInstance;
class CComponent;
class LRClickableAreaWText;
class MoraleLuckBox;
class CAdventureMapButton;
struct UpgradeInfo;
class CPicture;
class CCreaturePic;
class LRClickableAreaWTextComp;
class CSlider;
class CLabel;
class CAnimImage;
class CSelectableSkill;
// New creature window
class CCreatureWindow : public CWindowObject, public CArtifactHolder
{
public:
enum CreWinType {OTHER = 0, BATTLE = 1, ARMY = 2, HERO = 3, COMMANDER = 4, COMMANDER_LEVEL_UP = 5, COMMANDER_BATTLE = 6}; // > 3 are opened permanently
//bool active; //TODO: comment me
CreWinType type;
int bonusRows; //height of skill window
ArtifactPosition displayedArtifact;
std::string count; //creature count in text format
const CCreature *c; //related creature
const CStackInstance *stack;
const CBonusSystemNode *stackNode;
const CCommanderInstance * commander;
const CGHeroInstance *heroOwner;
const CArtifactInstance *creatureArtifact; //currently worn artifact
std::vector<CComponent*> upgResCost; //cost of upgrade (if not possible then empty)
std::vector<CBonusItem*> bonusItems;
std::vector<LRClickableAreaWText*> spellEffects;
CCreaturePic *anim; //related creature's animation
MoraleLuckBox *luck, *morale;
LRClickableAreaWTextComp * expArea; //displays exp details
CSlider * slider; //Abilities
CAdventureMapButton *dismiss, *upgrade, *ok;
CAdventureMapButton * leftArtRoll, * rightArtRoll; //artifact selection
CAdventureMapButton * passArtToHero;
CAnimImage * artifactImage;
CAnimation * spellEffectsPics; //bitmaps representing spells affecting a stack in battle
//commander level-up
int selectedOption; //index for upgradeOptions
std::vector<ui32> upgradeOptions; //value 0-5 - secondary skills, 100+ - special skills
std::vector<CSelectableSkill *> selectableSkills, selectableBonuses;
std::vector<CPicture *> skillPictures; //secondary skills
std::string skillToFile(int skill); //return bitmap for secondary skill depending on selection / avaliability
void selectSkill (ui32 which);
void setArt(const CArtifactInstance *creatureArtifact);
void artifactRemoved (const ArtifactLocation &artLoc);
void artifactMoved (const ArtifactLocation &artLoc, const ArtifactLocation &destLoc);
void artifactDisassembled (const ArtifactLocation &artLoc) {return;};
void artifactAssembled (const ArtifactLocation &artLoc) {return;};
std::function<void()> dsm; //dismiss button callback
std::function<void()> Upg; //upgrade button callback
std::function<void(ui32)> levelUp; //choose commander skill to level up
CCreatureWindow(const CStack & stack, CreWinType type); //battle c-tor
CCreatureWindow (const CStackInstance &stack, CreWinType Type); //pop-up c-tor
CCreatureWindow(const CStackInstance &st, CreWinType Type, std::function<void()> Upg, std::function<void()> Dsm, UpgradeInfo *ui); //full garrison window
CCreatureWindow(const CCommanderInstance * commander, const CStack * stack = nullptr); //commander window
CCreatureWindow(std::vector<ui32> &skills, const CCommanderInstance * commander, std::function<void(ui32)> callback);
CCreatureWindow(CreatureID Cid, CreWinType Type, int creatureCount); //c-tor
void init(const CStackInstance *stack, const CBonusSystemNode *stackNode, const CGHeroInstance *heroOwner);
void showAll(SDL_Surface * to);
void show(SDL_Surface * to);
void printLine(int nr, const std::string &text, int baseVal, int val=-1, bool range=false);
void sliderMoved(int newpos);
void close();
~CCreatureWindow(); //d-tor
void recreateSkillList(int pos);
void scrollArt(int dir);
void passArtifactToHero();
};
class CBonusItem : public LRClickableAreaWTextComp //responsible for displaying creature skill, active or not
{
public:
std::string name, description;
CPicture * bonusGraphics;
bool visible;
CBonusItem();
CBonusItem(const Rect &Pos, const std::string &Name, const std::string &Description, const std::string &graphicsName);
~CBonusItem();
void showAll (SDL_Surface * to);
};
class CSelectableSkill : public LRClickableAreaWText
{
public:
std::function<void()> callback; //TODO: create more generic clickable class than AdvMapButton?
virtual void clickLeft(tribool down, bool previousState);
virtual void clickRight(tribool down, bool previousState){};
};
/// original creature info window
class CCreInfoWindow : public CWindowObject
{
public:
CLabel * creatureCount;
CLabel * creatureName;
CLabel * abilityText;
CCreaturePic * animation;
std::vector<CComponent *> upgResCost; //cost of upgrade (if not possible then empty)
std::vector<CAnimImage *> effects;
std::map<size_t, std::pair<CLabel *, CLabel * > > infoTexts;
MoraleLuckBox * luck, * morale;
CAdventureMapButton * dismiss, * upgrade, * ok;
CCreInfoWindow(const CStackInstance & st, bool LClicked, std::function<void()> Upg = nullptr, std::function<void()> Dsm = nullptr, UpgradeInfo * ui = nullptr);
CCreInfoWindow(const CStack & st, bool LClicked = 0);
CCreInfoWindow(int Cid, bool LClicked, int creatureCount);
~CCreInfoWindow();
void init(const CCreature * cre, const CBonusSystemNode * stackNode, const CGHeroInstance * heroOwner, int creatureCount, bool LClicked);
void printLine(int nr, const std::string & text, int baseVal, int val = -1, bool range = false);
void show(SDL_Surface * to);
};
CIntObject *createCreWindow(const CStack *s, bool lclick = false);
CIntObject *createCreWindow(CreatureID Cid, CCreatureWindow::CreWinType Type, int creatureCount);
CIntObject *createCreWindow(const CStackInstance *s, CCreatureWindow::CreWinType type, std::function<void()> Upg = nullptr, std::function<void()> Dsm = nullptr, UpgradeInfo *ui = nullptr);

View File

@ -8,13 +8,13 @@
#include "../lib/filesystem/Filesystem.h" #include "../lib/filesystem/Filesystem.h"
#include "CPreGame.h" #include "CPreGame.h"
#include "CCastleInterface.h" #include "windows/CCastleInterface.h"
#include "../lib/CConsoleHandler.h" #include "../lib/CConsoleHandler.h"
#include "gui/CCursorHandler.h" #include "gui/CCursorHandler.h"
#include "../lib/CGameState.h" #include "../lib/CGameState.h"
#include "../CCallback.h" #include "../CCallback.h"
#include "CPlayerInterface.h" #include "CPlayerInterface.h"
#include "CAdvmapInterface.h" #include "windows/CAdvmapInterface.h"
#include "../lib/CBuildingHandler.h" #include "../lib/CBuildingHandler.h"
#include "CVideoHandler.h" #include "CVideoHandler.h"
#include "../lib/CHeroHandler.h" #include "../lib/CHeroHandler.h"
@ -39,6 +39,7 @@
#include "../lib/GameConstants.h" #include "../lib/GameConstants.h"
#include "gui/CGuiHandler.h" #include "gui/CGuiHandler.h"
#include "../lib/logging/CBasicLogConfigurator.h" #include "../lib/logging/CBasicLogConfigurator.h"
#include "../lib/CondSh.h"
#ifdef _WIN32 #ifdef _WIN32
#include "SDL_syswm.h" #include "SDL_syswm.h"

View File

@ -14,39 +14,56 @@ set(client_SRCS
battle/CBattleInterfaceClasses.cpp battle/CBattleInterfaceClasses.cpp
battle/CCreatureAnimation.cpp battle/CCreatureAnimation.cpp
gui/CAnimation.cpp
gui/CCursorHandler.cpp
gui/CGuiHandler.cpp gui/CGuiHandler.cpp
gui/CIntObject.cpp gui/CIntObject.cpp
gui/CIntObjectClasses.cpp
gui/Fonts.cpp gui/Fonts.cpp
gui/Geometries.cpp gui/Geometries.cpp
gui/CCursorHandler.cpp
gui/SDL_Extensions.cpp gui/SDL_Extensions.cpp
CPreGame.cpp widgets/AdventureMapClasses.cpp
Client.cpp widgets/Buttons.cpp
CPlayerInterface.cpp widgets/CArtifactHolder.cpp
CMT.cpp widgets/CComponent.cpp
GUIClasses.cpp widgets/CGarrisonInt.cpp
AdventureMapClasses.cpp widgets/Images.cpp
CAdvmapInterface.cpp widgets/MiscWidgets.cpp
CAnimation.cpp widgets/ObjectLists.cpp
widgets/TextControls.cpp
windows/CAdvmapInterface.cpp
windows/CCastleInterface.cpp
windows/CCreatureWindow.cpp
windows/CHeroWindow.cpp
windows/CKingdomInterface.cpp
windows/CQuestLog.cpp
windows/CSpellWindow.cpp
windows/CTradeWindow.cpp
windows/CWindowObject
windows/InfoWindows.cpp
windows/GUIClasses.cpp
CBitmapHandler.cpp CBitmapHandler.cpp
CCastleInterface.cpp
CCreatureWindow.cpp
CDefHandler.cpp CDefHandler.cpp
CGameInfo.cpp CGameInfo.cpp
CHeroWindow.cpp Client.cpp
CKingdomInterface.cpp
CMessage.cpp CMessage.cpp
CMT.cpp
CMusicHandler.cpp CMusicHandler.cpp
CSpellWindow.cpp CPlayerInterface.cpp
CPreGame.cpp
CVideoHandler.cpp CVideoHandler.cpp
CQuestLog.cpp
Graphics.cpp Graphics.cpp
mapHandler.cpp mapHandler.cpp
NetPacksClient.cpp NetPacksClient.cpp
) )
set(client_HEADERS
gui/SDL_Pixels.h
gui/SDL_Compat.h
)
if(APPLE) if(APPLE)
# OS X specific includes # OS X specific includes
include_directories(${SPARKLE_INCLUDE_DIR}) include_directories(${SPARKLE_INCLUDE_DIR})

View File

@ -11,17 +11,19 @@
#include "StdInc.h" #include "StdInc.h"
#include "CMessage.h" #include "CMessage.h"
#include "SDL_ttf.h"
#include "CDefHandler.h" #include "CDefHandler.h"
#include "CAnimation.h"
#include "CGameInfo.h" #include "CGameInfo.h"
#include "gui/SDL_Extensions.h" #include "gui/SDL_Extensions.h"
#include "../lib/CGeneralTextHandler.h" #include "../lib/CGeneralTextHandler.h"
#include "Graphics.h" #include "Graphics.h"
#include "GUIClasses.h" #include "windows/GUIClasses.h"
#include "../lib/CConfigHandler.h" #include "../lib/CConfigHandler.h"
#include "CBitmapHandler.h" #include "CBitmapHandler.h"
#include "gui/CIntObjectClasses.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 BETWEEN_COMPS_ROWS = 10;
const int BEFORE_COMPONENTS = 30; const int BEFORE_COMPONENTS = 30;

View File

@ -2,7 +2,6 @@
#include "../lib/CConfigHandler.h" #include "../lib/CConfigHandler.h"
#include "../lib/CSoundBase.h" #include "../lib/CSoundBase.h"
#include "../lib/CCreatureHandler.h"
/* /*
* CMusicHandler.h, part of VCMI engine * CMusicHandler.h, part of VCMI engine

View File

@ -1,21 +1,24 @@
#include "StdInc.h" #include "StdInc.h"
#include "CAdvmapInterface.h" #include "windows/CAdvmapInterface.h"
#include "battle/CBattleInterface.h" #include "battle/CBattleInterface.h"
#include "battle/CBattleInterfaceClasses.h" #include "battle/CBattleInterfaceClasses.h"
#include "../CCallback.h" #include "../CCallback.h"
#include "CCastleInterface.h" #include "windows/CCastleInterface.h"
#include "gui/CCursorHandler.h" #include "gui/CCursorHandler.h"
#include "CKingdomInterface.h" #include "windows/CKingdomInterface.h"
#include "CGameInfo.h" #include "CGameInfo.h"
#include "CHeroWindow.h" #include "windows/CHeroWindow.h"
#include "CCreatureWindow.h" #include "windows/CCreatureWindow.h"
#include "CQuestLog.h" #include "windows/CQuestLog.h"
#include "CMessage.h" #include "CMessage.h"
#include "CPlayerInterface.h" #include "CPlayerInterface.h"
#include "gui/SDL_Extensions.h" #include "gui/SDL_Extensions.h"
#include "widgets/CComponent.h"
#include "windows/CTradeWindow.h"
#include "../lib/CConfigHandler.h" #include "../lib/CConfigHandler.h"
#include "battle/CCreatureAnimation.h" #include "battle/CCreatureAnimation.h"
#include "Graphics.h" #include "Graphics.h"
#include "windows/GUIClasses.h"
#include "../lib/CArtHandler.h" #include "../lib/CArtHandler.h"
#include "../lib/CGeneralTextHandler.h" #include "../lib/CGeneralTextHandler.h"
#include "../lib/CHeroHandler.h" #include "../lib/CHeroHandler.h"
@ -35,7 +38,9 @@
#include "../lib/CGameState.h" #include "../lib/CGameState.h"
#include "../lib/GameConstants.h" #include "../lib/GameConstants.h"
#include "gui/CGuiHandler.h" #include "gui/CGuiHandler.h"
#include "windows/InfoWindows.h"
#include "../lib/UnlockGuard.h" #include "../lib/UnlockGuard.h"
#include <SDL.h>
#ifdef min #ifdef min
#undef min #undef min
@ -494,10 +499,12 @@ void CPlayerInterface::commanderGotLevel (const CCommanderInstance * commander,
waitWhileDialog(); waitWhileDialog();
CCS->soundh->playSound(soundBase::heroNewLevel); CCS->soundh->playSound(soundBase::heroNewLevel);
CCreatureWindow * cw = new CCreatureWindow(skills, commander, GH.pushInt(new CStackWindow(commander, skills, [=](ui32 selection)
[=](ui32 selection){ cb->selectionMade(selection, queryID); }); {
GH.pushInt(cw); cb->selectionMade(selection, queryID);
}));
} }
void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town) void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
@ -1285,8 +1292,8 @@ void CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
if (adventureInt && adventureInt->isHeroSleeping(h)) if (adventureInt && adventureInt->isHeroSleeping(h))
{ {
adventureInt->sleepWake.clickLeft(true, false); adventureInt->sleepWake->clickLeft(true, false);
adventureInt->sleepWake.clickLeft(false, true); adventureInt->sleepWake->clickLeft(false, true);
//could've just called //could've just called
//adventureInt->fsleepWake(); //adventureInt->fsleepWake();
//but no authentic button click/sound ;-) //but no authentic button click/sound ;-)
@ -1321,7 +1328,7 @@ void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHer
waitForAllDialogs(); waitForAllDialogs();
auto cgw = new CGarrisonWindow(up,down,removableUnits); auto cgw = new CGarrisonWindow(up,down,removableUnits);
cgw->quit->callback += onEnd; cgw->quit->addCallback(onEnd);
GH.pushInt(cgw); GH.pushInt(cgw);
} }
@ -2239,7 +2246,7 @@ void CPlayerInterface::acceptTurn()
if(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.topInt())) if(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.topInt()))
iw->close(); iw->close();
adventureInt->endTurn.callback(); adventureInt->fendTurn();
} }
// warn player if he has no town // warn player if he has no town

View File

@ -1,11 +1,12 @@
#pragma once #pragma once
#include "../lib/CondSh.h" //#include "../lib/CondSh.h"
#include "../lib/FunctionList.h" #include "../lib/FunctionList.h"
#include "../lib/CGameInterface.h" #include "../lib/CGameInterface.h"
#include "../lib/NetPacksBase.h"
#include "gui/CIntObject.h" #include "gui/CIntObject.h"
#include "../lib/CGameState.h" //#include "../lib/CGameState.h"
#ifdef __GNUC__ #ifdef __GNUC__
#define sprintf_s snprintf #define sprintf_s snprintf
@ -29,8 +30,8 @@
*/ */
class CDefEssential; class CDefEssential;
class CAdventureMapButton; class CButton;
class CHighlightableButtonsGroup; class CToggleGroup;
class CDefHandler; class CDefHandler;
struct TryMoveHero; struct TryMoveHero;
class CDefEssential; class CDefEssential;

View File

@ -9,7 +9,6 @@
#include "gui/SDL_Extensions.h" #include "gui/SDL_Extensions.h"
#include "CGameInfo.h" #include "CGameInfo.h"
#include "gui/CCursorHandler.h" #include "gui/CCursorHandler.h"
#include "CAnimation.h"
#include "CDefHandler.h" #include "CDefHandler.h"
#include "../lib/CGeneralTextHandler.h" #include "../lib/CGeneralTextHandler.h"
#include "../lib/CTownHandler.h" #include "../lib/CTownHandler.h"
@ -23,7 +22,7 @@
#include "../lib/Connection.h" #include "../lib/Connection.h"
#include "../lib/VCMIDirs.h" #include "../lib/VCMIDirs.h"
#include "../lib/mapping/CMap.h" #include "../lib/mapping/CMap.h"
#include "GUIClasses.h" #include "windows/GUIClasses.h"
#include "CPlayerInterface.h" #include "CPlayerInterface.h"
#include "../CCallback.h" #include "../CCallback.h"
#include "CMessage.h" #include "CMessage.h"
@ -38,7 +37,13 @@
#include "../lib/CConfigHandler.h" #include "../lib/CConfigHandler.h"
#include "../lib/GameConstants.h" #include "../lib/GameConstants.h"
#include "gui/CGuiHandler.h" #include "gui/CGuiHandler.h"
#include "gui/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/CMapService.h"
#include "../lib/mapping/CMap.h" #include "../lib/mapping/CMap.h"
#include "../lib/CRandomGenerator.h" #include "../lib/CRandomGenerator.h"
@ -367,7 +372,7 @@ static std::function<void()> genCommand(CMenuScreen* menu, std::vector<std::stri
return std::function<void()>(); return std::function<void()>();
} }
CAdventureMapButton* CMenuEntry::createButton(CMenuScreen* parent, const JsonNode& button) CButton* CMenuEntry::createButton(CMenuScreen* parent, const JsonNode& button)
{ {
std::function<void()> command = genCommand(parent, parent->menuNameToEntry, button["command"].String()); std::function<void()> command = genCommand(parent, parent->menuNameToEntry, button["command"].String());
@ -383,7 +388,7 @@ CAdventureMapButton* CMenuEntry::createButton(CMenuScreen* parent, const JsonNod
if (posy < 0) if (posy < 0)
posy = pos.h + posy; posy = pos.h + posy;
return new CAdventureMapButton(help, command, posx, posy, button["name"].String(), button["hotkey"].Float()); return new CButton(Point(posx, posy), button["name"].String(), help, command, button["hotkey"].Float());
} }
CMenuEntry::CMenuEntry(CMenuScreen* parent, const JsonNode &config) CMenuEntry::CMenuEntry(CMenuScreen* parent, const JsonNode &config)
@ -639,38 +644,39 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
{ {
case CMenuScreen::newGame: case CMenuScreen::newGame:
{ {
card->difficulty->onChange = std::bind(&CSelectionScreen::difficultyChange, this, _1); SDL_Color orange = {232, 184, 32, 0};
card->difficulty->select(1, 0); SDL_Color overlayColor = multiPlayer == CMenuScreen::MULTI_NETWORK_GUEST ? orange : Colors::WHITE;
CAdventureMapButton * select = new CAdventureMapButton(CGI->generaltexth->zelp[45], 0, 411, 80, "GSPBUTT.DEF", SDLK_s);
select->callback = [&]() card->difficulty->addCallback(std::bind(&CSelectionScreen::difficultyChange, this, _1));
card->difficulty->setSelected(1);
CButton * select = new CButton(Point(411, 80), "GSPBUTT.DEF", CGI->generaltexth->zelp[45], 0, SDLK_s);
select->addCallback([&]()
{ {
toggleTab(sel); toggleTab(sel);
changeSelection(sel->getSelectedMapInfo()); changeSelection(sel->getSelectedMapInfo());
}; });
select->addTextOverlay(CGI->generaltexth->allTexts[500], FONT_SMALL); select->addTextOverlay(CGI->generaltexth->allTexts[500], FONT_SMALL, overlayColor);
CAdventureMapButton *opts = new CAdventureMapButton(CGI->generaltexth->zelp[46], std::bind(&CSelectionScreen::toggleTab, this, opt), 411, 510, "GSPBUTT.DEF", SDLK_a); CButton *opts = new CButton(Point(411, 510), "GSPBUTT.DEF", CGI->generaltexth->zelp[46], boost::bind(&CSelectionScreen::toggleTab, this, opt), SDLK_a);
opts->addTextOverlay(CGI->generaltexth->allTexts[501], FONT_SMALL); opts->addTextOverlay(CGI->generaltexth->allTexts[501], FONT_SMALL, overlayColor);
CAdventureMapButton * randomBtn = new CAdventureMapButton(CGI->generaltexth->zelp[47], 0, 411, 105, "GSPBUTT.DEF", SDLK_r); CButton * randomBtn = new CButton(Point(411, 105), "GSPBUTT.DEF", CGI->generaltexth->zelp[47], 0, SDLK_r);
randomBtn->addTextOverlay(CGI->generaltexth->allTexts[740], FONT_SMALL); randomBtn->addTextOverlay(CGI->generaltexth->allTexts[740], FONT_SMALL, overlayColor);
randomBtn->callback = [&]() randomBtn->addCallback([&]()
{ {
toggleTab(randMapTab); toggleTab(randMapTab);
changeSelection(randMapTab->getMapInfo()); changeSelection(randMapTab->getMapInfo());
}; });
start = new CAdventureMapButton(CGI->generaltexth->zelp[103], std::bind(&CSelectionScreen::startScenario, this), 411, 535, "SCNRBEG.DEF", SDLK_b); start = new CButton(Point(411, 535), "SCNRBEG.DEF", CGI->generaltexth->zelp[103], boost::bind(&CSelectionScreen::startScenario, this), SDLK_b);
if(network) if(network)
{ {
CAdventureMapButton *hideChat = new CAdventureMapButton(CGI->generaltexth->zelp[48], std::bind(&InfoCard::toggleChat, card), 619, 83, "GSPBUT2.DEF", SDLK_h); CButton *hideChat = new CButton(Point(619, 83), "GSPBUT2.DEF", CGI->generaltexth->zelp[48], boost::bind(&InfoCard::toggleChat, card), SDLK_h);
hideChat->addTextOverlay(CGI->generaltexth->allTexts[531], FONT_SMALL); hideChat->addTextOverlay(CGI->generaltexth->allTexts[531], FONT_SMALL);
if(multiPlayer == CMenuScreen::MULTI_NETWORK_GUEST) if(multiPlayer == CMenuScreen::MULTI_NETWORK_GUEST)
{ {
SDL_Color orange = {232, 184, 32, 0};
select->text->color = opts->text->color = randomBtn->text->color = orange;
select->block(true); select->block(true);
opts->block(true); opts->block(true);
randomBtn->block(true); randomBtn->block(true);
@ -681,21 +687,21 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
break; break;
case CMenuScreen::loadGame: case CMenuScreen::loadGame:
sel->recActions = 255; sel->recActions = 255;
start = new CAdventureMapButton(CGI->generaltexth->zelp[103], std::bind(&CSelectionScreen::startScenario, this), 411, 535, "SCNRLOD.DEF", SDLK_l); start = new CButton(Point(411, 535), "SCNRLOD.DEF", CGI->generaltexth->zelp[103], boost::bind(&CSelectionScreen::startScenario, this), SDLK_l);
break; break;
case CMenuScreen::saveGame: case CMenuScreen::saveGame:
sel->recActions = 255; sel->recActions = 255;
start = new CAdventureMapButton("", CGI->generaltexth->zelp[103].second, std::bind(&CSelectionScreen::startScenario, this), 411, 535, "SCNRSAV.DEF"); start = new CButton(Point(411, 535), "SCNRSAV.DEF", CGI->generaltexth->zelp[103], boost::bind(&CSelectionScreen::startScenario, this), SDLK_s);
break; break;
case CMenuScreen::campaignList: case CMenuScreen::campaignList:
sel->recActions = 255; sel->recActions = 255;
start = new CAdventureMapButton(std::pair<std::string, std::string>(), std::bind(&CSelectionScreen::startCampaign, this), 411, 535, "SCNRLOD.DEF", SDLK_b); start = new CButton(Point(411, 535), "SCNRLOD.DEF", CButton::tooltip(), boost::bind(&CSelectionScreen::startCampaign, this), SDLK_b);
break; break;
} }
start->assignedKeys.insert(SDLK_RETURN); start->assignedKeys.insert(SDLK_RETURN);
back = new CAdventureMapButton("", CGI->generaltexth->zelp[105].second, std::bind(&CGuiHandler::popIntTotally, &GH, this), 581, 535, "SCNRBACK.DEF", SDLK_ESCAPE); back = new CButton(Point(581, 535), "SCNRBACK.DEF", CGI->generaltexth->zelp[105], boost::bind(&CGuiHandler::popIntTotally, &GH, this), SDLK_ESCAPE);
if(network) if(network)
{ {
@ -995,7 +1001,7 @@ void CSelectionScreen::setSInfo(const StartInfo &si)
if(current) if(current)
opt->recreate(); //will force to recreate using current sInfo opt->recreate(); //will force to recreate using current sInfo
card->difficulty->select(si.difficulty, 0); card->difficulty->setSelected(si.difficulty);
GH.totalRedraw(); GH.totalRedraw();
} }
@ -1258,7 +1264,7 @@ SelectionTab::SelectionTab(CMenuScreen::EState Type, const std::function<void(CM
int sizes[] = {36, 72, 108, 144, 0}; int sizes[] = {36, 72, 108, 144, 0};
const char * names[] = {"SCSMBUT.DEF", "SCMDBUT.DEF", "SCLGBUT.DEF", "SCXLBUT.DEF", "SCALBUT.DEF"}; const char * names[] = {"SCSMBUT.DEF", "SCMDBUT.DEF", "SCLGBUT.DEF", "SCXLBUT.DEF", "SCALBUT.DEF"};
for(int i = 0; i < 5; i++) for(int i = 0; i < 5; i++)
new CAdventureMapButton("", CGI->generaltexth->zelp[54+i].second, std::bind(&SelectionTab::filter, this, sizes[i], true), 158 + 47*i, 46, names[i]); new CButton(Point(158 + 47*i, 46), names[i], CGI->generaltexth->zelp[54+i], boost::bind(&SelectionTab::filter, this, sizes[i], true));
} }
//sort buttons buttons //sort buttons buttons
@ -1272,20 +1278,19 @@ SelectionTab::SelectionTab(CMenuScreen::EState Type, const std::function<void(CM
if(criteria == _name) if(criteria == _name)
criteria = generalSortingBy; criteria = generalSortingBy;
new CAdventureMapButton("", CGI->generaltexth->zelp[107+i].second, std::bind(&SelectionTab::sortBy, this, criteria), xpos[i], 86, names[i]); new CButton(Point(xpos[i], 86), names[i], CGI->generaltexth->zelp[107+i], boost::bind(&SelectionTab::sortBy, this, criteria));
} }
} }
} }
else else
{ {
//sort by buttons //sort by buttons
new CAdventureMapButton("", "", std::bind(&SelectionTab::sortBy, this, _numOfMaps), 23, 86, "CamCusM.DEF"); //by num of maps new CButton(Point(23, 86), "CamCusM.DEF", CButton::tooltip(), boost::bind(&SelectionTab::sortBy, this, _numOfMaps)); //by num of maps
new CAdventureMapButton("", "", std::bind(&SelectionTab::sortBy, this, _name), 55, 86, "CamCusL.DEF"); //by name new CButton(Point(55, 86), "CamCusL.DEF", CButton::tooltip(), boost::bind(&SelectionTab::sortBy, this, _name)); //by name
} }
slider = new CSlider(372, 86, tabType != CMenuScreen::saveGame ? 480 : 430, std::bind(&SelectionTab::sliderMove, this, _1), positions, curItems.size(), 0, false, 1); slider = new CSlider(Point(372, 86), tabType != CMenuScreen::saveGame ? 480 : 430, boost::bind(&SelectionTab::sliderMove, this, _1), positions, curItems.size(), 0, false, CSlider::BLUE);
slider->addUsedEvents(WHEEL); slider->addUsedEvents(WHEEL);
slider->slider->keepFrame = true;
format = CDefHandler::giveDef("SCSELC.DEF"); format = CDefHandler::giveDef("SCSELC.DEF");
sortingBy = _format; sortingBy = _format;
@ -1351,16 +1356,16 @@ void SelectionTab::select( int position )
if(!curItems.size()) return; if(!curItems.size()) return;
// New selection. py is the index in curItems. // New selection. py is the index in curItems.
int py = position + slider->value; int py = position + slider->getValue();
vstd::amax(py, 0); vstd::amax(py, 0);
vstd::amin(py, curItems.size()-1); vstd::amin(py, curItems.size()-1);
selectionPos = py; selectionPos = py;
if(position < 0) if(position < 0)
slider->moveTo(slider->value + position); slider->moveBy(position);
else if(position >= positions) else if(position >= positions)
slider->moveTo(slider->value + position - positions + 1); slider->moveBy(position - positions + 1);
if(txt) if(txt)
{ {
@ -1374,7 +1379,7 @@ void SelectionTab::select( int position )
void SelectionTab::selectAbs( int position ) void SelectionTab::selectAbs( int position )
{ {
select(position - slider->value); select(position - slider->getValue());
} }
int SelectionTab::getPosition( int x, int y ) int SelectionTab::getPosition( int x, int y )
@ -1397,7 +1402,7 @@ void SelectionTab::sliderMove( int slidPos )
void SelectionTab::printMaps(SDL_Surface *to) void SelectionTab::printMaps(SDL_Surface *to)
{ {
int elemIdx = slider->value; int elemIdx = slider->getValue();
// Display all elements if there's enough space // Display all elements if there's enough space
//if(slider->amount < slider->capacity) //if(slider->amount < slider->capacity)
@ -1555,15 +1560,15 @@ void SelectionTab::keyPressed( const SDL_KeyboardEvent & key )
moveBy = +positions-1; moveBy = +positions-1;
break; break;
case SDLK_HOME: case SDLK_HOME:
select(-slider->value); select(-slider->getValue());
return; return;
case SDLK_END: case SDLK_END:
select(curItems.size() - slider->value); select(curItems.size() - slider->getValue());
return; return;
default: default:
return; return;
} }
select(selectionPos - slider->value + moveBy); select(selectionPos - slider->getValue() + moveBy);
} }
void SelectionTab::onDoubleClick() void SelectionTab::onDoubleClick()
@ -1571,7 +1576,7 @@ void SelectionTab::onDoubleClick()
if(getLine() != -1) //double clicked scenarios list if(getLine() != -1) //double clicked scenarios list
{ {
//act as if start button was pressed //act as if start button was pressed
(static_cast<CSelectionScreen*>(parent))->start->callback(); (static_cast<CSelectionScreen*>(parent))->start->clickLeft(false, true);
} }
} }
@ -1616,27 +1621,25 @@ CRandomMapTab::CRandomMapTab()
bg = new CPicture("RANMAPBK", 0, 6); bg = new CPicture("RANMAPBK", 0, 6);
// Map Size // Map Size
mapSizeBtnGroup = new CHighlightableButtonsGroup(0); mapSizeBtnGroup = new CToggleGroup(0);
mapSizeBtnGroup->pos.y += 81; mapSizeBtnGroup->pos.y += 81;
mapSizeBtnGroup->pos.x += 158; mapSizeBtnGroup->pos.x += 158;
const std::vector<std::string> mapSizeBtns = boost::assign::list_of("RANSIZS")("RANSIZM")("RANSIZL")("RANSIZX"); const std::vector<std::string> mapSizeBtns = boost::assign::list_of("RANSIZS")("RANSIZM")("RANSIZL")("RANSIZX");
addButtonsToGroup(mapSizeBtnGroup, mapSizeBtns, 0, 3, 47, 198); addButtonsToGroup(mapSizeBtnGroup, mapSizeBtns, 0, 3, 47, 198);
mapSizeBtnGroup->select(1, false); mapSizeBtnGroup->setSelected(1);
mapSizeBtnGroup->onChange = [&](int btnId) mapSizeBtnGroup->addCallback([&](int btnId)
{ {
const std::vector<int> mapSizeVal = boost::assign::list_of(CMapHeader::MAP_SIZE_SMALL)(CMapHeader::MAP_SIZE_MIDDLE) const std::vector<int> mapSizeVal = boost::assign::list_of(CMapHeader::MAP_SIZE_SMALL)(CMapHeader::MAP_SIZE_MIDDLE)
(CMapHeader::MAP_SIZE_LARGE)(CMapHeader::MAP_SIZE_XLARGE); (CMapHeader::MAP_SIZE_LARGE)(CMapHeader::MAP_SIZE_XLARGE);
mapGenOptions.setWidth(mapSizeVal[btnId]); mapGenOptions.setWidth(mapSizeVal[btnId]);
mapGenOptions.setHeight(mapSizeVal[btnId]); mapGenOptions.setHeight(mapSizeVal[btnId]);
updateMapInfo(); updateMapInfo();
}; });
// Two levels // Two levels
twoLevelsBtn = new CHighlightableButton(0, 0, std::map<int,std::string>(), twoLevelsBtn = new CToggleButton(Point(346, 81), "RANUNDR", CGI->generaltexth->zelp[202]);
CGI->generaltexth->zelp[202].second, false, "RANUNDR", nullptr, 346, 81);
//twoLevelsBtn->select(true); for now, deactivated //twoLevelsBtn->select(true); for now, deactivated
twoLevelsBtn->callback = [&]() { mapGenOptions.setHasTwoLevels(true); updateMapInfo(); }; twoLevelsBtn->addCallback([&](bool on) { mapGenOptions.setHasTwoLevels(on); updateMapInfo(); });
twoLevelsBtn->callback2 = [&]() { mapGenOptions.setHasTwoLevels(false); updateMapInfo(); };
// Create number defs list // Create number defs list
std::vector<std::string> numberDefs; std::vector<std::string> numberDefs;
@ -1648,128 +1651,130 @@ CRandomMapTab::CRandomMapTab()
const int NUMBERS_WIDTH = 32; const int NUMBERS_WIDTH = 32;
const int BTNS_GROUP_LEFT_MARGIN = 67; const int BTNS_GROUP_LEFT_MARGIN = 67;
// Amount of players // Amount of players
playersCntGroup = new CHighlightableButtonsGroup(0); playersCntGroup = new CToggleGroup(0);
playersCntGroup->pos.y += 153; playersCntGroup->pos.y += 153;
playersCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN; playersCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
addButtonsWithRandToGroup(playersCntGroup, numberDefs, 1, 8, NUMBERS_WIDTH, 204, 212); addButtonsWithRandToGroup(playersCntGroup, numberDefs, 1, 8, NUMBERS_WIDTH, 204, 212);
playersCntGroup->onChange = [&](int btnId) playersCntGroup->addCallback([&](int btnId)
{ {
mapGenOptions.setPlayerCount(btnId); mapGenOptions.setPlayerCount(btnId);
deactivateButtonsFrom(teamsCntGroup, btnId); deactivateButtonsFrom(teamsCntGroup, btnId);
deactivateButtonsFrom(compOnlyPlayersCntGroup, 8 - btnId + 1); deactivateButtonsFrom(compOnlyPlayersCntGroup, 8 - btnId + 1);
validatePlayersCnt(btnId); validatePlayersCnt(btnId);
updateMapInfo(); updateMapInfo();
}; });
// Amount of teams // Amount of teams
teamsCntGroup = new CHighlightableButtonsGroup(0); teamsCntGroup = new CToggleGroup(0);
teamsCntGroup->pos.y += 219; teamsCntGroup->pos.y += 219;
teamsCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN; teamsCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
addButtonsWithRandToGroup(teamsCntGroup, numberDefs, 0, 7, NUMBERS_WIDTH, 214, 222); addButtonsWithRandToGroup(teamsCntGroup, numberDefs, 0, 7, NUMBERS_WIDTH, 214, 222);
teamsCntGroup->onChange = [&](int btnId) teamsCntGroup->addCallback([&](int btnId)
{ {
mapGenOptions.setTeamCount(btnId); mapGenOptions.setTeamCount(btnId);
updateMapInfo(); updateMapInfo();
}; });
// Computer only players // Computer only players
compOnlyPlayersCntGroup = new CHighlightableButtonsGroup(0); compOnlyPlayersCntGroup = new CToggleGroup(0);
compOnlyPlayersCntGroup->pos.y += 285; compOnlyPlayersCntGroup->pos.y += 285;
compOnlyPlayersCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN; compOnlyPlayersCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
addButtonsWithRandToGroup(compOnlyPlayersCntGroup, numberDefs, 0, 7, NUMBERS_WIDTH, 224, 232); addButtonsWithRandToGroup(compOnlyPlayersCntGroup, numberDefs, 0, 7, NUMBERS_WIDTH, 224, 232);
compOnlyPlayersCntGroup->select(0, true); compOnlyPlayersCntGroup->setSelected(0);
compOnlyPlayersCntGroup->onChange = [&](int btnId) compOnlyPlayersCntGroup->addCallback([&](int btnId)
{ {
mapGenOptions.setCompOnlyPlayerCount(btnId); mapGenOptions.setCompOnlyPlayerCount(btnId);
deactivateButtonsFrom(compOnlyTeamsCntGroup, btnId); deactivateButtonsFrom(compOnlyTeamsCntGroup, btnId);
validateCompOnlyPlayersCnt(btnId); validateCompOnlyPlayersCnt(btnId);
updateMapInfo(); updateMapInfo();
}; });
// Computer only teams // Computer only teams
compOnlyTeamsCntGroup = new CHighlightableButtonsGroup(0); compOnlyTeamsCntGroup = new CToggleGroup(0);
compOnlyTeamsCntGroup->pos.y += 351; compOnlyTeamsCntGroup->pos.y += 351;
compOnlyTeamsCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN; compOnlyTeamsCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
addButtonsWithRandToGroup(compOnlyTeamsCntGroup, numberDefs, 0, 6, NUMBERS_WIDTH, 234, 241); addButtonsWithRandToGroup(compOnlyTeamsCntGroup, numberDefs, 0, 6, NUMBERS_WIDTH, 234, 241);
deactivateButtonsFrom(compOnlyTeamsCntGroup, 0); deactivateButtonsFrom(compOnlyTeamsCntGroup, 0);
compOnlyTeamsCntGroup->onChange = [&](int btnId) compOnlyTeamsCntGroup->addCallback([&](int btnId)
{ {
mapGenOptions.setCompOnlyTeamCount(btnId); mapGenOptions.setCompOnlyTeamCount(btnId);
updateMapInfo(); updateMapInfo();
}; });
const int WIDE_BTN_WIDTH = 85; const int WIDE_BTN_WIDTH = 85;
// Water content // Water content
waterContentGroup = new CHighlightableButtonsGroup(0); waterContentGroup = new CToggleGroup(0);
waterContentGroup->pos.y += 419; waterContentGroup->pos.y += 419;
waterContentGroup->pos.x += BTNS_GROUP_LEFT_MARGIN; waterContentGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
const std::vector<std::string> waterContentBtns = boost::assign::list_of("RANNONE")("RANNORM")("RANISLD"); const std::vector<std::string> waterContentBtns = boost::assign::list_of("RANNONE")("RANNORM")("RANISLD");
addButtonsWithRandToGroup(waterContentGroup, waterContentBtns, 0, 2, WIDE_BTN_WIDTH, 243, 246); addButtonsWithRandToGroup(waterContentGroup, waterContentBtns, 0, 2, WIDE_BTN_WIDTH, 243, 246);
waterContentGroup->onChange = [&](int btnId) waterContentGroup->addCallback([&](int btnId)
{ {
mapGenOptions.setWaterContent(static_cast<EWaterContent::EWaterContent>(btnId)); mapGenOptions.setWaterContent(static_cast<EWaterContent::EWaterContent>(btnId));
}; });
// Monster strength // Monster strength
monsterStrengthGroup = new CHighlightableButtonsGroup(0); monsterStrengthGroup = new CToggleGroup(0);
monsterStrengthGroup->pos.y += 485; monsterStrengthGroup->pos.y += 485;
monsterStrengthGroup->pos.x += BTNS_GROUP_LEFT_MARGIN; monsterStrengthGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
const std::vector<std::string> monsterStrengthBtns = boost::assign::list_of("RANWEAK")("RANNORM")("RANSTRG"); const std::vector<std::string> monsterStrengthBtns = boost::assign::list_of("RANWEAK")("RANNORM")("RANSTRG");
addButtonsWithRandToGroup(monsterStrengthGroup, monsterStrengthBtns, 0, 2, WIDE_BTN_WIDTH, 248, 251); addButtonsWithRandToGroup(monsterStrengthGroup, monsterStrengthBtns, 0, 2, WIDE_BTN_WIDTH, 248, 251);
monsterStrengthGroup->onChange = [&](int btnId) monsterStrengthGroup->addCallback([&](int btnId)
{ {
if (btnId < 0) if (btnId < 0)
mapGenOptions.setMonsterStrength(EMonsterStrength::RANDOM); mapGenOptions.setMonsterStrength(EMonsterStrength::RANDOM);
else else
mapGenOptions.setMonsterStrength(static_cast<EMonsterStrength::EMonsterStrength>(btnId + EMonsterStrength::GLOBAL_WEAK)); //value 2 to 4 mapGenOptions.setMonsterStrength(static_cast<EMonsterStrength::EMonsterStrength>(btnId + EMonsterStrength::GLOBAL_WEAK)); //value 2 to 4
}; });
// Show random maps btn // Show random maps btn
showRandMaps = new CAdventureMapButton("", CGI->generaltexth->zelp[252].second, 0, 54, 535, "RANSHOW"); showRandMaps = new CButton(Point(54, 535), "RANSHOW", CGI->generaltexth->zelp[252]);
// Initialize map info object // Initialize map info object
updateMapInfo(); updateMapInfo();
} }
void CRandomMapTab::addButtonsWithRandToGroup(CHighlightableButtonsGroup * group, const std::vector<std::string> & defs, int nStart, int nEnd, int btnWidth, int helpStartIndex, int helpRandIndex) const void CRandomMapTab::addButtonsWithRandToGroup(CToggleGroup * group, const std::vector<std::string> & defs, int nStart, int nEnd, int btnWidth, int helpStartIndex, int helpRandIndex) const
{ {
addButtonsToGroup(group, defs, nStart, nEnd, btnWidth, helpStartIndex); addButtonsToGroup(group, defs, nStart, nEnd, btnWidth, helpStartIndex);
// Buttons are relative to button group, TODO better solution? // Buttons are relative to button group, TODO better solution?
SObjectConstruction obj__i(group); SObjectConstruction obj__i(group);
const std::string RANDOM_DEF = "RANRAND"; const std::string RANDOM_DEF = "RANRAND";
group->addButton(new CHighlightableButton("", CGI->generaltexth->zelp[helpRandIndex].second, 0, 256, 0, RANDOM_DEF, CMapGenOptions::RANDOM_SIZE)); group->addToggle(CMapGenOptions::RANDOM_SIZE, new CToggleButton(Point(256, 0), RANDOM_DEF, CGI->generaltexth->zelp[helpRandIndex]));
group->select(CMapGenOptions::RANDOM_SIZE, true); group->setSelected(CMapGenOptions::RANDOM_SIZE);
} }
void CRandomMapTab::addButtonsToGroup(CHighlightableButtonsGroup * group, const std::vector<std::string> & defs, int nStart, int nEnd, int btnWidth, int helpStartIndex) const void CRandomMapTab::addButtonsToGroup(CToggleGroup * group, const std::vector<std::string> & defs, int nStart, int nEnd, int btnWidth, int helpStartIndex) const
{ {
// Buttons are relative to button group, TODO better solution? // Buttons are relative to button group, TODO better solution?
SObjectConstruction obj__i(group); SObjectConstruction obj__i(group);
int cnt = nEnd - nStart + 1; int cnt = nEnd - nStart + 1;
for(int i = 0; i < cnt; ++i) for(int i = 0; i < cnt; ++i)
{ {
group->addButton(new CHighlightableButton("", CGI->generaltexth->zelp[helpStartIndex + i].second, 0, i * btnWidth, 0, defs[i + nStart], i + nStart)); auto button = new CToggleButton(Point(i * btnWidth, 0), defs[i + nStart], CGI->generaltexth->zelp[helpStartIndex + i]);
// For blocked state we should use pressed image actually
button->setImageOrder(0, 1, 1, 3);
group->addToggle(i + nStart, button);
} }
} }
void CRandomMapTab::deactivateButtonsFrom(CHighlightableButtonsGroup * group, int startId) void CRandomMapTab::deactivateButtonsFrom(CToggleGroup * group, int startId)
{ {
for(CHighlightableButton * btn : group->buttons) logGlobal->infoStream() << "Blocking buttons from " << startId;
for(auto toggle : group->buttons)
{ {
if(startId == CMapGenOptions::RANDOM_SIZE || btn->ID < startId) if (auto button = dynamic_cast<CToggleButton*>(toggle.second))
{ {
if(btn->isBlocked()) if(startId == CMapGenOptions::RANDOM_SIZE || toggle.first < startId)
{ {
btn->setOffset(0); button->block(false);
btn->setState(CButtonBase::NORMAL); }
else
{
button->block(true);
} }
}
else
{
// Blocked state looks like frame 'selected'=1
btn->setOffset(-1);
btn->setState(CButtonBase::BLOCKED);
} }
} }
} }
@ -1784,12 +1789,12 @@ void CRandomMapTab::validatePlayersCnt(int playersCnt)
if(mapGenOptions.getTeamCount() >= playersCnt) if(mapGenOptions.getTeamCount() >= playersCnt)
{ {
mapGenOptions.setTeamCount(playersCnt - 1); mapGenOptions.setTeamCount(playersCnt - 1);
teamsCntGroup->select(mapGenOptions.getTeamCount(), true); teamsCntGroup->setSelected(mapGenOptions.getTeamCount());
} }
if(mapGenOptions.getCompOnlyPlayerCount() > 8 - playersCnt) if(mapGenOptions.getCompOnlyPlayerCount() > 8 - playersCnt)
{ {
mapGenOptions.setCompOnlyPlayerCount(8 - playersCnt); mapGenOptions.setCompOnlyPlayerCount(8 - playersCnt);
compOnlyPlayersCntGroup->select(mapGenOptions.getCompOnlyPlayerCount(), true); compOnlyPlayersCntGroup->setSelected(mapGenOptions.getCompOnlyPlayerCount());
} }
validateCompOnlyPlayersCnt(mapGenOptions.getCompOnlyPlayerCount()); validateCompOnlyPlayersCnt(mapGenOptions.getCompOnlyPlayerCount());
@ -1805,7 +1810,7 @@ void CRandomMapTab::validateCompOnlyPlayersCnt(int compOnlyPlayersCnt)
if(mapGenOptions.getCompOnlyTeamCount() >= compOnlyPlayersCnt) if(mapGenOptions.getCompOnlyTeamCount() >= compOnlyPlayersCnt)
{ {
mapGenOptions.setCompOnlyTeamCount(compOnlyPlayersCnt - 1); mapGenOptions.setCompOnlyTeamCount(compOnlyPlayersCnt - 1);
compOnlyTeamsCntGroup->select(mapGenOptions.getCompOnlyTeamCount(), true); compOnlyTeamsCntGroup->setSelected(mapGenOptions.getCompOnlyTeamCount());
} }
} }
@ -1960,20 +1965,20 @@ InfoCard::InfoCard( bool Network )
pos.h = bg->pos.h; pos.h = bg->pos.h;
sizes = CDefHandler::giveDef("SCNRMPSZ.DEF"); sizes = CDefHandler::giveDef("SCNRMPSZ.DEF");
sFlags = CDefHandler::giveDef("ITGFLAGS.DEF"); sFlags = CDefHandler::giveDef("ITGFLAGS.DEF");
difficulty = new CHighlightableButtonsGroup(0); difficulty = new CToggleGroup(0);
{ {
static const char *difButns[] = {"GSPBUT3.DEF", "GSPBUT4.DEF", "GSPBUT5.DEF", "GSPBUT6.DEF", "GSPBUT7.DEF"}; static const char *difButns[] = {"GSPBUT3.DEF", "GSPBUT4.DEF", "GSPBUT5.DEF", "GSPBUT6.DEF", "GSPBUT7.DEF"};
for(int i = 0; i < 5; i++) for(int i = 0; i < 5; i++)
{ {
difficulty->addButton(new CHighlightableButton("", CGI->generaltexth->zelp[24+i].second, 0, 110 + i*32, 450, difButns[i], i)); auto button = new CToggleButton(Point(110 + i*32, 450), difButns[i], CGI->generaltexth->zelp[24+i]);
difficulty->addToggle(i, button);
if(SEL->screenType != CMenuScreen::newGame)
button->block(true);
} }
} }
if(SEL->screenType != CMenuScreen::newGame)
difficulty->block(true);
if(network) if(network)
{ {
playerListBg = new CPicture("CHATPLUG.bmp", 16, 276); playerListBg = new CPicture("CHATPLUG.bmp", 16, 276);
@ -2161,8 +2166,8 @@ void InfoCard::changeSelection( const CMapInfo *to )
mapDescription->setText(to->mapHeader->description); mapDescription->setText(to->mapHeader->description);
if(SEL->screenType != CMenuScreen::newGame && SEL->screenType != CMenuScreen::campaignList) { if(SEL->screenType != CMenuScreen::newGame && SEL->screenType != CMenuScreen::campaignList) {
difficulty->block(true); //difficulty->block(true);
difficulty->select(SEL->sInfo.difficulty, 0); difficulty->setSelected(SEL->sInfo.difficulty);
} }
} }
redraw(); redraw();
@ -2242,7 +2247,7 @@ OptionsTab::OptionsTab():
pos = bg->pos; pos = bg->pos;
if(SEL->screenType == CMenuScreen::newGame) if(SEL->screenType == CMenuScreen::newGame)
turnDuration = new CSlider(55, 551, 194, std::bind(&OptionsTab::setTurnLength, this, _1), 1, 11, 11, true, 1); turnDuration = new CSlider(Point(55, 551), 194, boost::bind(&OptionsTab::setTurnLength, this, _1), 1, 11, 11, true, CSlider::BLUE);
} }
OptionsTab::~OptionsTab() OptionsTab::~OptionsTab()
@ -2261,7 +2266,7 @@ void OptionsTab::showAll(SDL_Surface * to)
printAtMiddleWBLoc(CGI->generaltexth->allTexts[520], 349, 110, FONT_SMALL, 70, Colors::YELLOW, to); //Starting Bonus printAtMiddleWBLoc(CGI->generaltexth->allTexts[520], 349, 110, FONT_SMALL, 70, Colors::YELLOW, to); //Starting Bonus
printAtMiddleLoc(CGI->generaltexth->allTexts[521], 222, 538, FONT_SMALL, Colors::YELLOW, to); // Player Turn Duration printAtMiddleLoc(CGI->generaltexth->allTexts[521], 222, 538, FONT_SMALL, Colors::YELLOW, to); // Player Turn Duration
if (turnDuration) if (turnDuration)
printAtMiddleLoc(CGI->generaltexth->turnDurations[turnDuration->value], 319,559, FONT_SMALL, Colors::WHITE, to);//Turn duration value printAtMiddleLoc(CGI->generaltexth->turnDurations[turnDuration->getValue()], 319,559, FONT_SMALL, Colors::WHITE, to);//Turn duration value
} }
void OptionsTab::nextCastle( PlayerColor player, int dir ) void OptionsTab::nextCastle( PlayerColor player, int dir )
@ -2546,12 +2551,12 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry( OptionsTab *owner, PlayerSet
bg = new CPicture(BitmapHandler::loadBitmap(bgs[s.color.getNum()]), 0, 0, true); bg = new CPicture(BitmapHandler::loadBitmap(bgs[s.color.getNum()]), 0, 0, true);
if(SEL->screenType == CMenuScreen::newGame) if(SEL->screenType == CMenuScreen::newGame)
{ {
btns[0] = new CAdventureMapButton(CGI->generaltexth->zelp[132], std::bind(&OptionsTab::nextCastle, owner, s.color, -1), 107, 5, "ADOPLFA.DEF"); btns[0] = new CButton(Point(107, 5), "ADOPLFA.DEF", CGI->generaltexth->zelp[132], boost::bind(&OptionsTab::nextCastle, owner, s.color, -1));
btns[1] = new CAdventureMapButton(CGI->generaltexth->zelp[133], std::bind(&OptionsTab::nextCastle, owner, s.color, +1), 168, 5, "ADOPRTA.DEF"); btns[1] = new CButton(Point(168, 5), "ADOPRTA.DEF", CGI->generaltexth->zelp[133], boost::bind(&OptionsTab::nextCastle, owner, s.color, +1));
btns[2] = new CAdventureMapButton(CGI->generaltexth->zelp[148], std::bind(&OptionsTab::nextHero, owner, s.color, -1), 183, 5, "ADOPLFA.DEF"); btns[2] = new CButton(Point(183, 5), "ADOPLFA.DEF", CGI->generaltexth->zelp[148], boost::bind(&OptionsTab::nextHero, owner, s.color, -1));
btns[3] = new CAdventureMapButton(CGI->generaltexth->zelp[149], std::bind(&OptionsTab::nextHero, owner, s.color, +1), 244, 5, "ADOPRTA.DEF"); btns[3] = new CButton(Point(244, 5), "ADOPRTA.DEF", CGI->generaltexth->zelp[149], boost::bind(&OptionsTab::nextHero, owner, s.color, +1));
btns[4] = new CAdventureMapButton(CGI->generaltexth->zelp[164], std::bind(&OptionsTab::nextBonus, owner, s.color, -1), 259, 5, "ADOPLFA.DEF"); btns[4] = new CButton(Point(259, 5), "ADOPLFA.DEF", CGI->generaltexth->zelp[164], boost::bind(&OptionsTab::nextBonus, owner, s.color, -1));
btns[5] = new CAdventureMapButton(CGI->generaltexth->zelp[165], std::bind(&OptionsTab::nextBonus, owner, s.color, +1), 320, 5, "ADOPRTA.DEF"); btns[5] = new CButton(Point(320, 5), "ADOPRTA.DEF", CGI->generaltexth->zelp[165], boost::bind(&OptionsTab::nextBonus, owner, s.color, +1));
} }
else else
for(auto & elem : btns) for(auto & elem : btns)
@ -2573,7 +2578,7 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry( OptionsTab *owner, PlayerSet
&& SEL->current->mapHeader->players[s.color.getNum()].canHumanPlay && SEL->current->mapHeader->players[s.color.getNum()].canHumanPlay
&& SEL->multiPlayer != CMenuScreen::MULTI_NETWORK_GUEST) && SEL->multiPlayer != CMenuScreen::MULTI_NETWORK_GUEST)
{ {
flag = new CAdventureMapButton(CGI->generaltexth->zelp[180], std::bind(&OptionsTab::flagPressed, owner, s.color), -43, 2, flags[s.color.getNum()]); flag = new CButton(Point(-43, 2), flags[s.color.getNum()], CGI->generaltexth->zelp[180], boost::bind(&OptionsTab::flagPressed, owner, s.color));
flag->hoverable = true; flag->hoverable = true;
} }
else else
@ -2979,8 +2984,8 @@ CScenarioInfo::CScenarioInfo(const CMapHeader *mapHeader, const StartInfo *start
opt->recreate(); opt->recreate();
card->changeSelection(current); card->changeSelection(current);
card->difficulty->select(startInfo->difficulty, 0); card->difficulty->setSelected(startInfo->difficulty);
back = new CAdventureMapButton("", CGI->generaltexth->zelp[105].second, std::bind(&CGuiHandler::popIntTotally, &GH, this), 584, 535, "SCNRBACK.DEF", SDLK_ESCAPE); back = new CButton(Point(584, 535), "SCNRBACK.DEF", CGI->generaltexth->zelp[105], boost::bind(&CGuiHandler::popIntTotally, &GH, this), SDLK_ESCAPE);
} }
CScenarioInfo::~CScenarioInfo() CScenarioInfo::~CScenarioInfo()
@ -3059,10 +3064,10 @@ CMultiMode::CMultiMode()
txt = new CTextInput(Rect(19, 436, 334, 16), *bg); txt = new CTextInput(Rect(19, 436, 334, 16), *bg);
txt->setText(settings["general"]["playerName"].String()); //Player txt->setText(settings["general"]["playerName"].String()); //Player
btns[0] = new CAdventureMapButton(CGI->generaltexth->zelp[266], std::bind(&CMultiMode::openHotseat, this), 373, 78, "MUBHOT.DEF"); btns[0] = new CButton(Point(373, 78), "MUBHOT.DEF", CGI->generaltexth->zelp[266], boost::bind(&CMultiMode::openHotseat, this));
btns[1] = new CAdventureMapButton("Host TCP/IP game", "", std::bind(&CMultiMode::hostTCP, this), 373, 78 + 57*1, "MUBHOST.DEF"); btns[1] = new CButton(Point(373, 78 + 57*1), "MUBHOST.DEF", CButton::tooltip("Host TCP/IP game", ""), boost::bind(&CMultiMode::hostTCP, this));
btns[2] = new CAdventureMapButton("Join TCP/IP game", "", std::bind(&CMultiMode::joinTCP, this), 373, 78 + 57*2, "MUBJOIN.DEF"); btns[2] = new CButton(Point(373, 78 + 57*2), "MUBJOIN.DEF", CButton::tooltip("Join TCP/IP game", ""), boost::bind(&CMultiMode::joinTCP, this));
btns[6] = new CAdventureMapButton(CGI->generaltexth->zelp[288], std::bind(&CGuiHandler::popIntTotally, std::ref(GH), this), 373, 424, "MUBCANC.DEF", SDLK_ESCAPE); btns[6] = new CButton(Point(373, 424), "MUBCANC.DEF", CGI->generaltexth->zelp[288], [&] { GH.popIntTotally(this);}, SDLK_ESCAPE);
} }
void CMultiMode::openHotseat() void CMultiMode::openHotseat()
@ -3102,8 +3107,8 @@ CHotSeatPlayers::CHotSeatPlayers(const std::string &firstPlayer)
txt[i]->cb += std::bind(&CHotSeatPlayers::onChange, this, _1); txt[i]->cb += std::bind(&CHotSeatPlayers::onChange, this, _1);
} }
ok = new CAdventureMapButton(CGI->generaltexth->zelp[560], std::bind(&CHotSeatPlayers::enterSelectionScreen, this), 95, 338, "MUBCHCK.DEF", SDLK_RETURN); ok = new CButton(Point(95, 338), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], boost::bind(&CHotSeatPlayers::enterSelectionScreen, this), SDLK_RETURN);
cancel = new CAdventureMapButton(CGI->generaltexth->zelp[561], std::bind(&CGuiHandler::popIntTotally, std::ref(GH), this), 205, 338, "MUBCANC.DEF", SDLK_ESCAPE); cancel = new CButton(Point(205, 338), "MUBCANC.DEF", CGI->generaltexth->zelp[561], boost::bind(&CGuiHandler::popIntTotally, boost::ref(GH), this), SDLK_ESCAPE);
bar = new CGStatusBar(new CPicture(Rect(7, 381, 348, 18), 0));//226, 472 bar = new CGStatusBar(new CPicture(Rect(7, 381, 348, 18), 0));//226, 472
txt[0]->setText(firstPlayer, true); txt[0]->setText(firstPlayer, true);
@ -3166,9 +3171,9 @@ void CBonusSelection::init()
blitAt(panel, 456, 6, background); blitAt(panel, 456, 6, background);
startB = new CAdventureMapButton("", "", std::bind(&CBonusSelection::startMap, this), 475, 536, "CBBEGIB.DEF", SDLK_RETURN); startB = new CButton(Point(475, 536), "CBBEGIB.DEF", CButton::tooltip(), boost::bind(&CBonusSelection::startMap, this), SDLK_RETURN);
restartB = new CAdventureMapButton("", "", std::bind(&CBonusSelection::restartMap, this), 475, 536, "CBRESTB.DEF", SDLK_RETURN); restartB = new CButton(Point(475, 536), "CBRESTB.DEF", CButton::tooltip(), boost::bind(&CBonusSelection::restartMap, this), SDLK_RETURN);
backB = new CAdventureMapButton("", "", std::bind(&CBonusSelection::goBack, this), 624, 536, "CBCANCB.DEF", SDLK_ESCAPE); backB = new CButton(Point(624, 536), "CBCANCB.DEF", CButton::tooltip(), boost::bind(&CBonusSelection::goBack, this), SDLK_ESCAPE);
//campaign name //campaign name
if (ourCampaign->camp->header.name.length()) if (ourCampaign->camp->header.name.length())
@ -3190,7 +3195,7 @@ void CBonusSelection::init()
//bonus choosing //bonus choosing
graphics->fonts[FONT_MEDIUM]->renderTextLeft(background, CGI->generaltexth->allTexts[71], Colors::WHITE, Point(511, 432)); graphics->fonts[FONT_MEDIUM]->renderTextLeft(background, CGI->generaltexth->allTexts[71], Colors::WHITE, Point(511, 432));
bonuses = new CHighlightableButtonsGroup(bind(&CBonusSelection::selectBonus, this, _1)); bonuses = new CToggleGroup(bind(&CBonusSelection::selectBonus, this, _1));
//set left part of window //set left part of window
bool isCurrentMapConquerable = ourCampaign->currentMap && ourCampaign->camp->conquerable(*ourCampaign->currentMap); bool isCurrentMapConquerable = ourCampaign->currentMap && ourCampaign->camp->conquerable(*ourCampaign->currentMap);
@ -3241,8 +3246,8 @@ void CBonusSelection::init()
//difficulty selection buttons //difficulty selection buttons
if (ourCampaign->camp->header.difficultyChoosenByPlayer) if (ourCampaign->camp->header.difficultyChoosenByPlayer)
{ {
diffLb = new CAdventureMapButton("", "", std::bind(&CBonusSelection::decreaseDifficulty, this), 694, 508, "SCNRBLF.DEF"); diffLb = new CButton(Point(694, 508), "SCNRBLF.DEF", CButton::tooltip(), boost::bind(&CBonusSelection::decreaseDifficulty, this));
diffRb = new CAdventureMapButton("", "", std::bind(&CBonusSelection::increaseDifficulty, this), 738, 508, "SCNRBRT.DEF"); diffRb = new CButton(Point(738, 508), "SCNRBRT.DEF", CButton::tooltip(), boost::bind(&CBonusSelection::increaseDifficulty, this));
} }
//load miniflags //load miniflags
@ -3442,13 +3447,8 @@ void CBonusSelection::updateBonusSelection()
updateStartButtonState(-1); updateStartButtonState(-1);
for (auto & elem : bonuses->buttons) delete bonuses;
{ bonuses = new CToggleGroup(bind(&CBonusSelection::selectBonus, this, _1));
if (elem->active)
elem->deactivate();
delete elem;
}
bonuses->buttons.clear();
static const char *bonusPics[] = {"SPELLBON.DEF", "TWCRPORT.DEF", "", "ARTIFBON.DEF", "SPELLBON.DEF", static const char *bonusPics[] = {"SPELLBON.DEF", "TWCRPORT.DEF", "", "ARTIFBON.DEF", "SPELLBON.DEF",
"PSKILBON.DEF", "SSKILBON.DEF", "BORES.DEF", "PORTRAITSLARGE", "PORTRAITSLARGE"}; "PSKILBON.DEF", "SSKILBON.DEF", "BORES.DEF", "PORTRAITSLARGE", "PORTRAITSLARGE"};
@ -3602,7 +3602,7 @@ void CBonusSelection::updateBonusSelection()
break; break;
} }
CHighlightableButton *bonusButton = new CHighlightableButton(desc, desc, 0, 475 + i*68, 455, "", i); CToggleButton *bonusButton = new CToggleButton(Point(475 + i*68, 455), "", CButton::tooltip(desc, desc));
if (picNumber != -1) if (picNumber != -1)
picName += ":" + boost::lexical_cast<std::string>(picNumber); picName += ":" + boost::lexical_cast<std::string>(picNumber);
@ -3612,13 +3612,13 @@ void CBonusSelection::updateBonusSelection()
bonusButton->setImage(anim); bonusButton->setImage(anim);
const SDL_Color brightYellow = { 242, 226, 110, 0 }; const SDL_Color brightYellow = { 242, 226, 110, 0 };
bonusButton->borderColor = brightYellow; bonusButton->borderColor = brightYellow;
bonuses->addButton(bonusButton); bonuses->addToggle(i, bonusButton);
} }
// set bonus if already chosen // set bonus if already chosen
if(vstd::contains(ourCampaign->chosenCampaignBonuses, selectedMap)) if(vstd::contains(ourCampaign->chosenCampaignBonuses, selectedMap))
{ {
bonuses->select(ourCampaign->chosenCampaignBonuses[selectedMap], false); bonuses->setSelected(ourCampaign->chosenCampaignBonuses[selectedMap]);
} }
} }
@ -3727,11 +3727,11 @@ void CBonusSelection::updateStartButtonState(int selected /*= -1*/)
{ {
if(selected == -1) if(selected == -1)
{ {
startB->setState(ourCampaign->camp->scenarios[selectedMap].travelOptions.bonusesToChoose.size() ? CButtonBase::BLOCKED : CButtonBase::NORMAL); startB->block(ourCampaign->camp->scenarios[selectedMap].travelOptions.bonusesToChoose.size());
} }
else if(startB->getState() == CButtonBase::BLOCKED) else if(startB->isBlocked())
{ {
startB->setState(CButtonBase::NORMAL); startB->block(false);
} }
} }
@ -4091,14 +4091,14 @@ void CCampaignScreen::CCampaignButton::show(SDL_Surface * to)
} }
} }
CAdventureMapButton* CCampaignScreen::createExitButton(const JsonNode& button) CButton* CCampaignScreen::createExitButton(const JsonNode& button)
{ {
std::pair<std::string, std::string> help; std::pair<std::string, std::string> help;
if (!button["help"].isNull() && button["help"].Float() > 0) if (!button["help"].isNull() && button["help"].Float() > 0)
help = CGI->generaltexth->zelp[button["help"].Float()]; help = CGI->generaltexth->zelp[button["help"].Float()];
std::function<void()> close = std::bind(&CGuiHandler::popIntTotally, &GH, this); std::function<void()> close = boost::bind(&CGuiHandler::popIntTotally, &GH, this);
return new CAdventureMapButton(help, close, button["x"].Float(), button["y"].Float(), button["name"].String(), button["hotkey"].Float()); return new CButton(Point(button["x"].Float(), button["y"].Float()), button["name"].String(), help, close, button["hotkey"].Float());
} }
@ -4239,8 +4239,8 @@ CSimpleJoinScreen::CSimpleJoinScreen()
port->cb += std::bind(&CSimpleJoinScreen::onChange, this, _1); port->cb += std::bind(&CSimpleJoinScreen::onChange, this, _1);
port->filters.add(std::bind(&CTextInput::numberFilter, _1, _2, 0, 65535)); port->filters.add(std::bind(&CTextInput::numberFilter, _1, _2, 0, 65535));
ok = new CAdventureMapButton(CGI->generaltexth->zelp[560], std::bind(&CSimpleJoinScreen::enterSelectionScreen, this), 26, 142, "MUBCHCK.DEF", SDLK_RETURN); ok = new CButton(Point( 26, 142), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], boost::bind(&CSimpleJoinScreen::enterSelectionScreen, this), SDLK_RETURN);
cancel = new CAdventureMapButton(CGI->generaltexth->zelp[561], std::bind(&CGuiHandler::popIntTotally, std::ref(GH), this), 142, 142, "MUBCANC.DEF", SDLK_ESCAPE); cancel = new CButton(Point(142, 142), "MUBCANC.DEF", CGI->generaltexth->zelp[561], boost::bind(&CGuiHandler::popIntTotally, boost::ref(GH), this), SDLK_ESCAPE);
bar = new CGStatusBar(new CPicture(Rect(7, 186, 218, 18), 0)); bar = new CGStatusBar(new CPicture(Rect(7, 186, 218, 18), 0));
port->setText(boost::lexical_cast<std::string>(settings["server"]["port"].Float()), true); port->setText(boost::lexical_cast<std::string>(settings["server"]["port"].Float()), true);

View File

@ -1,12 +1,11 @@
#pragma once #pragma once
#include "../lib/filesystem/Filesystem.h" //#include "../lib/filesystem/Filesystem.h"
#include <SDL.h>
#include "../lib/StartInfo.h" #include "../lib/StartInfo.h"
#include "GUIClasses.h"
#include "../lib/FunctionList.h" #include "../lib/FunctionList.h"
#include "../lib/mapping/CMapInfo.h" #include "../lib/mapping/CMapInfo.h"
#include "../lib/rmg/CMapGenerator.h" #include "../lib/rmg/CMapGenerator.h"
#include "windows/CWindowObject.h"
/* /*
* CPreGame.h, part of VCMI engine * CPreGame.h, part of VCMI engine
@ -18,6 +17,7 @@
* *
*/ */
class CMapInfo;
class CMusicHandler; class CMusicHandler;
class CMapHeader; class CMapHeader;
class CCampaignHeader; class CCampaignHeader;
@ -32,6 +32,12 @@ class CMapGenOptions;
class CRandomMapTab; class CRandomMapTab;
struct CPackForSelectionScreen; struct CPackForSelectionScreen;
struct PlayerInfo; struct PlayerInfo;
class CMultiLineLabel;
class CToggleButton;
class CToggleGroup;
class CTabbedInt;
class CButton;
class CSlider;
namespace boost{ class thread; class recursive_mutex;} namespace boost{ class thread; class recursive_mutex;}
@ -80,9 +86,9 @@ public:
class CMenuEntry : public CIntObject class CMenuEntry : public CIntObject
{ {
std::vector<CPicture*> images; std::vector<CPicture*> images;
std::vector<CAdventureMapButton*> buttons; std::vector<CButton*> buttons;
CAdventureMapButton* createButton(CMenuScreen* parent, const JsonNode& button); CButton* createButton(CMenuScreen* parent, const JsonNode& button);
public: public:
CMenuEntry(CMenuScreen* parent, const JsonNode &config); CMenuEntry(CMenuScreen* parent, const JsonNode &config);
}; };
@ -126,7 +132,7 @@ public:
CChatBox *chat; CChatBox *chat;
CPicture *playerListBg; CPicture *playerListBg;
CHighlightableButtonsGroup *difficulty; CToggleGroup *difficulty;
CDefHandler *sizes, *sFlags; CDefHandler *sizes, *sFlags;
void changeSelection(const CMapInfo *to); void changeSelection(const CMapInfo *to);
@ -239,8 +245,8 @@ public:
PlayerInfo &pi; PlayerInfo &pi;
PlayerSettings &s; PlayerSettings &s;
CPicture *bg; CPicture *bg;
CAdventureMapButton *btns[6]; //left and right for town, hero, bonus CButton *btns[6]; //left and right for town, hero, bonus
CAdventureMapButton *flag; CButton *flag;
SelectedBox *town; SelectedBox *town;
SelectedBox *hero; SelectedBox *hero;
SelectedBox *bonus; SelectedBox *bonus;
@ -296,17 +302,17 @@ public:
const CMapGenOptions & getMapGenOptions() const; const CMapGenOptions & getMapGenOptions() const;
private: private:
void addButtonsToGroup(CHighlightableButtonsGroup * group, const std::vector<std::string> & defs, int startIndex, int endIndex, int btnWidth, int helpStartIndex) const; void addButtonsToGroup(CToggleGroup * group, const std::vector<std::string> & defs, int startIndex, int endIndex, int btnWidth, int helpStartIndex) const;
void addButtonsWithRandToGroup(CHighlightableButtonsGroup * group, const std::vector<std::string> & defs, int startIndex, int endIndex, int btnWidth, int helpStartIndex, int helpRandIndex) const; void addButtonsWithRandToGroup(CToggleGroup * group, const std::vector<std::string> & defs, int startIndex, int endIndex, int btnWidth, int helpStartIndex, int helpRandIndex) const;
void deactivateButtonsFrom(CHighlightableButtonsGroup * group, int startId); void deactivateButtonsFrom(CToggleGroup * group, int startId);
void validatePlayersCnt(int playersCnt); void validatePlayersCnt(int playersCnt);
void validateCompOnlyPlayersCnt(int compOnlyPlayersCnt); void validateCompOnlyPlayersCnt(int compOnlyPlayersCnt);
CPicture * bg; CPicture * bg;
CHighlightableButton * twoLevelsBtn; CToggleButton * twoLevelsBtn;
CHighlightableButtonsGroup * mapSizeBtnGroup, * playersCntGroup, * teamsCntGroup, * compOnlyPlayersCntGroup, CToggleGroup * mapSizeBtnGroup, * playersCntGroup, * teamsCntGroup, * compOnlyPlayersCntGroup,
* compOnlyTeamsCntGroup, * waterContentGroup, * monsterStrengthGroup; * compOnlyTeamsCntGroup, * waterContentGroup, * monsterStrengthGroup;
CAdventureMapButton * showRandMaps; CButton * showRandMaps;
CMapGenOptions mapGenOptions; CMapGenOptions mapGenOptions;
unique_ptr<CMapInfo> mapInfo; unique_ptr<CMapInfo> mapInfo;
CFunctionList<void(const CMapInfo *)> mapInfoChanged; CFunctionList<void(const CMapInfo *)> mapInfoChanged;
@ -347,7 +353,7 @@ public:
InfoCard *card; InfoCard *card;
OptionsTab *opt; OptionsTab *opt;
CRandomMapTab * randMapTab; CRandomMapTab * randMapTab;
CAdventureMapButton *start, *back; CButton *start, *back;
SelectionTab *sel; SelectionTab *sel;
CIntObject *curTab; CIntObject *curTab;
@ -395,7 +401,7 @@ public:
class CScenarioInfo : public CIntObject, public ISelectionScreenInfo class CScenarioInfo : public CIntObject, public ISelectionScreenInfo
{ {
public: public:
CAdventureMapButton *back; CButton *back;
InfoCard *card; InfoCard *card;
OptionsTab *opt; OptionsTab *opt;
@ -409,7 +415,7 @@ class CMultiMode : public CIntObject
public: public:
CPicture *bg; CPicture *bg;
CTextInput *txt; CTextInput *txt;
CAdventureMapButton *btns[7]; //0 - hotseat, 6 - cancel CButton *btns[7]; //0 - hotseat, 6 - cancel
CGStatusBar *bar; CGStatusBar *bar;
CMultiMode(); CMultiMode();
@ -424,7 +430,7 @@ class CHotSeatPlayers : public CIntObject
CPicture *bg; CPicture *bg;
CTextBox *title; CTextBox *title;
CTextInput* txt[8]; CTextInput* txt[8];
CAdventureMapButton *ok, *cancel; CButton *ok, *cancel;
CGStatusBar *bar; CGStatusBar *bar;
void onChange(std::string newText); void onChange(std::string newText);
@ -512,14 +518,14 @@ private:
// GUI components // GUI components
SDL_Surface * background; SDL_Surface * background;
CAdventureMapButton * startB, * restartB, * backB; CButton * startB, * restartB, * backB;
CTextBox * campaignDescription, * mapDescription; CTextBox * campaignDescription, * mapDescription;
std::vector<SCampPositions> campDescriptions; std::vector<SCampPositions> campDescriptions;
std::vector<CRegion *> regions; std::vector<CRegion *> regions;
CRegion * highlightedRegion; CRegion * highlightedRegion;
CHighlightableButtonsGroup * bonuses; CToggleGroup * bonuses;
SDL_Surface * diffPics[5]; //pictures of difficulties, user-selectable (or not if campaign locks this) SDL_Surface * diffPics[5]; //pictures of difficulties, user-selectable (or not if campaign locks this)
CAdventureMapButton * diffLb, * diffRb; //buttons for changing difficulty CButton * diffLb, * diffRb; //buttons for changing difficulty
CDefHandler * sizes; //icons of map sizes CDefHandler * sizes; //icons of map sizes
CDefHandler * sFlags; CDefHandler * sFlags;
@ -560,11 +566,11 @@ private:
void show(SDL_Surface * to); void show(SDL_Surface * to);
}; };
CAdventureMapButton *back; CButton *back;
std::vector<CCampaignButton*> campButtons; std::vector<CCampaignButton*> campButtons;
std::vector<CPicture*> images; std::vector<CPicture*> images;
CAdventureMapButton* createExitButton(const JsonNode& button); CButton* createExitButton(const JsonNode& button);
public: public:
enum CampaignSet {ROE, AB, SOD, WOG}; enum CampaignSet {ROE, AB, SOD, WOG};
@ -630,7 +636,7 @@ class CSimpleJoinScreen : public CIntObject
{ {
CPicture * bg; CPicture * bg;
CTextBox * title; CTextBox * title;
CAdventureMapButton * ok, * cancel; CButton * ok, * cancel;
CGStatusBar * bar; CGStatusBar * bar;
CTextInput * address; CTextInput * address;
CTextInput * port; CTextInput * port;

View File

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

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -17,7 +17,7 @@
#include "../lib/CSoundBase.h" #include "../lib/CSoundBase.h"
#include "../lib/StartInfo.h" #include "../lib/StartInfo.h"
#include "mapHandler.h" #include "mapHandler.h"
#include "GUIClasses.h" #include "windows/GUIClasses.h"
#include "../lib/CConfigHandler.h" #include "../lib/CConfigHandler.h"
#include "gui/SDL_Extensions.h" #include "gui/SDL_Extensions.h"
#include "battle/CBattleInterface.h" #include "battle/CBattleInterface.h"
@ -26,6 +26,8 @@
#include "../lib/BattleState.h" #include "../lib/BattleState.h"
#include "../lib/GameConstants.h" #include "../lib/GameConstants.h"
#include "gui/CGuiHandler.h" #include "gui/CGuiHandler.h"
#include "widgets/MiscWidgets.h"
#include "widgets/AdventureMapClasses.h"
#include "CMT.h" #include "CMT.h"
//macros to avoid code duplication - calls given method with given arguments if interface for specific player is present //macros to avoid code duplication - calls given method with given arguments if interface for specific player is present

View File

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

View File

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

View File

@ -1,40 +1,38 @@
#include "StdInc.h" #include "StdInc.h"
#include "CBattleInterface.h" #include "CBattleInterface.h"
#include "../CGameInfo.h"
#include "../gui/SDL_Extensions.h"
#include "../CAdvmapInterface.h"
#include "../CAnimation.h"
#include "../CBitmapHandler.h"
#include "../../lib/CHeroHandler.h"
# include "../CDefHandler.h"
#include "../../lib/CSpellHandler.h"
#include "../CMusicHandler.h"
#include "../CMessage.h"
#include "../../CCallback.h"
#include "../../lib/BattleState.h"
#include "../../lib/CGeneralTextHandler.h"
#include "CCreatureAnimation.h"
#include "../Graphics.h"
#include "../CSpellWindow.h"
#include "../../lib/CConfigHandler.h"
#include "../../lib/CondSh.h"
#include "../../lib/NetPacks.h"
#include "../CPlayerInterface.h"
#include "../CCreatureWindow.h"
#include "../CVideoHandler.h"
#include "../../lib/CTownHandler.h"
#include "../../lib/mapping/CMap.h"
#include "../../lib/CRandomGenerator.h"
#include "CBattleAnimations.h" #include "CBattleAnimations.h"
#include "CBattleInterfaceClasses.h" #include "CBattleInterfaceClasses.h"
#include "CCreatureAnimation.h"
#include "../CBitmapHandler.h"
#include "../CDefHandler.h"
#include "../CGameInfo.h"
#include "../CMessage.h"
#include "../CMT.h"
#include "../CMusicHandler.h"
#include "../CPlayerInterface.h"
#include "../CVideoHandler.h"
#include "../Graphics.h"
#include "../gui/CCursorHandler.h" #include "../gui/CCursorHandler.h"
#include "../gui/CGuiHandler.h" #include "../gui/CGuiHandler.h"
#include "../CMT.h" #include "../gui/SDL_Extensions.h"
#include "../windows/CAdvmapInterface.h"
#include "../windows/CCreatureWindow.h"
#include "../windows/CSpellWindow.h"
#include "../../CCallback.h"
#include "../../lib/BattleState.h"
#include "../../lib/CConfigHandler.h"
#include "../../lib/CGeneralTextHandler.h"
#include "../../lib/CHeroHandler.h"
#include "../../lib/CondSh.h"
#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" #include "../../lib/UnlockGuard.h"
using namespace boost::assign; using namespace boost::assign;
@ -224,17 +222,17 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
// blitAt(menu, pos.x, 556 + pos.y); // blitAt(menu, pos.x, 556 + pos.y);
//preparing buttons and console //preparing buttons and console
bOptions = new CAdventureMapButton (CGI->generaltexth->zelp[381].first, CGI->generaltexth->zelp[381].second, std::bind(&CBattleInterface::bOptionsf,this), 3, 561, "icm003.def", SDLK_o); bOptions = new CButton (Point( 3, 561), "icm003.def", CGI->generaltexth->zelp[381], boost::bind(&CBattleInterface::bOptionsf,this), SDLK_o);
bSurrender = new CAdventureMapButton (CGI->generaltexth->zelp[379].first, CGI->generaltexth->zelp[379].second, std::bind(&CBattleInterface::bSurrenderf,this), 54, 561, "icm001.def", SDLK_s); bSurrender = new CButton (Point( 54, 561), "icm001.def", CGI->generaltexth->zelp[379], boost::bind(&CBattleInterface::bSurrenderf,this), SDLK_s);
bFlee = new CAdventureMapButton (CGI->generaltexth->zelp[380].first, CGI->generaltexth->zelp[380].second, std::bind(&CBattleInterface::bFleef,this), 105, 561, "icm002.def", SDLK_r); bFlee = new CButton (Point(105, 561), "icm002.def", CGI->generaltexth->zelp[380], boost::bind(&CBattleInterface::bFleef,this), SDLK_r);
bAutofight = new CAdventureMapButton (CGI->generaltexth->zelp[382].first, CGI->generaltexth->zelp[382].second, std::bind(&CBattleInterface::bAutofightf,this), 157, 561, "icm004.def", SDLK_a); bAutofight = new CButton (Point(157, 561), "icm004.def", CGI->generaltexth->zelp[382], boost::bind(&CBattleInterface::bAutofightf,this), SDLK_a);
bSpell = new CAdventureMapButton (CGI->generaltexth->zelp[385].first, CGI->generaltexth->zelp[385].second, std::bind(&CBattleInterface::bSpellf,this), 645, 561, "icm005.def", SDLK_c); bSpell = new CButton (Point(645, 561), "icm005.def", CGI->generaltexth->zelp[385], boost::bind(&CBattleInterface::bSpellf,this), SDLK_c);
bWait = new CAdventureMapButton (CGI->generaltexth->zelp[386].first, CGI->generaltexth->zelp[386].second, std::bind(&CBattleInterface::bWaitf,this), 696, 561, "icm006.def", SDLK_w); bWait = new CButton (Point(696, 561), "icm006.def", CGI->generaltexth->zelp[386], boost::bind(&CBattleInterface::bWaitf,this), SDLK_w);
bDefence = new CAdventureMapButton (CGI->generaltexth->zelp[387].first, CGI->generaltexth->zelp[387].second, std::bind(&CBattleInterface::bDefencef,this), 747, 561, "icm007.def", SDLK_d); bDefence = new CButton (Point(747, 561), "icm007.def", CGI->generaltexth->zelp[387], boost::bind(&CBattleInterface::bDefencef,this), SDLK_d);
bDefence->assignedKeys.insert(SDLK_SPACE); bDefence->assignedKeys.insert(SDLK_SPACE);
bConsoleUp = new CAdventureMapButton (std::string(), std::string(), std::bind(&CBattleInterface::bConsoleUpf,this), 624, 561, "ComSlide.def", SDLK_UP); bConsoleUp = new CButton (Point(624, 561), "ComSlide.def", std::make_pair("", ""), boost::bind(&CBattleInterface::bConsoleUpf,this), SDLK_UP);
bConsoleDown = new CAdventureMapButton (std::string(), std::string(), std::bind(&CBattleInterface::bConsoleDownf,this), 624, 580, "ComSlide.def", SDLK_DOWN); bConsoleDown = new CButton (Point(624, 580), "ComSlide.def", std::make_pair("", ""), boost::bind(&CBattleInterface::bConsoleDownf,this), SDLK_DOWN);
bConsoleDown->setOffset(2); bConsoleDown->setImageOrder(2, 3, 4, 5);
console = new CBattleConsole(); console = new CBattleConsole();
console->pos.x += 211; console->pos.x += 211;
console->pos.y += 560; console->pos.y += 560;
@ -242,8 +240,8 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
console->pos.h = 38; console->pos.h = 38;
if(tacticsMode) if(tacticsMode)
{ {
btactNext = new CAdventureMapButton(std::string(), std::string(), std::bind(&CBattleInterface::bTacticNextStack,this, (CStack*)nullptr), 213, 560, "icm011.def", SDLK_SPACE); btactNext = new CButton(Point(213, 560), "icm011.def", std::make_pair("", ""), [&]{ bTacticNextStack(nullptr);}, SDLK_SPACE);
btactEnd = new CAdventureMapButton(std::string(), std::string(), std::bind(&CBattleInterface::bEndTacticPhase,this), 419, 560, "icm012.def", SDLK_RETURN); btactEnd = new CButton(Point(419, 560), "icm012.def", std::make_pair("", ""), [&]{ bEndTacticPhase();}, SDLK_RETURN);
menu = BitmapHandler::loadBitmap("COPLACBR.BMP"); menu = BitmapHandler::loadBitmap("COPLACBR.BMP");
} }
else else
@ -2432,7 +2430,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
{ {
cursorFrame = ECursor::COMBAT_QUERY; cursorFrame = ECursor::COMBAT_QUERY;
consoleMsg = (boost::format(CGI->generaltexth->allTexts[297]) % shere->getName()).str(); consoleMsg = (boost::format(CGI->generaltexth->allTexts[297]) % shere->getName()).str();
realizeAction = [=]{ GH.pushInt(createCreWindow(shere, true)); }; realizeAction = [=]{ GH.pushInt(new CStackWindow(shere, false)); };
break; break;
} }
} }

View File

@ -1,10 +1,10 @@
#pragma once #pragma once
#include "../../lib/CCreatureSet.h" //#include "../../lib/CCreatureSet.h"
#include "../../lib/ConstTransitivePtr.h" //may be reundant #include "../../lib/ConstTransitivePtr.h" //may be reundant
#include "../CAnimation.h"
#include "../../lib/GameConstants.h" #include "../../lib/GameConstants.h"
#include "CBattleAnimations.h" #include "CBattleAnimations.h"
/* /*
@ -23,9 +23,9 @@ class CGHeroInstance;
class CDefHandler; class CDefHandler;
class CStack; class CStack;
class CCallback; class CCallback;
class CAdventureMapButton; class CButton;
class CHighlightableButton; class CToggleButton;
class CHighlightableButtonsGroup; class CToggleGroup;
struct BattleResult; struct BattleResult;
struct BattleSpellCast; struct BattleSpellCast;
struct CObstacleInstance; struct CObstacleInstance;
@ -120,7 +120,7 @@ class CBattleInterface : public CIntObject
}; };
private: private:
SDL_Surface * background, * menu, * amountNormal, * amountNegative, * amountPositive, * amountEffNeutral, * cellBorders, * backgroundWithHexes; SDL_Surface * background, * menu, * amountNormal, * amountNegative, * amountPositive, * amountEffNeutral, * cellBorders, * backgroundWithHexes;
CAdventureMapButton * bOptions, * bSurrender, * bFlee, * bAutofight, * bSpell, CButton * bOptions, * bSurrender, * bFlee, * bAutofight, * bSpell,
* bWait, * bDefence, * bConsoleUp, * bConsoleDown, *btactNext, *btactEnd; * bWait, * bDefence, * bConsoleUp, * bConsoleDown, *btactNext, *btactEnd;
CBattleConsole * console; CBattleConsole * console;
CBattleHero * attackingHero, * defendingHero; //fighting heroes CBattleHero * attackingHero, * defendingHero; //fighting heroes
@ -338,7 +338,7 @@ public:
InfoAboutHero enemyHero() const; InfoAboutHero enemyHero() const;
friend class CPlayerInterface; friend class CPlayerInterface;
friend class CAdventureMapButton; friend class CButton;
friend class CInGameConsole; friend class CInGameConsole;
friend class CBattleResultWindow; friend class CBattleResultWindow;

View File

@ -1,29 +1,34 @@
#include "StdInc.h" #include "StdInc.h"
#include "CBattleInterfaceClasses.h" #include "CBattleInterfaceClasses.h"
#include "../gui/SDL_Extensions.h"
#include "CBattleInterface.h" #include "CBattleInterface.h"
#include "../CGameInfo.h"
#include "../CDefHandler.h"
#include "../gui/CCursorHandler.h"
#include "../CPlayerInterface.h"
#include "../../CCallback.h"
#include "../CSpellWindow.h"
#include "../Graphics.h"
#include "../../lib/CConfigHandler.h"
#include "../gui/CGuiHandler.h"
#include "../gui/CIntObjectClasses.h"
#include "../../lib/CGeneralTextHandler.h"
#include "../../lib/NetPacks.h"
#include "../../lib/CCreatureHandler.h"
#include "../../lib/BattleState.h"
#include "../../lib/StartInfo.h"
#include "../CMusicHandler.h"
#include "../CVideoHandler.h"
#include "../../lib/CTownHandler.h"
#include "../CBitmapHandler.h" #include "../CBitmapHandler.h"
#include "../CCreatureWindow.h" #include "../CDefHandler.h"
#include "../CGameInfo.h"
#include "../CMessage.h" #include "../CMessage.h"
#include "../CMusicHandler.h"
#include "../CPlayerInterface.h"
#include "../CVideoHandler.h"
#include "../Graphics.h"
#include "../gui/CCursorHandler.h"
#include "../gui/CGuiHandler.h"
#include "../gui/SDL_Extensions.h"
#include "../widgets/Buttons.h"
#include "../widgets/TextControls.h"
#include "../windows/CCreatureWindow.h"
#include "../windows/CSpellWindow.h"
#include "../../CCallback.h"
#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 * CBattleInterfaceClasses.cpp, part of VCMI engine
@ -258,26 +263,23 @@ CBattleOptionsWindow::CBattleOptionsWindow(const SDL_Rect & position, CBattleInt
background = new CPicture("comopbck.bmp"); background = new CPicture("comopbck.bmp");
background->colorize(owner->getCurrentPlayerInterface()->playerID); background->colorize(owner->getCurrentPlayerInterface()->playerID);
viewGrid = new CHighlightableButton(std::bind(&CBattleInterface::setPrintCellBorders, owner, true), std::bind(&CBattleInterface::setPrintCellBorders, owner, false), boost::assign::map_list_of(0,CGI->generaltexth->zelp[427].first)(3,CGI->generaltexth->zelp[427].first), CGI->generaltexth->zelp[427].second, false, "sysopchk.def", nullptr, 25, 56, false); viewGrid = new CToggleButton(Point(25, 56), "sysopchk.def", CGI->generaltexth->zelp[427], [&](bool on){owner->setPrintCellBorders(on);} );
viewGrid->select(settings["battle"]["cellBorders"].Bool()); viewGrid->setSelected(settings["battle"]["cellBorders"].Bool());
movementShadow = new CHighlightableButton(std::bind(&CBattleInterface::setPrintStackRange, owner, true), std::bind(&CBattleInterface::setPrintStackRange, owner, false), boost::assign::map_list_of(0,CGI->generaltexth->zelp[428].first)(3,CGI->generaltexth->zelp[428].first), CGI->generaltexth->zelp[428].second, false, "sysopchk.def", nullptr, 25, 89, false); movementShadow = new CToggleButton(Point(25, 89), "sysopchk.def", CGI->generaltexth->zelp[428], [&](bool on){owner->setPrintStackRange(on);});
movementShadow->select(settings["battle"]["stackRange"].Bool()); movementShadow->setSelected(settings["battle"]["stackRange"].Bool());
mouseShadow = new CHighlightableButton(std::bind(&CBattleInterface::setPrintMouseShadow, owner, true), std::bind(&CBattleInterface::setPrintMouseShadow, owner, false), boost::assign::map_list_of(0,CGI->generaltexth->zelp[429].first)(3,CGI->generaltexth->zelp[429].first), CGI->generaltexth->zelp[429].second, false, "sysopchk.def", nullptr, 25, 122, false); mouseShadow = new CToggleButton(Point(25, 122), "sysopchk.def", CGI->generaltexth->zelp[429], [&](bool on){owner->setPrintMouseShadow(on);});
mouseShadow->select(settings["battle"]["mouseShadow"].Bool()); mouseShadow->setSelected(settings["battle"]["mouseShadow"].Bool());
animSpeeds = new CHighlightableButtonsGroup(0); animSpeeds = new CToggleGroup([&](int value){ owner->setAnimSpeed(value);});
animSpeeds->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[422].first),CGI->generaltexth->zelp[422].second, "sysopb9.def", 28, 225, 40); animSpeeds->addToggle(40, new CToggleButton(Point( 28, 225), "sysopb9.def", CGI->generaltexth->zelp[422]));
animSpeeds->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[423].first),CGI->generaltexth->zelp[423].second, "sysob10.def", 92, 225, 63); animSpeeds->addToggle(63, new CToggleButton(Point( 92, 225), "sysob10.def", CGI->generaltexth->zelp[423]));
animSpeeds->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[424].first),CGI->generaltexth->zelp[424].second, "sysob11.def",156, 225, 100); animSpeeds->addToggle(100, new CToggleButton(Point(156, 225), "sysob11.def", CGI->generaltexth->zelp[424]));
animSpeeds->select(owner->getAnimSpeed(), 1); animSpeeds->setSelected(owner->getAnimSpeed());
animSpeeds->onChange = std::bind(&CBattleInterface::setAnimSpeed, owner, _1);
setToDefault = new CAdventureMapButton (CGI->generaltexth->zelp[393], std::bind(&CBattleOptionsWindow::bDefaultf,this), 246, 359, "codefaul.def"); setToDefault = new CButton (Point(246, 359), "codefaul.def", CGI->generaltexth->zelp[393], [&]{ bDefaultf(); });
setToDefault->swappedImages = true; setToDefault->setImageOrder(1, 0, 2, 3);
setToDefault->update(); exit = new CButton (Point(357, 359), "soretrn.def", CGI->generaltexth->zelp[392], [&]{ bExitf();}, SDLK_RETURN);
exit = new CAdventureMapButton (CGI->generaltexth->zelp[392], std::bind(&CBattleOptionsWindow::bExitf,this), 357, 359, "soretrn.def",SDLK_RETURN); exit->setImageOrder(1, 0, 2, 3);
exit->swappedImages = true;
exit->update();
//creating labels //creating labels
labels.push_back(new CLabel(242, 32, FONT_BIG, CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[392]));//window title labels.push_back(new CLabel(242, 32, FONT_BIG, CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[392]));//window title
@ -307,6 +309,7 @@ CBattleOptionsWindow::CBattleOptionsWindow(const SDL_Rect & position, CBattleInt
void CBattleOptionsWindow::bDefaultf() void CBattleOptionsWindow::bDefaultf()
{ {
//TODO: implement
} }
void CBattleOptionsWindow::bExitf() void CBattleOptionsWindow::bExitf()
@ -322,9 +325,8 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
CPicture * bg = new CPicture("CPRESULT"); CPicture * bg = new CPicture("CPRESULT");
bg->colorize(owner.playerID); bg->colorize(owner.playerID);
exit = new CAdventureMapButton ("", "", std::bind(&CBattleResultWindow::bExitf,this), 384, 505, "iok6432.def", SDLK_RETURN); exit = new CButton (Point(384, 505), "iok6432.def", std::make_pair("", ""), [&]{ bExitf();}, SDLK_RETURN);
exit->borderColor = Colors::METALLIC_GOLD; exit->borderColor = Colors::METALLIC_GOLD;
exit->borderEnabled = true;
if(br.winner==0) //attacker won if(br.winner==0) //attacker won
{ {
@ -606,7 +608,7 @@ void CClickableHex::clickRight(tribool down, bool previousState)
if(!myst->alive()) return; if(!myst->alive()) return;
if(down) if(down)
{ {
GH.pushInt(createCreWindow(myst)); GH.pushInt(new CStackWindow(myst, true));
} }
} }
} }
@ -701,7 +703,7 @@ CStackQueue::StackBox::StackBox(bool small):
small(small) small(small)
{ {
OBJ_CONSTRUCTION_CAPTURING_ALL; OBJ_CONSTRUCTION_CAPTURING_ALL;
bg = new CPicture(small ? "StackQueueBgSmall" : "StackQueueBgBig" ); bg = new CPicture(small ? "StackQueueSmall" : "StackQueueLarge" );
if (small) if (small)
{ {

View File

@ -8,9 +8,9 @@ class CDefHandler;
class CGHeroInstance; class CGHeroInstance;
class CBattleInterface; class CBattleInterface;
class CPicture; class CPicture;
class CAdventureMapButton; class CButton;
class CHighlightableButton; class CToggleButton;
class CHighlightableButtonsGroup; class CToggleGroup;
class CLabel; class CLabel;
struct BattleResult; struct BattleResult;
class CStack; class CStack;
@ -72,9 +72,9 @@ class CBattleOptionsWindow : public CIntObject
{ {
private: private:
CPicture * background; CPicture * background;
CAdventureMapButton * setToDefault, * exit; CButton * setToDefault, * exit;
CHighlightableButton * viewGrid, * movementShadow, * mouseShadow; CToggleButton * viewGrid, * movementShadow, * mouseShadow;
CHighlightableButtonsGroup * animSpeeds; CToggleGroup * animSpeeds;
std::vector<CLabel*> labels; std::vector<CLabel*> labels;
public: public:
@ -88,7 +88,7 @@ public:
class CBattleResultWindow : public CIntObject class CBattleResultWindow : public CIntObject
{ {
private: private:
CAdventureMapButton *exit; CButton *exit;
CPlayerInterface &owner; CPlayerInterface &owner;
public: public:
CBattleResultWindow(const BattleResult & br, const SDL_Rect & pos, CPlayerInterface &_owner); //c-tor CBattleResultWindow(const BattleResult & br, const SDL_Rect & pos, CPlayerInterface &_owner); //c-tor
@ -152,4 +152,4 @@ public:
void update(); void update();
void showAll(SDL_Surface *to); void showAll(SDL_Surface *to);
void blitBg(SDL_Surface * to); void blitBg(SDL_Surface * to);
}; };

View File

@ -1,16 +1,16 @@
#include "StdInc.h" #include "StdInc.h"
#include "CCreatureAnimation.h" #include "CCreatureAnimation.h"
#include "../../lib/vcmi_endian.h"
#include "../../lib/CConfigHandler.h" #include "../../lib/CConfigHandler.h"
#include "../../lib/CCreatureHandler.h" #include "../../lib/CCreatureHandler.h"
#include "../../lib/vcmi_endian.h"
#include "../gui/SDL_Extensions.h"
#include "../gui/SDL_Pixels.h"
#include "../../lib/filesystem/Filesystem.h" #include "../../lib/filesystem/Filesystem.h"
#include "../../lib/filesystem/CBinaryReader.h" #include "../../lib/filesystem/CBinaryReader.h"
#include "../../lib/filesystem/CMemoryStream.h" #include "../../lib/filesystem/CMemoryStream.h"
#include "../gui/SDL_Extensions.h"
#include "../gui/SDL_Pixels.h"
/* /*
* CCreatureAnimation.cpp, part of VCMI engine * CCreatureAnimation.cpp, part of VCMI engine
* *

View File

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

View File

@ -1,17 +1,18 @@
#include "StdInc.h" #include "StdInc.h"
#include "CAnimation.h"
#include <SDL_image.h> #include <SDL_image.h>
#include "../CBitmapHandler.h"
#include "../Graphics.h"
#include "../gui/SDL_Extensions.h"
#include "../gui/SDL_Pixels.h"
#include "../lib/filesystem/Filesystem.h" #include "../lib/filesystem/Filesystem.h"
#include "../lib/filesystem/ISimpleResourceLoader.h" #include "../lib/filesystem/ISimpleResourceLoader.h"
#include "../lib/JsonNode.h" #include "../lib/JsonNode.h"
#include "../lib/CRandomGenerator.h" #include "../lib/CRandomGenerator.h"
#include "CBitmapHandler.h"
#include "Graphics.h"
#include "CAnimation.h"
#include "gui/SDL_Extensions.h"
#include "gui/SDL_Pixels.h"
/* /*
* CAnimation.cpp, part of VCMI engine * CAnimation.cpp, part of VCMI engine
* *
@ -1221,6 +1222,7 @@ void CAnimation::getAnimInfo()
logGlobal->errorStream()<<", "<<anim->images.begin()->second.size()<<" image loaded in group "<< anim->images.begin()->first; logGlobal->errorStream()<<", "<<anim->images.begin()->second.size()<<" image loaded in group "<< anim->images.begin()->first;
} }
} }
<<<<<<< HEAD:client/CAnimation.cpp
CAnimImage::CAnimImage(std::string name, size_t Frame, size_t Group, int x, int y, ui8 Flags): CAnimImage::CAnimImage(std::string name, size_t Frame, size_t Group, int x, int y, ui8 Flags):
frame(Frame), frame(Frame),
@ -1537,3 +1539,5 @@ void CCreatureAnim::clearAndSet(EAnimType type)
queue.pop(); queue.pop();
set(type); set(type);
} }
=======
>>>>>>> refactoring/guiClasses:client/gui/CAnimation.cpp

View File

@ -1,7 +1,8 @@
#pragma once #pragma once
#include "../lib/vcmi_endian.h" #include "../../lib/vcmi_endian.h"
#include "gui/CIntObject.h" #include "gui/Geometries.h"
#include "../../lib/GameConstants.h"
/* /*
* CAnimation.h, part of VCMI engine * CAnimation.h, part of VCMI engine
@ -219,162 +220,3 @@ public:
//total count of frames in group (including not loaded) //total count of frames in group (including not loaded)
size_t size(size_t group=0) const; 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

@ -2,9 +2,11 @@
#include "CCursorHandler.h" #include "CCursorHandler.h"
#include <SDL.h> #include <SDL.h>
#include "SDL_Extensions.h" #include "SDL_Extensions.h"
#include "../CAnimation.h"
#include "CGuiHandler.h" #include "CGuiHandler.h"
#include "widgets/Images.h"
#include "../CMT.h" #include "../CMT.h"
/* /*

View File

@ -1,10 +1,12 @@
#include "StdInc.h" #include "StdInc.h"
#include "CGuiHandler.h" #include "CGuiHandler.h"
#include <SDL.h>
#include "CIntObject.h" #include "CIntObject.h"
#include "../CGameInfo.h"
#include "CCursorHandler.h" #include "CCursorHandler.h"
#include "../CGameInfo.h"
#include "../../lib/CThreadHelper.h" #include "../../lib/CThreadHelper.h"
#include "../../lib/CConfigHandler.h" #include "../../lib/CConfigHandler.h"
#include "../CMT.h" #include "../CMT.h"

View File

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

View File

@ -1,9 +1,15 @@
#include "StdInc.h" #include "StdInc.h"
#include "CIntObject.h" #include "CIntObject.h"
#include "CGuiHandler.h" #include "CGuiHandler.h"
#include "SDL_Extensions.h" #include "SDL_Extensions.h"
#include "../CMessage.h" #include "../CMessage.h"
IShowActivatable::IShowActivatable()
{
type = 0;
}
void ILockedUpdatable::runLocked(std::function<void(IUpdateable*)> cb) void ILockedUpdatable::runLocked(std::function<void(IUpdateable*)> cb)
{ {
boost::unique_lock<boost::recursive_mutex> lock(updateGuard); boost::unique_lock<boost::recursive_mutex> lock(updateGuard);
@ -317,6 +323,19 @@ bool CIntObject::captureThisEvent(const SDL_KeyboardEvent & key)
return captureAllKeys; return captureAllKeys;
} }
CKeyShortcut::CKeyShortcut()
{}
CKeyShortcut::CKeyShortcut(int key)
{
if (key != SDLK_UNKNOWN)
assignedKeys.insert(key);
}
CKeyShortcut::CKeyShortcut(std::set<int> Keys)
:assignedKeys(Keys)
{}
void CKeyShortcut::keyPressed(const SDL_KeyboardEvent & key) void CKeyShortcut::keyPressed(const SDL_KeyboardEvent & key)
{ {
if(vstd::contains(assignedKeys,key.keysym.sym) if(vstd::contains(assignedKeys,key.keysym.sym)

View File

@ -10,7 +10,7 @@
#pragma once #pragma once
#include <SDL_events.h> //#include <SDL_events.h>
#include "Geometries.h" #include "Geometries.h"
#include "../Graphics.h" #include "../Graphics.h"
@ -18,6 +18,8 @@ struct SDL_Surface;
class CPicture; class CPicture;
class CGuiHandler; class CGuiHandler;
struct SDL_KeyboardEvent;
using boost::logic::tribool; using boost::logic::tribool;
// Defines a activate/deactive method // Defines a activate/deactive method
@ -216,8 +218,8 @@ class CKeyShortcut : public virtual CIntObject
{ {
public: public:
std::set<int> assignedKeys; std::set<int> assignedKeys;
CKeyShortcut(){}; //c-tor CKeyShortcut();
CKeyShortcut(int key){assignedKeys.insert(key);}; //c-tor CKeyShortcut(int key);
CKeyShortcut(std::set<int> Keys):assignedKeys(Keys){}; //c-tor CKeyShortcut(std::set<int> Keys);
virtual void keyPressed(const SDL_KeyboardEvent & key); //call-in virtual void keyPressed(const SDL_KeyboardEvent & key); //call-in
}; };

File diff suppressed because it is too large Load Diff

View File

@ -1,557 +0,0 @@
#pragma once
#include "CIntObject.h"
#include "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 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
CLabel * text;//text 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 std::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();
};

View File

@ -1,6 +1,11 @@
#include "StdInc.h" #include "StdInc.h"
#include "Geometries.h" #include "Geometries.h"
#include "../CMT.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 ) 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) Rect Rect::centerIn(const Rect &r)
{ {
return Rect(r.x + (r.w - w) / 2, r.y + (r.h - h) / 2, w, h); return Rect(r.x + (r.w - w) / 2, r.y + (r.h - h) / 2, w, h);
} }

View File

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

View File

@ -2,7 +2,6 @@
#include "SDL_Extensions.h" #include "SDL_Extensions.h"
#include "SDL_Pixels.h" #include "SDL_Pixels.h"
#include <SDL_ttf.h>
#include "../CGameInfo.h" #include "../CGameInfo.h"
#include "../CMessage.h" #include "../CMessage.h"
#include "../CDefHandler.h" #include "../CDefHandler.h"

View File

@ -16,10 +16,11 @@
#endif #endif
#include <SDL_video.h> #include <SDL_video.h>
#include <SDL_ttf.h> #include <SDL_events.h>
#include "../../lib/int3.h" #include "../../lib/int3.h"
#include "../Graphics.h" //#include "../Graphics.h"
#include "Geometries.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 //A macro to force inlining some of our functions. Compiler (at least MSVC) is not so smart here-> without that displaying is MUCH slower
@ -141,15 +142,16 @@ typename boost::enable_if_c<boost::is_unsigned<T>::type, T>::type abs(T arg)
} }
template<typename IntType> template<typename IntType>
std::string makeNumberShort(IntType number) //the output is a string containing at most 5 characters [4 if positive] (eg. intead 10000 it gives 10k) std::string makeNumberShort(IntType number, IntType maxLength = 3) //the output is a string containing at most 5 characters [4 if positive] (eg. intead 10000 it gives 10k)
{ {
if (abs(number) < 1000) IntType max = pow(10, maxLength);
if (abs(number) < max)
return boost::lexical_cast<std::string>(number); return boost::lexical_cast<std::string>(number);
std::string symbols = "kMGTPE"; std::string symbols = " kMGTPE";
auto iter = symbols.begin(); auto iter = symbols.begin();
while (number >= 1000) while (number >= max)
{ {
number /= 1000; number /= 1000;
iter++; iter++;

View File

@ -1,30 +1,43 @@
#include "StdInc.h" #include "StdInc.h"
#include "AdventureMapClasses.h" #include "AdventureMapClasses.h"
#include "../CCallback.h" #include <SDL.h>
#include "../lib/JsonNode.h"
#include "../lib/filesystem/Filesystem.h" #include "MiscWidgets.h"
#include "../lib/mapping/CMap.h" #include "CComponent.h"
#include "../lib/CModHandler.h"
#include "../lib/mapObjects/CGHeroInstance.h" #include "../CGameInfo.h"
#include "../lib/CGameState.h" #include "../CMusicHandler.h"
#include "../lib/CGeneralTextHandler.h" #include "../CPlayerInterface.h"
#include "../lib/CTownHandler.h" #include "../CPreGame.h"
#include "../lib/NetPacksBase.h" #include "../Graphics.h"
#include "../lib/CHeroHandler.h"
#include "../lib/StringConstants.h" #include "../gui/CGuiHandler.h"
#include "CAdvmapInterface.h" #include "../gui/SDL_Pixels.h"
#include "CAnimation.h"
#include "CGameInfo.h" #include "../windows/InfoWindows.h"
#include "CPlayerInterface.h" #include "../windows/CAdvmapInterface.h"
#include "CMusicHandler.h" #include "../windows/GUIClasses.h"
#include "Graphics.h"
#include "GUIClasses.h" #include "../battle/CBattleInterfaceClasses.h"
#include "gui/CGuiHandler.h" #include "../battle/CBattleInterface.h"
#include "gui/SDL_Pixels.h"
#include "../../CCallback.h"
#include "../../lib/StartInfo.h"
#include "../../lib/CGameState.h"
#include "../../lib/CGeneralTextHandler.h"
#include "../../lib/CHeroHandler.h"
#include "../../lib/CModHandler.h"
#include "../../lib/CTownHandler.h"
#include "../../lib/filesystem/Filesystem.h"
#include "../../lib/JsonNode.h"
#include "../../lib/mapObjects/CGHeroInstance.h"
#include "../../lib/mapping/CMap.h"
#include "../../lib/NetPacksBase.h"
#include "../../lib/StringConstants.h"
/* /*
* CAdventureMapClasses.h, part of VCMI engine * CAdventureMapClasses.cpp, part of VCMI engine
* *
* Authors: listed in file AUTHORS in main folder * Authors: listed in file AUTHORS in main folder
* *
@ -93,15 +106,23 @@ CList::CList(int Size, Point position, std::string btnUp, std::string btnDown, s
selected(nullptr) selected(nullptr)
{ {
OBJ_CONSTRUCTION_CAPTURING_ALL; OBJ_CONSTRUCTION_CAPTURING_ALL;
scrollUp = new CAdventureMapButton(CGI->generaltexth->zelp[helpUp], 0, 0, 0, btnUp); scrollUp = new CButton(Point(0, 0), btnUp, CGI->generaltexth->zelp[helpUp]);
list = new CListBox(create, destroy, Point(1,scrollUp->pos.h), Point(0, 32), size, listAmount); list = new CListBox(create, destroy, Point(1,scrollUp->pos.h), Point(0, 32), size, listAmount);
//assign callback only after list was created //assign callback only after list was created
<<<<<<< HEAD:client/AdventureMapClasses.cpp
scrollUp->callback = std::bind(&CListBox::moveToPrev, list); scrollUp->callback = std::bind(&CListBox::moveToPrev, list);
scrollDown = new CAdventureMapButton(CGI->generaltexth->zelp[helpDown], std::bind(&CListBox::moveToNext, list), 0, scrollUp->pos.h + 32*size, btnDown); scrollDown = new CAdventureMapButton(CGI->generaltexth->zelp[helpDown], std::bind(&CListBox::moveToNext, list), 0, scrollUp->pos.h + 32*size, btnDown);
scrollDown->callback += std::bind(&CList::update, this); scrollDown->callback += std::bind(&CList::update, this);
scrollUp->callback += std::bind(&CList::update, this); scrollUp->callback += std::bind(&CList::update, this);
=======
scrollUp->addCallback(boost::bind(&CListBox::moveToPrev, list));
scrollDown = new CButton(Point(0, scrollUp->pos.h + 32*size), btnDown, CGI->generaltexth->zelp[helpDown], boost::bind(&CListBox::moveToNext, list));
scrollDown->addCallback(boost::bind(&CList::update, this));
scrollUp->addCallback(boost::bind(&CList::update, this));
>>>>>>> refactoring/guiClasses:client/widgets/AdventureMapClasses.cpp
update(); update();
} }
@ -950,3 +971,248 @@ void CInfoBar::showGameStatus()
setTimer(3000); setTimer(3000);
redraw(); redraw();
} }
void CInGameConsole::show(SDL_Surface * to)
{
int number = 0;
std::vector<std::list< std::pair< std::string, int > >::iterator> toDel;
boost::unique_lock<boost::mutex> lock(texts_mx);
for(auto it = texts.begin(); it != texts.end(); ++it, ++number)
{
Point leftBottomCorner(0, screen->h);
if(LOCPLINT->battleInt)
{
leftBottomCorner = LOCPLINT->battleInt->pos.bottomLeft();
}
graphics->fonts[FONT_MEDIUM]->renderTextLeft(to, it->first, Colors::GREEN,
Point(leftBottomCorner.x + 50, leftBottomCorner.y - texts.size() * 20 - 80 + number*20));
if(SDL_GetTicks() - it->second > defaultTimeout)
{
toDel.push_back(it);
}
}
for(auto & elem : toDel)
{
texts.erase(elem);
}
}
void CInGameConsole::print(const std::string &txt)
{
boost::unique_lock<boost::mutex> lock(texts_mx);
int lineLen = conf.go()->ac.outputLineLength;
if(txt.size() < lineLen)
{
texts.push_back(std::make_pair(txt, SDL_GetTicks()));
if(texts.size() > maxDisplayedTexts)
{
texts.pop_front();
}
}
else
{
assert(lineLen);
for(int g=0; g<txt.size() / lineLen + 1; ++g)
{
std::string part = txt.substr(g * lineLen, lineLen);
if(part.size() == 0)
break;
texts.push_back(std::make_pair(part, SDL_GetTicks()));
if(texts.size() > maxDisplayedTexts)
{
texts.pop_front();
}
}
}
}
void CInGameConsole::keyPressed (const SDL_KeyboardEvent & key)
{
if(key.type != SDL_KEYDOWN) return;
if(!captureAllKeys && key.keysym.sym != SDLK_TAB) return; //because user is not entering any text
switch(key.keysym.sym)
{
case SDLK_TAB:
case SDLK_ESCAPE:
{
if(captureAllKeys)
{
captureAllKeys = false;
endEnteringText(false);
}
else if(SDLK_TAB)
{
captureAllKeys = true;
startEnteringText();
}
break;
}
case SDLK_RETURN: //enter key
{
if(enteredText.size() > 0 && captureAllKeys)
{
captureAllKeys = false;
endEnteringText(true);
CCS->soundh->playSound("CHAT");
}
break;
}
case SDLK_BACKSPACE:
{
if(enteredText.size() > 1)
{
Unicode::trimRight(enteredText,2);
enteredText += '_';
refreshEnteredText();
}
break;
}
case SDLK_UP: //up arrow
{
if(previouslyEntered.size() == 0)
break;
if(prevEntDisp == -1)
{
prevEntDisp = previouslyEntered.size() - 1;
enteredText = previouslyEntered[prevEntDisp] + "_";
refreshEnteredText();
}
else if( prevEntDisp > 0)
{
--prevEntDisp;
enteredText = previouslyEntered[prevEntDisp] + "_";
refreshEnteredText();
}
break;
}
case SDLK_DOWN: //down arrow
{
if(prevEntDisp != -1 && prevEntDisp+1 < previouslyEntered.size())
{
++prevEntDisp;
enteredText = previouslyEntered[prevEntDisp] + "_";
refreshEnteredText();
}
else if(prevEntDisp+1 == previouslyEntered.size()) //useful feature
{
prevEntDisp = -1;
enteredText = "_";
refreshEnteredText();
}
break;
}
default:
{
#ifdef VCMI_SDL1
if(enteredText.size() > 0 && enteredText.size() < conf.go()->ac.inputLineLength)
{
if( key.keysym.unicode < 0x80 && key.keysym.unicode > 0 )
{
enteredText[enteredText.size()-1] = (char)key.keysym.unicode;
enteredText += "_";
refreshEnteredText();
}
}
#endif // VCMI_SDL1
break;
}
}
}
#ifndef VCMI_SDL1
void CInGameConsole::textInputed(const SDL_TextInputEvent & event)
{
if(!captureAllKeys || enteredText.size() == 0)
return;
enteredText.resize(enteredText.size()-1);
enteredText += event.text;
enteredText += "_";
refreshEnteredText();
}
void CInGameConsole::textEdited(const SDL_TextEditingEvent & event)
{
//do nothing here
}
#endif // VCMI_SDL1
void CInGameConsole::startEnteringText()
{
CSDL_Ext::startTextInput(&pos);
enteredText = "_";
if(GH.topInt() == adventureInt)
{
GH.statusbar->alignment = TOPLEFT;
GH.statusbar->setText(enteredText);
//Prevent changes to the text from mouse interaction with the adventure map
GH.statusbar->lock(true);
}
else if(LOCPLINT->battleInt)
{
LOCPLINT->battleInt->console->ingcAlter = enteredText;
}
}
void CInGameConsole::endEnteringText(bool printEnteredText)
{
CSDL_Ext::stopTextInput();
prevEntDisp = -1;
if(printEnteredText)
{
std::string txt = enteredText.substr(0, enteredText.size()-1);
LOCPLINT->cb->sendMessage(txt);
previouslyEntered.push_back(txt);
//print(txt);
}
enteredText = "";
if(GH.topInt() == adventureInt)
{
GH.statusbar->alignment = CENTER;
GH.statusbar->lock(false);
GH.statusbar->clear();
}
else if(LOCPLINT->battleInt)
{
LOCPLINT->battleInt->console->ingcAlter = "";
}
}
void CInGameConsole::refreshEnteredText()
{
if(GH.topInt() == adventureInt)
{
GH.statusbar->lock(false);
GH.statusbar->clear();
GH.statusbar->setText(enteredText);
GH.statusbar->lock(true);
}
else if(LOCPLINT->battleInt)
{
LOCPLINT->battleInt->console->ingcAlter = enteredText;
}
}
CInGameConsole::CInGameConsole() : prevEntDisp(-1), defaultTimeout(10000), maxDisplayedTexts(10)
{
#ifdef VCMI_SDL1
addUsedEvents(KEYBOARD);
#else
addUsedEvents(KEYBOARD | TEXTINPUT);
#endif
}

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "gui/CIntObject.h" #include "ObjectLists.h"
#include "gui/CIntObjectClasses.h" #include "../../lib/FunctionList.h"
class CArmedInstance; class CArmedInstance;
class CShowableAnim; class CShowableAnim;
@ -9,6 +9,7 @@ class CGGarrison;
class CGObjectInstance; class CGObjectInstance;
class CGHeroInstance; class CGHeroInstance;
class CGTownInstance; class CGTownInstance;
class CButton;
struct Component; struct Component;
struct InfoAboutArmy; struct InfoAboutArmy;
struct InfoAboutHero; struct InfoAboutHero;
@ -82,8 +83,8 @@ protected:
public: public:
CAdventureMapButton * scrollUp; CButton * scrollUp;
CAdventureMapButton * scrollDown; CButton * scrollDown;
/// functions that will be called when selection changes /// functions that will be called when selection changes
CFunctionList<void()> onSelect; CFunctionList<void()> onSelect;
@ -313,3 +314,30 @@ public:
/// for 3 seconds shows amount of town halls and players status /// for 3 seconds shows amount of town halls and players status
void showGameStatus(); void showGameStatus();
}; };
class CInGameConsole : public CIntObject
{
private:
std::list< std::pair< std::string, int > > texts; //list<text to show, time of add>
boost::mutex texts_mx; // protects texts
std::vector< std::string > previouslyEntered; //previously entered texts, for up/down arrows to work
int prevEntDisp; //displayed entry from previouslyEntered - if none it's -1
int defaultTimeout; //timeout for new texts (in ms)
int maxDisplayedTexts; //hiw many texts can be displayed simultaneously
public:
std::string enteredText;
void show(SDL_Surface * to);
void print(const std::string &txt);
void keyPressed (const SDL_KeyboardEvent & key); //call-in
#ifndef VCMI_SDL1
void textInputed(const SDL_TextInputEvent & event) override;
void textEdited(const SDL_TextEditingEvent & event) override;
#endif // VCMI_SDL1
void startEnteringText();
void endEnteringText(bool printEnteredText);
void refreshEnteredText();
CInGameConsole(); //c-tor
};

740
client/widgets/Buttons.cpp Normal file
View File

@ -0,0 +1,740 @@
#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
*
*/
ClickableArea::ClickableArea(CIntObject * object, CFunctionList<void()> callback):
callback(callback),
area(nullptr)
{
if (object)
pos = object->pos;
setArea(object);
}
void ClickableArea::addCallback(std::function<void()> callback)
{
this->callback += callback;
}
void ClickableArea::setArea(CIntObject * object)
{
delete area;
addChild(area);
pos.w = object->pos.w;
pos.h = object->pos.h;
}
void ClickableArea::onClick()
{
callback();
}
void ClickableArea::clickLeft(tribool down, bool previousState)
{
if (down)
onClick();
}
void CButton::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 = stateToIndex[int(state)];
if (newPos < 0)
newPos = 0;
if (state == HIGHLIGHTED && image->size() < 4)
newPos = image->size()-1;
image->setFrame(newPos);
if (active)
redraw();
}
void CButton::addCallback(std::function<void()> callback)
{
this->callback += callback;
}
void CButton::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 CButton::addOverlay(CIntObject *newOverlay)
{
delete overlay;
overlay = newOverlay;
addChild(newOverlay);
overlay->moveTo(overlay->pos.centerIn(pos).topLeft());
update();
}
void CButton::addImage(std::string filename)
{
imageNames.push_back(filename);
}
void CButton::addHoverText(ButtonState state, std::string text)
{
hoverTexts[state] = text;
}
void CButton::setImageOrder(int state1, int state2, int state3, int state4)
{
stateToIndex[0] = state1;
stateToIndex[1] = state2;
stateToIndex[2] = state3;
stateToIndex[3] = state4;
update();
}
void CButton::setState(ButtonState newState)
{
if (state == newState)
return;
state = newState;
update();
}
CButton::ButtonState CButton::getState()
{
return state;
}
bool CButton::isBlocked()
{
return state == BLOCKED;
}
bool CButton::isHighlighted()
{
return state == HIGHLIGHTED;
}
void CButton::block(bool on)
{
setState(on?BLOCKED:NORMAL);
}
void CButton::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 << ", " << callback.funcs.size() << " functions";
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 CButton::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 CButton::clickRight(tribool down, bool previousState)
{
if(down && helpBox.size()) //there is no point to show window with nothing inside...
CRClickPopup::createAndPush(helpBox);
}
void CButton::hover (bool on)
{
if(hoverable && !isBlocked())
{
if(on)
setState(HIGHLIGHTED);
else
setState(NORMAL);
}
/*if(pressedL && on) // WTF is this? When this is used?
setState(PRESSED);*/
std::string name = hoverTexts[getState()].empty()
? hoverTexts[getState()]
: hoverTexts[0];
if(!name.empty() && !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();
}
}
}
CButton::CButton(Point position, const std::string &defName, const std::pair<std::string, std::string> &help, CFunctionList<void()> Callback, int key, bool playerColoredButton):
CKeyShortcut(key),
callback(Callback)
{
addUsedEvents(LCLICK | RCLICK | HOVER | KEYBOARD);
stateToIndex[0] = 0;
stateToIndex[1] = 1;
stateToIndex[2] = 2;
stateToIndex[3] = 3;
state=NORMAL;
image = nullptr;
overlay = nullptr;
currentImage = -1;
hoverable = actOnDown = soundDisabled = false;
hoverTexts[0] = help.first;
helpBox=help.second;
pos.x += position.x;
pos.y += position.y;
if (!defName.empty())
{
imageNames.push_back(defName);
setIndex(0, playerColoredButton);
}
}
void CButton::setIndex(size_t index, bool playerColoredButton)
{
if (index == currentImage || index>=imageNames.size())
return;
currentImage = index;
setImage(new CAnimation(imageNames[index]), playerColoredButton);
}
void CButton::setImage(CAnimation* anim, bool playerColoredButton, int animFlags)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
image = new CAnimImage(anim, getState(), 0, 0, 0, animFlags);
if (playerColoredButton)
image->playerColored(LOCPLINT->playerID);
pos = image->pos;
}
void CButton::setPlayerColor(PlayerColor player)
{
if (image)
image->playerColored(player);
}
void CButton::showAll(SDL_Surface * to)
{
CIntObject::showAll(to);
#ifdef VCMI_SDL1
if (borderColor && 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 (borderColor && 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
}
std::pair<std::string, std::string> CButton::tooltip()
{
return std::pair<std::string, std::string>();
}
std::pair<std::string, std::string> CButton::tooltip(const JsonNode & localizedTexts)
{
return std::make_pair(localizedTexts["label"].String(), localizedTexts["help"].String());
}
std::pair<std::string, std::string> CButton::tooltip(const std::string & hover, const std::string & help)
{
return std::make_pair(hover, help);
}
CToggleBase::CToggleBase(CFunctionList<void (bool)> callback):
callback(callback),
selected(false),
allowDeselection(true)
{
}
CToggleBase::~CToggleBase()
{
}
void CToggleBase::doSelect(bool on)
{
// for overrides
}
void CToggleBase::setSelected(bool on)
{
bool changed = (on != selected);
selected = on;
doSelect(on);
if (changed)
callback(on);
}
bool CToggleBase::canActivate()
{
if (selected && !allowDeselection)
return false;
return true;
}
void CToggleBase::addCallback(std::function<void(bool)> function)
{
callback.add(function);
}
CToggleButton::CToggleButton(Point position, const std::string &defName, const std::pair<std::string, std::string> &help,
CFunctionList<void(bool)> callback, int key, bool playerColoredButton):
CButton(position, defName, help, 0, key, playerColoredButton),
CToggleBase(callback)
{
allowDeselection = true;
}
void CToggleButton::doSelect(bool on)
{
if (on)
{
setState(HIGHLIGHTED);
}
else
{
setState(NORMAL);
}
}
void CToggleButton::clickLeft(tribool down, bool previousState)
{
// force refresh
hover(false);
hover(true);
if(isBlocked())
return;
if (down && canActivate())
{
CCS->soundh->playSound(soundBase::button);
setState(PRESSED);
}
if(previousState)//mouse up
{
if(down == false && getState() == PRESSED && canActivate())
{
onButtonClicked();
setSelected(!selected);
}
else
doSelect(selected); // restore
}
}
void CToggleGroup::addCallback(std::function<void(int)> callback)
{
onChange += callback;
}
void CToggleGroup::addToggle(int identifier, CToggleBase* bt)
{
if (auto intObj = dynamic_cast<CIntObject*>(bt)) // hack-ish workagound to avoid diamond problem with inheritance
{
if (intObj->parent)
intObj->parent->removeChild(intObj);
addChild(intObj);
}
bt->addCallback([=] (bool on) { if (on) selectionChanged(identifier);});
bt->allowDeselection = false;
assert(buttons[identifier] == nullptr);
buttons[identifier] = bt;
}
CToggleGroup::CToggleGroup(const CFunctionList<void(int)> &OnChange, bool musicLikeButtons)
: onChange(OnChange), musicLike(musicLikeButtons)
{}
void CToggleGroup::setSelected(int id)
{
selectionChanged(id);
}
void CToggleGroup::selectionChanged(int to)
{
if (to == selectedID)
return;
int oldSelection = selectedID;
selectedID = to;
if (buttons.count(oldSelection))
buttons[oldSelection]->setSelected(false);
if (buttons.count(to))
buttons[to]->setSelected(true);
onChange(to);
if (parent)
parent->redraw();
}
void CToggleGroup::show(SDL_Surface * to)
{
if (musicLike)
{
if (auto intObj = dynamic_cast<CIntObject*>(buttons[selectedID])) // hack-ish workagound to avoid diamond problem with inheritance
intObj->show(to);
}
else
CIntObject::show(to);
}
void CToggleGroup::showAll(SDL_Surface * to)
{
if (musicLike)
{
if (auto intObj = dynamic_cast<CIntObject*>(buttons[selectedID])) // hack-ish workagound to avoid diamond problem with inheritance
intObj->showAll(to);
}
else
CIntObject::showAll(to);
}
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);
}
}
void CSlider::setScrollStep(int to)
{
scrollStep = to;
}
int CSlider::getAmount()
{
return amount;
}
int CSlider::getValue()
{
return value;
}
void CSlider::moveLeft()
{
moveTo(value-1);
}
void CSlider::moveRight()
{
moveTo(value+1);
}
void CSlider::moveBy(int amount)
{
moveTo(value + amount);
}
void CSlider::updateSliderPos()
{
if(horizontal)
{
if(positions)
{
double part = static_cast<double>(value) / 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>(value) / 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));
}
}
void CSlider::moveTo(int to)
{
vstd::amax(to, 0);
vstd::amin(to, positions);
//same, old position?
if(value == to)
return;
value = to;
updateSliderPos();
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(Point position, int totalw, std::function<void(int)> Moved, int Capacity, int Amount, int Value, bool Horizontal, CSlider::EStyle style):
capacity(Capacity),
horizontal(Horizontal),
amount(Amount),
value(Value),
scrollStep(1),
moved(Moved)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
setAmount(amount);
addUsedEvents(LCLICK | KEYBOARD | WHEEL);
strongInterest = true;
pos.x += position.x;
pos.y += position.y;
if(style == BROWN)
{
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...)
left = new CButton(Point(), name, CButton::tooltip());
right = new CButton(Point(), name, CButton::tooltip());
slider = new CButton(Point(), name, CButton::tooltip());
left->setImageOrder(0, 1, 1, 1);
right->setImageOrder(2, 3, 3, 3);
slider->setImageOrder(4, 4, 4, 4);
}
else
{
left = new CButton(Point(), horizontal ? "SCNRBLF.DEF" : "SCNRBUP.DEF", CButton::tooltip());
right = new CButton(Point(), horizontal ? "SCNRBRT.DEF" : "SCNRBDN.DEF", CButton::tooltip());
slider = new CButton(Point(), "SCNRBSL.DEF", CButton::tooltip());
}
slider->actOnDown = true;
slider->soundDisabled = true;
left->soundDisabled = true;
right->soundDisabled = true;
if (horizontal)
right->moveBy(Point(totalw - right->pos.w, 0));
else
right->moveBy(Point(0, totalw - right->pos.h));
left->addCallback(boost::bind(&CSlider::moveLeft,this));
right->addCallback(boost::bind(&CSlider::moveRight,this));
slider->addCallback(boost::bind(&CSlider::sliderClicked,this));
if(horizontal)
{
pos.h = slider->pos.h;
pos.w = totalw;
}
else
{
pos.w = slider->pos.w;
pos.h = totalw;
}
updateSliderPos();
}
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);
}

261
client/widgets/Buttons.h Normal file
View File

@ -0,0 +1,261 @@
#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
*
*/
class ClickableArea : public CIntObject //TODO: derive from LRCLickableArea? Or somehow use its right-click/hover data?
{
CFunctionList<void()> callback;
CIntObject * area;
protected:
void onClick();
public:
ClickableArea(CIntObject * object, CFunctionList<void()> callback);
void addCallback(std::function<void()> callback);
void setArea(CIntObject * object);
void clickLeft(tribool down, bool previousState) override;
};
/// Typical Heroes 3 button which can be inactive or active and can
/// hold further information if you right-click it
class CButton : public CKeyShortcut
{
CFunctionList<void()> callback;
public:
enum ButtonState
{
NORMAL=0,
PRESSED=1,
BLOCKED=2,
HIGHLIGHTED=3
};
private:
std::vector<std::string> imageNames;//store list of images that can be used by this button
size_t currentImage;
ButtonState state;//current state of button from enum
std::array<int, 4> stateToIndex; // mapping of button state to index of frame in animation
std::array<std::string, 4> hoverTexts; //texts for statusbar, if empty - first entry will be used
std::string helpBox; //for right-click help
CAnimImage * image; //image for this button
CIntObject * overlay;//object-overlay, can be null
protected:
void onButtonClicked(); // calls callback
void update();//to refresh button after image or text change
// internal method to change state. Public change can be done only via block()
void setState(ButtonState newState);
ButtonState getState();
public:
bool actOnDown,//runs when mouse is pressed down over it, not when up
hoverable,//if true, button will be highlighted when hovered (e.g. main menu)
soundDisabled;
// if set, button will have 1-px border around it with this color
boost::optional<SDL_Color> borderColor;
/// adds one more callback to on-click actions
void addCallback(std::function<void()> callback);
/// adds overlay on top of button image. Only one overlay can be active at once
void addOverlay(CIntObject * newOverlay);
void addTextOverlay(const std::string &Text, EFonts font, SDL_Color color = Colors::WHITE);
void addImage(std::string filename);
void addHoverText(ButtonState state, std::string text);
void setImageOrder(int state1, int state2, int state3, int state4);
void block(bool on);
/// State modifiers
bool isBlocked();
bool isHighlighted();
/// Constructor
CButton(Point position, const std::string &defName, const std::pair<std::string, std::string> &help,
CFunctionList<void()> Callback = 0, int key=0, bool playerColoredButton = false );
/// Appearance modifiers
void setIndex(size_t index, bool playerColoredButton=false);
void setImage(CAnimation* anim, bool playerColoredButton=false, int animFlags=0);
void setPlayerColor(PlayerColor player);
/// CIntObject overrides
void clickRight(tribool down, bool previousState) override;
void clickLeft(tribool down, bool previousState) override;
void hover (bool on) override;
void showAll(SDL_Surface * to) override;
/// generates tooltip that can be passed into constructor
static std::pair<std::string, std::string> tooltip();
static std::pair<std::string, std::string> tooltip(const JsonNode & localizedTexts);
static std::pair<std::string, std::string> tooltip(const std::string & hover, const std::string & help = "");
};
class CToggleBase
{
CFunctionList<void(bool)> callback;
protected:
bool selected;
// internal method for overrides
virtual void doSelect(bool on);
// returns true if toggle can change its state
bool canActivate();
public:
/// if set to false - button can not be deselected normally
bool allowDeselection;
CToggleBase(CFunctionList<void(bool)> callback);
virtual ~CToggleBase();
/// Changes selection to "on", and calls callback
void setSelected(bool on);
void addCallback(std::function<void(bool)> callback);
};
class ClickableToggle : public ClickableArea, public CToggleBase
{
public:
ClickableToggle(CIntObject * object, CFunctionList<void()> selectFun, CFunctionList<void()> deselectFun);
void clickLeft(tribool down, bool previousState) override;
};
/// A button which can be selected/deselected, checkbox
class CToggleButton : public CButton, public CToggleBase
{
void doSelect(bool on) override;
public:
CToggleButton(Point position, const std::string &defName, const std::pair<std::string, std::string> &help,
CFunctionList<void(bool)> Callback = 0, int key=0, bool playerColoredButton = false );
void clickLeft(tribool down, bool previousState) override;
// bring overrides into scope
using CButton::addCallback;
using CToggleBase::addCallback;
};
class CToggleGroup : public CIntObject
{
CFunctionList<void(int)> onChange; //called when changing selected button with new button's id
int selectedID;
bool musicLike; //determines the behaviour of this group
void selectionChanged(int to);
public:
std::map<int, CToggleBase*> buttons;
CToggleGroup(const CFunctionList<void(int)> & OnChange, bool musicLikeButtons = false);
void addCallback(std::function<void(int)> callback);
/// add one toggle/button into group
void addToggle(int index, CToggleBase * button);
/// Changes selection to specific value. Will select toggle with this ID, if present
void setSelected(int id);
void show(SDL_Surface * to);
void showAll(SDL_Surface * to);
};
/// A typical slider which can be orientated horizontally/vertically.
class CSlider : public CIntObject
{
CButton *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 positions; //number of highest position (0 if there is only one)
bool horizontal;
bool wheelScrolling;
bool keyScrolling;
int amount; //total amount of elements (e.g. hero list = 0-8)
int value; //first active element
int scrollStep; // how many elements will be scrolled via one click, default = 1
CFunctionList<void(int)> moved;
void updateSliderPos();
void sliderClicked();
public:
enum EStyle {
BROWN,
BLUE
};
void block(bool on);
/// Controls how many items wil be scrolled via one click
void setScrollStep(int to);
/// Value modifiers
void moveLeft();
void moveRight();
void moveTo(int value);
void moveBy(int amount);
void moveToMax();
/// Amount modifier
void setAmount(int to);
/// Accessors
int getAmount();
int getValue();
void addCallback(std::function<void(int)> callback);
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);
/**
* @param position, coordinates of slider
* @param length, length of slider ribbon, including left/right buttons
* @param Moved, function that will be called whenever slider moves
* @param Capacity, maximal number of visible at once elements
* @param Amount, total amount of elements, including not visible
* @param Value, starting position
*/
CSlider(Point position, int length, std::function<void(int)> Moved, int Capacity, int Amount,
int Value=0, bool Horizontal=true, EStyle style = BROWN);
~CSlider();
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,145 @@
#pragma once
//#include "CComponent.h"
#include "MiscWidgets.h"
/*
* CArtifactHolder.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 CArtifactsOfHero;
class CAnimImage;
class CButton;
struct ArtifactLocation;
class CArtifactHolder
{
public:
CArtifactHolder();
virtual void artifactRemoved(const ArtifactLocation &artLoc)=0;
virtual void artifactMoved(const ArtifactLocation &artLoc, const ArtifactLocation &destLoc)=0;
virtual void artifactDisassembled(const ArtifactLocation &artLoc)=0;
virtual void artifactAssembled(const ArtifactLocation &artLoc)=0;
};
class CWindowWithArtifacts : public CArtifactHolder
{
public:
std::vector<CArtifactsOfHero *> artSets;
void artifactRemoved(const ArtifactLocation &artLoc);
void artifactMoved(const ArtifactLocation &artLoc, const ArtifactLocation &destLoc);
void artifactDisassembled(const ArtifactLocation &artLoc);
void artifactAssembled(const ArtifactLocation &artLoc);
};
/// Artifacts can be placed there. Gets shown at the hero window
class CArtPlace: public LRClickableAreaWTextComp
{
CAnimImage *image;
CAnimImage *selection;
void createImage();
public:
// consider these members as const - change them only with appropriate methods e.g. lockSlot()
bool locked;
bool picked;
bool marked;
ArtifactPosition slotID; //Arts::EPOS enum + backpack starting from Arts::BACKPACK_START
void lockSlot(bool on);
void pickSlot(bool on);
void selectSlot(bool on);
CArtifactsOfHero * ourOwner;
const CArtifactInstance * ourArt; // should be changed only with setArtifact()
CArtPlace(Point position, const CArtifactInstance * Art = nullptr); //c-tor
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
void select ();
void deselect ();
void showAll(SDL_Surface * to);
bool fitsHere (const CArtifactInstance * art) const; //returns true if given artifact can be placed here
void setMeAsDest(bool backpackAsVoid = true);
void setArtifact(const CArtifactInstance *art);
};
/// Contains artifacts of hero. Distincts which artifacts are worn or backpacked
class CArtifactsOfHero : public CIntObject
{
const CGHeroInstance * curHero;
std::vector<CArtPlace *> artWorn; // 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
std::vector<CArtPlace *> backpack; //hero's visible backpack (only 5 elements!)
int backpackPos; //number of first art visible in backpack (in hero's vector)
public:
struct SCommonPart
{
struct Artpos
{
ArtifactPosition slotID;
const CArtifactsOfHero *AOH;
const CArtifactInstance *art;
Artpos();
void clear();
void setTo(const CArtPlace *place, bool dontTakeBackpack);
bool valid();
bool operator==(const ArtifactLocation &al) const;
} src, dst;
std::set<CArtifactsOfHero *> participants; // Needed to mark slots.
void reset();
} * commonInfo; //when we have more than one CArtifactsOfHero in one window with exchange possibility, we use this (eg. in exchange window); to be provided externally
bool updateState; // Whether the commonInfo should be updated on setHero or not.
CButton * leftArtRoll, * rightArtRoll;
bool allowedAssembling;
std::multiset<const CArtifactInstance*> artifactsOnAltar; //artifacts id that are technically present in backpack but in GUI are moved to the altar - they'll be omitted in backpack slots
std::function<void(CArtPlace*)> highlightModeCallback; //if set, clicking on art place doesn't pick artifact but highlights the slot and calls this function
void realizeCurrentTransaction(); //calls callback with parameters stored in commonInfo
void artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst);
void artifactRemoved(const ArtifactLocation &al);
void artifactAssembled(const ArtifactLocation &al);
void artifactDisassembled(const ArtifactLocation &al);
CArtPlace *getArtPlace(int slot);
void setHero(const CGHeroInstance * hero);
const CGHeroInstance *getHero() const;
void dispose(); //free resources not needed after closing windows and reset state
void scrollBackpack(int dir); //dir==-1 => to left; dir==1 => to right
void safeRedraw();
void markPossibleSlots(const CArtifactInstance* art);
void unmarkSlots(bool withRedraw = true); //unmarks slots in all visible AOHs
void unmarkLocalSlots(bool withRedraw = true); //unmarks slots in that particular AOH
void setSlotData (CArtPlace* artPlace, ArtifactPosition slotID);
void updateWornSlots (bool redrawParent = true);
void updateSlot(ArtifactPosition i);
void eraseSlotData (CArtPlace* artPlace, ArtifactPosition slotID);
CArtifactsOfHero(const Point& position, bool createCommonPart = false);
//Alternative constructor, used if custom artifacts positioning required (Kingdom interface)
CArtifactsOfHero(std::vector<CArtPlace *> ArtWorn, std::vector<CArtPlace *> Backpack,
CButton *leftScroll, CButton *rightScroll, bool createCommonPart = false);
~CArtifactsOfHero(); //d-tor
void updateParentWindow();
friend class CArtPlace;
};

View File

@ -0,0 +1,453 @@
#include "StdInc.h"
#include "CComponent.h"
#include "../gui/CGuiHandler.h"
#include "../gui/CCursorHandler.h"
#include "../CMessage.h"
#include "../CGameInfo.h"
#include "../widgets/Images.h"
#include "../windows/CAdvmapInterface.h"
#include "../../lib/CArtHandler.h"
#include "../../lib/CTownHandler.h"
#include "../../lib/CCreatureHandler.h"
#include "../../lib/CSpellHandler.h"
#include "../../lib/CGeneralTextHandler.h"
#include "../../lib/NetPacksBase.h"
/*
* CComponent.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
*
*/
CComponent::CComponent(Etype Type, int Subtype, int Val, ESize imageSize):
image(nullptr),
perDay(false)
{
addUsedEvents(RCLICK);
init(Type, Subtype, Val, imageSize);
}
CComponent::CComponent(const Component &c):
image(nullptr),
perDay(false)
{
addUsedEvents(RCLICK);
if(c.id == Component::RESOURCE && c.when==-1)
perDay = true;
init((Etype)c.id,c.subtype,c.val, large);
}
void CComponent::init(Etype Type, int Subtype, int Val, ESize imageSize)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
compType = Type;
subtype = Subtype;
val = Val;
size = imageSize;
assert(compType < typeInvalid);
assert(size < sizeInvalid);
setSurface(getFileName()[size], getIndex());
pos.w = image->pos.w;
pos.h = image->pos.h;
EFonts font = FONT_SMALL;
if (imageSize < small)
font = FONT_TINY; //other sizes?
pos.h += 4; //distance between text and image
std::vector<std::string> textLines = CMessage::breakText(getSubtitle(), std::max<int>(80, pos.w), font);
for(auto & line : textLines)
{
int height = graphics->fonts[font]->getLineHeight();
auto label = new CLabel(pos.w/2, pos.h + height/2, font, CENTER, Colors::WHITE, line);
pos.h += height;
if (label->pos.w > pos.w)
{
pos.x -= (label->pos.w - pos.w)/2;
pos.w = label->pos.w;
}
}
}
const std::vector<std::string> CComponent::getFileName()
{
static const std::string primSkillsArr [] = {"PSKIL32", "PSKIL32", "PSKIL42", "PSKILL"};
static const std::string secSkillsArr [] = {"SECSK32", "SECSK32", "SECSKILL", "SECSK82"};
static const std::string resourceArr [] = {"SMALRES", "RESOURCE", "RESOUR82", "RESOUR82"};
static const std::string creatureArr [] = {"CPRSMALL", "CPRSMALL", "TWCRPORT", "TWCRPORT"};
static const std::string artifactArr[] = {"Artifact", "Artifact", "Artifact", "Artifact"};
static const std::string spellsArr [] = {"SpellInt", "SpellInt", "SPELLSCR", "SPELLSCR"};
static const std::string moraleArr [] = {"IMRL22", "IMRL30", "IMRL42", "imrl82"};
static const std::string luckArr [] = {"ILCK22", "ILCK30", "ILCK42", "ilck82"};
static const std::string heroArr [] = {"PortraitsSmall", "PortraitsSmall", "PortraitsLarge", "PortraitsLarge"};
static const std::string flagArr [] = {"CREST58", "CREST58", "CREST58", "CREST58"};
auto gen = [](const std::string * arr)
{
return std::vector<std::string>(arr, arr + 4);
};
switch(compType)
{
case primskill: return gen(primSkillsArr);
case secskill: return gen(secSkillsArr);
case resource: return gen(resourceArr);
case creature: return gen(creatureArr);
case artifact: return gen(artifactArr);
case experience: return gen(primSkillsArr);
case spell: return gen(spellsArr);
case morale: return gen(moraleArr);
case luck: return gen(luckArr);
case building: return std::vector<std::string>(4, CGI->townh->factions[subtype]->town->clientInfo.buildingsIcons);
case hero: return gen(heroArr);
case flag: return gen(flagArr);
}
assert(0);
return std::vector<std::string>();
}
size_t CComponent::getIndex()
{
switch(compType)
{
case primskill: return subtype;
case secskill: return subtype*3 + 3 + val - 1;
case resource: return subtype;
case creature: return CGI->creh->creatures[subtype]->iconIndex;
case artifact: return CGI->arth->artifacts[subtype]->iconIndex;
case experience: return 4;
case spell: return subtype;
case morale: return val+3;
case luck: return val+3;
case building: return val;
case hero: return subtype;
case flag: return subtype;
}
assert(0);
return 0;
}
std::string CComponent::getDescription()
{
switch (compType)
{
case primskill: return (subtype < 4)? CGI->generaltexth->arraytxt[2+subtype] //Primary skill
: CGI->generaltexth->allTexts[149]; //mana
case secskill: return CGI->generaltexth->skillInfoTexts[subtype][val-1];
case resource: return CGI->generaltexth->allTexts[242];
case creature: return "";
case artifact: return CGI->arth->artifacts[subtype]->Description();
case experience: return CGI->generaltexth->allTexts[241];
case spell: return CGI->spellh->objects[subtype]->getLevelInfo(val).description;
case morale: return CGI->generaltexth->heroscrn[ 4 - (val>0) + (val<0)];
case luck: return CGI->generaltexth->heroscrn[ 7 - (val>0) + (val<0)];
case building: return CGI->townh->factions[subtype]->town->buildings[BuildingID(val)]->Description();
case hero: return "";
case flag: return "";
}
assert(0);
return "";
}
std::string CComponent::getSubtitle()
{
if (!perDay)
return getSubtitleInternal();
std::string ret = CGI->generaltexth->allTexts[3];
boost::replace_first(ret, "%d", getSubtitleInternal());
return ret;
}
std::string CComponent::getSubtitleInternal()
{
//FIXME: some of these are horrible (e.g creature)
switch(compType)
{
case primskill: return boost::str(boost::format("%+d %s") % val % (subtype < 4 ? CGI->generaltexth->primarySkillNames[subtype] : CGI->generaltexth->allTexts[387]));
case secskill: return CGI->generaltexth->levels[val-1] + "\n" + CGI->generaltexth->skillName[subtype];
case resource: return boost::lexical_cast<std::string>(val);
case creature: return (val? boost::lexical_cast<std::string>(val) + " " : "") + CGI->creh->creatures[subtype]->*(val != 1 ? &CCreature::namePl : &CCreature::nameSing);
case artifact: return CGI->arth->artifacts[subtype]->Name();
case experience:
{
if (subtype == 1) //+1 level - tree of knowledge
{
std::string level = CGI->generaltexth->allTexts[442];
boost::replace_first(level, "1", boost::lexical_cast<std::string>(val));
return level;
}
else
return boost::lexical_cast<std::string>(val); //amount of experience OR level required for seer hut;
}
case spell: return CGI->spellh->objects[subtype]->name;
case morale: return "";
case luck: return "";
case building: return CGI->townh->factions[subtype]->town->buildings[BuildingID(val)]->Name();
case hero: return "";
case flag: return CGI->generaltexth->capColors[subtype];
}
assert(0);
return "";
}
void CComponent::setSurface(std::string defName, int imgPos)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
vstd::clear_pointer(image);
image = new CAnimImage(defName, imgPos);
}
void CComponent::clickRight(tribool down, bool previousState)
{
if(!getDescription().empty())
adventureInt->handleRightClick(getDescription(), down);
}
void CSelectableComponent::clickLeft(tribool down, bool previousState)
{
if (down)
{
if(onSelect)
onSelect();
}
}
void CSelectableComponent::init()
{
selected = false;
}
CSelectableComponent::CSelectableComponent(const Component &c, std::function<void()> OnSelect):
CComponent(c),onSelect(OnSelect)
{
type |= REDRAW_PARENT;
addUsedEvents(LCLICK | KEYBOARD);
init();
}
CSelectableComponent::CSelectableComponent(Etype Type, int Sub, int Val, ESize imageSize, std::function<void()> OnSelect):
CComponent(Type,Sub,Val, imageSize),onSelect(OnSelect)
{
type |= REDRAW_PARENT;
addUsedEvents(LCLICK | KEYBOARD);
init();
}
void CSelectableComponent::select(bool on)
{
if(on != selected)
{
selected = on;
redraw();
}
}
void CSelectableComponent::showAll(SDL_Surface * to)
{
CComponent::showAll(to);
if(selected)
{
CSDL_Ext::drawBorder(to, Rect::around(image->pos), int3(239,215,123));
}
}
void CComponentBox::selectionChanged(CSelectableComponent * newSelection)
{
if (newSelection == selected)
return;
if (selected)
selected->select(false);
selected = newSelection;
if (onSelect)
onSelect(selectedIndex());
if (selected)
selected->select(true);
}
int CComponentBox::selectedIndex()
{
if (selected)
return std::find(components.begin(), components.end(), selected) - components.begin();
return -1;
}
Point CComponentBox::getOrTextPos(CComponent *left, CComponent *right)
{
int leftSubtitle = ( left->pos.w - left->image->pos.w) / 2;
int rightSubtitle = (right->pos.w - right->image->pos.w) / 2;
int fullDistance = getDistance(left, right) + leftSubtitle + rightSubtitle;
return Point(fullDistance/2 - leftSubtitle, (left->image->pos.h + right->image->pos.h) / 4);
}
int CComponentBox::getDistance(CComponent *left, CComponent *right)
{
static const int betweenImagesMin = 20;
static const int betweenSubtitlesMin = 10;
int leftSubtitle = ( left->pos.w - left->image->pos.w) / 2;
int rightSubtitle = (right->pos.w - right->image->pos.w) / 2;
int subtitlesOffset = leftSubtitle + rightSubtitle;
return std::max(betweenSubtitlesMin, betweenImagesMin - subtitlesOffset);
}
void CComponentBox::placeComponents(bool selectable)
{
static const int betweenRows = 22;
OBJ_CONSTRUCTION_CAPTURING_ALL;
if (components.empty())
return;
//prepare components
for(auto & comp : components)
{
addChild(comp);
comp->moveTo(Point(pos.x, pos.y));
}
struct RowData
{
size_t comps;
int width;
int height;
RowData (size_t Comps, int Width, int Height):
comps(Comps), width (Width), height (Height){};
};
std::vector<RowData> rows;
rows.push_back (RowData (0,0,0));
//split components in rows
CComponent * prevComp = nullptr;
for(CComponent * comp : components)
{
//make sure that components are smaller than our width
//assert(pos.w == 0 || pos.w < comp->pos.w);
const int distance = prevComp ? getDistance(prevComp, comp) : 0;
//start next row
if ((pos.w != 0 && rows.back().width + comp->pos.w + distance > pos.w) // row is full
|| rows.back().comps >= 4) // no more than 4 comps per row
{
prevComp = nullptr;
rows.push_back (RowData (0,0,0));
}
if (prevComp)
rows.back().width += distance;
rows.back().comps++;
rows.back().width += comp->pos.w;
vstd::amax(rows.back().height, comp->pos.h);
prevComp = comp;
}
if (pos.w == 0)
{
for(auto & row : rows)
vstd::amax(pos.w, row.width);
}
int height = (rows.size() - 1) * betweenRows;
for(auto & row : rows)
height += row.height;
//assert(pos.h == 0 || pos.h < height);
if (pos.h == 0)
pos.h = height;
auto iter = components.begin();
int currentY = (pos.h - height) / 2;
//move components to their positions
for (auto & rows_row : rows)
{
// amount of free space we may add on each side of every component
int freeSpace = (pos.w - rows_row.width) / (rows_row.comps * 2);
prevComp = nullptr;
int currentX = 0;
for (size_t col = 0; col < rows_row.comps; col++)
{
currentX += freeSpace;
if (prevComp)
{
if (selectable)
{
Point orPos = Point(currentX - freeSpace, currentY) + getOrTextPos(prevComp, *iter);
new CLabel(orPos.x, orPos.y, FONT_MEDIUM, CENTER, Colors::WHITE, CGI->generaltexth->allTexts[4]);
}
currentX += getDistance(prevComp, *iter);
}
(*iter)->moveBy(Point(currentX, currentY));
currentX += (*iter)->pos.w;
currentX += freeSpace;
prevComp = *(iter++);
}
currentY += rows_row.height + betweenRows;
}
}
CComponentBox::CComponentBox(CComponent * _components, Rect position):
components(1, _components),
selected(nullptr)
{
type |= REDRAW_PARENT;
pos = position + pos;
placeComponents(false);
}
CComponentBox::CComponentBox(std::vector<CComponent *> _components, Rect position):
components(_components),
selected(nullptr)
{
type |= REDRAW_PARENT;
pos = position + pos;
placeComponents(false);
}
CComponentBox::CComponentBox(std::vector<CSelectableComponent *> _components, Rect position, std::function<void(int newID)> _onSelect):
components(_components.begin(), _components.end()),
selected(nullptr),
onSelect(_onSelect)
{
type |= REDRAW_PARENT;
pos = position + pos;
placeComponents(true);
assert(!components.empty());
int key = SDLK_1;
for(auto & comp : _components)
{
comp->onSelect = boost::bind(&CComponentBox::selectionChanged, this, comp);
comp->assignedKeys.insert(key++);
}
selectionChanged(_components.front());
}

112
client/widgets/CComponent.h Normal file
View File

@ -0,0 +1,112 @@
#pragma once
#include "../gui/CIntObject.h"
/*
* CComponent.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
*
*/
struct Component;
class CAnimImage;
/// common popup window component
class CComponent : public virtual CIntObject
{
public:
enum Etype
{
primskill, secskill, resource, creature, artifact, experience, spell, morale, luck, building, hero, flag, typeInvalid
};
//NOTE: not all types have exact these sizes or have less than 4 of them. In such cases closest one will be used
enum ESize
{
tiny, // ~22-24px
small, // ~30px
medium,// ~42px
large, // ~82px
sizeInvalid
};
private:
size_t getIndex();
const std::vector<std::string> getFileName();
void setSurface(std::string defName, int imgPos);
std::string getSubtitleInternal();
void init(Etype Type, int Subtype, int Val, ESize imageSize);
public:
CAnimImage *image; //our image
Etype compType; //component type
ESize size; //component size.
int subtype; //type-dependant subtype. See getSomething methods for details
int val; // value \ strength \ amount of component. See getSomething methods for details
bool perDay; // add "per day" text to subtitle
std::string getDescription();
std::string getSubtitle();
CComponent(Etype Type, int Subtype, int Val = 0, ESize imageSize=large);//c-tor
CComponent(const Component &c); //c-tor
void clickRight(tribool down, bool previousState); //call-in
};
/// component that can be selected or deselected
class CSelectableComponent : public CComponent, public CKeyShortcut
{
void init();
public:
bool selected; //if true, this component is selected
std::function<void()> onSelect; //function called on selection change
void showAll(SDL_Surface * to);
void select(bool on);
void clickLeft(tribool down, bool previousState); //call-in
CSelectableComponent(Etype Type, int Sub, int Val, ESize imageSize=large, std::function<void()> OnSelect = nullptr); //c-tor
CSelectableComponent(const Component &c, std::function<void()> OnSelect = nullptr); //c-tor
};
/// box with multiple components (up to 8?)
/// will take ownership on components and delete them afterwards
class CComponentBox : public CIntObject
{
std::vector<CComponent *> components;
CSelectableComponent * selected;
std::function<void(int newID)> onSelect;
void selectionChanged(CSelectableComponent * newSelection);
//get position of "or" text between these comps
//it will place "or" equidistant to both images
Point getOrTextPos(CComponent *left, CComponent * right);
//get distance between these copmonents
int getDistance(CComponent *left, CComponent * right);
void placeComponents(bool selectable);
public:
/// return index of selected item
int selectedIndex();
/// constructor for quite common 1-components popups
/// if position width or height are 0 then it will be determined automatically
CComponentBox(CComponent * components, Rect position);
/// constructor for non-selectable components
CComponentBox(std::vector<CComponent *> components, Rect position);
/// constructor for selectable components
/// will also create "or" labels between components
/// 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);
};

View File

@ -0,0 +1,512 @@
#include "StdInc.h"
#include "CGarrisonInt.h"
#include "../gui/CGuiHandler.h"
#include "../CGameInfo.h"
#include "../CPlayerInterface.h"
#include "../widgets/Buttons.h"
#include "../widgets/TextControls.h"
#include "../windows/CCreatureWindow.h"
#include "../windows/GUIClasses.h"
#include "../../CCallback.h"
#include "../../lib/CGeneralTextHandler.h"
#include "../../lib/CCreatureHandler.h"
#include "../../lib/mapObjects/CGHeroInstance.h"
#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)
selectionImage->enable(); //show
else
selectionImage->disable(); //hide
}
void CGarrisonSlot::hover (bool on)
{
////Hoverable::hover(on);
if(on)
{
std::string temp;
if(creature)
{
if(owner->getSelection())
{
if(owner->getSelection() == this)
{
temp = CGI->generaltexth->tcommands[4]; //View %s
boost::algorithm::replace_first(temp,"%s",creature->nameSing);
}
else if (owner->getSelection()->creature == creature)
{
temp = CGI->generaltexth->tcommands[2]; //Combine %s armies
boost::algorithm::replace_first(temp,"%s",creature->nameSing);
}
else if (owner->getSelection()->creature)
{
temp = CGI->generaltexth->tcommands[7]; //Exchange %s with %s
boost::algorithm::replace_first(temp,"%s",owner->getSelection()->creature->nameSing);
boost::algorithm::replace_first(temp,"%s",creature->nameSing);
}
else
{
logGlobal->warnStream() << "Warning - shouldn't be - highlighted void slot "<<owner->getSelection();
logGlobal->warnStream() << "Highlighted set to nullptr";
owner->selectSlot(nullptr);
}
}
else
{
if(upg)
{
temp = CGI->generaltexth->tcommands[32]; //Select %s (visiting)
}
else if(owner->armedObjs[0] && owner->armedObjs[0]->ID == Obj::TOWN)
{
temp = CGI->generaltexth->tcommands[12]; //Select %s (in garrison)
}
else
{
temp = CGI->generaltexth->allTexts[481]; //Select %s
}
boost::algorithm::replace_first(temp,"%s",creature->nameSing);
};
}
else
{
if(owner->getSelection())
{
const CArmedInstance *highl = owner->getSelection()->getObj();
if( highl->needsLastStack() //we are moving stack from hero's
&& highl->stacksCount() == 1 //it's only stack
&& owner->getSelection()->upg != upg //we're moving it to the other garrison
)
{
temp = CGI->generaltexth->tcommands[5]; //Cannot move last army to garrison
}
else
{
temp = CGI->generaltexth->tcommands[6]; //Move %s
boost::algorithm::replace_first(temp,"%s",owner->getSelection()->creature->nameSing);
}
}
else
{
temp = CGI->generaltexth->tcommands[11]; //Empty
}
}
GH.statusbar->setText(temp);
}
else
{
GH.statusbar->clear();
}
}
const CArmedInstance * CGarrisonSlot::getObj() const
{
return (!upg)?(owner->armedObjs[0]):(owner->armedObjs[1]);
}
bool CGarrisonSlot::our() const
{
return upg?(owner->owned[1]):(owner->owned[0]);
}
void CGarrisonSlot::clickRight(tribool down, bool previousState)
{
if(down && creature)
{
GH.pushInt(new CStackWindow(myStack, true));
}
}
void CGarrisonSlot::clickLeft(tribool down, bool previousState)
{
if(down)
{
bool refr = false;
if(owner->getSelection())
{
if(owner->getSelection() == this) //view info
{
UpgradeInfo pom;
LOCPLINT->cb->getUpgradeInfo(getObj(), ID, pom);
bool canUpgrade = getObj()->tempOwner == LOCPLINT->playerID && pom.oldID>=0; //upgrade is possible
bool canDismiss = getObj()->tempOwner == LOCPLINT->playerID && (getObj()->stacksCount()>1 || !getObj()->needsLastStack());
std::function<void(CreatureID)> upgr = nullptr;
std::function<void()> dism = nullptr;
if(canUpgrade) upgr = [=] (CreatureID newID) { LOCPLINT->cb->upgradeCreature(getObj(), ID, newID); };
if(canDismiss) dism = [=] { LOCPLINT->cb->dismissCreature(getObj(), ID); };
owner->selectSlot(nullptr);
owner->setSplittingMode(false);
for(auto & elem : owner->splitButtons)
elem->block(true);
redraw();
refr = true;
GH.pushInt(new CStackWindow(myStack, dism, pom, upgr));
}
else
{
// Only allow certain moves if troops aren't removable or not ours.
if ( ( owner->getSelection()->our()//our creature is selected
|| owner->getSelection()->creature == creature )//or we are rebalancing army
&& ( owner->removableUnits
|| (upg == 0 && ( owner->getSelection()->upg == 1 && !creature ) )
|| (upg == 1 && owner->getSelection()->upg == 1 ) ) )
{
//we want to split
if((owner->getSplittingMode() || LOCPLINT->shiftPressed())
&& (!creature
|| (creature == owner->getSelection()->creature)))
{
owner->p2 = ID; //store the second stack pos
owner->pb = upg;//store the second stack owner (up or down army)
owner->setSplittingMode(false);
int minLeft=0, minRight=0;
if(upg != owner->getSelection()->upg) //not splitting within same army
{
if(owner->getSelection()->getObj()->stacksCount() == 1 //we're splitting away the last stack
&& owner->getSelection()->getObj()->needsLastStack() )
{
minLeft = 1;
}
if(getObj()->stacksCount() == 1 //destination army can't be emptied, unless we're rebalancing two stacks of same creature
&& owner->getSelection()->creature == creature
&& getObj()->needsLastStack() )
{
minRight = 1;
}
}
int countLeft = owner->getSelection()->myStack ? owner->getSelection()->myStack->count : 0;
int countRight = myStack ? myStack->count : 0;
GH.pushInt(new CSplitWindow(owner->getSelection()->creature, boost::bind(&CGarrisonInt::splitStacks, owner, _1, _2),
minLeft, minRight, countLeft, countRight));
refr = true;
}
else if(creature != owner->getSelection()->creature) //swap
{
LOCPLINT->cb->swapCreatures(
(!upg)?(owner->armedObjs[0]):(owner->armedObjs[1]),
(!owner->getSelection()->upg)?(owner->armedObjs[0]):(owner->armedObjs[1]),
ID,owner->getSelection()->ID);
}
else //merge
{
LOCPLINT->cb->mergeStacks(
(!owner->getSelection()->upg)?(owner->armedObjs[0]):(owner->armedObjs[1]),
(!upg)?(owner->armedObjs[0]):(owner->armedObjs[1]),
owner->getSelection()->ID,ID);
}
}
else // Highlight
{
if(creature)
owner->selectSlot(this);
redraw();
refr = true;
}
}
}
else //highlight or drop artifact
{
bool artSelected = false;
if (CWindowWithArtifacts* chw = dynamic_cast<CWindowWithArtifacts*>(GH.topInt())) //dirty solution
{
const CArtifactsOfHero::SCommonPart *commonInfo = chw->artSets.front()->commonInfo;
if (const CArtifactInstance *art = commonInfo->src.art)
{
const CGHeroInstance *srcHero = commonInfo->src.AOH->getHero();
artSelected = true;
ArtifactLocation src(srcHero, commonInfo->src.slotID);
ArtifactLocation dst(myStack, ArtifactPosition::CREATURE_SLOT);
if (art->canBePutAt(dst, true))
{ //equip clicked stack
if(dst.getArt())
{
//creature can wear only one active artifact
//if we are placing a new one, the old one will be returned to the hero's backpack
LOCPLINT->cb->swapArtifacts(dst, ArtifactLocation(srcHero, dst.getArt()->firstBackpackSlot(srcHero)));
}
LOCPLINT->cb->swapArtifacts(src, dst);
}
}
}
if (!artSelected && creature)
{
owner->selectSlot(this);
if(creature)
{
for(auto & elem : owner->splitButtons)
elem->block(false);
}
}
redraw();
refr = true;
}
if(refr) {hover(false); hover(true); } //to refresh statusbar
}
}
void CGarrisonSlot::update()
{
if (getObj() != nullptr)
{
addUsedEvents(LCLICK | RCLICK | HOVER);
myStack = getObj()->getStackPtr(ID);
creature = myStack ? myStack->type : nullptr;
}
else
{
removeUsedEvents(LCLICK | RCLICK | HOVER);
myStack = nullptr;
creature = nullptr;
}
if (creature)
{
creatureImage->enable();
creatureImage->setFrame(creature->iconIndex);
stackCount->enable();
stackCount->setText(boost::lexical_cast<std::string>(myStack->count));
}
else
{
creatureImage->disable();
stackCount->disable();
}
}
CGarrisonSlot::CGarrisonSlot(CGarrisonInt *Owner, int x, int y, SlotID IID, int Upg, const CStackInstance * Creature):
ID(IID),
owner(Owner),
myStack(Creature),
creature(Creature ? Creature->type : nullptr),
upg(Upg)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
if (getObj())
addUsedEvents(LCLICK | RCLICK | HOVER);
pos.x += x;
pos.y += y;
std::string imgName = owner->smallIcons ? "cprsmall" : "TWCRPORT";
creatureImage = new CAnimImage(imgName, creature ? creature->iconIndex : 0);
if (!creature)
creatureImage->disable();
selectionImage = new CAnimImage(imgName, 1);
selectionImage->disable();
if(Owner->smallIcons)
{
pos.w = 32;
pos.h = 32;
}
else
{
pos.w = 58;
pos.h = 64;
}
stackCount = new CLabel(pos.w, pos.h, owner->smallIcons ? FONT_TINY : FONT_MEDIUM, BOTTOMRIGHT, Colors::WHITE);
if (!creature)
stackCount->disable();
else
stackCount->setText(boost::lexical_cast<std::string>(myStack->count));
}
void CGarrisonInt::addSplitBtn(CButton * button)
{
addChild(button);
button->recActions = defActions;
splitButtons.push_back(button);
button->block(getSelection() == nullptr);
}
void CGarrisonInt::createSet(std::vector<CGarrisonSlot*> &ret, const CCreatureSet * set, int posX, int posY, int distance, int Upg )
{
ret.resize(7);
if (set)
{
for(auto & elem : set->Slots())
{
ret[elem.first.getNum()] = new CGarrisonSlot(this, posX + (elem.first.getNum()*distance), posY, elem.first, Upg, elem.second);
}
}
for(int i=0; i<ret.size(); i++)
if(!ret[i])
ret[i] = new CGarrisonSlot(this, posX + (i*distance), posY, SlotID(i), Upg, nullptr);
if (twoRows)
for (int i=4; i<ret.size(); i++)
{
ret[i]->pos.x -= 126;
ret[i]->pos.y += 37;
};
}
void CGarrisonInt::createSlots()
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
int width = smallIcons? 32 : 58;
createSet(slotsUp, armedObjs[0], 0, 0, width+interx, 0);
createSet(slotsDown, armedObjs[1], garOffset.x, garOffset.y, width+interx, 1);
}
void CGarrisonInt::recreateSlots()
{
selectSlot(nullptr);
setSplittingMode(false);
for(auto & elem : splitButtons)
elem->block(true);
for(CGarrisonSlot * slot : slotsUp)
slot->update();
for(CGarrisonSlot * slot : slotsDown)
slot->update();
}
void CGarrisonInt::splitClick()
{
if(!getSelection())
return;
setSplittingMode(!getSplittingMode());
redraw();
}
void CGarrisonInt::splitStacks(int, int amountRight)
{
LOCPLINT->cb->splitStack(armedObjs[getSelection()->upg], armedObjs[pb], getSelection()->ID, p2, amountRight);
}
CGarrisonInt::CGarrisonInt(int x, int y, int inx, const Point &garsOffset,
SDL_Surface *pomsur, const Point& SurOffset,
const CArmedInstance *s1, const CArmedInstance *s2,
bool _removableUnits, bool smallImgs, bool _twoRows ) :
highlighted(nullptr),
inSplittingMode(false),
interx(inx),
garOffset(garsOffset),
smallIcons(smallImgs),
removableUnits(_removableUnits),
twoRows(_twoRows)
{
setArmy(s1, false);
setArmy(s2, true);
pos.x += x;
pos.y += y;
createSlots();
}
const CGarrisonSlot * CGarrisonInt::getSelection()
{
return highlighted;
}
void CGarrisonInt::selectSlot(CGarrisonSlot *slot)
{
if (slot != highlighted)
{
if (highlighted)
highlighted->setHighlight(false);
highlighted = slot;
for (auto button : splitButtons)
button->block(highlighted == nullptr);
if (highlighted)
highlighted->setHighlight(true);
}
}
void CGarrisonInt::setSplittingMode(bool on)
{
assert(on == false || highlighted != nullptr); //can't be in splitting mode without selection
if (inSplittingMode || on)
{
for(CGarrisonSlot * slot : slotsUp)
slot->setHighlight( ( on && (slot->creature == nullptr || slot->creature == getSelection()->creature)));
for(CGarrisonSlot * slot : slotsDown)
slot->setHighlight( ( on && (slot->creature == nullptr || slot->creature == getSelection()->creature)));
inSplittingMode = on;
}
}
bool CGarrisonInt::getSplittingMode()
{
return inSplittingMode;
}
void CGarrisonInt::setArmy(const CArmedInstance *army, bool bottomGarrison)
{
owned[bottomGarrison] = army ? (army->tempOwner == LOCPLINT->playerID || army->tempOwner == PlayerColor::UNFLAGGABLE) : false;
armedObjs[bottomGarrison] = army;
}
CGarrisonWindow::CGarrisonWindow( const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits ):
CWindowObject(PLAYER_COLORED, "GARRISON")
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
garr = new CGarrisonInt(92, 127, 4, Point(0,96), background->bg, Point(93,127), up, down, removableUnits);
{
CButton *split = new CButton(Point(88, 314), "IDV6432.DEF", CButton::tooltip(CGI->generaltexth->tcommands[3], ""), [&]{ garr->splitClick(); } );
removeChild(split);
garr->addSplitBtn(split);
}
quit = new CButton(Point(399, 314), "IOK6432.DEF", CButton::tooltip(CGI->generaltexth->tcommands[8], ""), [&]{ close(); }, SDLK_RETURN);
std::string titleText;
if (garr->armedObjs[1]->tempOwner == garr->armedObjs[0]->tempOwner)
titleText = CGI->generaltexth->allTexts[709];
else
{
titleText = CGI->generaltexth->allTexts[35];
boost::algorithm::replace_first(titleText, "%s", garr->armedObjs[0]->Slots().begin()->second->type->namePl);
}
new CLabel(275, 30, FONT_BIG, CENTER, Colors::YELLOW, titleText);
new CAnimImage("CREST58", garr->armedObjs[0]->getOwner().getNum(), 0, 28, 124);
new CAnimImage("PortraitsLarge", dynamic_cast<const CGHeroInstance*>(garr->armedObjs[1])->portrait, 0, 29, 222);
}
CGarrisonHolder::CGarrisonHolder()
{
}
void CWindowWithGarrison::updateGarrisons()
{
garr->recreateSlots();
}

View File

@ -0,0 +1,122 @@
#pragma once
#include "../windows/CWindowObject.h"
/*
* CGarrisonInt.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 CGarrisonInt;
class CButton;
class CArmedInstance;
class CAnimImage;
class CCreatureSet;
class CGarrisonSlot;
class CStackInstance;
class CLabel;
/// A single garrison slot which holds one creature of a specific amount
class CGarrisonSlot : public CIntObject
{
SlotID ID; //for identification
CGarrisonInt *owner;
const CStackInstance *myStack; //nullptr if slot is empty
const CCreature *creature;
int upg; //0 - up garrison, 1 - down garrison
CAnimImage * creatureImage;
CAnimImage * selectionImage; // image for selection, not always visible
CLabel * stackCount;
void setHighlight(bool on);
public:
virtual void hover (bool on); //call-in
const CArmedInstance * getObj() const;
bool our() const;
void clickRight(tribool down, bool previousState);
void clickLeft(tribool down, bool previousState);
void update();
CGarrisonSlot(CGarrisonInt *Owner, int x, int y, SlotID IID, int Upg=0, const CStackInstance * Creature=nullptr);
friend class CGarrisonInt;
};
/// Class which manages slots of upper and lower garrison, splitting of units
class CGarrisonInt :public CIntObject
{
CGarrisonSlot *highlighted; //chosen slot. Should be changed only via selectSlot
bool inSplittingMode;
public:
void selectSlot(CGarrisonSlot * slot); //null = deselect
const CGarrisonSlot * getSelection();
void setSplittingMode(bool on);
bool getSplittingMode();
int interx; //space between slots
Point garOffset; //offset between garrisons (not used if only one hero)
std::vector<CButton *> splitButtons; //may be empty if no buttons
SlotID p2; //TODO: comment me
int shiftPos;//1st slot of the second row, set shiftPoint for effect
bool pb,
smallIcons, //true - 32x32 imgs, false - 58x64
removableUnits,//player can remove units from up
twoRows,//slots will be placed in 2 rows
owned[2];//player owns up or down army [0] upper, [1] lower
// const CCreatureSet *set1; //top set of creatures
// const CCreatureSet *set2; //bottom set of creatures
std::vector<CGarrisonSlot*> slotsUp, slotsDown; //slots of upper and lower garrison
const CArmedInstance *armedObjs[2]; //[0] is upper, [1] is down
//const CArmedInstance *oup, *odown; //upper and lower garrisons (heroes or towns)
void setArmy(const CArmedInstance *army, bool bottomGarrison);
void addSplitBtn(CButton * button);
void createSet(std::vector<CGarrisonSlot*> &ret, const CCreatureSet * set, int posX, int distance, int posY, int Upg );
void createSlots();
void recreateSlots();
void splitClick(); //handles click on split button
void splitStacks(int amountLeft, int amountRight); //TODO: comment me
//x, y - position;
//inx - distance between slots;
//pomsur, SurOffset - UNUSED
//s1, s2 - top and bottom armies;
//removableUnits - you can take units from top;
//smallImgs - units images size 64x58 or 32x32;
//twoRows - display slots in 2 row (1st row = 4 slots, 2nd = 3 slots)
CGarrisonInt(int x, int y, int inx, const Point &garsOffset, SDL_Surface *pomsur, const Point &SurOffset, const CArmedInstance *s1, const CArmedInstance *s2=nullptr, bool _removableUnits = true, bool smallImgs = false, bool _twoRows=false); //c-tor
};
class CGarrisonHolder
{
public:
CGarrisonHolder();
virtual void updateGarrisons()=0;
};
class CWindowWithGarrison : public virtual CGarrisonHolder
{
public:
CGarrisonInt *garr;
virtual void updateGarrisons();
};
/// Garrison window where you can take creatures out of the hero to place it on the garrison
class CGarrisonWindow : public CWindowObject, public CWindowWithGarrison
{
public:
CButton * quit;
CGarrisonWindow(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits); //c-tor
};

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

@ -0,0 +1,442 @@
#include "StdInc.h"
#include "MiscWidgets.h"
#include "CComponent.h"
#include "../gui/CGuiHandler.h"
#include "../gui/CCursorHandler.h"
#include "../CBitmapHandler.h"
#include "../CPlayerInterface.h"
#include "../CMessage.h"
#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
*
* 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 CHoverableArea::hover (bool on)
{
if (on)
GH.statusbar->setText(hoverText);
else if (GH.statusbar->getText()==hoverText)
GH.statusbar->clear();
}
CHoverableArea::CHoverableArea()
{
addUsedEvents(HOVER);
}
CHoverableArea::~CHoverableArea()
{
}
void LRClickableAreaWText::clickLeft(tribool down, bool previousState)
{
if(!down && previousState && !text.empty())
{
LOCPLINT->showInfoDialog(text);
}
}
void LRClickableAreaWText::clickRight(tribool down, bool previousState)
{
if (!text.empty())
adventureInt->handleRightClick(text, down);
}
LRClickableAreaWText::LRClickableAreaWText()
{
init();
}
LRClickableAreaWText::LRClickableAreaWText(const Rect &Pos, const std::string &HoverText /*= ""*/, const std::string &ClickText /*= ""*/)
{
init();
pos = Pos + pos;
hoverText = HoverText;
text = ClickText;
}
LRClickableAreaWText::~LRClickableAreaWText()
{
}
void LRClickableAreaWText::init()
{
addUsedEvents(LCLICK | RCLICK | HOVER);
}
void LRClickableAreaWTextComp::clickLeft(tribool down, bool previousState)
{
if((!down) && previousState)
{
std::vector<CComponent*> comp(1, createComponent());
LOCPLINT->showInfoDialog(text, comp);
}
}
LRClickableAreaWTextComp::LRClickableAreaWTextComp(const Rect &Pos, int BaseType)
: LRClickableAreaWText(Pos), baseType(BaseType), bonusValue(-1)
{
}
CComponent * LRClickableAreaWTextComp::createComponent() const
{
if(baseType >= 0)
return new CComponent(CComponent::Etype(baseType), type, bonusValue);
else
return nullptr;
}
void LRClickableAreaWTextComp::clickRight(tribool down, bool previousState)
{
if(down)
{
if(CComponent *comp = createComponent())
{
CRClickPopup::createAndPush(text, CInfoWindow::TCompsInfo(1, comp));
return;
}
}
LRClickableAreaWText::clickRight(down, previousState); //only if with-component variant not occurred
}
CHeroArea::CHeroArea(int x, int y, const CGHeroInstance * _hero):hero(_hero)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
addUsedEvents(LCLICK | RCLICK | HOVER);
pos.x += x; pos.w = 58;
pos.y += y; pos.h = 64;
if (hero)
new CAnimImage("PortraitsLarge", hero->portrait);
}
void CHeroArea::clickLeft(tribool down, bool previousState)
{
if((!down) && previousState && hero)
LOCPLINT->openHeroWindow(hero);
}
void CHeroArea::clickRight(tribool down, bool previousState)
{
if((!down) && previousState && hero)
LOCPLINT->openHeroWindow(hero);
}
void CHeroArea::hover(bool on)
{
if (on && hero)
GH.statusbar->setText(hero->getObjectName());
else
GH.statusbar->clear();
}
void LRClickableAreaOpenTown::clickLeft(tribool down, bool previousState)
{
if((!down) && previousState && town)
{
LOCPLINT->openTownWindow(town);
if ( type == 2 )
LOCPLINT->castleInt->builds->buildingClicked(BuildingID::VILLAGE_HALL);
else if ( type == 3 && town->fortLevel() )
LOCPLINT->castleInt->builds->buildingClicked(BuildingID::FORT);
}
}
void LRClickableAreaOpenTown::clickRight(tribool down, bool previousState)
{
if((!down) && previousState && town)
LOCPLINT->openTownWindow(town);//TODO: popup?
}
LRClickableAreaOpenTown::LRClickableAreaOpenTown()
: LRClickableAreaWTextComp(Rect(0,0,0,0), -1)
{
}
void CMinorResDataBar::show(SDL_Surface * to)
{
}
void CMinorResDataBar::showAll(SDL_Surface * to)
{
blitAt(bg,pos.x,pos.y,to);
for (Res::ERes i=Res::WOOD; i<=Res::GOLD; vstd::advance(i, 1))
{
std::string text = boost::lexical_cast<std::string>(LOCPLINT->cb->getResourceAmount(i));
graphics->fonts[FONT_SMALL]->renderTextCenter(to, text, Colors::WHITE, Point(pos.x + 50 + 76 * i, pos.y + pos.h/2));
}
std::vector<std::string> temp;
temp.push_back(boost::lexical_cast<std::string>(LOCPLINT->cb->getDate(Date::MONTH)));
temp.push_back(boost::lexical_cast<std::string>(LOCPLINT->cb->getDate(Date::WEEK)));
temp.push_back(boost::lexical_cast<std::string>(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK)));
std::string datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63]
+ ": %s, " + CGI->generaltexth->allTexts[64] + ": %s";
graphics->fonts[FONT_SMALL]->renderTextCenter(to, CSDL_Ext::processStr(datetext,temp), Colors::WHITE, Point(pos.x+545+(pos.w-545)/2,pos.y+pos.h/2));
}
CMinorResDataBar::CMinorResDataBar()
{
bg = BitmapHandler::loadBitmap("KRESBAR.bmp");
CSDL_Ext::setDefaultColorKey(bg);
graphics->blueToPlayersAdv(bg,LOCPLINT->playerID);
pos.x = 7;
pos.y = 575;
pos.w = bg->w;
pos.h = bg->h;
}
CMinorResDataBar::~CMinorResDataBar()
{
SDL_FreeSurface(bg);
}
void CArmyTooltip::init(const InfoAboutArmy &army)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
new CLabel(66, 2, FONT_SMALL, TOPLEFT, Colors::WHITE, army.name);
std::vector<Point> slotsPos;
slotsPos.push_back(Point(36,73));
slotsPos.push_back(Point(72,73));
slotsPos.push_back(Point(108,73));
slotsPos.push_back(Point(18,122));
slotsPos.push_back(Point(54,122));
slotsPos.push_back(Point(90,122));
slotsPos.push_back(Point(126,122));
for(auto & slot : army.army)
{
if(slot.first.getNum() >= GameConstants::ARMY_SIZE)
{
logGlobal->warnStream() << "Warning: " << army.name << " has stack in slot " << slot.first;
continue;
}
new CAnimImage("CPRSMALL", slot.second.type->iconIndex, 0, slotsPos[slot.first.getNum()].x, slotsPos[slot.first.getNum()].y);
std::string subtitle;
if(army.army.isDetailed)
subtitle = boost::lexical_cast<std::string>(slot.second.count);
else
{
//if =0 - we have no information about stack size at all
if (slot.second.count)
subtitle = CGI->generaltexth->arraytxt[171 + 3*(slot.second.count)];
}
new CLabel(slotsPos[slot.first.getNum()].x + 17, slotsPos[slot.first.getNum()].y + 41, FONT_TINY, CENTER, Colors::WHITE, subtitle);
}
}
CArmyTooltip::CArmyTooltip(Point pos, const InfoAboutArmy &army):
CIntObject(0, pos)
{
init(army);
}
CArmyTooltip::CArmyTooltip(Point pos, const CArmedInstance * army):
CIntObject(0, pos)
{
init(InfoAboutArmy(army, true));
}
void CHeroTooltip::init(const InfoAboutHero &hero)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
new CAnimImage("PortraitsLarge", hero.portrait, 0, 3, 2);
if(hero.details)
{
for (size_t i = 0; i < hero.details->primskills.size(); i++)
new CLabel(75 + 28 * i, 58, FONT_SMALL, CENTER, Colors::WHITE,
boost::lexical_cast<std::string>(hero.details->primskills[i]));
new CLabel(158, 98, FONT_TINY, CENTER, Colors::WHITE,
boost::lexical_cast<std::string>(hero.details->mana));
new CAnimImage("IMRL22", hero.details->morale + 3, 0, 5, 74);
new CAnimImage("ILCK22", hero.details->luck + 3, 0, 5, 91);
}
}
CHeroTooltip::CHeroTooltip(Point pos, const InfoAboutHero &hero):
CArmyTooltip(pos, hero)
{
init(hero);
}
CHeroTooltip::CHeroTooltip(Point pos, const CGHeroInstance * hero):
CArmyTooltip(pos, InfoAboutHero(hero, true))
{
init(InfoAboutHero(hero, true));
}
void CTownTooltip::init(const InfoAboutTown &town)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
//order of icons in def: fort, citadel, castle, no fort
size_t fortIndex = town.fortLevel ? town.fortLevel - 1 : 3;
new CAnimImage("ITMCLS", fortIndex, 0, 105, 31);
assert(town.tType);
size_t iconIndex = town.tType->clientInfo.icons[town.fortLevel > 0][town.built >= CGI->modh->settings.MAX_BUILDING_PER_TURN];
new CAnimImage("itpt", iconIndex, 0, 3, 2);
if(town.details)
{
new CAnimImage("ITMTLS", town.details->hallLevel, 0, 67, 31);
if (town.details->goldIncome)
new CLabel(157, 58, FONT_TINY, CENTER, Colors::WHITE,
boost::lexical_cast<std::string>(town.details->goldIncome));
if(town.details->garrisonedHero) //garrisoned hero icon
new CPicture("TOWNQKGH", 149, 76);
if(town.details->customRes)//silo is built
{
if (town.tType->primaryRes == Res::WOOD_AND_ORE )// wood & ore
{
new CAnimImage("SMALRES", Res::WOOD, 0, 7, 75);
new CAnimImage("SMALRES", Res::ORE , 0, 7, 88);
}
else
new CAnimImage("SMALRES", town.tType->primaryRes, 0, 7, 81);
}
}
}
CTownTooltip::CTownTooltip(Point pos, const InfoAboutTown &town):
CArmyTooltip(pos, town)
{
init(town);
}
CTownTooltip::CTownTooltip(Point pos, const CGTownInstance * town):
CArmyTooltip(pos, InfoAboutTown(town, true))
{
init(InfoAboutTown(town, true));
}
void MoraleLuckBox::set(const IBonusBearer *node)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
const int textId[] = {62, 88}; //eg %s \n\n\n {Current Luck Modifiers:}
const int noneTxtId = 108; //Russian version uses same text for neutral morale\luck
const int neutralDescr[] = {60, 86}; //eg {Neutral Morale} \n\n Neutral morale means your armies will neither be blessed with extra attacks or freeze in combat.
const int componentType[] = {CComponent::luck, CComponent::morale};
const int hoverTextBase[] = {7, 4};
const Bonus::BonusType bonusType[] = {Bonus::LUCK, Bonus::MORALE};
int (IBonusBearer::*getValue[])() const = {&IBonusBearer::LuckVal, &IBonusBearer::MoraleVal};
int mrlt = -9;
TModDescr mrl;
if (node)
{
node->getModifiersWDescr(mrl, bonusType[morale]);
bonusValue = (node->*getValue[morale])();
}
else
bonusValue = 0;
mrlt = (bonusValue>0)-(bonusValue<0); //signum: -1 - bad luck / morale, 0 - neutral, 1 - good
hoverText = CGI->generaltexth->heroscrn[hoverTextBase[morale] - mrlt];
baseType = componentType[morale];
text = CGI->generaltexth->arraytxt[textId[morale]];
boost::algorithm::replace_first(text,"%s",CGI->generaltexth->arraytxt[neutralDescr[morale]-mrlt]);
if (!mrl.size())
text += CGI->generaltexth->arraytxt[noneTxtId];
else
{
//it's a creature window
if ((morale && node->hasBonusOfType(Bonus::UNDEAD)) ||
node->hasBonusOfType(Bonus::BLOCK_MORALE) || node->hasBonusOfType(Bonus::NON_LIVING))
{
text += CGI->generaltexth->arraytxt[113]; //unaffected by morale
}
else
{
for(auto & elem : mrl)
{
if (elem.first) //no bonuses with value 0
text += "\n" + elem.second;
}
}
}
std::string imageName;
if (small)
imageName = morale ? "IMRL30": "ILCK30";
else
imageName = morale ? "IMRL42" : "ILCK42";
delete image;
image = new CAnimImage(imageName, bonusValue + 3);
image->moveBy(Point(pos.w/2 - image->pos.w/2, pos.h/2 - image->pos.h/2));//center icon
}
MoraleLuckBox::MoraleLuckBox(bool Morale, const Rect &r, bool Small):
image(nullptr),
morale(Morale),
small(Small)
{
bonusValue = 0;
pos = r + pos;
}
CCreaturePic::CCreaturePic(int x, int y, const CCreature *cre, bool Big, bool Animated)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
pos.x+=x;
pos.y+=y;
TFaction faction = cre->faction;
assert(CGI->townh->factions.size() > faction);
if(Big)
bg = new CPicture(CGI->townh->factions[faction]->creatureBg130);
else
bg = new CPicture(CGI->townh->factions[faction]->creatureBg120);
bg->needRefresh = true;
anim = new CCreatureAnim(0, 0, cre->animDefName, Rect());
anim->clipRect(cre->isDoubleWide()?170:150, 155, bg->pos.w, bg->pos.h);
anim->startPreview(cre->hasBonusOfType(Bonus::SIEGE_WEAPON));
pos.w = bg->pos.w;
pos.h = bg->pos.h;
}

View File

@ -0,0 +1,150 @@
#pragma once
#include "../gui/CIntObject.h"
/*
* MiscWidgets.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 CCreatureAnim;
class CComponent;
class CGGarrison;
class CSelectableComponent;
class InfoAboutArmy;
class CArmedInstance;
class IBonusBearer;
class CAnimImage;
/// 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);
};
/// base class for hero/town/garrison tooltips
class CArmyTooltip : public CIntObject
{
void init(const InfoAboutArmy &army);
public:
CArmyTooltip(Point pos, const InfoAboutArmy &army);
CArmyTooltip(Point pos, const CArmedInstance * army);
};
/// Class for hero tooltip. Does not have any background!
/// background for infoBox: ADSTATHR
/// background for tooltip: HEROQVBK
class CHeroTooltip : public CArmyTooltip
{
void init(const InfoAboutHero &hero);
public:
CHeroTooltip(Point pos, const InfoAboutHero &hero);
CHeroTooltip(Point pos, const CGHeroInstance * hero);
};
/// Class for town tooltip. Does not have any background!
/// background for infoBox: ADSTATCS
/// background for tooltip: TOWNQVBK
class CTownTooltip : public CArmyTooltip
{
void init(const InfoAboutTown &town);
public:
CTownTooltip(Point pos, const InfoAboutTown &town);
CTownTooltip(Point pos, const CGTownInstance * town);
};
/// draws picture with creature on background, use Animated=true to get animation
class CCreaturePic : public CIntObject
{
private:
CPicture *bg;
CCreatureAnim *anim; //displayed animation
public:
CCreaturePic(int x, int y, const CCreature *cre, bool Big=true, bool Animated=true); //c-tor
};
/// Resource bar like that at the bottom of the adventure map screen
class CMinorResDataBar : public CIntObject
{
public:
SDL_Surface *bg; //background bitmap
void show(SDL_Surface * to);
void showAll(SDL_Surface * to);
CMinorResDataBar(); //c-tor
~CMinorResDataBar(); //d-tor
};
/// Opens hero window by left-clicking on it
class CHeroArea: public CIntObject
{
const CGHeroInstance * hero;
public:
CHeroArea(int x, int y, const CGHeroInstance * _hero);
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);
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
{
public:
const CGTownInstance * town;
void clickLeft(tribool down, bool previousState);
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.topLeft(), SliderPos.w, boost::bind(&CListBox::moveToPos, this, _1),
VisibleSize, TotalSize, InitialPos, Slider & 2, Slider & 4 ? CSlider::BLUE : CSlider::BROWN);
}
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(Point(pos.w - 32, 0), pos.h, boost::bind(&CTextBox::sliderMoved, this, _1),
label->pos.h, label->textSize.y, 0, false, CSlider::EStyle(sliderStyle));
slider->setScrollStep(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

@ -1,36 +1,43 @@
#include "StdInc.h" #include "StdInc.h"
#include "CAdvmapInterface.h" #include "CAdvmapInterface.h"
#include "../CCallback.h"
#include "CCastleInterface.h" #include "CCastleInterface.h"
#include "gui/CCursorHandler.h"
#include "CGameInfo.h"
#include "CHeroWindow.h" #include "CHeroWindow.h"
#include "CKingdomInterface.h" #include "CKingdomInterface.h"
#include "CMessage.h"
#include "CPlayerInterface.h"
#include "gui/SDL_Extensions.h"
#include "CBitmapHandler.h"
#include "../lib/CConfigHandler.h"
#include "CSpellWindow.h" #include "CSpellWindow.h"
#include "Graphics.h" #include "GUIClasses.h"
#include "CDefHandler.h" #include "CTradeWindow.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CHeroHandler.h" #include "../CBitmapHandler.h"
#include "../lib/mapObjects/CGHeroInstance.h" #include "../CDefHandler.h"
#include "../lib/CTownHandler.h" #include "../CGameInfo.h"
#include "../lib/mapping/CMap.h" #include "../CMessage.h"
#include "../lib/JsonNode.h" #include "../CMusicHandler.h"
#include "mapHandler.h" #include "../CPlayerInterface.h"
#include "CPreGame.h" #include "../CPreGame.h"
#include "../lib/VCMI_Lib.h" #include "../Graphics.h"
#include "../lib/CSpellHandler.h" #include "../mapHandler.h"
#include "../lib/CSoundBase.h"
#include "../lib/CGameState.h" #include "../gui/CCursorHandler.h"
#include "CMusicHandler.h" #include "../gui/CGuiHandler.h"
#include "gui/CGuiHandler.h" #include "../gui/SDL_Extensions.h"
#include "gui/CIntObjectClasses.h" #include "../widgets/MiscWidgets.h"
#include "../lib/UnlockGuard.h" #include "../windows/InfoWindows.h"
#include "../../CCallback.h"
#include "../../lib/CConfigHandler.h"
#include "../../lib/CGameState.h"
#include "../../lib/CGeneralTextHandler.h"
#include "../../lib/CHeroHandler.h"
#include "../../lib/CSoundBase.h"
#include "../../lib/CSpellHandler.h"
#include "../../lib/CTownHandler.h"
#include "../../lib/JsonNode.h"
#include "../../lib/mapObjects/CGHeroInstance.h"
#include "../../lib/mapping/CMap.h"
#include "../../lib/UnlockGuard.h"
#include "../../lib/VCMI_Lib.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning (disable : 4355) #pragma warning (disable : 4355)
@ -363,6 +370,7 @@ void CResDataBar::showAll(SDL_Surface * to)
CAdvMapInt::CAdvMapInt(): CAdvMapInt::CAdvMapInt():
minimap(Rect(ADVOPT.minimapX, ADVOPT.minimapY, ADVOPT.minimapW, ADVOPT.minimapH)), minimap(Rect(ADVOPT.minimapX, ADVOPT.minimapY, ADVOPT.minimapW, ADVOPT.minimapH)),
statusbar(ADVOPT.statusbarX,ADVOPT.statusbarY,ADVOPT.statusbarG), statusbar(ADVOPT.statusbarX,ADVOPT.statusbarY,ADVOPT.statusbarG),
<<<<<<< HEAD:client/CAdvmapInterface.cpp
kingOverview(CGI->generaltexth->zelp[293].first,CGI->generaltexth->zelp[293].second, kingOverview(CGI->generaltexth->zelp[293].first,CGI->generaltexth->zelp[293].second,
std::bind(&CAdvMapInt::fshowOverview,this),&ADVOPT.kingOverview, SDLK_k), std::bind(&CAdvMapInt::fshowOverview,this),&ADVOPT.kingOverview, SDLK_k),
@ -392,6 +400,8 @@ nextHero(CGI->generaltexth->zelp[301].first,CGI->generaltexth->zelp[301].second,
endTurn(CGI->generaltexth->zelp[302].first,CGI->generaltexth->zelp[302].second, endTurn(CGI->generaltexth->zelp[302].first,CGI->generaltexth->zelp[302].second,
std::bind(&CAdvMapInt::fendTurn,this), &ADVOPT.endTurn, SDLK_e), std::bind(&CAdvMapInt::fendTurn,this), &ADVOPT.endTurn, SDLK_e),
=======
>>>>>>> refactoring/guiClasses:client/windows/CAdvmapInterface.cpp
heroList(ADVOPT.hlistSize, Point(ADVOPT.hlistX, ADVOPT.hlistY), ADVOPT.hlistAU, ADVOPT.hlistAD), heroList(ADVOPT.hlistSize, Point(ADVOPT.hlistX, ADVOPT.hlistY), ADVOPT.hlistAU, ADVOPT.hlistAD),
townList(ADVOPT.tlistSize, Point(ADVOPT.tlistX, ADVOPT.tlistY), ADVOPT.tlistAU, ADVOPT.tlistAD), townList(ADVOPT.tlistSize, Point(ADVOPT.tlistX, ADVOPT.tlistY), ADVOPT.tlistAU, ADVOPT.tlistAD),
@ -420,9 +430,28 @@ infoBar(Rect(ADVOPT.infoboxX, ADVOPT.infoboxY, 192, 192) )
gems.push_back(CDefHandler::giveDef(ADVOPT.gemG[g])); gems.push_back(CDefHandler::giveDef(ADVOPT.gemG[g]));
} }
auto makeButton = [&] (int textID, std::function<void()> callback, config::ButtonInfo info, int key) -> CButton *
{
auto button = new CButton(Point(info.x, info.y), info.defName, CGI->generaltexth->zelp[textID], callback, key, info.playerColoured);
for (auto image : info.additionalDefs)
button->addImage(image);
return button;
};
kingOverview = makeButton(293, boost::bind(&CAdvMapInt::fshowOverview,this), ADVOPT.kingOverview, SDLK_k);
underground = makeButton(294, boost::bind(&CAdvMapInt::fswitchLevel,this), ADVOPT.underground, SDLK_u);
questlog = makeButton(295, boost::bind(&CAdvMapInt::fshowQuestlog,this), ADVOPT.questlog, SDLK_q);
sleepWake = makeButton(296, boost::bind(&CAdvMapInt::fsleepWake,this), ADVOPT.sleepWake, SDLK_w);
moveHero = makeButton(297, boost::bind(&CAdvMapInt::fmoveHero,this), ADVOPT.moveHero, SDLK_m);
spellbook = makeButton(298, boost::bind(&CAdvMapInt::fshowSpellbok,this), ADVOPT.spellbook, SDLK_c);
advOptions = makeButton(299, boost::bind(&CAdvMapInt::fadventureOPtions,this), ADVOPT.advOptions, SDLK_a);
sysOptions = makeButton(300, boost::bind(&CAdvMapInt::fsystemOptions,this), ADVOPT.sysOptions, SDLK_o);
nextHero = makeButton(301, boost::bind(&CAdvMapInt::fnextHero,this), ADVOPT.nextHero, SDLK_h);
endTurn = makeButton(302, boost::bind(&CAdvMapInt::fendTurn,this), ADVOPT.endTurn, SDLK_e);
setPlayer(LOCPLINT->playerID); setPlayer(LOCPLINT->playerID);
underground.block(!CGI->mh->map->twoLevel); underground->block(!CGI->mh->map->twoLevel);
addUsedEvents(MOVE); addUsedEvents(MOVE);
} }
@ -445,14 +474,14 @@ void CAdvMapInt::fswitchLevel()
if (position.z) if (position.z)
{ {
position.z--; position.z--;
underground.setIndex(0,true); underground->setIndex(0,true);
underground.showAll(screenBuf); underground->showAll(screenBuf);
} }
else else
{ {
underground.setIndex(1,true); underground->setIndex(1,true);
position.z++; position.z++;
underground.showAll(screenBuf); underground->showAll(screenBuf);
} }
updateScreen = true; updateScreen = true;
minimap.setLevel(position.z); minimap.setLevel(position.z);
@ -537,14 +566,13 @@ void CAdvMapInt::fendTurn()
void CAdvMapInt::updateSleepWake(const CGHeroInstance *h) void CAdvMapInt::updateSleepWake(const CGHeroInstance *h)
{ {
sleepWake.block(!h); sleepWake->block(!h);
if (!h) if (!h)
return; return;
bool state = isHeroSleeping(h); bool state = isHeroSleeping(h);
sleepWake.setIndex(state ? 1 : 0, true); sleepWake->setIndex(state ? 1 : 0, true);
sleepWake.assignedKeys.clear(); sleepWake->assignedKeys.clear();
sleepWake.assignedKeys.insert(state ? SDLK_w : SDLK_z); sleepWake->assignedKeys.insert(state ? SDLK_w : SDLK_z);
sleepWake.update();
} }
void CAdvMapInt::updateMoveHero(const CGHeroInstance *h, tribool hasPath) void CAdvMapInt::updateMoveHero(const CGHeroInstance *h, tribool hasPath)
@ -554,10 +582,10 @@ void CAdvMapInt::updateMoveHero(const CGHeroInstance *h, tribool hasPath)
hasPath = LOCPLINT->paths[h].nodes.size() ? true : false; hasPath = LOCPLINT->paths[h].nodes.size() ? true : false;
if (!h) if (!h)
{ {
moveHero.block(true); moveHero->block(true);
return; return;
} }
moveHero.block(!hasPath || (h->movement == 0)); moveHero->block(!hasPath || (h->movement == 0));
} }
int CAdvMapInt::getNextHeroIndex(int startIndex) int CAdvMapInt::getNextHeroIndex(int startIndex)
@ -587,12 +615,12 @@ void CAdvMapInt::updateNextHero(const CGHeroInstance *h)
int next = getNextHeroIndex(start); int next = getNextHeroIndex(start);
if (next < 0) if (next < 0)
{ {
nextHero.block(true); nextHero->block(true);
return; return;
} }
const CGHeroInstance *nextH = LOCPLINT->wanderingHeroes[next]; const CGHeroInstance *nextH = LOCPLINT->wanderingHeroes[next];
bool noActiveHeroes = (next == start) && ((nextH->movement == 0) || isHeroSleeping(nextH)); bool noActiveHeroes = (next == start) && ((nextH->movement == 0) || isHeroSleeping(nextH));
nextHero.block(noActiveHeroes); nextHero->block(noActiveHeroes);
} }
void CAdvMapInt::activate() void CAdvMapInt::activate()
@ -605,16 +633,16 @@ void CAdvMapInt::activate()
GH.statusbar = &statusbar; GH.statusbar = &statusbar;
if(!duringAITurn) if(!duringAITurn)
{ {
kingOverview.activate(); kingOverview->activate();
underground.activate(); underground->activate();
questlog.activate(); questlog->activate();
sleepWake.activate(); sleepWake->activate();
moveHero.activate(); moveHero->activate();
spellbook.activate(); spellbook->activate();
sysOptions.activate(); sysOptions->activate();
advOptions.activate(); advOptions->activate();
nextHero.activate(); nextHero->activate();
endTurn.activate(); endTurn->activate();
minimap.activate(); minimap.activate();
heroList.activate(); heroList.activate();
@ -635,16 +663,16 @@ void CAdvMapInt::deactivate()
scrollingDir = 0; scrollingDir = 0;
CCS->curh->changeGraphic(ECursor::ADVENTURE,0); CCS->curh->changeGraphic(ECursor::ADVENTURE,0);
kingOverview.deactivate(); kingOverview->deactivate();
underground.deactivate(); underground->deactivate();
questlog.deactivate(); questlog->deactivate();
sleepWake.deactivate(); sleepWake->deactivate();
moveHero.deactivate(); moveHero->deactivate();
spellbook.deactivate(); spellbook->deactivate();
advOptions.deactivate(); advOptions->deactivate();
sysOptions.deactivate(); sysOptions->deactivate();
nextHero.deactivate(); nextHero->deactivate();
endTurn.deactivate(); endTurn->deactivate();
minimap.deactivate(); minimap.deactivate();
heroList.deactivate(); heroList.deactivate();
townList.deactivate(); townList.deactivate();
@ -661,16 +689,16 @@ void CAdvMapInt::showAll(SDL_Surface * to)
if(state != INGAME) if(state != INGAME)
return; return;
kingOverview.showAll(to); kingOverview->showAll(to);
underground.showAll(to); underground->showAll(to);
questlog.showAll(to); questlog->showAll(to);
sleepWake.showAll(to); sleepWake->showAll(to);
moveHero.showAll(to); moveHero->showAll(to);
spellbook.showAll(to); spellbook->showAll(to);
advOptions.showAll(to); advOptions->showAll(to);
sysOptions.showAll(to); sysOptions->showAll(to);
nextHero.showAll(to); nextHero->showAll(to);
endTurn.showAll(to); endTurn->showAll(to);
minimap.showAll(to); minimap.showAll(to);
heroList.showAll(to); heroList.showAll(to);
@ -781,8 +809,8 @@ void CAdvMapInt::centerOn(int3 on)
position = on; position = on;
updateScreen=true; updateScreen=true;
underground.setIndex(on.z,true); //change underground switch button image underground->setIndex(on.z,true); //change underground switch button image
underground.redraw(); underground->redraw();
if (switchedLevels) if (switchedLevels)
minimap.setLevel(position.z); minimap.setLevel(position.z);
} }
@ -1096,16 +1124,16 @@ void CAdvMapInt::setPlayer(PlayerColor Player)
player = Player; player = Player;
graphics->blueToPlayersAdv(bg,player); graphics->blueToPlayersAdv(bg,player);
kingOverview.setPlayerColor(player); kingOverview->setPlayerColor(player);
underground.setPlayerColor(player); underground->setPlayerColor(player);
questlog.setPlayerColor(player); questlog->setPlayerColor(player);
sleepWake.setPlayerColor(player); sleepWake->setPlayerColor(player);
moveHero.setPlayerColor(player); moveHero->setPlayerColor(player);
spellbook.setPlayerColor(player); spellbook->setPlayerColor(player);
sysOptions.setPlayerColor(player); sysOptions->setPlayerColor(player);
advOptions.setPlayerColor(player); advOptions->setPlayerColor(player);
nextHero.setPlayerColor(player); nextHero->setPlayerColor(player);
endTurn.setPlayerColor(player); endTurn->setPlayerColor(player);
graphics->blueToPlayersAdv(resdatabar.bg,player); graphics->blueToPlayersAdv(resdatabar.bg,player);
//heroList.updateHList(); //heroList.updateHList();
@ -1525,10 +1553,11 @@ void CAdvMapInt::adjustActiveness(bool aiTurnStart)
} }
CAdventureOptions::CAdventureOptions(): CAdventureOptions::CAdventureOptions():
CWindowObject(PLAYER_COLORED, "ADVOPTS") CWindowObject(PLAYER_COLORED, "ADVOPTS")
{ {
OBJ_CONSTRUCTION_CAPTURING_ALL; OBJ_CONSTRUCTION_CAPTURING_ALL;
<<<<<<< HEAD:client/CAdvmapInterface.cpp
exit = new CAdventureMapButton("","",std::bind(&CAdventureOptions::close, this), 204, 313, "IOK6432.DEF",SDLK_RETURN); exit = new CAdventureMapButton("","",std::bind(&CAdventureOptions::close, this), 204, 313, "IOK6432.DEF",SDLK_RETURN);
exit->assignedKeys.insert(SDLK_ESCAPE); exit->assignedKeys.insert(SDLK_ESCAPE);
@ -1542,6 +1571,22 @@ CAdventureOptions::CAdventureOptions():
dig = new CAdventureMapButton("","", std::bind(&CAdventureOptions::close, this), 24, 139, "ADVDIG.DEF"); dig = new CAdventureMapButton("","", std::bind(&CAdventureOptions::close, this), 24, 139, "ADVDIG.DEF");
if(const CGHeroInstance *h = adventureInt->curHero()) if(const CGHeroInstance *h = adventureInt->curHero())
dig->callback += std::bind(&CPlayerInterface::tryDiggging, LOCPLINT, h); dig->callback += std::bind(&CPlayerInterface::tryDiggging, LOCPLINT, h);
=======
exit = new CButton(Point(204, 313), "IOK6432.DEF", CButton::tooltip(), boost::bind(&CAdventureOptions::close, this), SDLK_RETURN);
exit->assignedKeys.insert(SDLK_ESCAPE);
scenInfo = new CButton(Point(24, 198), "ADVINFO.DEF", CButton::tooltip(), [&]{ close(); }, SDLK_i);
scenInfo->addCallback(CAdventureOptions::showScenarioInfo);
//viewWorld = new CButton("","",boost::bind(&CGuiHandler::popIntTotally, &GH, this), 204, 313, "IOK6432.DEF",SDLK_RETURN);
puzzle = new CButton(Point(24, 81), "ADVPUZ.DEF", CButton::tooltip(), [&]{ close(); }, SDLK_p);
puzzle->addCallback(boost::bind(&CPlayerInterface::showPuzzleMap, LOCPLINT));
dig = new CButton(Point(24, 139), "ADVDIG.DEF", CButton::tooltip(), [&]{ close(); }, SDLK_d);
if(const CGHeroInstance *h = adventureInt->curHero())
dig->addCallback(boost::bind(&CPlayerInterface::tryDiggging, LOCPLINT, h));
>>>>>>> refactoring/guiClasses:client/windows/CAdvmapInterface.cpp
else else
dig->block(true); dig->block(true);
} }

View File

@ -1,11 +1,10 @@
#pragma once #pragma once
#include <typeinfo> #include "../widgets/AdventureMapClasses.h"
#include "CWindowObject.h"
#include "SDL.h" #include "../widgets/TextControls.h"
#include "gui/CIntObjectClasses.h" #include "../widgets/Buttons.h"
#include "GUIClasses.h"
#include "AdventureMapClasses.h"
class CDefHandler; class CDefHandler;
class CCallback; class CCallback;
@ -33,7 +32,7 @@ class IShipyard;
class CAdventureOptions : public CWindowObject class CAdventureOptions : public CWindowObject
{ {
public: public:
CAdventureMapButton *exit, *viewWorld, *puzzle, *dig, *scenInfo, *replay; CButton *exit, *viewWorld, *puzzle, *dig, *scenInfo, *replay;
CAdventureOptions(); CAdventureOptions();
static void showScenarioInfo(); static void showScenarioInfo();
@ -111,16 +110,16 @@ public:
CMinimap minimap; CMinimap minimap;
CGStatusBar statusbar; CGStatusBar statusbar;
CAdventureMapButton kingOverview,//- kingdom overview CButton * kingOverview;
underground,//- underground switch CButton * underground;
questlog,//- questlog CButton * questlog;
sleepWake, //- sleep/wake hero CButton * sleepWake;
moveHero, //- move hero CButton * moveHero;
spellbook,//- spellbook CButton * spellbook;
advOptions, //- adventure options CButton * advOptions;
sysOptions,//- system options CButton * sysOptions;
nextHero, //- next hero CButton * nextHero;
endTurn;//- end turn CButton * endTurn;
CTerrainRect terrain; //visible terrain CTerrainRect terrain; //visible terrain
CResDataBar resdatabar; CResDataBar resdatabar;

View File

@ -1,29 +1,36 @@
#include "StdInc.h" #include "StdInc.h"
#include "CCastleInterface.h" #include "CCastleInterface.h"
#include "../CCallback.h"
#include "../lib/CArtHandler.h"
#include "../lib/CBuildingHandler.h"
#include "../lib/CCreatureHandler.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CModHandler.h"
#include "../lib/mapObjects/CGHeroInstance.h"
#include "../lib/CSpellHandler.h"
#include "../lib/CTownHandler.h"
#include "CAdvmapInterface.h" #include "CAdvmapInterface.h"
#include "CAnimation.h"
#include "CBitmapHandler.h"
#include "CDefHandler.h"
#include "CGameInfo.h"
#include "CHeroWindow.h" #include "CHeroWindow.h"
#include "CMessage.h" #include "CTradeWindow.h"
#include "CMusicHandler.h" #include "GUIClasses.h"
#include "CPlayerInterface.h"
#include "Graphics.h" #include "../CBitmapHandler.h"
#include "gui/SDL_Extensions.h" #include "../CDefHandler.h"
#include "../lib/GameConstants.h" #include "../CGameInfo.h"
#include "gui/CGuiHandler.h" #include "../CMessage.h"
#include "gui/CIntObjectClasses.h" #include "../CMusicHandler.h"
#include "../CPlayerInterface.h"
#include "../Graphics.h"
#include "../gui/CGuiHandler.h"
#include "../gui/SDL_Extensions.h"
#include "../windows/InfoWindows.h"
#include "../widgets/MiscWidgets.h"
#include "../widgets/CComponent.h"
#include "../../CCallback.h"
#include "../../lib/CArtHandler.h"
#include "../../lib/CBuildingHandler.h"
#include "../../lib/CCreatureHandler.h"
#include "../../lib/CGeneralTextHandler.h"
#include "../../lib/CModHandler.h"
#include "../../lib/CSpellHandler.h"
#include "../../lib/CTownHandler.h"
#include "../../lib/GameConstants.h"
#include "../../lib/mapObjects/CGHeroInstance.h"
#include "../../lib/mapObjects/CGTownInstance.h"
using namespace boost::assign; using namespace boost::assign;
@ -836,7 +843,11 @@ void CCastleBuildings::enterTownHall()
else else
{ {
LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[673]); LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[673]);
<<<<<<< HEAD:client/CCastleInterface.cpp
(dynamic_cast<CInfoWindow*>(GH.topInt()))->buttons[0]->callback += std::bind(&CCastleBuildings::openTownHall, this); (dynamic_cast<CInfoWindow*>(GH.topInt()))->buttons[0]->callback += std::bind(&CCastleBuildings::openTownHall, this);
=======
dynamic_cast<CInfoWindow*>(GH.topInt())->buttons[0]->addCallback(boost::bind(&CCastleBuildings::openTownHall, this));
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
} }
} }
else else
@ -881,12 +892,21 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, const CGTownInst
income = new CLabel(195, 443, FONT_SMALL, CENTER); income = new CLabel(195, 443, FONT_SMALL, CENTER);
icon = new CAnimImage("ITPT", 0, 0, 15, 387); icon = new CAnimImage("ITPT", 0, 0, 15, 387);
<<<<<<< HEAD:client/CCastleInterface.cpp
exit = new CAdventureMapButton(CGI->generaltexth->tcommands[8], "", std::bind(&CCastleInterface::close,this), 744, 544, "TSBTNS", SDLK_RETURN); exit = new CAdventureMapButton(CGI->generaltexth->tcommands[8], "", std::bind(&CCastleInterface::close,this), 744, 544, "TSBTNS", SDLK_RETURN);
=======
exit = new CButton(Point(744, 544), "TSBTNS", CButton::tooltip(CGI->generaltexth->tcommands[8]), [&]{close();}, SDLK_RETURN);
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
exit->assignedKeys.insert(SDLK_ESCAPE); exit->assignedKeys.insert(SDLK_ESCAPE);
exit->setOffset(4); exit->setImageOrder(4, 5, 6, 7);
<<<<<<< HEAD:client/CCastleInterface.cpp
split = new CAdventureMapButton(CGI->generaltexth->tcommands[3], "", std::bind(&CGarrisonInt::splitClick,garr), 744, 382, "TSBTNS.DEF"); split = new CAdventureMapButton(CGI->generaltexth->tcommands[3], "", std::bind(&CGarrisonInt::splitClick,garr), 744, 382, "TSBTNS.DEF");
split->callback += std::bind(&HeroSlots::splitClicked, heroes); split->callback += std::bind(&HeroSlots::splitClicked, heroes);
=======
split = new CButton(Point(744, 382), "TSBTNS.DEF", CButton::tooltip(CGI->generaltexth->tcommands[3]), [&]{garr->splitClick();});
split->addCallback(boost::bind(&HeroSlots::splitClicked, heroes));
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
garr->addSplitBtn(split); garr->addSplitBtn(split);
Rect barRect(9, 182, 732, 18); Rect barRect(9, 182, 732, 18);
@ -1304,8 +1324,12 @@ CHallInterface::CHallInterface(const CGTownInstance *Town):
statusBar = new CGStatusBar(new CPicture(*background, barRect, 5, 556, false)); statusBar = new CGStatusBar(new CPicture(*background, barRect, 5, 556, false));
title = new CLabel(399, 12, FONT_MEDIUM, CENTER, Colors::WHITE, town->town->buildings.at(BuildingID(town->hallLevel()+BuildingID::VILLAGE_HALL))->Name()); title = new CLabel(399, 12, FONT_MEDIUM, CENTER, Colors::WHITE, town->town->buildings.at(BuildingID(town->hallLevel()+BuildingID::VILLAGE_HALL))->Name());
<<<<<<< HEAD:client/CCastleInterface.cpp
exit = new CAdventureMapButton(CGI->generaltexth->hcommands[8], "", exit = new CAdventureMapButton(CGI->generaltexth->hcommands[8], "",
std::bind(&CHallInterface::close,this), 748, 556, "TPMAGE1.DEF", SDLK_RETURN); std::bind(&CHallInterface::close,this), 748, 556, "TPMAGE1.DEF", SDLK_RETURN);
=======
exit = new CButton(Point(748, 556), "TPMAGE1.DEF", CButton::tooltip(CGI->generaltexth->hcommands[8]), [&]{close();}, SDLK_RETURN);
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
exit->assignedKeys.insert(SDLK_ESCAPE); exit->assignedKeys.insert(SDLK_ESCAPE);
auto & boxList = town->town->clientInfo.hallSlots; auto & boxList = town->town->clientInfo.hallSlots;
@ -1403,15 +1427,24 @@ CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Buildin
if(!rightClick) if(!rightClick)
{ //normal window { //normal window
<<<<<<< HEAD:client/CCastleInterface.cpp
buy = new CAdventureMapButton(boost::str(boost::format(CGI->generaltexth->allTexts[595]) % building->Name()), buy = new CAdventureMapButton(boost::str(boost::format(CGI->generaltexth->allTexts[595]) % building->Name()),
"", std::bind(&CBuildWindow::buyFunc,this), 45, 446,"IBUY30", SDLK_RETURN); "", std::bind(&CBuildWindow::buyFunc,this), 45, 446,"IBUY30", SDLK_RETURN);
buy->borderColor = Colors::METALLIC_GOLD; =======
buy->borderEnabled = true; std::string tooltipYes = boost::str(boost::format(CGI->generaltexth->allTexts[595]) % building->Name());
std::string tooltipNo = boost::str(boost::format(CGI->generaltexth->allTexts[596]) % building->Name());
buy = new CButton(Point(45, 446), "IBUY30", CButton::tooltip(tooltipYes), [&]{ buyFunc(); }, SDLK_RETURN);
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
buy->borderColor = Colors::METALLIC_GOLD;
<<<<<<< HEAD:client/CCastleInterface.cpp
cancel = new CAdventureMapButton(boost::str(boost::format(CGI->generaltexth->allTexts[596]) % building->Name()), cancel = new CAdventureMapButton(boost::str(boost::format(CGI->generaltexth->allTexts[596]) % building->Name()),
"", std::bind(&CBuildWindow::close,this), 290, 445, "ICANCEL", SDLK_ESCAPE); "", std::bind(&CBuildWindow::close,this), 290, 445, "ICANCEL", SDLK_ESCAPE);
=======
cancel = new CButton(Point(290, 445), "ICANCEL", CButton::tooltip(tooltipNo), [&] { close();}, SDLK_ESCAPE);
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
cancel->borderColor = Colors::METALLIC_GOLD; cancel->borderColor = Colors::METALLIC_GOLD;
cancel->borderEnabled = true;
buy->block(state!=7 || LOCPLINT->playerID != town->tempOwner); buy->block(state!=7 || LOCPLINT->playerID != town->tempOwner);
} }
} }
@ -1441,7 +1474,11 @@ CFortScreen::CFortScreen(const CGTownInstance * town):
title = new CLabel(400, 12, FONT_BIG, CENTER, Colors::WHITE, fortBuilding->Name()); title = new CLabel(400, 12, FONT_BIG, CENTER, Colors::WHITE, fortBuilding->Name());
std::string text = boost::str(boost::format(CGI->generaltexth->fcommands[6]) % fortBuilding->Name()); std::string text = boost::str(boost::format(CGI->generaltexth->fcommands[6]) % fortBuilding->Name());
<<<<<<< HEAD:client/CCastleInterface.cpp
exit = new CAdventureMapButton(text, "", std::bind(&CFortScreen::close,this) ,748, 556, "TPMAGE1", SDLK_RETURN); exit = new CAdventureMapButton(text, "", std::bind(&CFortScreen::close,this) ,748, 556, "TPMAGE1", SDLK_RETURN);
=======
exit = new CButton(Point(748, 556), "TPMAGE1", CButton::tooltip(text), [&]{ close(); }, SDLK_RETURN);
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
exit->assignedKeys.insert(SDLK_ESCAPE); exit->assignedKeys.insert(SDLK_ESCAPE);
std::vector<Point> positions; std::vector<Point> positions;
@ -1640,7 +1677,6 @@ void CFortScreen::RecruitArea::clickRight(tribool down, bool previousState)
CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner,std::string imagem) :CWindowObject(BORDERED,imagem) CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner,std::string imagem) :CWindowObject(BORDERED,imagem)
{ {
OBJ_CONSTRUCTION_CAPTURING_ALL; OBJ_CONSTRUCTION_CAPTURING_ALL;
window = new CPicture(owner->town->town->clientInfo.guildWindow , 332, 76); window = new CPicture(owner->town->town->clientInfo.guildWindow , 332, 76);
@ -1651,7 +1687,11 @@ CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner,std::string imagem)
Rect barRect(7, 556, 737, 18); Rect barRect(7, 556, 737, 18);
statusBar = new CGStatusBar(new CPicture(*background, barRect, 7, 556, false)); statusBar = new CGStatusBar(new CPicture(*background, barRect, 7, 556, false));
<<<<<<< HEAD:client/CCastleInterface.cpp
exit = new CAdventureMapButton(CGI->generaltexth->allTexts[593],"",std::bind(&CMageGuildScreen::close,this), 748, 556,"TPMAGE1.DEF",SDLK_RETURN); exit = new CAdventureMapButton(CGI->generaltexth->allTexts[593],"",std::bind(&CMageGuildScreen::close,this), 748, 556,"TPMAGE1.DEF",SDLK_RETURN);
=======
exit = new CButton(Point(748, 556), "TPMAGE1.DEF", CButton::tooltip(CGI->generaltexth->allTexts[593]), [&]{ close(); }, SDLK_RETURN);
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
exit->assignedKeys.insert(SDLK_ESCAPE); exit->assignedKeys.insert(SDLK_ESCAPE);
std::vector<std::vector<Point> > positions; std::vector<std::vector<Point> > positions;
@ -1728,13 +1768,20 @@ CBlacksmithDialog::CBlacksmithDialog(bool possible, CreatureID creMachineID, Art
boost::lexical_cast<std::string>(CGI->arth->artifacts[aid]->price)); boost::lexical_cast<std::string>(CGI->arth->artifacts[aid]->price));
std::string text = boost::str(boost::format(CGI->generaltexth->allTexts[595]) % creature->nameSing); std::string text = boost::str(boost::format(CGI->generaltexth->allTexts[595]) % creature->nameSing);
<<<<<<< HEAD:client/CCastleInterface.cpp
buy = new CAdventureMapButton(text,"",std::bind(&CBlacksmithDialog::close, this), 42, 312,"IBUY30.DEF",SDLK_RETURN); buy = new CAdventureMapButton(text,"",std::bind(&CBlacksmithDialog::close, this), 42, 312,"IBUY30.DEF",SDLK_RETURN);
text = boost::str(boost::format(CGI->generaltexth->allTexts[596]) % creature->nameSing); text = boost::str(boost::format(CGI->generaltexth->allTexts[596]) % creature->nameSing);
cancel = new CAdventureMapButton(text,"",std::bind(&CBlacksmithDialog::close, this), 224, 312,"ICANCEL.DEF",SDLK_ESCAPE); cancel = new CAdventureMapButton(text,"",std::bind(&CBlacksmithDialog::close, this), 224, 312,"ICANCEL.DEF",SDLK_ESCAPE);
=======
buy = new CButton(Point(42, 312), "IBUY30.DEF", CButton::tooltip(text), [&]{ close(); }, SDLK_RETURN);
text = boost::str(boost::format(CGI->generaltexth->allTexts[596]) % creature->nameSing);
cancel = new CButton(Point(224, 312), "ICANCEL.DEF", CButton::tooltip(text), [&]{ close(); }, SDLK_ESCAPE);
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
if(possible) if(possible)
buy->callback += [=]{ LOCPLINT->cb->buyArtifact(LOCPLINT->cb->getHero(hid),aid); }; buy->addCallback([=]{ LOCPLINT->cb->buyArtifact(LOCPLINT->cb->getHero(hid),aid); });
else else
buy->block(true); buy->block(true);

View File

@ -1,10 +1,9 @@
#pragma once #pragma once
#include "../widgets/CGarrisonInt.h"
#include "../widgets/Images.h"
#include "CAnimation.h" class CButton;
#include "GUIClasses.h"
class CAdventureMapButton;
class CBuilding; class CBuilding;
class CCastleBuildings; class CCastleBuildings;
class CCreaturePic; class CCreaturePic;
@ -204,8 +203,8 @@ class CCastleInterface : public CWindowObject, public CWindowWithGarrison
CTownInfo *hall, *fort; CTownInfo *hall, *fort;
CAdventureMapButton *exit; CButton *exit;
CAdventureMapButton *split; CButton *split;
std::vector<CCreaInfo*> creainfo;//small icons of creatures (bottom-left corner); std::vector<CCreaInfo*> creainfo;//small icons of creatures (bottom-left corner);
@ -261,7 +260,7 @@ class CHallInterface : public CWindowObject
CLabel *title; CLabel *title;
CGStatusBar *statusBar; CGStatusBar *statusBar;
CMinorResDataBar * resdatabar; CMinorResDataBar * resdatabar;
CAdventureMapButton *exit; CButton *exit;
public: public:
CHallInterface(const CGTownInstance * Town); //c-tor CHallInterface(const CGTownInstance * Town); //c-tor
@ -273,8 +272,8 @@ class CBuildWindow: public CWindowObject
const CGTownInstance *town; const CGTownInstance *town;
const CBuilding *building; const CBuilding *building;
CAdventureMapButton *buy; CButton *buy;
CAdventureMapButton *cancel; CButton *cancel;
std::string getTextForState(int state); std::string getTextForState(int state);
void buyFunc(); void buyFunc();
@ -329,7 +328,7 @@ class CFortScreen : public CWindowObject
std::vector<RecruitArea*> recAreas; std::vector<RecruitArea*> recAreas;
CMinorResDataBar * resdatabar; CMinorResDataBar * resdatabar;
CGStatusBar *statusBar; CGStatusBar *statusBar;
CAdventureMapButton *exit; CButton *exit;
std::string getBgName(const CGTownInstance *town); std::string getBgName(const CGTownInstance *town);
@ -354,7 +353,7 @@ class CMageGuildScreen : public CWindowObject
void hover(bool on); void hover(bool on);
}; };
CPicture *window; CPicture *window;
CAdventureMapButton *exit; CButton *exit;
std::vector<Scroll *> spells; std::vector<Scroll *> spells;
CMinorResDataBar * resdatabar; CMinorResDataBar * resdatabar;
CGStatusBar *statusBar; CGStatusBar *statusBar;
@ -366,7 +365,7 @@ public:
/// The blacksmith window where you can buy available in town war machine /// The blacksmith window where you can buy available in town war machine
class CBlacksmithDialog : public CWindowObject class CBlacksmithDialog : public CWindowObject
{ {
CAdventureMapButton *buy, *cancel; CButton *buy, *cancel;
CPicture *animBG; CPicture *animBG;
CCreatureAnim * anim; CCreatureAnim * anim;
CLabel * title; CLabel * title;

View File

@ -0,0 +1,871 @@
#include "StdInc.h"
#include "CCreatureWindow.h"
#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 "../../CCallback.h"
#include "../../lib/BattleState.h"
#include "../../lib/CBonusTypeHandler.h"
#include "../../lib/CGeneralTextHandler.h"
#include "../../lib/CModHandler.h"
#include "../../lib/CHeroHandler.h"
#include "../../lib/CSpellHandler.h"
#include "../../lib/CGameState.h"
using namespace CSDL_Ext;
class CCreatureArtifactInstance;
class CSelectableSkill;
/*
* CCreatureWindow.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
*
*/
struct StackWindowInfo
{
// helper structs
struct CommanderLevelInfo
{
std::vector<ui32> skills;
std::function<void(ui32)> callback;
};
struct StackDismissInfo
{
std::function<void()> callback;
};
struct StackUpgradeInfo
{
UpgradeInfo info;
std::function<void(CreatureID)> callback;
};
// pointers to permament objects in game state
const CCreature * creature;
const CCommanderInstance * commander;
const CStackInstance * stackNode;
const CGHeroInstance * owner;
// temporary objects which should be kept as copy if needed
boost::optional<CommanderLevelInfo> levelupInfo;
boost::optional<StackDismissInfo> dismissInfo;
boost::optional<StackUpgradeInfo> upgradeInfo;
// misc fields
unsigned int creatureCount;
bool popupWindow;
StackWindowInfo();
};
namespace
{
namespace EStat
{
enum EStat
{
ATTACK,
DEFENCE,
SHOTS,
DAMAGE,
HEALTH,
HEALTH_LEFT,
SPEED,
MANA
};
}
}
StackWindowInfo::StackWindowInfo():
creature(nullptr),
commander(nullptr),
stackNode(nullptr),
owner(nullptr),
creatureCount(0),
popupWindow(false)
{
}
void CStackWindow::CWindowSection::createBackground(std::string path)
{
background = new CPicture("stackWindow/" + path);
pos = background->pos;
}
void CStackWindow::CWindowSection::printStatString(int index, std::string name, std::string value)
{
new CLabel(145, 32 + index*19, FONT_SMALL, TOPLEFT, Colors::WHITE, name);
new CLabel(307, 48 + index*19, FONT_SMALL, BOTTOMRIGHT, Colors::WHITE, value);
}
void CStackWindow::CWindowSection::printStatRange(int index, std::string name, int min, int max)
{
if(min != max)
printStatString(index, name, boost::str(boost::format("%d - %d") % min % max));
else
printStatString(index, name, boost::str(boost::format("%d") % min));
}
void CStackWindow::CWindowSection::printStatBase(int index, std::string name, int base, int current)
{
if(base != current)
printStatString(index, name, boost::str(boost::format("%d (%d)") % base % current));
else
printStatString(index, name, boost::str(boost::format("%d") % base));
}
void CStackWindow::CWindowSection::printStat(int index, std::string name, int value)
{
printStatBase(index, name, value, value);
}
std::string CStackWindow::generateStackExpDescription()
{
const CStackInstance * stack = info->stackNode;
const CCreature * creature = info->creature;
int tier = stack->type->level;
int rank = stack->getExpRank();
if (!vstd::iswithin(tier, 1, 7))
tier = 0;
int number;
std::string expText = CGI->generaltexth->zcrexp[325];
boost::replace_first (expText, "%s", creature->namePl);
boost::replace_first (expText, "%s", CGI->generaltexth->zcrexp[rank]);
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(rank));
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(stack->experience));
number = CGI->creh->expRanks[tier][rank] - stack->experience;
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number));
number = CGI->creh->maxExpPerBattle[tier]; //percent
boost::replace_first (expText, "%i%", boost::lexical_cast<std::string>(number));
number *= CGI->creh->expRanks[tier].back() / 100; //actual amount
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number));
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(stack->count)); //Number of Creatures in stack
int expmin = std::max(CGI->creh->expRanks[tier][std::max(rank-1, 0)], (ui32)1);
number = (stack->count * (stack->experience - expmin)) / expmin; //Maximum New Recruits without losing current Rank
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number)); //TODO
boost::replace_first (expText, "%.2f", boost::lexical_cast<std::string>(1)); //TODO Experience Multiplier
number = CGI->creh->expAfterUpgrade;
boost::replace_first (expText, "%.2f", boost::lexical_cast<std::string>(number) + "%"); //Upgrade Multiplier
expmin = CGI->creh->expRanks[tier][9];
int expmax = CGI->creh->expRanks[tier][10];
number = expmax - expmin;
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number)); //Experience after Rank 10
number = (stack->count * (expmax - expmin)) / expmin;
boost::replace_first (expText, "%i", boost::lexical_cast<std::string>(number)); //Maximum New Recruits to remain at Rank 10 if at Maximum Experience
return expText;
}
void CStackWindow::removeStackArtifact(ArtifactPosition pos)
{
auto art = info->stackNode->getArt(ArtifactPosition::CREATURE_SLOT);
LOCPLINT->cb->swapArtifacts(ArtifactLocation(info->stackNode, pos),
ArtifactLocation(info->owner, art->firstBackpackSlot(info->owner)));
delete stackArtifactButton;
delete stackArtifactHelp;
delete stackArtifactIcon;
}
void CStackWindow::setStackArtifact(const CArtifactInstance * art, Point artPos)
{
if (art)
{
stackArtifactIcon = new CAnimImage("ARTIFACT", art->artType->iconIndex, 0, pos.x, pos.y);
stackArtifactHelp = new LRClickableAreaWTextComp(Rect(artPos, Point(44, 44)), CComponent::artifact);
stackArtifactHelp->type = art->artType->id;
const JsonNode & text = VLC->generaltexth->localizedTexts["creatureWindow"]["returnArtifact"];
if (info->owner)
{
stackArtifactButton = new CButton(Point(artPos.x - 2 , artPos.y + 46), "stackWindow/cancelButton",
CButton::tooltip(text),
[=]{ removeStackArtifact(ArtifactPosition::CREATURE_SLOT); });
}
}
}
void CStackWindow::CWindowSection::createStackInfo(bool showExp, bool showArt)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
if (showExp && showArt)
createBackground("info-panel-2");
else if (showExp || showArt)
createBackground("info-panel-1");
else
createBackground("info-panel-0");
new CCreaturePic(5, 41, parent->info->creature);
std::string visibleName;
if (parent->info->commander != nullptr)
visibleName = parent->info->commander->type->nameSing;
else
visibleName = parent->info->creature->namePl;
new CLabel(215, 12, FONT_SMALL, CENTER, Colors::YELLOW, visibleName);
int dmgMultiply = 1;
if(parent->info->owner && parent->info->stackNode->hasBonusOfType(Bonus::SIEGE_WEAPON))
dmgMultiply += parent->info->owner->Attack();
new CPicture("stackWindow/icons", 117, 32);
printStatBase(EStat::ATTACK, CGI->generaltexth->primarySkillNames[0], parent->info->creature->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), parent->info->stackNode->Attack());
printStatBase(EStat::DEFENCE, CGI->generaltexth->primarySkillNames[1], parent->info->creature->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), parent->info->stackNode->Defense());
printStatRange(EStat::DAMAGE, CGI->generaltexth->allTexts[199], parent->info->stackNode->getMinDamage() * dmgMultiply, parent->info->stackNode->getMaxDamage() * dmgMultiply);
printStatBase(EStat::HEALTH, CGI->generaltexth->allTexts[388], parent->info->creature->valOfBonuses(Bonus::STACK_HEALTH), parent->info->stackNode->valOfBonuses(Bonus::STACK_HEALTH));
printStatBase(EStat::SPEED, CGI->generaltexth->zelp[441].first, parent->info->creature->Speed(), parent->info->stackNode->Speed());
const CStack * battleStack = dynamic_cast<const CStack*>(parent->info->stackNode);
bool shooter = parent->info->stackNode->hasBonusOfType(Bonus::SHOOTER) && parent->info->stackNode->valOfBonuses(Bonus::SHOTS);
bool caster = parent->info->stackNode->valOfBonuses(Bonus::CASTS);
if (battleStack != nullptr) // in battle
{
if (shooter)
printStatBase(EStat::SHOTS, CGI->generaltexth->allTexts[198], battleStack->valOfBonuses(Bonus::SHOTS), battleStack->shots);
if (caster)
printStatBase(EStat::MANA, CGI->generaltexth->allTexts[399], battleStack->valOfBonuses(Bonus::CASTS), battleStack->casts);
printStat(EStat::HEALTH_LEFT, CGI->generaltexth->allTexts[200], battleStack->firstHPleft);
}
else
{
if (shooter)
printStat(EStat::SHOTS, CGI->generaltexth->allTexts[198], parent->info->stackNode->valOfBonuses(Bonus::SHOTS));
if (caster)
printStat(EStat::MANA, CGI->generaltexth->allTexts[399], parent->info->stackNode->valOfBonuses(Bonus::CASTS));
}
auto morale = new MoraleLuckBox(true, genRect(42, 42, 321, 110));
morale->set(parent->info->stackNode);
auto luck = new MoraleLuckBox(false, genRect(42, 42, 375, 110));
luck->set(parent->info->stackNode);
if (showArt)
{
Point pos = showExp ? Point(375, 32) : Point(347, 32);
parent->setStackArtifact(parent->info->stackNode->getArt(ArtifactPosition::CREATURE_SLOT), pos);
}
if (showExp)
{
const CStackInstance * stack = parent->info->stackNode;
Point pos = showArt ? Point(321, 32) : Point(347, 32);
if (parent->info->commander)
{
const CCommanderInstance * commander = parent->info->commander;
new CAnimImage("PSKIL42", 4, 0, pos.x, pos.y); // experience icon
auto expArea = new LRClickableAreaWTextComp(Rect(pos.x, pos.y, 44, 44), CComponent::experience);
expArea->text = CGI->generaltexth->allTexts[2];
expArea->bonusValue = commander->getExpRank();
boost::replace_first(expArea->text, "%d", boost::lexical_cast<std::string>(commander->getExpRank()));
boost::replace_first(expArea->text, "%d", boost::lexical_cast<std::string>(CGI->heroh->reqExp(commander->getExpRank()+1)));
boost::replace_first(expArea->text, "%d", boost::lexical_cast<std::string>(commander->experience));
}
else
{
new CAnimImage("stackWindow/levels", stack->getExpRank(), 0, pos.x, pos.y);
auto expArea = new LRClickableAreaWText(Rect(pos.x, pos.y, 44, 44));
expArea->text = parent->generateStackExpDescription();
}
new CLabel(pos.x + 21, pos.y + 52, FONT_SMALL, CENTER, Colors::WHITE, makeNumberShort<TExpType>(stack->experience, 6));
}
}
void CStackWindow::CWindowSection::createActiveSpells()
{
static const Point firstPos(7 ,4); // position of 1st spell box
static const Point offset(54, 0); // offset of each spell box from previous
OBJ_CONSTRUCTION_CAPTURING_ALL;
createBackground("spell-effects");
const CStack * battleStack = dynamic_cast<const CStack*>(parent->info->stackNode);
assert(battleStack); // Section should be created only for battles
//spell effects
int printed=0; //how many effect pics have been printed
std::vector<si32> spells = battleStack->activeSpells();
for(si32 effect : spells)
{
std::string spellText;
if (effect < 77) //not all effects have graphics (for eg. Acid Breath)
{
spellText = CGI->generaltexth->allTexts[610]; //"%s, duration: %d rounds."
boost::replace_first (spellText, "%s", CGI->spellh->objects[effect]->name);
int duration = battleStack->getBonusLocalFirst(Selector::source(Bonus::SPELL_EFFECT,effect))->turnsRemain;
boost::replace_first (spellText, "%d", boost::lexical_cast<std::string>(duration));
new CAnimImage("SpellInt", effect + 1, 0, firstPos.x + offset.x * printed, firstPos.x + offset.y * printed);
new LRClickableAreaWText(Rect(firstPos + offset * printed, Point(50, 38)), spellText, spellText);
if (++printed >= 8) // interface limit reached
break;
}
}
}
void CStackWindow::CWindowSection::createCommanderSection()
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
auto onCreate = [=](size_t index) -> CIntObject *
{
return parent->switchTab(index);
};
auto onDestroy = [=](CIntObject * obj)
{
delete obj;
};
parent->commanderTab = new CTabbedInt(onCreate, onDestroy, Point(0,0), 0);
pos.w = parent->pos.w;
pos.h = 177; // height of commander info
if (parent->info->levelupInfo)
pos.h += 59; // height of abilities selection
}
static std::string skillToFile (int skill, int level, bool selected)
{
// FIXME: is this a correct hadling?
// level 0 = skill not present, use image with "no" suffix
// level 1-5 = skill available, mapped to images indexed as 0-4
// selecting skill means that it will appear one level higher (as if alredy upgraded)
std::string file = "zvs/Lib1.res/_";
switch (skill)
{
case ECommander::ATTACK:
file += "AT";
break;
case ECommander::DEFENSE:
file += "DF";
break;
case ECommander::HEALTH:
file += "HP";
break;
case ECommander::DAMAGE:
file += "DM";
break;
case ECommander::SPEED:
file += "SP";
break;
case ECommander::SPELL_POWER:
file += "MP";
break;
}
std::string sufix;
if (selected)
level++; // UI will display resulting level
if (level == 0)
sufix = "no"; //not avaliable - no number
else
sufix = boost::lexical_cast<std::string>(level-1);
if (selected)
sufix += "="; //level-up highlight
return file + sufix + ".bmp";
}
void CStackWindow::CWindowSection::createCommander()
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
createBackground("commander-bg");
auto getSkillPos = [&](int index)
{
return Point(10 + 80 * (index%3), 20 + 80 * (index/3));
};
auto getSkillImage = [this](int skillIndex) -> std::string
{
bool selected = ((parent->selectedSkill == skillIndex) && parent->info->levelupInfo );
return skillToFile(skillIndex, parent->info->commander->secondarySkills[skillIndex], selected);
};
for (int index = ECommander::ATTACK; index <= ECommander::SPELL_POWER; ++index)
{
Point skillPos = getSkillPos(index);
auto icon = new CClickableObject(new CPicture(getSkillImage(index), skillPos.x, skillPos.y), [=]{});
if (parent->selectedSkill == index)
parent->selectedIcon = icon;
if (parent->info->levelupInfo && vstd::contains(parent->info->levelupInfo->skills, index)) // can be upgraded - enable selection switch
{
icon->callback = [=]
{
parent->setSelection(index, icon);
};
}
}
//TODO: commander artifacts
}
CIntObject * CStackWindow::createSkillEntry(int index)
{
for (auto skillID : info->levelupInfo->skills)
{
if (index == 0 && skillID >= 100)
{
const Bonus *bonus = CGI->creh->skillRequirements[skillID-100].first;
const CStackInstance *stack = info->commander;
CClickableObject * icon = new CClickableObject(new CPicture(stack->bonusToGraphics(bonus)), []{});
icon->callback = [=]
{
setSelection(skillID, icon);
};
icon->text = stack->bonusToString(bonus, true);
icon->hoverText = stack->bonusToString(bonus, false);
return icon;
}
if (skillID >= 100)
index--;
}
return nullptr;
}
void CStackWindow::CWindowSection::createCommanderAbilities()
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
auto bg2 = new CPicture("stackWindow/commander-abilities.png");
bg2->moveBy(Point(0, pos.h));
size_t abilitiesCount = boost::range::count_if(parent->info->levelupInfo->skills, [](ui32 skillID)
{
return skillID >= 100;
});
auto list = new CListBox([=] (int index)
{
return parent->createSkillEntry(index);
},
[=] (CIntObject * elem)
{
delete elem;
},
Point(38, 3+pos.h), Point(63, 0), 6, abilitiesCount);
auto leftBtn = new CButton(Point(10, pos.h + 6), "hsbtns3.def", CButton::tooltip(), [=]{ list->moveToPrev(); }, SDLK_LEFT);
auto rightBtn = new CButton(Point(411, pos.h + 6), "hsbtns5.def", CButton::tooltip(), [=]{ list->moveToNext(); }, SDLK_RIGHT);
if (abilitiesCount <= 6)
{
leftBtn->block(true);
rightBtn->block(true);
}
}
void CStackWindow::setSelection(si32 newSkill, CClickableObject * newIcon)
{
auto getSkillImage = [this](int skillIndex) -> std::string
{
bool selected = ((selectedSkill == skillIndex) && info->levelupInfo );
return skillToFile(skillIndex, info->commander->secondarySkills[skillIndex], selected);
};
OBJ_CONSTRUCTION_CAPTURING_ALL;
int oldSelection = selectedSkill; // update selection
selectedSkill = newSkill;
if (selectedIcon && oldSelection < 100) // recreate image on old selection, only for skills
selectedIcon->setObject(new CPicture(getSkillImage(oldSelection)));
selectedIcon = newIcon; // update new selection
if (newSkill < 100)
newIcon->setObject(new CPicture(getSkillImage(newSkill)));
}
void CStackWindow::CWindowSection::createBonuses(boost::optional<size_t> preferredSize)
{
// size of single image for an item
static const int itemHeight = 59;
OBJ_CONSTRUCTION_CAPTURING_ALL;
size_t totalSize = (parent->activeBonuses.size() + 1) / 2;
size_t visibleSize = preferredSize ? preferredSize.get() : std::min<size_t>(3, totalSize);
pos.w = parent->pos.w;
pos.h = itemHeight * visibleSize;
auto onCreate = [=](size_t index) -> CIntObject *
{
return parent->createBonusEntry(index);
};
auto onDestroy = [=](CIntObject * obj)
{
delete obj;
};
new CListBox(onCreate, onDestroy, Point(0, 0), Point(0, itemHeight), visibleSize, totalSize, 0, 1, Rect(pos.w - 15, 0, pos.h, pos.h));
}
void CStackWindow::CWindowSection::createButtonPanel()
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
createBackground("button-panel");
if (parent->info->dismissInfo)
{
auto onDismiss = [=]()
{
parent->info->dismissInfo->callback();
parent->close();
};
auto onClick = [=] ()
{
LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[12], onDismiss, 0, false, std::vector<CComponent*>());
};
new CButton(Point(5, 5),"IVIEWCR2.DEF", CGI->generaltexth->zelp[445], onClick, SDLK_d);
}
if (parent->info->upgradeInfo)
{
// used space overlaps with commander switch button
// besides - should commander really be upgradeable?
assert(!parent->info->commander);
StackWindowInfo::StackUpgradeInfo & upgradeInfo = parent->info->upgradeInfo.get();
size_t buttonsToCreate = std::min<size_t>(upgradeInfo.info.newID.size(), 3); // no more than 3 windows on UI - space limit
for (size_t i=0; i<buttonsToCreate; i++)
{
TResources totalCost = upgradeInfo.info.cost[i] * parent->info->creatureCount;
auto onUpgrade = [=]()
{
upgradeInfo.callback(upgradeInfo.info.newID[i]);
parent->close();
};
auto onClick = [=]()
{
std::vector<CComponent*> resComps;
for(TResources::nziterator i(totalCost); i.valid(); i++)
{
resComps.push_back(new CComponent(CComponent::resource, i->resType, i->resVal));
}
LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[207], onUpgrade, nullptr, true, resComps);
};
auto upgradeBtn = new CButton(Point(221 + i * 40, 5), "stackWindow/upgradeButton", CGI->generaltexth->zelp[446], onClick, SDLK_1);
upgradeBtn->addOverlay(new CAnimImage("CPRSMALL", VLC->creh->creatures[upgradeInfo.info.newID[i]]->iconIndex));
if (!LOCPLINT->cb->getResourceAmount().canAfford(totalCost))
upgradeBtn->block(true);
}
}
if (parent->info->commander)
{
for (size_t i=0; i<2; i++)
{
std::string btnIDs[2] = { "showSkills", "showBonuses" };
auto onSwitch = [&, i]()
{
parent->switchButtons[parent->activeTab]->enable();
parent->commanderTab->setActive(i);
parent->switchButtons[i]->disable();
parent->redraw(); // FIXME: enable/disable don't redraw screen themselves
};
const JsonNode & text = VLC->generaltexth->localizedTexts["creatureWindow"][btnIDs[i]];
parent->switchButtons[i] = new CButton(Point(302 + i*40, 5), "stackWindow/upgradeButton", CButton::tooltip(text), onSwitch);
parent->switchButtons[i]->addOverlay(new CAnimImage("stackWindow/switchModeIcons", i));
}
parent->switchButtons[parent->activeTab]->disable();
}
auto exitBtn = new CButton(Point(382, 5), "hsbtns.def", CGI->generaltexth->zelp[445], [=]{ parent->close(); }, SDLK_RETURN);
exitBtn->assignedKeys.insert(SDLK_ESCAPE);
}
CStackWindow::CWindowSection::CWindowSection(CStackWindow * parent):
parent(parent)
{
}
CClickableObject::CClickableObject(CIntObject *object, std::function<void()> callback):
object(nullptr),
callback(callback)
{
pos = object->pos;
setObject(object);
}
void CClickableObject::setObject(CIntObject *newObject)
{
delete object;
object = newObject;
addChild(object);
object->moveTo(pos.topLeft());
redraw();
}
void CClickableObject::clickLeft(tribool down, bool previousState)
{
if (down)
callback();
}
CIntObject * CStackWindow::createBonusEntry(size_t index)
{
auto section = new CWindowSection(this);
section->createBonusEntry(index);
return section;
}
void CStackWindow::CWindowSection::createBonusEntry(size_t index)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
createBackground("bonus-effects");
createBonusItem(index * 2, Point(6, 4));
createBonusItem(index * 2 + 1, Point(214, 4));
}
void CStackWindow::CWindowSection::createBonusItem(size_t index, Point position)
{
if (parent->activeBonuses.size() > index)
{
BonusInfo & bi = parent->activeBonuses[index];
new CPicture(bi.imagePath, position.x, position.y);
new CLabel(position.x + 60, position.y + 2, FONT_SMALL, TOPLEFT, Colors::WHITE, bi.name);
new CLabel(position.x + 60, position.y + 25, FONT_SMALL, TOPLEFT, Colors::WHITE, bi.description);
}
}
CIntObject * CStackWindow::switchTab(size_t index)
{
switch (index)
{
case 0:
{
activeTab = 0;
auto ret = new CWindowSection(this);
ret->createCommander();
if (info->levelupInfo)
ret->createCommanderAbilities();
return ret;
}
case 1:
{
activeTab = 1;
auto ret = new CWindowSection(this);
if (info->levelupInfo)
ret->createBonuses(4);
else
ret->createBonuses(3);
return ret;
}
default:
{
return nullptr;
}
}
}
void CStackWindow::initSections()
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
CWindowSection * currentSection;
bool showArt = CGI->modh->modules.STACK_ARTIFACT && info->commander == nullptr && info->stackNode;
bool showExp = (CGI->modh->modules.STACK_EXP || info->commander != nullptr) && info->stackNode;
currentSection = new CWindowSection(this);
currentSection->createStackInfo(showExp, showArt);
pos.w = currentSection->pos.w;
pos.h += currentSection->pos.h;
if (dynamic_cast<const CStack*>(info->stackNode)) // in battle
{
currentSection = new CWindowSection(this);
currentSection->pos.y += pos.h;
currentSection->createActiveSpells();
pos.h += currentSection->pos.h;
}
if (info->commander)
{
currentSection = new CWindowSection(this);
currentSection->pos.y += pos.h;
currentSection->createCommanderSection();
pos.h += currentSection->pos.h;
}
if (!info->commander && !activeBonuses.empty())
{
currentSection = new CWindowSection(this);
currentSection->pos.y += pos.h;
currentSection->createBonuses();
pos.h += currentSection->pos.h;
}
if (!info->popupWindow)
{
currentSection = new CWindowSection(this);
currentSection->pos.y += pos.h;
currentSection->createButtonPanel();
pos.h += currentSection->pos.h;
//FIXME: add status bar to image?
}
updateShadow();
pos = center(pos);
}
void CStackWindow::initBonusesList()
{
BonusList output, input;
input = *(info->stackNode->getBonuses(Selector::durationType(Bonus::PERMANENT).And(Selector::anyRange())));
while (!input.empty())
{
Bonus * b = input.front();
output.push_back(new Bonus(*b));
output.back()->val = input.valOfBonuses(Selector::typeSubtype(b->type, b->subtype)); //merge multiple bonuses into one
input.remove_if (Selector::typeSubtype(b->type, b->subtype)); //remove used bonuses
}
BonusInfo bonusInfo;
for(Bonus* b : output)
{
bonusInfo.name = info->stackNode->bonusToString(b, false);
bonusInfo.imagePath = info->stackNode->bonusToGraphics(b);
//if it's possible to give any description or image for this kind of bonus
//TODO: figure out why half of bonuses don't have proper description
if (!bonusInfo.name.empty() || !bonusInfo.imagePath.empty())
activeBonuses.push_back(bonusInfo);
}
//handle Magic resistance separately :/
int magicResistance = info->stackNode->magicResistance();
if (magicResistance)
{
BonusInfo bonusInfo;
Bonus b;
b.type = Bonus::MAGIC_RESISTANCE;
bonusInfo.name = VLC->getBth()->bonusToString(&b, info->stackNode, false);
bonusInfo.description = VLC->getBth()->bonusToString(&b, info->stackNode, true);
bonusInfo.imagePath = info->stackNode->bonusToGraphics(&b);
activeBonuses.push_back(bonusInfo);
}
}
void CStackWindow::init()
{
stackArtifactHelp = nullptr;
stackArtifactIcon = nullptr;
stackArtifactButton = nullptr;
selectedIcon = nullptr;
selectedSkill = 0;
if (info->levelupInfo)
{
selectedSkill = info->levelupInfo->skills.front();
logGlobal->debugStream() << "Received commander level-up. Possible options are: ";
for (auto skill : info->levelupInfo->skills)
logGlobal->debugStream() << "Skill #" << skill;
}
commanderTab = nullptr;
activeTab = 0;
initBonusesList();
initSections();
}
CStackWindow::CStackWindow(const CStack * stack, bool popup):
CWindowObject(BORDERED | (popup ? RCLICK_POPUP : 0))
{
info->stackNode = stack->base;
info->creature = stack->type;
info->creatureCount = stack->count;
info->popupWindow = popup;
init();
}
CStackWindow::CStackWindow(const CCreature * creature, bool popup):
CWindowObject(BORDERED | (popup ? RCLICK_POPUP : 0)),
info(new StackWindowInfo())
{
info->stackNode = new CStackInstance(creature, 1); // FIXME: free data
info->creature = creature;
info->popupWindow = popup;
init();
}
CStackWindow::CStackWindow(const CStackInstance * stack, bool popup):
CWindowObject(BORDERED | (popup ? RCLICK_POPUP : 0)),
info(new StackWindowInfo())
{
info->stackNode = stack;
info->creature = stack->type;
info->creatureCount = stack->count;
info->popupWindow = popup;
init();
}
CStackWindow::CStackWindow(const CStackInstance * stack, std::function<void()> dismiss, const UpgradeInfo & upgradeInfo, std::function<void(CreatureID)> callback):
CWindowObject(BORDERED),
info(new StackWindowInfo())
{
info->stackNode = stack;
info->creature = stack->type;
info->creatureCount = stack->count;
info->upgradeInfo = StackWindowInfo::StackUpgradeInfo();
info->dismissInfo = StackWindowInfo::StackDismissInfo();
info->upgradeInfo->info = upgradeInfo;
info->upgradeInfo->callback = callback;
info->dismissInfo->callback = dismiss;
init();
}
CStackWindow::CStackWindow(const CCommanderInstance * commander, bool popup):
CWindowObject(BORDERED | (popup ? RCLICK_POPUP : 0)),
info(new StackWindowInfo())
{
info->stackNode = commander;
info->creature = commander->type;
info->commander = commander;
info->creatureCount = 1;
info->popupWindow = popup;
init();
}
CStackWindow::CStackWindow(const CCommanderInstance * commander, std::vector<ui32> &skills, std::function<void(ui32)> callback):
CWindowObject(BORDERED),
info(new StackWindowInfo())
{
info->stackNode = commander;
info->creature = commander->type;
info->commander = commander;
info->creatureCount = 1;
info->levelupInfo = StackWindowInfo::CommanderLevelInfo();
info->levelupInfo->skills = skills;
info->levelupInfo->callback = callback;
init();
}
CStackWindow::~CStackWindow()
{
if (info->levelupInfo)
{
logGlobal->debugStream() << "Selected skill was " << selectedSkill;
info->levelupInfo->callback(vstd::find_pos(info->levelupInfo->skills, selectedSkill));
}
}

View File

@ -0,0 +1,120 @@
#pragma once
#include "../../lib/HeroBonus.h"
#include "../widgets/MiscWidgets.h"
#include "CWindowObject.h"
/*
* CCreatureWindow.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 StackWindowInfo;
class CCommanderInstance;
class CStackInstance;
class CStack;
struct UpgradeInfo;
class CTabbedInt;
class CButton;
class CClickableObject : public LRClickableAreaWText
{
CIntObject * object; // passive object that will be used to determine clickable area
public:
CClickableObject(CIntObject * object, std::function<void()> callback);
std::function<void()> callback; //TODO: create more generic clickable class than AdvMapButton?
void clickLeft(tribool down, bool previousState) override;
//void clickRight(tribool down, bool previousState){};
void setObject(CIntObject * object);
};
class CStackWindow : public CWindowObject
{
struct BonusInfo
{
std::string name;
std::string description;
std::string imagePath;
};
class CWindowSection : public CIntObject
{
CStackWindow * parent;
CPicture * background;
void createBackground(std::string path);
void createBonusItem(size_t index, Point position);
void printStatString(int index, std::string name, std::string value);
void printStatRange(int index, std::string name, int min, int max);
void printStatBase(int index, std::string name, int base, int current);
void printStat(int index, std::string name, int value);
public:
void createStackInfo(bool showExp, bool showArt);
void createActiveSpells();
void createCommanderSection();
void createCommander();
void createCommanderAbilities();
void createBonuses(boost::optional<size_t> size = boost::optional<size_t>());
void createBonusEntry(size_t index);
void createButtonPanel();
CWindowSection(CStackWindow * parent);
};
CAnimImage * stackArtifactIcon;
LRClickableAreaWTextComp * stackArtifactHelp;
CButton * stackArtifactButton;
std::unique_ptr<StackWindowInfo> info;
std::vector<BonusInfo> activeBonuses;
size_t activeTab;
CTabbedInt * commanderTab;
std::map<int, CButton *> switchButtons;
void setSelection(si32 newSkill, CClickableObject * newIcon);
CClickableObject * selectedIcon;
si32 selectedSkill;
CIntObject * createBonusEntry(size_t index);
CIntObject * switchTab(size_t index);
void removeStackArtifact(ArtifactPosition pos);
void setStackArtifact(const CArtifactInstance * art, Point artPos);
void initSections();
void initBonusesList();
void init();
std::string generateStackExpDescription();
CIntObject * createSkillEntry(int index);
public:
// for battles
CStackWindow(const CStack * stack, bool popup);
// for non-existing stacks, e.g. recruit screen
CStackWindow(const CCreature * creature, bool popup);
// for normal stacks in armies
CStackWindow(const CStackInstance * stack, bool popup);
CStackWindow(const CStackInstance * stack, std::function<void()> dismiss, const UpgradeInfo & info, std::function<void(CreatureID)> callback);
// for commanders & commander level-up dialog
CStackWindow(const CCommanderInstance * commander, bool popup);
CStackWindow(const CCommanderInstance * commander, std::vector<ui32> &skills, std::function<void(ui32)> callback);
~CStackWindow();
};

View File

@ -1,34 +1,34 @@
#include "StdInc.h" #include "StdInc.h"
#include "CAnimation.h"
#include "CAdvmapInterface.h"
#include "../CCallback.h"
#include "CGameInfo.h"
#include "CHeroWindow.h" #include "CHeroWindow.h"
#include "CMessage.h"
#include "CKingdomInterface.h" #include "CAdvmapInterface.h"
#include "CCreatureWindow.h" #include "CCreatureWindow.h"
#include "SDL.h" #include "CKingdomInterface.h"
#include "gui/SDL_Extensions.h"
#include "CBitmapHandler.h"
#include "Graphics.h"
#include "CSpellWindow.h" #include "CSpellWindow.h"
#include "../lib/CConfigHandler.h" #include "GUIClasses.h"
#include "CPlayerInterface.h"
#include "../CBitmapHandler.h"
#include "../CDefHandler.h"
#include "../CGameInfo.h"
#include "../CMessage.h"
#include "../CMT.h"
#include "../CPlayerInterface.h"
#include "../Graphics.h"
#include "../gui/SDL_Extensions.h"
#include "../gui/CGuiHandler.h"
#include "../widgets/MiscWidgets.h"
#include "../widgets/CComponent.h"
#include "../../CCallback.h"
#include "../lib/CArtHandler.h" #include "../lib/CArtHandler.h"
#include "CDefHandler.h" #include "../lib/CConfigHandler.h"
#include "../lib/CGeneralTextHandler.h" #include "../lib/CGeneralTextHandler.h"
#include "../lib/CHeroHandler.h" #include "../lib/CHeroHandler.h"
#include "../lib/mapObjects/CGHeroInstance.h" #include "../lib/mapObjects/CGHeroInstance.h"
#include "../lib/NetPacksBase.h" #include "../lib/NetPacksBase.h"
#include "gui/CGuiHandler.h"
#include "gui/CIntObjectClasses.h"
#include "CMT.h"
#undef min
/* /*
* CHeroWindow.cpp, part of VCMI engine * CHeroWindow.cpp, part of VCMI engine
* *
@ -93,8 +93,11 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero):
CWindowObject(PLAYER_COLORED, "HeroScr4"), CWindowObject(PLAYER_COLORED, "HeroScr4"),
heroWArt(this, hero) heroWArt(this, hero)
{ {
auto & heroscrn = CGI->generaltexth->heroscrn;
OBJ_CONSTRUCTION_CAPTURING_ALL; OBJ_CONSTRUCTION_CAPTURING_ALL;
garr = nullptr; garr = nullptr;
tacticsButton = nullptr;
curHero = hero; curHero = hero;
listSelection = nullptr; listSelection = nullptr;
@ -103,23 +106,32 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero):
//artifs = new CArtifactsOfHero(pos.topLeft(), true); //artifs = new CArtifactsOfHero(pos.topLeft(), true);
ourBar = new CGStatusBar(7, 559, "ADROLLVR.bmp", 660); // new CStatusBar(pos.x+72, pos.y+567, "ADROLLVR.bmp", 660); ourBar = new CGStatusBar(7, 559, "ADROLLVR.bmp", 660); // new CStatusBar(pos.x+72, pos.y+567, "ADROLLVR.bmp", 660);
<<<<<<< HEAD:client/CHeroWindow.cpp
quitButton = new CAdventureMapButton(CGI->generaltexth->heroscrn[17], std::string(),std::bind(&CHeroWindow::close,this), 609, 516, "hsbtns.def", SDLK_RETURN); quitButton = new CAdventureMapButton(CGI->generaltexth->heroscrn[17], std::string(),std::bind(&CHeroWindow::close,this), 609, 516, "hsbtns.def", SDLK_RETURN);
quitButton->assignedKeys.insert(SDLK_ESCAPE); quitButton->assignedKeys.insert(SDLK_ESCAPE);
dismissButton = new CAdventureMapButton(std::string(), CGI->generaltexth->heroscrn[28], std::bind(&CHeroWindow::dismissCurrent,this), 454, 429, "hsbtns2.def", SDLK_d); dismissButton = new CAdventureMapButton(std::string(), CGI->generaltexth->heroscrn[28], std::bind(&CHeroWindow::dismissCurrent,this), 454, 429, "hsbtns2.def", SDLK_d);
questlogButton = new CAdventureMapButton(CGI->generaltexth->heroscrn[0], std::string(), std::bind(&CHeroWindow::questlog,this), 314, 429, "hsbtns4.def", SDLK_q); questlogButton = new CAdventureMapButton(CGI->generaltexth->heroscrn[0], std::string(), std::bind(&CHeroWindow::questlog,this), 314, 429, "hsbtns4.def", SDLK_q);
=======
quitButton = new CButton(Point(609, 516), "hsbtns.def", CButton::tooltip(heroscrn[17]), [&]{ close(); }, SDLK_RETURN);
quitButton->assignedKeys.insert(SDLK_ESCAPE);
dismissButton = new CButton(Point(454, 429), "hsbtns2.def", CButton::tooltip(heroscrn[28]), [&]{ dismissCurrent(); }, SDLK_d);
questlogButton = new CButton(Point(314, 429), "hsbtns4.def", CButton::tooltip(heroscrn[0]), [&]{ questlog(); }, SDLK_q);
>>>>>>> refactoring/guiClasses:client/windows/CHeroWindow.cpp
formations = new CHighlightableButtonsGroup(0); formations = new CToggleGroup(0);
formations->addButton(map_list_of(0,CGI->generaltexth->heroscrn[23]),CGI->generaltexth->heroscrn[29], "hsbtns6.def", 481, 483, 0, 0, SDLK_t); formations->addToggle(0, new CToggleButton(Point(481, 483), "hsbtns6.def", std::make_pair(heroscrn[23], heroscrn[29]), 0, SDLK_t));
formations->addButton(map_list_of(0,CGI->generaltexth->heroscrn[24]),CGI->generaltexth->heroscrn[30], "hsbtns7.def", 481, 519, 1, 0, SDLK_l); formations->addToggle(1, new CToggleButton(Point(481, 519), "hsbtns7.def", std::make_pair(heroscrn[24], heroscrn[30]), 0, SDLK_l));
tacticsButton = new CHighlightableButton(0, 0, map_list_of(0,CGI->generaltexth->heroscrn[26])(3,CGI->generaltexth->heroscrn[25]), CGI->generaltexth->heroscrn[31], false, "hsbtns8.def", nullptr, 539, 483, SDLK_b);
if (hero->commander) if (hero->commander)
{ {
<<<<<<< HEAD:client/CHeroWindow.cpp
commanderButton = new CAdventureMapButton ("Commander", "Commander info", std::bind(&CHeroWindow::commanderWindow, this), 317, 18, "chftke.def", SDLK_c, nullptr, false); commanderButton = new CAdventureMapButton ("Commander", "Commander info", std::bind(&CHeroWindow::commanderWindow, this), 317, 18, "chftke.def", SDLK_c, nullptr, false);
=======
auto texts = CGI->generaltexth->localizedTexts["heroWindow"]["openCommander"];
commanderButton = new CButton (Point(317, 18), "buttons/commander", CButton::tooltip(texts), [&]{ commanderWindow(); }, SDLK_c);
>>>>>>> refactoring/guiClasses:client/windows/CHeroWindow.cpp
} }
//right list of heroes //right list of heroes
for(int i=0; i < std::min(LOCPLINT->cb->howManyHeroes(false), 8); i++) for(int i=0; i < std::min(LOCPLINT->cb->howManyHeroes(false), 8); i++)
heroList.push_back(new CHeroSwitcher(Point(612, 87 + i * 54), LOCPLINT->cb->getHeroBySerial(i, false))); heroList.push_back(new CHeroSwitcher(Point(612, 87 + i * 54), LOCPLINT->cb->getHeroBySerial(i, false)));
@ -180,7 +192,9 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero):
} }
void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= false*/) void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= false*/)
{ {
auto & heroscrn = CGI->generaltexth->heroscrn;
if(!hero) //something strange... no hero? it shouldn't happen if(!hero) //something strange... no hero? it shouldn't happen
{ {
logGlobal->errorStream() << "Set nullptr hero? no way..."; logGlobal->errorStream() << "Set nullptr hero? no way...";
@ -192,10 +206,11 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
specArea->text = curHero->type->specDescr; specArea->text = curHero->type->specDescr;
specImage->setFrame(curHero->type->imageIndex); specImage->setFrame(curHero->type->imageIndex);
tacticsButton->callback.clear(); delete tacticsButton;
tacticsButton->callback2.clear(); tacticsButton = new CToggleButton(Point(539, 483), "hsbtns8.def", std::make_pair(heroscrn[26], heroscrn[31]), 0, SDLK_b);
tacticsButton->addHoverText(CButton::HIGHLIGHTED, CGI->generaltexth->heroscrn[25]);
dismissButton->hoverTexts[0] = boost::str(boost::format(CGI->generaltexth->heroscrn[16]) % curHero->name % curHero->type->heroClass->name); dismissButton->addHoverText(CButton::NORMAL, boost::str(boost::format(CGI->generaltexth->heroscrn[16]) % curHero->name % curHero->type->heroClass->name));
portraitArea->hoverText = boost::str(boost::format(CGI->generaltexth->allTexts[15]) % curHero->name % curHero->type->heroClass->name); portraitArea->hoverText = boost::str(boost::format(CGI->generaltexth->allTexts[15]) % curHero->name % curHero->type->heroClass->name);
portraitArea->text = curHero->getBiography(); portraitArea->text = curHero->getBiography();
portraitImage->setFrame(curHero->portrait); portraitImage->setFrame(curHero->portrait);
@ -204,10 +219,17 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
OBJ_CONSTRUCTION_CAPTURING_ALL; OBJ_CONSTRUCTION_CAPTURING_ALL;
if(!garr) if(!garr)
{ {
std::string helpBox = heroscrn[32];
boost::algorithm::replace_first(helpBox, "%s", CGI->generaltexth->allTexts[43]);
garr = new CGarrisonInt(15, 485, 8, Point(), background->bg, Point(15,485), curHero); garr = new CGarrisonInt(15, 485, 8, Point(), background->bg, Point(15,485), curHero);
<<<<<<< HEAD:client/CHeroWindow.cpp
auto split = new CAdventureMapButton(CGI->generaltexth->allTexts[256], CGI->generaltexth->heroscrn[32], auto split = new CAdventureMapButton(CGI->generaltexth->allTexts[256], CGI->generaltexth->heroscrn[32],
std::bind(&CGarrisonInt::splitClick,garr), 539, 519, "hsbtns9.def", false, nullptr, false); //deleted by garrison destructor std::bind(&CGarrisonInt::splitClick,garr), 539, 519, "hsbtns9.def", false, nullptr, false); //deleted by garrison destructor
boost::algorithm::replace_first(split->hoverTexts[0],"%s",CGI->generaltexth->allTexts[43]); boost::algorithm::replace_first(split->hoverTexts[0],"%s",CGI->generaltexth->allTexts[43]);
=======
auto split = new CButton(Point(539, 519), "hsbtns9.def", CButton::tooltip(CGI->generaltexth->allTexts[256], helpBox), [&]{ garr->splitClick(); });
>>>>>>> refactoring/guiClasses:client/windows/CHeroWindow.cpp
garr->addSplitBtn(split); garr->addSplitBtn(split);
} }
@ -239,7 +261,7 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
secSkillAreas[g]->type = skill; secSkillAreas[g]->type = skill;
secSkillAreas[g]->bonusValue = level; secSkillAreas[g]->bonusValue = level;
secSkillAreas[g]->text = CGI->generaltexth->skillInfoTexts[skill][level-1]; secSkillAreas[g]->text = CGI->generaltexth->skillInfoTexts[skill][level-1];
secSkillAreas[g]->hoverText = boost::str(boost::format(CGI->generaltexth->heroscrn[21]) % CGI->generaltexth->levels[level-1] % CGI->generaltexth->skillName[skill]); secSkillAreas[g]->hoverText = boost::str(boost::format(heroscrn[21]) % CGI->generaltexth->levels[level-1] % CGI->generaltexth->skillName[skill]);
secSkillImages[g]->setFrame(skill*3 + level + 2); secSkillImages[g]->setFrame(skill*3 + level + 2);
} }
@ -274,14 +296,19 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
else else
{ {
tacticsButton->block(false); tacticsButton->block(false);
tacticsButton->callback = vstd::assigno(curHero->tacticFormationEnabled,true); tacticsButton->addCallback( [&](bool on) {curHero->tacticFormationEnabled = on;});
tacticsButton->callback2 = vstd::assigno(curHero->tacticFormationEnabled,false);
} }
//setting formations //setting formations
<<<<<<< HEAD:client/CHeroWindow.cpp
formations->onChange = 0; formations->onChange = 0;
formations->select(curHero->formation,true); formations->select(curHero->formation,true);
formations->onChange = std::bind(&CCallback::setFormation, LOCPLINT->cb.get(), curHero, _1); formations->onChange = std::bind(&CCallback::setFormation, LOCPLINT->cb.get(), curHero, _1);
=======
formations->setSelected(curHero->formation);
formations->addCallback([&] (int value) { LOCPLINT->cb->setFormation(curHero, value); });
>>>>>>> refactoring/guiClasses:client/windows/CHeroWindow.cpp
morale->set(&heroWArt); morale->set(&heroWArt);
luck->set(&heroWArt); luck->set(&heroWArt);
@ -328,7 +355,7 @@ void CHeroWindow::commanderWindow()
} }
} }
else else
GH.pushInt(new CCreatureWindow (curHero->commander)); GH.pushInt(new CStackWindow(curHero->commander, false));
} }

Some files were not shown because too many files have changed in this diff Show More