Merged GUI refactoring into develop, fixed conflicts
BIN
Mods/vcmi/Data/StackQueueLarge.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
Mods/vcmi/Data/StackQueueSmall.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
Mods/vcmi/Data/questDialog.png
Normal file
After Width: | Height: | Size: 268 KiB |
BIN
Mods/vcmi/Data/stackWindow/bonus-effects.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
Mods/vcmi/Data/stackWindow/button-panel.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
Mods/vcmi/Data/stackWindow/commander-abilities.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
Mods/vcmi/Data/stackWindow/commander-bg.png
Normal file
After Width: | Height: | Size: 65 KiB |
BIN
Mods/vcmi/Data/stackWindow/icons.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
Mods/vcmi/Data/stackWindow/info-panel-0.png
Normal file
After Width: | Height: | Size: 88 KiB |
BIN
Mods/vcmi/Data/stackWindow/info-panel-1.png
Normal file
After Width: | Height: | Size: 86 KiB |
BIN
Mods/vcmi/Data/stackWindow/info-panel-2.png
Normal file
After Width: | Height: | Size: 82 KiB |
BIN
Mods/vcmi/Data/stackWindow/spell-effects.png
Normal file
After Width: | Height: | Size: 20 KiB |
8
Mods/vcmi/Sprites/buttons/commander.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"basepath" : "buttons/",
|
||||
"images" :
|
||||
[
|
||||
{ "frame" : 0, "file" : "commanderNormal.png"},
|
||||
{ "frame" : 1, "file" : "commanderPressed.png"}
|
||||
]
|
||||
}
|
BIN
Mods/vcmi/Sprites/buttons/commanderNormal.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
Mods/vcmi/Sprites/buttons/commanderPressed.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
8
Mods/vcmi/Sprites/buttons/resolution.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"basepath" : "buttons/",
|
||||
"images" :
|
||||
[
|
||||
{ "frame" : 0, "file" : "resolutionNormal.png"},
|
||||
{ "frame" : 1, "file" : "resolutionPressed.png"}
|
||||
]
|
||||
}
|
BIN
Mods/vcmi/Sprites/buttons/resolutionNormal.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
Mods/vcmi/Sprites/buttons/resolutionPressed.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/cancel-normal.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/cancel-pressed.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
8
Mods/vcmi/Sprites/stackWindow/cancelButton.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"basepath" : "stackWindow/",
|
||||
"images" :
|
||||
[
|
||||
{ "frame" : 0, "file" : "cancel-normal.png"},
|
||||
{ "frame" : 1, "file" : "cancel-pressed.png"}
|
||||
]
|
||||
}
|
BIN
Mods/vcmi/Sprites/stackWindow/level-0.png
Normal file
After Width: | Height: | Size: 182 B |
BIN
Mods/vcmi/Sprites/stackWindow/level-1.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-10.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-2.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-3.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-4.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-5.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-6.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-7.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-8.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/level-9.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
17
Mods/vcmi/Sprites/stackWindow/levels.json
Normal 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"}
|
||||
]
|
||||
}
|
7
Mods/vcmi/Sprites/stackWindow/switchModeIcons.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"images" :
|
||||
[
|
||||
{ "frame" : 0, "file" : "SECSK32:69"},
|
||||
{ "frame" : 1, "file" : "SECSK32:28"}
|
||||
]
|
||||
}
|
BIN
Mods/vcmi/Sprites/stackWindow/upgrade-normal.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Mods/vcmi/Sprites/stackWindow/upgrade-pressed.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
8
Mods/vcmi/Sprites/stackWindow/upgradeButton.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"basepath" : "stackWindow/",
|
||||
"images" :
|
||||
[
|
||||
{ "frame" : 0, "file" : "upgrade-normal.png"},
|
||||
{ "frame" : 1, "file" : "upgrade-pressed.png"}
|
||||
]
|
||||
}
|
@ -15,6 +15,7 @@ For building from source see project wiki at http://wiki.vcmi.eu/
|
||||
|
||||
## 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)
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
@ -8,13 +8,13 @@
|
||||
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include "CPreGame.h"
|
||||
#include "CCastleInterface.h"
|
||||
#include "windows/CCastleInterface.h"
|
||||
#include "../lib/CConsoleHandler.h"
|
||||
#include "gui/CCursorHandler.h"
|
||||
#include "../lib/CGameState.h"
|
||||
#include "../CCallback.h"
|
||||
#include "CPlayerInterface.h"
|
||||
#include "CAdvmapInterface.h"
|
||||
#include "windows/CAdvmapInterface.h"
|
||||
#include "../lib/CBuildingHandler.h"
|
||||
#include "CVideoHandler.h"
|
||||
#include "../lib/CHeroHandler.h"
|
||||
@ -39,6 +39,7 @@
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "../lib/logging/CBasicLogConfigurator.h"
|
||||
#include "../lib/CondSh.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "SDL_syswm.h"
|
||||
|
@ -14,39 +14,56 @@ set(client_SRCS
|
||||
battle/CBattleInterfaceClasses.cpp
|
||||
battle/CCreatureAnimation.cpp
|
||||
|
||||
gui/CAnimation.cpp
|
||||
gui/CCursorHandler.cpp
|
||||
gui/CGuiHandler.cpp
|
||||
gui/CIntObject.cpp
|
||||
gui/CIntObjectClasses.cpp
|
||||
gui/Fonts.cpp
|
||||
gui/Geometries.cpp
|
||||
gui/CCursorHandler.cpp
|
||||
gui/SDL_Extensions.cpp
|
||||
|
||||
CPreGame.cpp
|
||||
Client.cpp
|
||||
CPlayerInterface.cpp
|
||||
CMT.cpp
|
||||
GUIClasses.cpp
|
||||
AdventureMapClasses.cpp
|
||||
CAdvmapInterface.cpp
|
||||
CAnimation.cpp
|
||||
widgets/AdventureMapClasses.cpp
|
||||
widgets/Buttons.cpp
|
||||
widgets/CArtifactHolder.cpp
|
||||
widgets/CComponent.cpp
|
||||
widgets/CGarrisonInt.cpp
|
||||
widgets/Images.cpp
|
||||
widgets/MiscWidgets.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
|
||||
CCastleInterface.cpp
|
||||
CCreatureWindow.cpp
|
||||
CDefHandler.cpp
|
||||
CGameInfo.cpp
|
||||
CHeroWindow.cpp
|
||||
CKingdomInterface.cpp
|
||||
Client.cpp
|
||||
CMessage.cpp
|
||||
CMT.cpp
|
||||
CMusicHandler.cpp
|
||||
CSpellWindow.cpp
|
||||
CPlayerInterface.cpp
|
||||
CPreGame.cpp
|
||||
CVideoHandler.cpp
|
||||
CQuestLog.cpp
|
||||
Graphics.cpp
|
||||
mapHandler.cpp
|
||||
NetPacksClient.cpp
|
||||
)
|
||||
|
||||
set(client_HEADERS
|
||||
gui/SDL_Pixels.h
|
||||
gui/SDL_Compat.h
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
# OS X specific includes
|
||||
include_directories(${SPARKLE_INCLUDE_DIR})
|
||||
|
@ -11,17 +11,19 @@
|
||||
#include "StdInc.h"
|
||||
#include "CMessage.h"
|
||||
|
||||
#include "SDL_ttf.h"
|
||||
#include "CDefHandler.h"
|
||||
#include "CAnimation.h"
|
||||
#include "CGameInfo.h"
|
||||
#include "gui/SDL_Extensions.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "Graphics.h"
|
||||
#include "GUIClasses.h"
|
||||
#include "windows/GUIClasses.h"
|
||||
#include "../lib/CConfigHandler.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 BEFORE_COMPONENTS = 30;
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "../lib/CSoundBase.h"
|
||||
#include "../lib/CCreatureHandler.h"
|
||||
|
||||
/*
|
||||
* CMusicHandler.h, part of VCMI engine
|
||||
|
@ -1,21 +1,24 @@
|
||||
#include "StdInc.h"
|
||||
#include "CAdvmapInterface.h"
|
||||
#include "windows/CAdvmapInterface.h"
|
||||
#include "battle/CBattleInterface.h"
|
||||
#include "battle/CBattleInterfaceClasses.h"
|
||||
#include "../CCallback.h"
|
||||
#include "CCastleInterface.h"
|
||||
#include "windows/CCastleInterface.h"
|
||||
#include "gui/CCursorHandler.h"
|
||||
#include "CKingdomInterface.h"
|
||||
#include "windows/CKingdomInterface.h"
|
||||
#include "CGameInfo.h"
|
||||
#include "CHeroWindow.h"
|
||||
#include "CCreatureWindow.h"
|
||||
#include "CQuestLog.h"
|
||||
#include "windows/CHeroWindow.h"
|
||||
#include "windows/CCreatureWindow.h"
|
||||
#include "windows/CQuestLog.h"
|
||||
#include "CMessage.h"
|
||||
#include "CPlayerInterface.h"
|
||||
#include "gui/SDL_Extensions.h"
|
||||
#include "widgets/CComponent.h"
|
||||
#include "windows/CTradeWindow.h"
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "battle/CCreatureAnimation.h"
|
||||
#include "Graphics.h"
|
||||
#include "windows/GUIClasses.h"
|
||||
#include "../lib/CArtHandler.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "../lib/CHeroHandler.h"
|
||||
@ -35,7 +38,9 @@
|
||||
#include "../lib/CGameState.h"
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "windows/InfoWindows.h"
|
||||
#include "../lib/UnlockGuard.h"
|
||||
#include <SDL.h>
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
@ -494,10 +499,12 @@ void CPlayerInterface::commanderGotLevel (const CCommanderInstance * commander,
|
||||
waitWhileDialog();
|
||||
CCS->soundh->playSound(soundBase::heroNewLevel);
|
||||
|
||||
CCreatureWindow * cw = new CCreatureWindow(skills, commander,
|
||||
[=](ui32 selection){ cb->selectionMade(selection, queryID); });
|
||||
GH.pushInt(cw);
|
||||
GH.pushInt(new CStackWindow(commander, skills, [=](ui32 selection)
|
||||
{
|
||||
cb->selectionMade(selection, queryID);
|
||||
}));
|
||||
}
|
||||
|
||||
void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
|
||||
{
|
||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||
@ -1285,8 +1292,8 @@ void CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
|
||||
|
||||
if (adventureInt && adventureInt->isHeroSleeping(h))
|
||||
{
|
||||
adventureInt->sleepWake.clickLeft(true, false);
|
||||
adventureInt->sleepWake.clickLeft(false, true);
|
||||
adventureInt->sleepWake->clickLeft(true, false);
|
||||
adventureInt->sleepWake->clickLeft(false, true);
|
||||
//could've just called
|
||||
//adventureInt->fsleepWake();
|
||||
//but no authentic button click/sound ;-)
|
||||
@ -1321,7 +1328,7 @@ void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHer
|
||||
waitForAllDialogs();
|
||||
|
||||
auto cgw = new CGarrisonWindow(up,down,removableUnits);
|
||||
cgw->quit->callback += onEnd;
|
||||
cgw->quit->addCallback(onEnd);
|
||||
GH.pushInt(cgw);
|
||||
}
|
||||
|
||||
@ -2239,7 +2246,7 @@ void CPlayerInterface::acceptTurn()
|
||||
if(CInfoWindow *iw = dynamic_cast<CInfoWindow *>(GH.topInt()))
|
||||
iw->close();
|
||||
|
||||
adventureInt->endTurn.callback();
|
||||
adventureInt->fendTurn();
|
||||
}
|
||||
|
||||
// warn player if he has no town
|
||||
|
@ -1,11 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "../lib/CondSh.h"
|
||||
//#include "../lib/CondSh.h"
|
||||
#include "../lib/FunctionList.h"
|
||||
#include "../lib/CGameInterface.h"
|
||||
#include "../lib/NetPacksBase.h"
|
||||
#include "gui/CIntObject.h"
|
||||
#include "../lib/CGameState.h"
|
||||
//#include "../lib/CGameState.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define sprintf_s snprintf
|
||||
@ -29,8 +30,8 @@
|
||||
*/
|
||||
|
||||
class CDefEssential;
|
||||
class CAdventureMapButton;
|
||||
class CHighlightableButtonsGroup;
|
||||
class CButton;
|
||||
class CToggleGroup;
|
||||
class CDefHandler;
|
||||
struct TryMoveHero;
|
||||
class CDefEssential;
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include "gui/SDL_Extensions.h"
|
||||
#include "CGameInfo.h"
|
||||
#include "gui/CCursorHandler.h"
|
||||
#include "CAnimation.h"
|
||||
#include "CDefHandler.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "../lib/CTownHandler.h"
|
||||
@ -23,7 +22,7 @@
|
||||
#include "../lib/Connection.h"
|
||||
#include "../lib/VCMIDirs.h"
|
||||
#include "../lib/mapping/CMap.h"
|
||||
#include "GUIClasses.h"
|
||||
#include "windows/GUIClasses.h"
|
||||
#include "CPlayerInterface.h"
|
||||
#include "../CCallback.h"
|
||||
#include "CMessage.h"
|
||||
@ -38,7 +37,13 @@
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "../lib/GameConstants.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/CMap.h"
|
||||
#include "../lib/CRandomGenerator.h"
|
||||
@ -367,7 +372,7 @@ static std::function<void()> genCommand(CMenuScreen* menu, std::vector<std::stri
|
||||
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());
|
||||
|
||||
@ -383,7 +388,7 @@ CAdventureMapButton* CMenuEntry::createButton(CMenuScreen* parent, const JsonNod
|
||||
if (posy < 0)
|
||||
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)
|
||||
@ -639,38 +644,39 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
|
||||
{
|
||||
case CMenuScreen::newGame:
|
||||
{
|
||||
card->difficulty->onChange = std::bind(&CSelectionScreen::difficultyChange, this, _1);
|
||||
card->difficulty->select(1, 0);
|
||||
CAdventureMapButton * select = new CAdventureMapButton(CGI->generaltexth->zelp[45], 0, 411, 80, "GSPBUTT.DEF", SDLK_s);
|
||||
select->callback = [&]()
|
||||
SDL_Color orange = {232, 184, 32, 0};
|
||||
SDL_Color overlayColor = multiPlayer == CMenuScreen::MULTI_NETWORK_GUEST ? orange : Colors::WHITE;
|
||||
|
||||
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);
|
||||
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);
|
||||
opts->addTextOverlay(CGI->generaltexth->allTexts[501], FONT_SMALL);
|
||||
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, overlayColor);
|
||||
|
||||
CAdventureMapButton * randomBtn = new CAdventureMapButton(CGI->generaltexth->zelp[47], 0, 411, 105, "GSPBUTT.DEF", SDLK_r);
|
||||
randomBtn->addTextOverlay(CGI->generaltexth->allTexts[740], FONT_SMALL);
|
||||
randomBtn->callback = [&]()
|
||||
CButton * randomBtn = new CButton(Point(411, 105), "GSPBUTT.DEF", CGI->generaltexth->zelp[47], 0, SDLK_r);
|
||||
randomBtn->addTextOverlay(CGI->generaltexth->allTexts[740], FONT_SMALL, overlayColor);
|
||||
randomBtn->addCallback([&]()
|
||||
{
|
||||
toggleTab(randMapTab);
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
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);
|
||||
opts->block(true);
|
||||
randomBtn->block(true);
|
||||
@ -681,21 +687,21 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
|
||||
break;
|
||||
case CMenuScreen::loadGame:
|
||||
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;
|
||||
case CMenuScreen::saveGame:
|
||||
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;
|
||||
case CMenuScreen::campaignList:
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -995,7 +1001,7 @@ void CSelectionScreen::setSInfo(const StartInfo &si)
|
||||
if(current)
|
||||
opt->recreate(); //will force to recreate using current sInfo
|
||||
|
||||
card->difficulty->select(si.difficulty, 0);
|
||||
card->difficulty->setSelected(si.difficulty);
|
||||
|
||||
GH.totalRedraw();
|
||||
}
|
||||
@ -1258,7 +1264,7 @@ SelectionTab::SelectionTab(CMenuScreen::EState Type, const std::function<void(CM
|
||||
int sizes[] = {36, 72, 108, 144, 0};
|
||||
const char * names[] = {"SCSMBUT.DEF", "SCMDBUT.DEF", "SCLGBUT.DEF", "SCXLBUT.DEF", "SCALBUT.DEF"};
|
||||
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
|
||||
@ -1272,20 +1278,19 @@ SelectionTab::SelectionTab(CMenuScreen::EState Type, const std::function<void(CM
|
||||
if(criteria == _name)
|
||||
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
|
||||
{
|
||||
//sort by buttons
|
||||
new CAdventureMapButton("", "", std::bind(&SelectionTab::sortBy, this, _numOfMaps), 23, 86, "CamCusM.DEF"); //by num of maps
|
||||
new CAdventureMapButton("", "", std::bind(&SelectionTab::sortBy, this, _name), 55, 86, "CamCusL.DEF"); //by name
|
||||
new CButton(Point(23, 86), "CamCusM.DEF", CButton::tooltip(), boost::bind(&SelectionTab::sortBy, this, _numOfMaps)); //by num of maps
|
||||
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->slider->keepFrame = true;
|
||||
format = CDefHandler::giveDef("SCSELC.DEF");
|
||||
|
||||
sortingBy = _format;
|
||||
@ -1351,16 +1356,16 @@ void SelectionTab::select( int position )
|
||||
if(!curItems.size()) return;
|
||||
|
||||
// New selection. py is the index in curItems.
|
||||
int py = position + slider->value;
|
||||
int py = position + slider->getValue();
|
||||
vstd::amax(py, 0);
|
||||
vstd::amin(py, curItems.size()-1);
|
||||
|
||||
selectionPos = py;
|
||||
|
||||
if(position < 0)
|
||||
slider->moveTo(slider->value + position);
|
||||
slider->moveBy(position);
|
||||
else if(position >= positions)
|
||||
slider->moveTo(slider->value + position - positions + 1);
|
||||
slider->moveBy(position - positions + 1);
|
||||
|
||||
if(txt)
|
||||
{
|
||||
@ -1374,7 +1379,7 @@ void SelectionTab::select( int position )
|
||||
|
||||
void SelectionTab::selectAbs( int position )
|
||||
{
|
||||
select(position - slider->value);
|
||||
select(position - slider->getValue());
|
||||
}
|
||||
|
||||
int SelectionTab::getPosition( int x, int y )
|
||||
@ -1397,7 +1402,7 @@ void SelectionTab::sliderMove( int slidPos )
|
||||
void SelectionTab::printMaps(SDL_Surface *to)
|
||||
{
|
||||
|
||||
int elemIdx = slider->value;
|
||||
int elemIdx = slider->getValue();
|
||||
|
||||
// Display all elements if there's enough space
|
||||
//if(slider->amount < slider->capacity)
|
||||
@ -1555,15 +1560,15 @@ void SelectionTab::keyPressed( const SDL_KeyboardEvent & key )
|
||||
moveBy = +positions-1;
|
||||
break;
|
||||
case SDLK_HOME:
|
||||
select(-slider->value);
|
||||
select(-slider->getValue());
|
||||
return;
|
||||
case SDLK_END:
|
||||
select(curItems.size() - slider->value);
|
||||
select(curItems.size() - slider->getValue());
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
select(selectionPos - slider->value + moveBy);
|
||||
select(selectionPos - slider->getValue() + moveBy);
|
||||
}
|
||||
|
||||
void SelectionTab::onDoubleClick()
|
||||
@ -1571,7 +1576,7 @@ void SelectionTab::onDoubleClick()
|
||||
if(getLine() != -1) //double clicked scenarios list
|
||||
{
|
||||
//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);
|
||||
|
||||
// Map Size
|
||||
mapSizeBtnGroup = new CHighlightableButtonsGroup(0);
|
||||
mapSizeBtnGroup = new CToggleGroup(0);
|
||||
mapSizeBtnGroup->pos.y += 81;
|
||||
mapSizeBtnGroup->pos.x += 158;
|
||||
const std::vector<std::string> mapSizeBtns = boost::assign::list_of("RANSIZS")("RANSIZM")("RANSIZL")("RANSIZX");
|
||||
addButtonsToGroup(mapSizeBtnGroup, mapSizeBtns, 0, 3, 47, 198);
|
||||
mapSizeBtnGroup->select(1, false);
|
||||
mapSizeBtnGroup->onChange = [&](int btnId)
|
||||
mapSizeBtnGroup->setSelected(1);
|
||||
mapSizeBtnGroup->addCallback([&](int btnId)
|
||||
{
|
||||
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);
|
||||
mapGenOptions.setWidth(mapSizeVal[btnId]);
|
||||
mapGenOptions.setHeight(mapSizeVal[btnId]);
|
||||
updateMapInfo();
|
||||
};
|
||||
});
|
||||
|
||||
// Two levels
|
||||
twoLevelsBtn = new CHighlightableButton(0, 0, std::map<int,std::string>(),
|
||||
CGI->generaltexth->zelp[202].second, false, "RANUNDR", nullptr, 346, 81);
|
||||
twoLevelsBtn = new CToggleButton(Point(346, 81), "RANUNDR", CGI->generaltexth->zelp[202]);
|
||||
//twoLevelsBtn->select(true); for now, deactivated
|
||||
twoLevelsBtn->callback = [&]() { mapGenOptions.setHasTwoLevels(true); updateMapInfo(); };
|
||||
twoLevelsBtn->callback2 = [&]() { mapGenOptions.setHasTwoLevels(false); updateMapInfo(); };
|
||||
twoLevelsBtn->addCallback([&](bool on) { mapGenOptions.setHasTwoLevels(on); updateMapInfo(); });
|
||||
|
||||
// Create number defs list
|
||||
std::vector<std::string> numberDefs;
|
||||
@ -1648,128 +1651,130 @@ CRandomMapTab::CRandomMapTab()
|
||||
const int NUMBERS_WIDTH = 32;
|
||||
const int BTNS_GROUP_LEFT_MARGIN = 67;
|
||||
// Amount of players
|
||||
playersCntGroup = new CHighlightableButtonsGroup(0);
|
||||
playersCntGroup = new CToggleGroup(0);
|
||||
playersCntGroup->pos.y += 153;
|
||||
playersCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||
addButtonsWithRandToGroup(playersCntGroup, numberDefs, 1, 8, NUMBERS_WIDTH, 204, 212);
|
||||
playersCntGroup->onChange = [&](int btnId)
|
||||
playersCntGroup->addCallback([&](int btnId)
|
||||
{
|
||||
mapGenOptions.setPlayerCount(btnId);
|
||||
deactivateButtonsFrom(teamsCntGroup, btnId);
|
||||
deactivateButtonsFrom(compOnlyPlayersCntGroup, 8 - btnId + 1);
|
||||
validatePlayersCnt(btnId);
|
||||
updateMapInfo();
|
||||
};
|
||||
});
|
||||
|
||||
// Amount of teams
|
||||
teamsCntGroup = new CHighlightableButtonsGroup(0);
|
||||
teamsCntGroup = new CToggleGroup(0);
|
||||
teamsCntGroup->pos.y += 219;
|
||||
teamsCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||
addButtonsWithRandToGroup(teamsCntGroup, numberDefs, 0, 7, NUMBERS_WIDTH, 214, 222);
|
||||
teamsCntGroup->onChange = [&](int btnId)
|
||||
teamsCntGroup->addCallback([&](int btnId)
|
||||
{
|
||||
mapGenOptions.setTeamCount(btnId);
|
||||
updateMapInfo();
|
||||
};
|
||||
});
|
||||
|
||||
// Computer only players
|
||||
compOnlyPlayersCntGroup = new CHighlightableButtonsGroup(0);
|
||||
compOnlyPlayersCntGroup = new CToggleGroup(0);
|
||||
compOnlyPlayersCntGroup->pos.y += 285;
|
||||
compOnlyPlayersCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||
addButtonsWithRandToGroup(compOnlyPlayersCntGroup, numberDefs, 0, 7, NUMBERS_WIDTH, 224, 232);
|
||||
compOnlyPlayersCntGroup->select(0, true);
|
||||
compOnlyPlayersCntGroup->onChange = [&](int btnId)
|
||||
compOnlyPlayersCntGroup->setSelected(0);
|
||||
compOnlyPlayersCntGroup->addCallback([&](int btnId)
|
||||
{
|
||||
mapGenOptions.setCompOnlyPlayerCount(btnId);
|
||||
deactivateButtonsFrom(compOnlyTeamsCntGroup, btnId);
|
||||
validateCompOnlyPlayersCnt(btnId);
|
||||
updateMapInfo();
|
||||
};
|
||||
});
|
||||
|
||||
// Computer only teams
|
||||
compOnlyTeamsCntGroup = new CHighlightableButtonsGroup(0);
|
||||
compOnlyTeamsCntGroup = new CToggleGroup(0);
|
||||
compOnlyTeamsCntGroup->pos.y += 351;
|
||||
compOnlyTeamsCntGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||
addButtonsWithRandToGroup(compOnlyTeamsCntGroup, numberDefs, 0, 6, NUMBERS_WIDTH, 234, 241);
|
||||
deactivateButtonsFrom(compOnlyTeamsCntGroup, 0);
|
||||
compOnlyTeamsCntGroup->onChange = [&](int btnId)
|
||||
compOnlyTeamsCntGroup->addCallback([&](int btnId)
|
||||
{
|
||||
mapGenOptions.setCompOnlyTeamCount(btnId);
|
||||
updateMapInfo();
|
||||
};
|
||||
});
|
||||
|
||||
const int WIDE_BTN_WIDTH = 85;
|
||||
// Water content
|
||||
waterContentGroup = new CHighlightableButtonsGroup(0);
|
||||
waterContentGroup = new CToggleGroup(0);
|
||||
waterContentGroup->pos.y += 419;
|
||||
waterContentGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||
const std::vector<std::string> waterContentBtns = boost::assign::list_of("RANNONE")("RANNORM")("RANISLD");
|
||||
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));
|
||||
};
|
||||
});
|
||||
|
||||
// Monster strength
|
||||
monsterStrengthGroup = new CHighlightableButtonsGroup(0);
|
||||
monsterStrengthGroup = new CToggleGroup(0);
|
||||
monsterStrengthGroup->pos.y += 485;
|
||||
monsterStrengthGroup->pos.x += BTNS_GROUP_LEFT_MARGIN;
|
||||
const std::vector<std::string> monsterStrengthBtns = boost::assign::list_of("RANWEAK")("RANNORM")("RANSTRG");
|
||||
addButtonsWithRandToGroup(monsterStrengthGroup, monsterStrengthBtns, 0, 2, WIDE_BTN_WIDTH, 248, 251);
|
||||
monsterStrengthGroup->onChange = [&](int btnId)
|
||||
monsterStrengthGroup->addCallback([&](int btnId)
|
||||
{
|
||||
if (btnId < 0)
|
||||
mapGenOptions.setMonsterStrength(EMonsterStrength::RANDOM);
|
||||
else
|
||||
mapGenOptions.setMonsterStrength(static_cast<EMonsterStrength::EMonsterStrength>(btnId + EMonsterStrength::GLOBAL_WEAK)); //value 2 to 4
|
||||
};
|
||||
});
|
||||
|
||||
// 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
|
||||
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);
|
||||
|
||||
// Buttons are relative to button group, TODO better solution?
|
||||
SObjectConstruction obj__i(group);
|
||||
const std::string RANDOM_DEF = "RANRAND";
|
||||
group->addButton(new CHighlightableButton("", CGI->generaltexth->zelp[helpRandIndex].second, 0, 256, 0, RANDOM_DEF, CMapGenOptions::RANDOM_SIZE));
|
||||
group->select(CMapGenOptions::RANDOM_SIZE, true);
|
||||
group->addToggle(CMapGenOptions::RANDOM_SIZE, new CToggleButton(Point(256, 0), RANDOM_DEF, CGI->generaltexth->zelp[helpRandIndex]));
|
||||
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?
|
||||
SObjectConstruction obj__i(group);
|
||||
int cnt = nEnd - nStart + 1;
|
||||
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);
|
||||
btn->setState(CButtonBase::NORMAL);
|
||||
button->block(false);
|
||||
}
|
||||
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)
|
||||
{
|
||||
mapGenOptions.setTeamCount(playersCnt - 1);
|
||||
teamsCntGroup->select(mapGenOptions.getTeamCount(), true);
|
||||
teamsCntGroup->setSelected(mapGenOptions.getTeamCount());
|
||||
}
|
||||
if(mapGenOptions.getCompOnlyPlayerCount() > 8 - playersCnt)
|
||||
{
|
||||
mapGenOptions.setCompOnlyPlayerCount(8 - playersCnt);
|
||||
compOnlyPlayersCntGroup->select(mapGenOptions.getCompOnlyPlayerCount(), true);
|
||||
compOnlyPlayersCntGroup->setSelected(mapGenOptions.getCompOnlyPlayerCount());
|
||||
}
|
||||
|
||||
validateCompOnlyPlayersCnt(mapGenOptions.getCompOnlyPlayerCount());
|
||||
@ -1805,7 +1810,7 @@ void CRandomMapTab::validateCompOnlyPlayersCnt(int compOnlyPlayersCnt)
|
||||
if(mapGenOptions.getCompOnlyTeamCount() >= compOnlyPlayersCnt)
|
||||
{
|
||||
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;
|
||||
sizes = CDefHandler::giveDef("SCNRMPSZ.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"};
|
||||
|
||||
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)
|
||||
{
|
||||
playerListBg = new CPicture("CHATPLUG.bmp", 16, 276);
|
||||
@ -2161,8 +2166,8 @@ void InfoCard::changeSelection( const CMapInfo *to )
|
||||
mapDescription->setText(to->mapHeader->description);
|
||||
|
||||
if(SEL->screenType != CMenuScreen::newGame && SEL->screenType != CMenuScreen::campaignList) {
|
||||
difficulty->block(true);
|
||||
difficulty->select(SEL->sInfo.difficulty, 0);
|
||||
//difficulty->block(true);
|
||||
difficulty->setSelected(SEL->sInfo.difficulty);
|
||||
}
|
||||
}
|
||||
redraw();
|
||||
@ -2242,7 +2247,7 @@ OptionsTab::OptionsTab():
|
||||
pos = bg->pos;
|
||||
|
||||
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()
|
||||
@ -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
|
||||
printAtMiddleLoc(CGI->generaltexth->allTexts[521], 222, 538, FONT_SMALL, Colors::YELLOW, to); // Player Turn Duration
|
||||
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 )
|
||||
@ -2546,12 +2551,12 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry( OptionsTab *owner, PlayerSet
|
||||
bg = new CPicture(BitmapHandler::loadBitmap(bgs[s.color.getNum()]), 0, 0, true);
|
||||
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[1] = new CAdventureMapButton(CGI->generaltexth->zelp[133], std::bind(&OptionsTab::nextCastle, owner, s.color, +1), 168, 5, "ADOPRTA.DEF");
|
||||
btns[2] = new CAdventureMapButton(CGI->generaltexth->zelp[148], std::bind(&OptionsTab::nextHero, owner, s.color, -1), 183, 5, "ADOPLFA.DEF");
|
||||
btns[3] = new CAdventureMapButton(CGI->generaltexth->zelp[149], std::bind(&OptionsTab::nextHero, owner, s.color, +1), 244, 5, "ADOPRTA.DEF");
|
||||
btns[4] = new CAdventureMapButton(CGI->generaltexth->zelp[164], std::bind(&OptionsTab::nextBonus, owner, s.color, -1), 259, 5, "ADOPLFA.DEF");
|
||||
btns[5] = new CAdventureMapButton(CGI->generaltexth->zelp[165], std::bind(&OptionsTab::nextBonus, owner, s.color, +1), 320, 5, "ADOPRTA.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 CButton(Point(168, 5), "ADOPRTA.DEF", CGI->generaltexth->zelp[133], boost::bind(&OptionsTab::nextCastle, owner, s.color, +1));
|
||||
btns[2] = new CButton(Point(183, 5), "ADOPLFA.DEF", CGI->generaltexth->zelp[148], boost::bind(&OptionsTab::nextHero, owner, s.color, -1));
|
||||
btns[3] = new CButton(Point(244, 5), "ADOPRTA.DEF", CGI->generaltexth->zelp[149], boost::bind(&OptionsTab::nextHero, owner, s.color, +1));
|
||||
btns[4] = new CButton(Point(259, 5), "ADOPLFA.DEF", CGI->generaltexth->zelp[164], boost::bind(&OptionsTab::nextBonus, owner, s.color, -1));
|
||||
btns[5] = new CButton(Point(320, 5), "ADOPRTA.DEF", CGI->generaltexth->zelp[165], boost::bind(&OptionsTab::nextBonus, owner, s.color, +1));
|
||||
}
|
||||
else
|
||||
for(auto & elem : btns)
|
||||
@ -2573,7 +2578,7 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry( OptionsTab *owner, PlayerSet
|
||||
&& SEL->current->mapHeader->players[s.color.getNum()].canHumanPlay
|
||||
&& 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;
|
||||
}
|
||||
else
|
||||
@ -2979,8 +2984,8 @@ CScenarioInfo::CScenarioInfo(const CMapHeader *mapHeader, const StartInfo *start
|
||||
opt->recreate();
|
||||
card->changeSelection(current);
|
||||
|
||||
card->difficulty->select(startInfo->difficulty, 0);
|
||||
back = new CAdventureMapButton("", CGI->generaltexth->zelp[105].second, std::bind(&CGuiHandler::popIntTotally, &GH, this), 584, 535, "SCNRBACK.DEF", SDLK_ESCAPE);
|
||||
card->difficulty->setSelected(startInfo->difficulty);
|
||||
back = new CButton(Point(584, 535), "SCNRBACK.DEF", CGI->generaltexth->zelp[105], boost::bind(&CGuiHandler::popIntTotally, &GH, this), SDLK_ESCAPE);
|
||||
}
|
||||
|
||||
CScenarioInfo::~CScenarioInfo()
|
||||
@ -3059,10 +3064,10 @@ CMultiMode::CMultiMode()
|
||||
txt = new CTextInput(Rect(19, 436, 334, 16), *bg);
|
||||
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[1] = new CAdventureMapButton("Host TCP/IP game", "", std::bind(&CMultiMode::hostTCP, this), 373, 78 + 57*1, "MUBHOST.DEF");
|
||||
btns[2] = new CAdventureMapButton("Join TCP/IP game", "", std::bind(&CMultiMode::joinTCP, this), 373, 78 + 57*2, "MUBJOIN.DEF");
|
||||
btns[6] = new CAdventureMapButton(CGI->generaltexth->zelp[288], std::bind(&CGuiHandler::popIntTotally, std::ref(GH), this), 373, 424, "MUBCANC.DEF", SDLK_ESCAPE);
|
||||
btns[0] = new CButton(Point(373, 78), "MUBHOT.DEF", CGI->generaltexth->zelp[266], boost::bind(&CMultiMode::openHotseat, this));
|
||||
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 CButton(Point(373, 78 + 57*2), "MUBJOIN.DEF", CButton::tooltip("Join TCP/IP game", ""), boost::bind(&CMultiMode::joinTCP, this));
|
||||
btns[6] = new CButton(Point(373, 424), "MUBCANC.DEF", CGI->generaltexth->zelp[288], [&] { GH.popIntTotally(this);}, SDLK_ESCAPE);
|
||||
}
|
||||
|
||||
void CMultiMode::openHotseat()
|
||||
@ -3102,8 +3107,8 @@ CHotSeatPlayers::CHotSeatPlayers(const std::string &firstPlayer)
|
||||
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);
|
||||
cancel = new CAdventureMapButton(CGI->generaltexth->zelp[561], std::bind(&CGuiHandler::popIntTotally, std::ref(GH), this), 205, 338, "MUBCANC.DEF", SDLK_ESCAPE);
|
||||
ok = new CButton(Point(95, 338), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], boost::bind(&CHotSeatPlayers::enterSelectionScreen, this), SDLK_RETURN);
|
||||
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
|
||||
|
||||
txt[0]->setText(firstPlayer, true);
|
||||
@ -3166,9 +3171,9 @@ void CBonusSelection::init()
|
||||
|
||||
blitAt(panel, 456, 6, background);
|
||||
|
||||
startB = new CAdventureMapButton("", "", std::bind(&CBonusSelection::startMap, this), 475, 536, "CBBEGIB.DEF", SDLK_RETURN);
|
||||
restartB = new CAdventureMapButton("", "", std::bind(&CBonusSelection::restartMap, this), 475, 536, "CBRESTB.DEF", SDLK_RETURN);
|
||||
backB = new CAdventureMapButton("", "", std::bind(&CBonusSelection::goBack, this), 624, 536, "CBCANCB.DEF", SDLK_ESCAPE);
|
||||
startB = new CButton(Point(475, 536), "CBBEGIB.DEF", CButton::tooltip(), boost::bind(&CBonusSelection::startMap, this), SDLK_RETURN);
|
||||
restartB = new CButton(Point(475, 536), "CBRESTB.DEF", CButton::tooltip(), boost::bind(&CBonusSelection::restartMap, this), SDLK_RETURN);
|
||||
backB = new CButton(Point(624, 536), "CBCANCB.DEF", CButton::tooltip(), boost::bind(&CBonusSelection::goBack, this), SDLK_ESCAPE);
|
||||
|
||||
//campaign name
|
||||
if (ourCampaign->camp->header.name.length())
|
||||
@ -3190,7 +3195,7 @@ void CBonusSelection::init()
|
||||
|
||||
//bonus choosing
|
||||
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
|
||||
bool isCurrentMapConquerable = ourCampaign->currentMap && ourCampaign->camp->conquerable(*ourCampaign->currentMap);
|
||||
@ -3241,8 +3246,8 @@ void CBonusSelection::init()
|
||||
//difficulty selection buttons
|
||||
if (ourCampaign->camp->header.difficultyChoosenByPlayer)
|
||||
{
|
||||
diffLb = new CAdventureMapButton("", "", std::bind(&CBonusSelection::decreaseDifficulty, this), 694, 508, "SCNRBLF.DEF");
|
||||
diffRb = new CAdventureMapButton("", "", std::bind(&CBonusSelection::increaseDifficulty, this), 738, 508, "SCNRBRT.DEF");
|
||||
diffLb = new CButton(Point(694, 508), "SCNRBLF.DEF", CButton::tooltip(), boost::bind(&CBonusSelection::decreaseDifficulty, this));
|
||||
diffRb = new CButton(Point(738, 508), "SCNRBRT.DEF", CButton::tooltip(), boost::bind(&CBonusSelection::increaseDifficulty, this));
|
||||
}
|
||||
|
||||
//load miniflags
|
||||
@ -3442,13 +3447,8 @@ void CBonusSelection::updateBonusSelection()
|
||||
|
||||
updateStartButtonState(-1);
|
||||
|
||||
for (auto & elem : bonuses->buttons)
|
||||
{
|
||||
if (elem->active)
|
||||
elem->deactivate();
|
||||
delete elem;
|
||||
}
|
||||
bonuses->buttons.clear();
|
||||
delete bonuses;
|
||||
bonuses = new CToggleGroup(bind(&CBonusSelection::selectBonus, this, _1));
|
||||
|
||||
static const char *bonusPics[] = {"SPELLBON.DEF", "TWCRPORT.DEF", "", "ARTIFBON.DEF", "SPELLBON.DEF",
|
||||
"PSKILBON.DEF", "SSKILBON.DEF", "BORES.DEF", "PORTRAITSLARGE", "PORTRAITSLARGE"};
|
||||
@ -3602,7 +3602,7 @@ void CBonusSelection::updateBonusSelection()
|
||||
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)
|
||||
picName += ":" + boost::lexical_cast<std::string>(picNumber);
|
||||
@ -3612,13 +3612,13 @@ void CBonusSelection::updateBonusSelection()
|
||||
bonusButton->setImage(anim);
|
||||
const SDL_Color brightYellow = { 242, 226, 110, 0 };
|
||||
bonusButton->borderColor = brightYellow;
|
||||
bonuses->addButton(bonusButton);
|
||||
bonuses->addToggle(i, bonusButton);
|
||||
}
|
||||
|
||||
// set bonus if already chosen
|
||||
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)
|
||||
{
|
||||
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;
|
||||
if (!button["help"].isNull() && button["help"].Float() > 0)
|
||||
help = CGI->generaltexth->zelp[button["help"].Float()];
|
||||
|
||||
std::function<void()> close = std::bind(&CGuiHandler::popIntTotally, &GH, this);
|
||||
return new CAdventureMapButton(help, close, button["x"].Float(), button["y"].Float(), button["name"].String(), button["hotkey"].Float());
|
||||
std::function<void()> close = boost::bind(&CGuiHandler::popIntTotally, &GH, this);
|
||||
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->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);
|
||||
cancel = new CAdventureMapButton(CGI->generaltexth->zelp[561], std::bind(&CGuiHandler::popIntTotally, std::ref(GH), this), 142, 142, "MUBCANC.DEF", SDLK_ESCAPE);
|
||||
ok = new CButton(Point( 26, 142), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], boost::bind(&CSimpleJoinScreen::enterSelectionScreen, this), SDLK_RETURN);
|
||||
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));
|
||||
|
||||
port->setText(boost::lexical_cast<std::string>(settings["server"]["port"].Float()), true);
|
||||
|
@ -1,12 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include <SDL.h>
|
||||
//#include "../lib/filesystem/Filesystem.h"
|
||||
#include "../lib/StartInfo.h"
|
||||
#include "GUIClasses.h"
|
||||
#include "../lib/FunctionList.h"
|
||||
#include "../lib/mapping/CMapInfo.h"
|
||||
#include "../lib/rmg/CMapGenerator.h"
|
||||
#include "windows/CWindowObject.h"
|
||||
|
||||
/*
|
||||
* CPreGame.h, part of VCMI engine
|
||||
@ -18,6 +17,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
class CMapInfo;
|
||||
class CMusicHandler;
|
||||
class CMapHeader;
|
||||
class CCampaignHeader;
|
||||
@ -32,6 +32,12 @@ class CMapGenOptions;
|
||||
class CRandomMapTab;
|
||||
struct CPackForSelectionScreen;
|
||||
struct PlayerInfo;
|
||||
class CMultiLineLabel;
|
||||
class CToggleButton;
|
||||
class CToggleGroup;
|
||||
class CTabbedInt;
|
||||
class CButton;
|
||||
class CSlider;
|
||||
|
||||
namespace boost{ class thread; class recursive_mutex;}
|
||||
|
||||
@ -80,9 +86,9 @@ public:
|
||||
class CMenuEntry : public CIntObject
|
||||
{
|
||||
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:
|
||||
CMenuEntry(CMenuScreen* parent, const JsonNode &config);
|
||||
};
|
||||
@ -126,7 +132,7 @@ public:
|
||||
CChatBox *chat;
|
||||
CPicture *playerListBg;
|
||||
|
||||
CHighlightableButtonsGroup *difficulty;
|
||||
CToggleGroup *difficulty;
|
||||
CDefHandler *sizes, *sFlags;
|
||||
|
||||
void changeSelection(const CMapInfo *to);
|
||||
@ -239,8 +245,8 @@ public:
|
||||
PlayerInfo π
|
||||
PlayerSettings &s;
|
||||
CPicture *bg;
|
||||
CAdventureMapButton *btns[6]; //left and right for town, hero, bonus
|
||||
CAdventureMapButton *flag;
|
||||
CButton *btns[6]; //left and right for town, hero, bonus
|
||||
CButton *flag;
|
||||
SelectedBox *town;
|
||||
SelectedBox *hero;
|
||||
SelectedBox *bonus;
|
||||
@ -296,17 +302,17 @@ public:
|
||||
const CMapGenOptions & getMapGenOptions() const;
|
||||
|
||||
private:
|
||||
void addButtonsToGroup(CHighlightableButtonsGroup * 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 deactivateButtonsFrom(CHighlightableButtonsGroup * group, int startId);
|
||||
void addButtonsToGroup(CToggleGroup * group, const std::vector<std::string> & defs, int startIndex, int endIndex, int btnWidth, int helpStartIndex) const;
|
||||
void addButtonsWithRandToGroup(CToggleGroup * group, const std::vector<std::string> & defs, int startIndex, int endIndex, int btnWidth, int helpStartIndex, int helpRandIndex) const;
|
||||
void deactivateButtonsFrom(CToggleGroup * group, int startId);
|
||||
void validatePlayersCnt(int playersCnt);
|
||||
void validateCompOnlyPlayersCnt(int compOnlyPlayersCnt);
|
||||
|
||||
CPicture * bg;
|
||||
CHighlightableButton * twoLevelsBtn;
|
||||
CHighlightableButtonsGroup * mapSizeBtnGroup, * playersCntGroup, * teamsCntGroup, * compOnlyPlayersCntGroup,
|
||||
CToggleButton * twoLevelsBtn;
|
||||
CToggleGroup * mapSizeBtnGroup, * playersCntGroup, * teamsCntGroup, * compOnlyPlayersCntGroup,
|
||||
* compOnlyTeamsCntGroup, * waterContentGroup, * monsterStrengthGroup;
|
||||
CAdventureMapButton * showRandMaps;
|
||||
CButton * showRandMaps;
|
||||
CMapGenOptions mapGenOptions;
|
||||
unique_ptr<CMapInfo> mapInfo;
|
||||
CFunctionList<void(const CMapInfo *)> mapInfoChanged;
|
||||
@ -347,7 +353,7 @@ public:
|
||||
InfoCard *card;
|
||||
OptionsTab *opt;
|
||||
CRandomMapTab * randMapTab;
|
||||
CAdventureMapButton *start, *back;
|
||||
CButton *start, *back;
|
||||
|
||||
SelectionTab *sel;
|
||||
CIntObject *curTab;
|
||||
@ -395,7 +401,7 @@ public:
|
||||
class CScenarioInfo : public CIntObject, public ISelectionScreenInfo
|
||||
{
|
||||
public:
|
||||
CAdventureMapButton *back;
|
||||
CButton *back;
|
||||
InfoCard *card;
|
||||
OptionsTab *opt;
|
||||
|
||||
@ -409,7 +415,7 @@ class CMultiMode : public CIntObject
|
||||
public:
|
||||
CPicture *bg;
|
||||
CTextInput *txt;
|
||||
CAdventureMapButton *btns[7]; //0 - hotseat, 6 - cancel
|
||||
CButton *btns[7]; //0 - hotseat, 6 - cancel
|
||||
CGStatusBar *bar;
|
||||
|
||||
CMultiMode();
|
||||
@ -424,7 +430,7 @@ class CHotSeatPlayers : public CIntObject
|
||||
CPicture *bg;
|
||||
CTextBox *title;
|
||||
CTextInput* txt[8];
|
||||
CAdventureMapButton *ok, *cancel;
|
||||
CButton *ok, *cancel;
|
||||
CGStatusBar *bar;
|
||||
|
||||
void onChange(std::string newText);
|
||||
@ -512,14 +518,14 @@ private:
|
||||
|
||||
// GUI components
|
||||
SDL_Surface * background;
|
||||
CAdventureMapButton * startB, * restartB, * backB;
|
||||
CButton * startB, * restartB, * backB;
|
||||
CTextBox * campaignDescription, * mapDescription;
|
||||
std::vector<SCampPositions> campDescriptions;
|
||||
std::vector<CRegion *> regions;
|
||||
CRegion * highlightedRegion;
|
||||
CHighlightableButtonsGroup * bonuses;
|
||||
CToggleGroup * bonuses;
|
||||
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 * sFlags;
|
||||
|
||||
@ -560,11 +566,11 @@ private:
|
||||
void show(SDL_Surface * to);
|
||||
};
|
||||
|
||||
CAdventureMapButton *back;
|
||||
CButton *back;
|
||||
std::vector<CCampaignButton*> campButtons;
|
||||
std::vector<CPicture*> images;
|
||||
|
||||
CAdventureMapButton* createExitButton(const JsonNode& button);
|
||||
CButton* createExitButton(const JsonNode& button);
|
||||
|
||||
public:
|
||||
enum CampaignSet {ROE, AB, SOD, WOG};
|
||||
@ -630,7 +636,7 @@ class CSimpleJoinScreen : public CIntObject
|
||||
{
|
||||
CPicture * bg;
|
||||
CTextBox * title;
|
||||
CAdventureMapButton * ok, * cancel;
|
||||
CButton * ok, * cancel;
|
||||
CGStatusBar * bar;
|
||||
CTextInput * address;
|
||||
CTextInput * port;
|
||||
|
@ -1,4 +1,7 @@
|
||||
#include "StdInc.h"
|
||||
#include "Client.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "CMusicHandler.h"
|
||||
#include "../lib/mapping/CCampaignHandler.h"
|
||||
|
@ -2,8 +2,9 @@
|
||||
|
||||
|
||||
#include "../lib/IGameCallback.h"
|
||||
#include "../lib/CondSh.h"
|
||||
#include "../lib/BattleAction.h"
|
||||
#include "../lib/CStopWatch.h"
|
||||
#include "../lib/int3.h"
|
||||
|
||||
/*
|
||||
* Client.h, part of VCMI engine
|
||||
@ -15,6 +16,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
class CPack;
|
||||
class CCampaignState;
|
||||
class CBattleCallback;
|
||||
class IGameEventsReceiver;
|
||||
class IBattleEventsReceiver;
|
||||
class CBattleGameInterface;
|
||||
|
1202
client/GUIClasses.h
@ -21,7 +21,6 @@
|
||||
#include "../lib/vcmi_endian.h"
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "../lib/CStopWatch.h"
|
||||
#include "CAnimation.h"
|
||||
#include "../lib/mapObjects/CObjectClassesHandler.h"
|
||||
|
||||
using namespace boost::assign;
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include "../lib/CSoundBase.h"
|
||||
#include "../lib/StartInfo.h"
|
||||
#include "mapHandler.h"
|
||||
#include "GUIClasses.h"
|
||||
#include "windows/GUIClasses.h"
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "gui/SDL_Extensions.h"
|
||||
#include "battle/CBattleInterface.h"
|
||||
@ -26,6 +26,8 @@
|
||||
#include "../lib/BattleState.h"
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "widgets/MiscWidgets.h"
|
||||
#include "widgets/AdventureMapClasses.h"
|
||||
#include "CMT.h"
|
||||
|
||||
//macros to avoid code duplication - calls given method with given arguments if interface for specific player is present
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "../../CCallback.h"
|
||||
#include "../../lib/BattleState.h"
|
||||
#include "../../lib/CTownHandler.h"
|
||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||
|
||||
/*
|
||||
* CBattleAnimations.cpp, part of VCMI engine
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../CAnimation.h"
|
||||
#include "../../lib/BattleHex.h"
|
||||
#include "../widgets/Images.h"
|
||||
|
||||
class CBattleInterface;
|
||||
class CStack;
|
||||
|
@ -1,40 +1,38 @@
|
||||
#include "StdInc.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 "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/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"
|
||||
|
||||
using namespace boost::assign;
|
||||
@ -224,17 +222,17 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
|
||||
// blitAt(menu, pos.x, 556 + pos.y);
|
||||
|
||||
//preparing buttons and console
|
||||
bOptions = new CAdventureMapButton (CGI->generaltexth->zelp[381].first, CGI->generaltexth->zelp[381].second, std::bind(&CBattleInterface::bOptionsf,this), 3, 561, "icm003.def", 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);
|
||||
bFlee = new CAdventureMapButton (CGI->generaltexth->zelp[380].first, CGI->generaltexth->zelp[380].second, std::bind(&CBattleInterface::bFleef,this), 105, 561, "icm002.def", 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);
|
||||
bSpell = new CAdventureMapButton (CGI->generaltexth->zelp[385].first, CGI->generaltexth->zelp[385].second, std::bind(&CBattleInterface::bSpellf,this), 645, 561, "icm005.def", 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);
|
||||
bDefence = new CAdventureMapButton (CGI->generaltexth->zelp[387].first, CGI->generaltexth->zelp[387].second, std::bind(&CBattleInterface::bDefencef,this), 747, 561, "icm007.def", SDLK_d);
|
||||
bOptions = new CButton (Point( 3, 561), "icm003.def", CGI->generaltexth->zelp[381], boost::bind(&CBattleInterface::bOptionsf,this), SDLK_o);
|
||||
bSurrender = new CButton (Point( 54, 561), "icm001.def", CGI->generaltexth->zelp[379], boost::bind(&CBattleInterface::bSurrenderf,this), SDLK_s);
|
||||
bFlee = new CButton (Point(105, 561), "icm002.def", CGI->generaltexth->zelp[380], boost::bind(&CBattleInterface::bFleef,this), SDLK_r);
|
||||
bAutofight = new CButton (Point(157, 561), "icm004.def", CGI->generaltexth->zelp[382], boost::bind(&CBattleInterface::bAutofightf,this), SDLK_a);
|
||||
bSpell = new CButton (Point(645, 561), "icm005.def", CGI->generaltexth->zelp[385], boost::bind(&CBattleInterface::bSpellf,this), SDLK_c);
|
||||
bWait = new CButton (Point(696, 561), "icm006.def", CGI->generaltexth->zelp[386], boost::bind(&CBattleInterface::bWaitf,this), SDLK_w);
|
||||
bDefence = new CButton (Point(747, 561), "icm007.def", CGI->generaltexth->zelp[387], boost::bind(&CBattleInterface::bDefencef,this), SDLK_d);
|
||||
bDefence->assignedKeys.insert(SDLK_SPACE);
|
||||
bConsoleUp = new CAdventureMapButton (std::string(), std::string(), std::bind(&CBattleInterface::bConsoleUpf,this), 624, 561, "ComSlide.def", SDLK_UP);
|
||||
bConsoleDown = new CAdventureMapButton (std::string(), std::string(), std::bind(&CBattleInterface::bConsoleDownf,this), 624, 580, "ComSlide.def", SDLK_DOWN);
|
||||
bConsoleDown->setOffset(2);
|
||||
bConsoleUp = new CButton (Point(624, 561), "ComSlide.def", std::make_pair("", ""), boost::bind(&CBattleInterface::bConsoleUpf,this), SDLK_UP);
|
||||
bConsoleDown = new CButton (Point(624, 580), "ComSlide.def", std::make_pair("", ""), boost::bind(&CBattleInterface::bConsoleDownf,this), SDLK_DOWN);
|
||||
bConsoleDown->setImageOrder(2, 3, 4, 5);
|
||||
console = new CBattleConsole();
|
||||
console->pos.x += 211;
|
||||
console->pos.y += 560;
|
||||
@ -242,8 +240,8 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
|
||||
console->pos.h = 38;
|
||||
if(tacticsMode)
|
||||
{
|
||||
btactNext = new CAdventureMapButton(std::string(), std::string(), std::bind(&CBattleInterface::bTacticNextStack,this, (CStack*)nullptr), 213, 560, "icm011.def", SDLK_SPACE);
|
||||
btactEnd = new CAdventureMapButton(std::string(), std::string(), std::bind(&CBattleInterface::bEndTacticPhase,this), 419, 560, "icm012.def", SDLK_RETURN);
|
||||
btactNext = new CButton(Point(213, 560), "icm011.def", std::make_pair("", ""), [&]{ bTacticNextStack(nullptr);}, SDLK_SPACE);
|
||||
btactEnd = new CButton(Point(419, 560), "icm012.def", std::make_pair("", ""), [&]{ bEndTacticPhase();}, SDLK_RETURN);
|
||||
menu = BitmapHandler::loadBitmap("COPLACBR.BMP");
|
||||
}
|
||||
else
|
||||
@ -2432,7 +2430,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
|
||||
{
|
||||
cursorFrame = ECursor::COMBAT_QUERY;
|
||||
consoleMsg = (boost::format(CGI->generaltexth->allTexts[297]) % shere->getName()).str();
|
||||
realizeAction = [=]{ GH.pushInt(createCreWindow(shere, true)); };
|
||||
realizeAction = [=]{ GH.pushInt(new CStackWindow(shere, false)); };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "../../lib/CCreatureSet.h"
|
||||
//#include "../../lib/CCreatureSet.h"
|
||||
#include "../../lib/ConstTransitivePtr.h" //may be reundant
|
||||
#include "../CAnimation.h"
|
||||
#include "../../lib/GameConstants.h"
|
||||
|
||||
#include "CBattleAnimations.h"
|
||||
|
||||
/*
|
||||
@ -23,9 +23,9 @@ class CGHeroInstance;
|
||||
class CDefHandler;
|
||||
class CStack;
|
||||
class CCallback;
|
||||
class CAdventureMapButton;
|
||||
class CHighlightableButton;
|
||||
class CHighlightableButtonsGroup;
|
||||
class CButton;
|
||||
class CToggleButton;
|
||||
class CToggleGroup;
|
||||
struct BattleResult;
|
||||
struct BattleSpellCast;
|
||||
struct CObstacleInstance;
|
||||
@ -120,7 +120,7 @@ class CBattleInterface : public CIntObject
|
||||
};
|
||||
private:
|
||||
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;
|
||||
CBattleConsole * console;
|
||||
CBattleHero * attackingHero, * defendingHero; //fighting heroes
|
||||
@ -338,7 +338,7 @@ public:
|
||||
InfoAboutHero enemyHero() const;
|
||||
|
||||
friend class CPlayerInterface;
|
||||
friend class CAdventureMapButton;
|
||||
friend class CButton;
|
||||
friend class CInGameConsole;
|
||||
|
||||
friend class CBattleResultWindow;
|
||||
|
@ -1,29 +1,34 @@
|
||||
#include "StdInc.h"
|
||||
#include "CBattleInterfaceClasses.h"
|
||||
|
||||
#include "../gui/SDL_Extensions.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 "../CCreatureWindow.h"
|
||||
#include "../CDefHandler.h"
|
||||
#include "../CGameInfo.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
|
||||
@ -258,26 +263,23 @@ CBattleOptionsWindow::CBattleOptionsWindow(const SDL_Rect & position, CBattleInt
|
||||
background = new CPicture("comopbck.bmp");
|
||||
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->select(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->select(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->select(settings["battle"]["mouseShadow"].Bool());
|
||||
viewGrid = new CToggleButton(Point(25, 56), "sysopchk.def", CGI->generaltexth->zelp[427], [&](bool on){owner->setPrintCellBorders(on);} );
|
||||
viewGrid->setSelected(settings["battle"]["cellBorders"].Bool());
|
||||
movementShadow = new CToggleButton(Point(25, 89), "sysopchk.def", CGI->generaltexth->zelp[428], [&](bool on){owner->setPrintStackRange(on);});
|
||||
movementShadow->setSelected(settings["battle"]["stackRange"].Bool());
|
||||
mouseShadow = new CToggleButton(Point(25, 122), "sysopchk.def", CGI->generaltexth->zelp[429], [&](bool on){owner->setPrintMouseShadow(on);});
|
||||
mouseShadow->setSelected(settings["battle"]["mouseShadow"].Bool());
|
||||
|
||||
animSpeeds = new CHighlightableButtonsGroup(0);
|
||||
animSpeeds->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[422].first),CGI->generaltexth->zelp[422].second, "sysopb9.def", 28, 225, 40);
|
||||
animSpeeds->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[423].first),CGI->generaltexth->zelp[423].second, "sysob10.def", 92, 225, 63);
|
||||
animSpeeds->addButton(boost::assign::map_list_of(0,CGI->generaltexth->zelp[424].first),CGI->generaltexth->zelp[424].second, "sysob11.def",156, 225, 100);
|
||||
animSpeeds->select(owner->getAnimSpeed(), 1);
|
||||
animSpeeds->onChange = std::bind(&CBattleInterface::setAnimSpeed, owner, _1);
|
||||
animSpeeds = new CToggleGroup([&](int value){ owner->setAnimSpeed(value);});
|
||||
animSpeeds->addToggle(40, new CToggleButton(Point( 28, 225), "sysopb9.def", CGI->generaltexth->zelp[422]));
|
||||
animSpeeds->addToggle(63, new CToggleButton(Point( 92, 225), "sysob10.def", CGI->generaltexth->zelp[423]));
|
||||
animSpeeds->addToggle(100, new CToggleButton(Point(156, 225), "sysob11.def", CGI->generaltexth->zelp[424]));
|
||||
animSpeeds->setSelected(owner->getAnimSpeed());
|
||||
|
||||
setToDefault = new CAdventureMapButton (CGI->generaltexth->zelp[393], std::bind(&CBattleOptionsWindow::bDefaultf,this), 246, 359, "codefaul.def");
|
||||
setToDefault->swappedImages = true;
|
||||
setToDefault->update();
|
||||
exit = new CAdventureMapButton (CGI->generaltexth->zelp[392], std::bind(&CBattleOptionsWindow::bExitf,this), 357, 359, "soretrn.def",SDLK_RETURN);
|
||||
exit->swappedImages = true;
|
||||
exit->update();
|
||||
setToDefault = new CButton (Point(246, 359), "codefaul.def", CGI->generaltexth->zelp[393], [&]{ bDefaultf(); });
|
||||
setToDefault->setImageOrder(1, 0, 2, 3);
|
||||
exit = new CButton (Point(357, 359), "soretrn.def", CGI->generaltexth->zelp[392], [&]{ bExitf();}, SDLK_RETURN);
|
||||
exit->setImageOrder(1, 0, 2, 3);
|
||||
|
||||
//creating labels
|
||||
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()
|
||||
{
|
||||
//TODO: implement
|
||||
}
|
||||
|
||||
void CBattleOptionsWindow::bExitf()
|
||||
@ -322,9 +325,8 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
|
||||
CPicture * bg = new CPicture("CPRESULT");
|
||||
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->borderEnabled = true;
|
||||
|
||||
if(br.winner==0) //attacker won
|
||||
{
|
||||
@ -606,7 +608,7 @@ void CClickableHex::clickRight(tribool down, bool previousState)
|
||||
if(!myst->alive()) return;
|
||||
if(down)
|
||||
{
|
||||
GH.pushInt(createCreWindow(myst));
|
||||
GH.pushInt(new CStackWindow(myst, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -701,7 +703,7 @@ CStackQueue::StackBox::StackBox(bool small):
|
||||
small(small)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
bg = new CPicture(small ? "StackQueueBgSmall" : "StackQueueBgBig" );
|
||||
bg = new CPicture(small ? "StackQueueSmall" : "StackQueueLarge" );
|
||||
|
||||
if (small)
|
||||
{
|
||||
|
@ -8,9 +8,9 @@ class CDefHandler;
|
||||
class CGHeroInstance;
|
||||
class CBattleInterface;
|
||||
class CPicture;
|
||||
class CAdventureMapButton;
|
||||
class CHighlightableButton;
|
||||
class CHighlightableButtonsGroup;
|
||||
class CButton;
|
||||
class CToggleButton;
|
||||
class CToggleGroup;
|
||||
class CLabel;
|
||||
struct BattleResult;
|
||||
class CStack;
|
||||
@ -72,9 +72,9 @@ class CBattleOptionsWindow : public CIntObject
|
||||
{
|
||||
private:
|
||||
CPicture * background;
|
||||
CAdventureMapButton * setToDefault, * exit;
|
||||
CHighlightableButton * viewGrid, * movementShadow, * mouseShadow;
|
||||
CHighlightableButtonsGroup * animSpeeds;
|
||||
CButton * setToDefault, * exit;
|
||||
CToggleButton * viewGrid, * movementShadow, * mouseShadow;
|
||||
CToggleGroup * animSpeeds;
|
||||
|
||||
std::vector<CLabel*> labels;
|
||||
public:
|
||||
@ -88,7 +88,7 @@ public:
|
||||
class CBattleResultWindow : public CIntObject
|
||||
{
|
||||
private:
|
||||
CAdventureMapButton *exit;
|
||||
CButton *exit;
|
||||
CPlayerInterface &owner;
|
||||
public:
|
||||
CBattleResultWindow(const BattleResult & br, const SDL_Rect & pos, CPlayerInterface &_owner); //c-tor
|
||||
@ -152,4 +152,4 @@ public:
|
||||
void update();
|
||||
void showAll(SDL_Surface *to);
|
||||
void blitBg(SDL_Surface * to);
|
||||
};
|
||||
};
|
||||
|
@ -1,16 +1,16 @@
|
||||
#include "StdInc.h"
|
||||
#include "CCreatureAnimation.h"
|
||||
|
||||
#include "../../lib/vcmi_endian.h"
|
||||
#include "../../lib/CConfigHandler.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/CBinaryReader.h"
|
||||
#include "../../lib/filesystem/CMemoryStream.h"
|
||||
|
||||
#include "../gui/SDL_Extensions.h"
|
||||
#include "../gui/SDL_Pixels.h"
|
||||
|
||||
/*
|
||||
* CCreatureAnimation.cpp, part of VCMI engine
|
||||
*
|
||||
|
@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../lib/FunctionList.h"
|
||||
#include "../CAnimation.h"
|
||||
#include "../gui/SDL_Extensions.h"
|
||||
#include "../widgets/Images.h"
|
||||
|
||||
/*
|
||||
* CCreatureAnimation.h, part of VCMI engine
|
||||
|
@ -1,17 +1,18 @@
|
||||
#include "StdInc.h"
|
||||
#include "CAnimation.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/ISimpleResourceLoader.h"
|
||||
#include "../lib/JsonNode.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
|
||||
*
|
||||
@ -1221,6 +1222,7 @@ void CAnimation::getAnimInfo()
|
||||
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):
|
||||
frame(Frame),
|
||||
@ -1537,3 +1539,5 @@ void CCreatureAnim::clearAndSet(EAnimType type)
|
||||
queue.pop();
|
||||
set(type);
|
||||
}
|
||||
=======
|
||||
>>>>>>> refactoring/guiClasses:client/gui/CAnimation.cpp
|
@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "../lib/vcmi_endian.h"
|
||||
#include "gui/CIntObject.h"
|
||||
#include "../../lib/vcmi_endian.h"
|
||||
#include "gui/Geometries.h"
|
||||
#include "../../lib/GameConstants.h"
|
||||
|
||||
/*
|
||||
* CAnimation.h, part of VCMI engine
|
||||
@ -219,162 +220,3 @@ public:
|
||||
//total count of frames in group (including not loaded)
|
||||
size_t size(size_t group=0) const;
|
||||
};
|
||||
|
||||
|
||||
/// Class for displaying one image from animation
|
||||
class CAnimImage: public CIntObject
|
||||
{
|
||||
private:
|
||||
CAnimation* anim;
|
||||
//displayed frame/group
|
||||
size_t frame;
|
||||
size_t group;
|
||||
PlayerColor player;
|
||||
ui8 flags;
|
||||
|
||||
void init();
|
||||
|
||||
public:
|
||||
CAnimImage(std::string name, size_t Frame, size_t Group=0, int x=0, int y=0, ui8 Flags=0);
|
||||
CAnimImage(CAnimation* anim, size_t Frame, size_t Group=0, int x=0, int y=0, ui8 Flags=0);
|
||||
~CAnimImage();//d-tor
|
||||
|
||||
//size of animation
|
||||
size_t size();
|
||||
|
||||
//change displayed frame on this one
|
||||
void setFrame(size_t Frame, size_t Group=0);
|
||||
|
||||
//makes image player-colored
|
||||
void playerColored(PlayerColor player);
|
||||
|
||||
void showAll(SDL_Surface * to);
|
||||
};
|
||||
|
||||
/// Base class for displaying animation, used as superclass for different animations
|
||||
class CShowableAnim: public CIntObject
|
||||
{
|
||||
public:
|
||||
enum EFlags
|
||||
{
|
||||
BASE=1, //base frame will be blitted before current one
|
||||
HORIZONTAL_FLIP=2, //TODO: will be displayed rotated
|
||||
VERTICAL_FLIP=4, //TODO: will be displayed rotated
|
||||
USE_RLE=8, //RLE-d version, support full alpha-channel for 8-bit images
|
||||
PLAYER_COLORED=16, //TODO: all loaded images will be player-colored
|
||||
PLAY_ONCE=32 //play animation only once and stop at last frame
|
||||
};
|
||||
protected:
|
||||
CAnimation anim;
|
||||
|
||||
size_t group, frame;//current frame
|
||||
|
||||
size_t first, last; //animation range
|
||||
|
||||
//TODO: replace with time delay(needed for battles)
|
||||
ui32 frameDelay;//delay in frames of each image
|
||||
ui32 value;//how many times current frame was showed
|
||||
|
||||
ui8 flags;//Flags from EFlags enum
|
||||
|
||||
//blit image with optional rotation, fitting into rect, etc
|
||||
void blitImage(size_t frame, size_t group, SDL_Surface *to);
|
||||
|
||||
//For clipping in rect, offsets of picture coordinates
|
||||
int xOffset, yOffset;
|
||||
|
||||
ui8 alpha;
|
||||
|
||||
public:
|
||||
//called when next animation sequence is required
|
||||
std::function<void()> callback;
|
||||
|
||||
//Set per-surface alpha, 0 = transparent, 255 = opaque
|
||||
void setAlpha(ui32 alphaValue);
|
||||
|
||||
CShowableAnim(int x, int y, std::string name, ui8 flags=0, ui32 Delay=4, size_t Group=0);
|
||||
~CShowableAnim();
|
||||
|
||||
//set animation to group or part of group
|
||||
bool set(size_t Group);
|
||||
bool set(size_t Group, size_t from, size_t to=-1);
|
||||
|
||||
//set rotation flags
|
||||
void rotate(bool on, bool vertical=false);
|
||||
|
||||
//move displayed part of picture (if picture is clipped to rect)
|
||||
void clipRect(int posX, int posY, int width, int height);
|
||||
|
||||
//set frame to first, call callback
|
||||
virtual void reset();
|
||||
|
||||
//show current frame and increase counter
|
||||
void show(SDL_Surface * to);
|
||||
void showAll(SDL_Surface * to);
|
||||
};
|
||||
|
||||
/// Creature-dependend animations like attacking, moving,...
|
||||
class CCreatureAnim: public CShowableAnim
|
||||
{
|
||||
public:
|
||||
|
||||
enum EHeroAnimType
|
||||
{
|
||||
HERO_HOLDING = 0,
|
||||
HERO_IDLE = 1, // idling movement that happens from time to time
|
||||
HERO_DEFEAT = 2, // played when army loses stack or on friendly fire
|
||||
HERO_VICTORY = 3, // when enemy stack killed or huge damage is dealt
|
||||
HERO_CAST_SPELL = 4 // spellcasting
|
||||
};
|
||||
|
||||
enum EAnimType // list of creature animations, numbers were taken from def files
|
||||
{
|
||||
MOVING=0,
|
||||
MOUSEON=1,
|
||||
HOLDING=2,
|
||||
HITTED=3,
|
||||
DEFENCE=4,
|
||||
DEATH=5,
|
||||
//DEATH2=6, //unused?
|
||||
TURN_L=7,
|
||||
TURN_R=8, //same
|
||||
//TURN_L2=9, //identical to previous?
|
||||
//TURN_R2=10,
|
||||
ATTACK_UP=11,
|
||||
ATTACK_FRONT=12,
|
||||
ATTACK_DOWN=13,
|
||||
SHOOT_UP=14,
|
||||
SHOOT_FRONT=15,
|
||||
SHOOT_DOWN=16,
|
||||
CAST_UP=17,
|
||||
CAST_FRONT=18,
|
||||
CAST_DOWN=19,
|
||||
MOVE_START=20,
|
||||
MOVE_END=21,
|
||||
DEAD = 22 // new group, used to show dead stacks. If empty - last frame from "DEATH" will be copied here
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
//queue of animations waiting to be displayed
|
||||
std::queue<EAnimType> queue;
|
||||
|
||||
//this function is used as callback if preview flag was set during construction
|
||||
void loopPreview(bool warMachine);
|
||||
|
||||
public:
|
||||
//change anim to next if queue is not empty, call callback othervice
|
||||
void reset();
|
||||
|
||||
//add sequence to the end of queue
|
||||
void addLast(EAnimType newType);
|
||||
|
||||
void startPreview(bool warMachine);
|
||||
|
||||
//clear queue and set animation to this sequence
|
||||
void clearAndSet(EAnimType type);
|
||||
|
||||
CCreatureAnim(int x, int y, std::string name, Rect picPos,
|
||||
ui8 flags= USE_RLE, EAnimType = HOLDING );
|
||||
|
||||
};
|
@ -2,9 +2,11 @@
|
||||
#include "CCursorHandler.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "SDL_Extensions.h"
|
||||
#include "../CAnimation.h"
|
||||
#include "CGuiHandler.h"
|
||||
#include "widgets/Images.h"
|
||||
|
||||
#include "../CMT.h"
|
||||
|
||||
/*
|
||||
|
@ -1,10 +1,12 @@
|
||||
#include "StdInc.h"
|
||||
#include "CGuiHandler.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "CIntObject.h"
|
||||
#include "../CGameInfo.h"
|
||||
#include "CCursorHandler.h"
|
||||
|
||||
#include "../CGameInfo.h"
|
||||
#include "../../lib/CThreadHelper.h"
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
#include "../CMT.h"
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../lib/CStopWatch.h"
|
||||
//#include "../../lib/CStopWatch.h"
|
||||
#include "Geometries.h"
|
||||
#include "SDL_Extensions.h"
|
||||
|
||||
|
@ -1,9 +1,15 @@
|
||||
#include "StdInc.h"
|
||||
#include "CIntObject.h"
|
||||
|
||||
#include "CGuiHandler.h"
|
||||
#include "SDL_Extensions.h"
|
||||
#include "../CMessage.h"
|
||||
|
||||
IShowActivatable::IShowActivatable()
|
||||
{
|
||||
type = 0;
|
||||
}
|
||||
|
||||
void ILockedUpdatable::runLocked(std::function<void(IUpdateable*)> cb)
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> lock(updateGuard);
|
||||
@ -317,6 +323,19 @@ bool CIntObject::captureThisEvent(const SDL_KeyboardEvent & key)
|
||||
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)
|
||||
{
|
||||
if(vstd::contains(assignedKeys,key.keysym.sym)
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <SDL_events.h>
|
||||
//#include <SDL_events.h>
|
||||
#include "Geometries.h"
|
||||
#include "../Graphics.h"
|
||||
|
||||
@ -18,6 +18,8 @@ struct SDL_Surface;
|
||||
class CPicture;
|
||||
class CGuiHandler;
|
||||
|
||||
struct SDL_KeyboardEvent;
|
||||
|
||||
using boost::logic::tribool;
|
||||
|
||||
// Defines a activate/deactive method
|
||||
@ -216,8 +218,8 @@ class CKeyShortcut : public virtual CIntObject
|
||||
{
|
||||
public:
|
||||
std::set<int> assignedKeys;
|
||||
CKeyShortcut(){}; //c-tor
|
||||
CKeyShortcut(int key){assignedKeys.insert(key);}; //c-tor
|
||||
CKeyShortcut(std::set<int> Keys):assignedKeys(Keys){}; //c-tor
|
||||
CKeyShortcut();
|
||||
CKeyShortcut(int key);
|
||||
CKeyShortcut(std::set<int> Keys);
|
||||
virtual void keyPressed(const SDL_KeyboardEvent & key); //call-in
|
||||
};
|
||||
|
@ -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();
|
||||
};
|
@ -1,6 +1,11 @@
|
||||
#include "StdInc.h"
|
||||
#include "Geometries.h"
|
||||
#include "../CMT.h"
|
||||
#include <SDL_events.h>
|
||||
|
||||
Point::Point(const SDL_MouseMotionEvent &a)
|
||||
:x(a.x),y(a.y)
|
||||
{}
|
||||
|
||||
Rect Rect::createCentered( int w, int h )
|
||||
{
|
||||
@ -15,4 +20,4 @@ Rect Rect::around(const Rect &r, int width /*= 1*/) /*creates rect around anothe
|
||||
Rect Rect::centerIn(const Rect &r)
|
||||
{
|
||||
return Rect(r.x + (r.w - w) / 2, r.y + (r.h - h) / 2, w, h);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL_video.h>
|
||||
#include <SDL_events.h>
|
||||
#include "../../lib/int3.h"
|
||||
|
||||
/*
|
||||
@ -21,6 +20,7 @@
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
struct SDL_MouseMotionEvent;
|
||||
|
||||
// A point with x/y coordinate, used mostly for graphic rendering
|
||||
struct Point
|
||||
@ -38,9 +38,7 @@ struct Point
|
||||
Point(const int3 &a)
|
||||
:x(a.x),y(a.y)
|
||||
{}
|
||||
Point(const SDL_MouseMotionEvent &a)
|
||||
:x(a.x),y(a.y)
|
||||
{}
|
||||
Point(const SDL_MouseMotionEvent &a);
|
||||
|
||||
template<typename T>
|
||||
Point operator+(const T &b) const
|
||||
@ -265,4 +263,4 @@ struct Rect : public SDL_Rect
|
||||
ret.h = y2 -ret.y;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include "SDL_Extensions.h"
|
||||
#include "SDL_Pixels.h"
|
||||
|
||||
#include <SDL_ttf.h>
|
||||
#include "../CGameInfo.h"
|
||||
#include "../CMessage.h"
|
||||
#include "../CDefHandler.h"
|
||||
|
@ -16,10 +16,11 @@
|
||||
#endif
|
||||
|
||||
#include <SDL_video.h>
|
||||
#include <SDL_ttf.h>
|
||||
#include <SDL_events.h>
|
||||
#include "../../lib/int3.h"
|
||||
#include "../Graphics.h"
|
||||
//#include "../Graphics.h"
|
||||
#include "Geometries.h"
|
||||
#include "../../lib/GameConstants.h"
|
||||
|
||||
|
||||
//A macro to force inlining some of our functions. Compiler (at least MSVC) is not so smart here-> without that displaying is MUCH slower
|
||||
@ -141,15 +142,16 @@ typename boost::enable_if_c<boost::is_unsigned<T>::type, T>::type abs(T arg)
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
std::string symbols = "kMGTPE";
|
||||
std::string symbols = " kMGTPE";
|
||||
auto iter = symbols.begin();
|
||||
|
||||
while (number >= 1000)
|
||||
while (number >= max)
|
||||
{
|
||||
number /= 1000;
|
||||
iter++;
|
||||
|
@ -1,30 +1,43 @@
|
||||
#include "StdInc.h"
|
||||
#include "AdventureMapClasses.h"
|
||||
|
||||
#include "../CCallback.h"
|
||||
#include "../lib/JsonNode.h"
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include "../lib/mapping/CMap.h"
|
||||
#include "../lib/CModHandler.h"
|
||||
#include "../lib/mapObjects/CGHeroInstance.h"
|
||||
#include "../lib/CGameState.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "../lib/CTownHandler.h"
|
||||
#include "../lib/NetPacksBase.h"
|
||||
#include "../lib/CHeroHandler.h"
|
||||
#include "../lib/StringConstants.h"
|
||||
#include "CAdvmapInterface.h"
|
||||
#include "CAnimation.h"
|
||||
#include "CGameInfo.h"
|
||||
#include "CPlayerInterface.h"
|
||||
#include "CMusicHandler.h"
|
||||
#include "Graphics.h"
|
||||
#include "GUIClasses.h"
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "gui/SDL_Pixels.h"
|
||||
#include <SDL.h>
|
||||
|
||||
#include "MiscWidgets.h"
|
||||
#include "CComponent.h"
|
||||
|
||||
#include "../CGameInfo.h"
|
||||
#include "../CMusicHandler.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../CPreGame.h"
|
||||
#include "../Graphics.h"
|
||||
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/SDL_Pixels.h"
|
||||
|
||||
#include "../windows/InfoWindows.h"
|
||||
#include "../windows/CAdvmapInterface.h"
|
||||
#include "../windows/GUIClasses.h"
|
||||
|
||||
#include "../battle/CBattleInterfaceClasses.h"
|
||||
#include "../battle/CBattleInterface.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
|
||||
*
|
||||
@ -93,15 +106,23 @@ CList::CList(int Size, Point position, std::string btnUp, std::string btnDown, s
|
||||
selected(nullptr)
|
||||
{
|
||||
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);
|
||||
|
||||
//assign callback only after list was created
|
||||
<<<<<<< HEAD:client/AdventureMapClasses.cpp
|
||||
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->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();
|
||||
}
|
||||
@ -950,3 +971,248 @@ void CInfoBar::showGameStatus()
|
||||
setTimer(3000);
|
||||
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
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "gui/CIntObject.h"
|
||||
#include "gui/CIntObjectClasses.h"
|
||||
#include "ObjectLists.h"
|
||||
#include "../../lib/FunctionList.h"
|
||||
|
||||
class CArmedInstance;
|
||||
class CShowableAnim;
|
||||
@ -9,6 +9,7 @@ class CGGarrison;
|
||||
class CGObjectInstance;
|
||||
class CGHeroInstance;
|
||||
class CGTownInstance;
|
||||
class CButton;
|
||||
struct Component;
|
||||
struct InfoAboutArmy;
|
||||
struct InfoAboutHero;
|
||||
@ -82,8 +83,8 @@ protected:
|
||||
|
||||
public:
|
||||
|
||||
CAdventureMapButton * scrollUp;
|
||||
CAdventureMapButton * scrollDown;
|
||||
CButton * scrollUp;
|
||||
CButton * scrollDown;
|
||||
|
||||
/// functions that will be called when selection changes
|
||||
CFunctionList<void()> onSelect;
|
||||
@ -313,3 +314,30 @@ public:
|
||||
/// for 3 seconds shows amount of town halls and players status
|
||||
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
@ -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
@ -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();
|
||||
};
|
1017
client/widgets/CArtifactHolder.cpp
Normal file
145
client/widgets/CArtifactHolder.h
Normal 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;
|
||||
};
|
453
client/widgets/CComponent.cpp
Normal 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
@ -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);
|
||||
};
|
512
client/widgets/CGarrisonInt.cpp
Normal 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();
|
||||
}
|
122
client/widgets/CGarrisonInt.h
Normal 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
@ -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
@ -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 );
|
||||
|
||||
};
|
442
client/widgets/MiscWidgets.cpp
Normal 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;
|
||||
}
|
150
client/widgets/MiscWidgets.h
Normal 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);
|
||||
};
|
234
client/widgets/ObjectLists.cpp
Normal 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;
|
||||
}
|
111
client/widgets/ObjectLists.h
Normal 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();
|
||||
};
|
642
client/widgets/TextControls.cpp
Normal 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;;
|
||||
}
|
||||
}
|
||||
}
|
189
client/widgets/TextControls.h
Normal 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);
|
||||
};
|
@ -1,36 +1,43 @@
|
||||
#include "StdInc.h"
|
||||
#include "CAdvmapInterface.h"
|
||||
|
||||
#include "../CCallback.h"
|
||||
#include "CCastleInterface.h"
|
||||
#include "gui/CCursorHandler.h"
|
||||
#include "CGameInfo.h"
|
||||
#include "CHeroWindow.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 "Graphics.h"
|
||||
#include "CDefHandler.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "../lib/CHeroHandler.h"
|
||||
#include "../lib/mapObjects/CGHeroInstance.h"
|
||||
#include "../lib/CTownHandler.h"
|
||||
#include "../lib/mapping/CMap.h"
|
||||
#include "../lib/JsonNode.h"
|
||||
#include "mapHandler.h"
|
||||
#include "CPreGame.h"
|
||||
#include "../lib/VCMI_Lib.h"
|
||||
#include "../lib/CSpellHandler.h"
|
||||
#include "../lib/CSoundBase.h"
|
||||
#include "../lib/CGameState.h"
|
||||
#include "CMusicHandler.h"
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "gui/CIntObjectClasses.h"
|
||||
#include "../lib/UnlockGuard.h"
|
||||
#include "GUIClasses.h"
|
||||
#include "CTradeWindow.h"
|
||||
|
||||
#include "../CBitmapHandler.h"
|
||||
#include "../CDefHandler.h"
|
||||
#include "../CGameInfo.h"
|
||||
#include "../CMessage.h"
|
||||
#include "../CMusicHandler.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../CPreGame.h"
|
||||
#include "../Graphics.h"
|
||||
#include "../mapHandler.h"
|
||||
|
||||
#include "../gui/CCursorHandler.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/SDL_Extensions.h"
|
||||
#include "../widgets/MiscWidgets.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
|
||||
#pragma warning (disable : 4355)
|
||||
@ -363,6 +370,7 @@ void CResDataBar::showAll(SDL_Surface * to)
|
||||
CAdvMapInt::CAdvMapInt():
|
||||
minimap(Rect(ADVOPT.minimapX, ADVOPT.minimapY, ADVOPT.minimapW, ADVOPT.minimapH)),
|
||||
statusbar(ADVOPT.statusbarX,ADVOPT.statusbarY,ADVOPT.statusbarG),
|
||||
<<<<<<< HEAD:client/CAdvmapInterface.cpp
|
||||
kingOverview(CGI->generaltexth->zelp[293].first,CGI->generaltexth->zelp[293].second,
|
||||
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,
|
||||
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),
|
||||
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]));
|
||||
}
|
||||
|
||||
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);
|
||||
underground.block(!CGI->mh->map->twoLevel);
|
||||
underground->block(!CGI->mh->map->twoLevel);
|
||||
addUsedEvents(MOVE);
|
||||
}
|
||||
|
||||
@ -445,14 +474,14 @@ void CAdvMapInt::fswitchLevel()
|
||||
if (position.z)
|
||||
{
|
||||
position.z--;
|
||||
underground.setIndex(0,true);
|
||||
underground.showAll(screenBuf);
|
||||
underground->setIndex(0,true);
|
||||
underground->showAll(screenBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
underground.setIndex(1,true);
|
||||
underground->setIndex(1,true);
|
||||
position.z++;
|
||||
underground.showAll(screenBuf);
|
||||
underground->showAll(screenBuf);
|
||||
}
|
||||
updateScreen = true;
|
||||
minimap.setLevel(position.z);
|
||||
@ -537,14 +566,13 @@ void CAdvMapInt::fendTurn()
|
||||
|
||||
void CAdvMapInt::updateSleepWake(const CGHeroInstance *h)
|
||||
{
|
||||
sleepWake.block(!h);
|
||||
sleepWake->block(!h);
|
||||
if (!h)
|
||||
return;
|
||||
bool state = isHeroSleeping(h);
|
||||
sleepWake.setIndex(state ? 1 : 0, true);
|
||||
sleepWake.assignedKeys.clear();
|
||||
sleepWake.assignedKeys.insert(state ? SDLK_w : SDLK_z);
|
||||
sleepWake.update();
|
||||
sleepWake->setIndex(state ? 1 : 0, true);
|
||||
sleepWake->assignedKeys.clear();
|
||||
sleepWake->assignedKeys.insert(state ? SDLK_w : SDLK_z);
|
||||
}
|
||||
|
||||
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;
|
||||
if (!h)
|
||||
{
|
||||
moveHero.block(true);
|
||||
moveHero->block(true);
|
||||
return;
|
||||
}
|
||||
moveHero.block(!hasPath || (h->movement == 0));
|
||||
moveHero->block(!hasPath || (h->movement == 0));
|
||||
}
|
||||
|
||||
int CAdvMapInt::getNextHeroIndex(int startIndex)
|
||||
@ -587,12 +615,12 @@ void CAdvMapInt::updateNextHero(const CGHeroInstance *h)
|
||||
int next = getNextHeroIndex(start);
|
||||
if (next < 0)
|
||||
{
|
||||
nextHero.block(true);
|
||||
nextHero->block(true);
|
||||
return;
|
||||
}
|
||||
const CGHeroInstance *nextH = LOCPLINT->wanderingHeroes[next];
|
||||
bool noActiveHeroes = (next == start) && ((nextH->movement == 0) || isHeroSleeping(nextH));
|
||||
nextHero.block(noActiveHeroes);
|
||||
nextHero->block(noActiveHeroes);
|
||||
}
|
||||
|
||||
void CAdvMapInt::activate()
|
||||
@ -605,16 +633,16 @@ void CAdvMapInt::activate()
|
||||
GH.statusbar = &statusbar;
|
||||
if(!duringAITurn)
|
||||
{
|
||||
kingOverview.activate();
|
||||
underground.activate();
|
||||
questlog.activate();
|
||||
sleepWake.activate();
|
||||
moveHero.activate();
|
||||
spellbook.activate();
|
||||
sysOptions.activate();
|
||||
advOptions.activate();
|
||||
nextHero.activate();
|
||||
endTurn.activate();
|
||||
kingOverview->activate();
|
||||
underground->activate();
|
||||
questlog->activate();
|
||||
sleepWake->activate();
|
||||
moveHero->activate();
|
||||
spellbook->activate();
|
||||
sysOptions->activate();
|
||||
advOptions->activate();
|
||||
nextHero->activate();
|
||||
endTurn->activate();
|
||||
|
||||
minimap.activate();
|
||||
heroList.activate();
|
||||
@ -635,16 +663,16 @@ void CAdvMapInt::deactivate()
|
||||
scrollingDir = 0;
|
||||
|
||||
CCS->curh->changeGraphic(ECursor::ADVENTURE,0);
|
||||
kingOverview.deactivate();
|
||||
underground.deactivate();
|
||||
questlog.deactivate();
|
||||
sleepWake.deactivate();
|
||||
moveHero.deactivate();
|
||||
spellbook.deactivate();
|
||||
advOptions.deactivate();
|
||||
sysOptions.deactivate();
|
||||
nextHero.deactivate();
|
||||
endTurn.deactivate();
|
||||
kingOverview->deactivate();
|
||||
underground->deactivate();
|
||||
questlog->deactivate();
|
||||
sleepWake->deactivate();
|
||||
moveHero->deactivate();
|
||||
spellbook->deactivate();
|
||||
advOptions->deactivate();
|
||||
sysOptions->deactivate();
|
||||
nextHero->deactivate();
|
||||
endTurn->deactivate();
|
||||
minimap.deactivate();
|
||||
heroList.deactivate();
|
||||
townList.deactivate();
|
||||
@ -661,16 +689,16 @@ void CAdvMapInt::showAll(SDL_Surface * to)
|
||||
if(state != INGAME)
|
||||
return;
|
||||
|
||||
kingOverview.showAll(to);
|
||||
underground.showAll(to);
|
||||
questlog.showAll(to);
|
||||
sleepWake.showAll(to);
|
||||
moveHero.showAll(to);
|
||||
spellbook.showAll(to);
|
||||
advOptions.showAll(to);
|
||||
sysOptions.showAll(to);
|
||||
nextHero.showAll(to);
|
||||
endTurn.showAll(to);
|
||||
kingOverview->showAll(to);
|
||||
underground->showAll(to);
|
||||
questlog->showAll(to);
|
||||
sleepWake->showAll(to);
|
||||
moveHero->showAll(to);
|
||||
spellbook->showAll(to);
|
||||
advOptions->showAll(to);
|
||||
sysOptions->showAll(to);
|
||||
nextHero->showAll(to);
|
||||
endTurn->showAll(to);
|
||||
|
||||
minimap.showAll(to);
|
||||
heroList.showAll(to);
|
||||
@ -781,8 +809,8 @@ void CAdvMapInt::centerOn(int3 on)
|
||||
|
||||
position = on;
|
||||
updateScreen=true;
|
||||
underground.setIndex(on.z,true); //change underground switch button image
|
||||
underground.redraw();
|
||||
underground->setIndex(on.z,true); //change underground switch button image
|
||||
underground->redraw();
|
||||
if (switchedLevels)
|
||||
minimap.setLevel(position.z);
|
||||
}
|
||||
@ -1096,16 +1124,16 @@ void CAdvMapInt::setPlayer(PlayerColor Player)
|
||||
player = Player;
|
||||
graphics->blueToPlayersAdv(bg,player);
|
||||
|
||||
kingOverview.setPlayerColor(player);
|
||||
underground.setPlayerColor(player);
|
||||
questlog.setPlayerColor(player);
|
||||
sleepWake.setPlayerColor(player);
|
||||
moveHero.setPlayerColor(player);
|
||||
spellbook.setPlayerColor(player);
|
||||
sysOptions.setPlayerColor(player);
|
||||
advOptions.setPlayerColor(player);
|
||||
nextHero.setPlayerColor(player);
|
||||
endTurn.setPlayerColor(player);
|
||||
kingOverview->setPlayerColor(player);
|
||||
underground->setPlayerColor(player);
|
||||
questlog->setPlayerColor(player);
|
||||
sleepWake->setPlayerColor(player);
|
||||
moveHero->setPlayerColor(player);
|
||||
spellbook->setPlayerColor(player);
|
||||
sysOptions->setPlayerColor(player);
|
||||
advOptions->setPlayerColor(player);
|
||||
nextHero->setPlayerColor(player);
|
||||
endTurn->setPlayerColor(player);
|
||||
graphics->blueToPlayersAdv(resdatabar.bg,player);
|
||||
|
||||
//heroList.updateHList();
|
||||
@ -1525,10 +1553,11 @@ void CAdvMapInt::adjustActiveness(bool aiTurnStart)
|
||||
}
|
||||
|
||||
CAdventureOptions::CAdventureOptions():
|
||||
CWindowObject(PLAYER_COLORED, "ADVOPTS")
|
||||
CWindowObject(PLAYER_COLORED, "ADVOPTS")
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
|
||||
<<<<<<< HEAD:client/CAdvmapInterface.cpp
|
||||
exit = new CAdventureMapButton("","",std::bind(&CAdventureOptions::close, this), 204, 313, "IOK6432.DEF",SDLK_RETURN);
|
||||
exit->assignedKeys.insert(SDLK_ESCAPE);
|
||||
|
||||
@ -1542,6 +1571,22 @@ CAdventureOptions::CAdventureOptions():
|
||||
dig = new CAdventureMapButton("","", std::bind(&CAdventureOptions::close, this), 24, 139, "ADVDIG.DEF");
|
||||
if(const CGHeroInstance *h = adventureInt->curHero())
|
||||
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
|
||||
dig->block(true);
|
||||
}
|
@ -1,11 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <typeinfo>
|
||||
#include "../widgets/AdventureMapClasses.h"
|
||||
#include "CWindowObject.h"
|
||||
|
||||
#include "SDL.h"
|
||||
#include "gui/CIntObjectClasses.h"
|
||||
#include "GUIClasses.h"
|
||||
#include "AdventureMapClasses.h"
|
||||
#include "../widgets/TextControls.h"
|
||||
#include "../widgets/Buttons.h"
|
||||
|
||||
class CDefHandler;
|
||||
class CCallback;
|
||||
@ -33,7 +32,7 @@ class IShipyard;
|
||||
class CAdventureOptions : public CWindowObject
|
||||
{
|
||||
public:
|
||||
CAdventureMapButton *exit, *viewWorld, *puzzle, *dig, *scenInfo, *replay;
|
||||
CButton *exit, *viewWorld, *puzzle, *dig, *scenInfo, *replay;
|
||||
|
||||
CAdventureOptions();
|
||||
static void showScenarioInfo();
|
||||
@ -111,16 +110,16 @@ public:
|
||||
CMinimap minimap;
|
||||
CGStatusBar statusbar;
|
||||
|
||||
CAdventureMapButton kingOverview,//- kingdom overview
|
||||
underground,//- underground switch
|
||||
questlog,//- questlog
|
||||
sleepWake, //- sleep/wake hero
|
||||
moveHero, //- move hero
|
||||
spellbook,//- spellbook
|
||||
advOptions, //- adventure options
|
||||
sysOptions,//- system options
|
||||
nextHero, //- next hero
|
||||
endTurn;//- end turn
|
||||
CButton * kingOverview;
|
||||
CButton * underground;
|
||||
CButton * questlog;
|
||||
CButton * sleepWake;
|
||||
CButton * moveHero;
|
||||
CButton * spellbook;
|
||||
CButton * advOptions;
|
||||
CButton * sysOptions;
|
||||
CButton * nextHero;
|
||||
CButton * endTurn;
|
||||
|
||||
CTerrainRect terrain; //visible terrain
|
||||
CResDataBar resdatabar;
|
@ -1,29 +1,36 @@
|
||||
#include "StdInc.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 "CAnimation.h"
|
||||
#include "CBitmapHandler.h"
|
||||
#include "CDefHandler.h"
|
||||
#include "CGameInfo.h"
|
||||
#include "CHeroWindow.h"
|
||||
#include "CMessage.h"
|
||||
#include "CMusicHandler.h"
|
||||
#include "CPlayerInterface.h"
|
||||
#include "Graphics.h"
|
||||
#include "gui/SDL_Extensions.h"
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "gui/CIntObjectClasses.h"
|
||||
#include "CTradeWindow.h"
|
||||
#include "GUIClasses.h"
|
||||
|
||||
#include "../CBitmapHandler.h"
|
||||
#include "../CDefHandler.h"
|
||||
#include "../CGameInfo.h"
|
||||
#include "../CMessage.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;
|
||||
|
||||
@ -836,7 +843,11 @@ void CCastleBuildings::enterTownHall()
|
||||
else
|
||||
{
|
||||
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]->addCallback(boost::bind(&CCastleBuildings::openTownHall, this));
|
||||
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -881,12 +892,21 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, const CGTownInst
|
||||
income = new CLabel(195, 443, FONT_SMALL, CENTER);
|
||||
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 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->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->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);
|
||||
|
||||
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));
|
||||
|
||||
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], "",
|
||||
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);
|
||||
|
||||
auto & boxList = town->town->clientInfo.hallSlots;
|
||||
@ -1403,15 +1427,24 @@ CBuildWindow::CBuildWindow(const CGTownInstance *Town, const CBuilding * Buildin
|
||||
|
||||
if(!rightClick)
|
||||
{ //normal window
|
||||
<<<<<<< HEAD:client/CCastleInterface.cpp
|
||||
buy = new CAdventureMapButton(boost::str(boost::format(CGI->generaltexth->allTexts[595]) % building->Name()),
|
||||
"", 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()),
|
||||
"", 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->borderEnabled = true;
|
||||
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());
|
||||
|
||||
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 CButton(Point(748, 556), "TPMAGE1", CButton::tooltip(text), [&]{ close(); }, SDLK_RETURN);
|
||||
>>>>>>> refactoring/guiClasses:client/windows/CCastleInterface.cpp
|
||||
exit->assignedKeys.insert(SDLK_ESCAPE);
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
|
||||
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);
|
||||
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 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);
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
=======
|
||||
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)
|
||||
buy->callback += [=]{ LOCPLINT->cb->buyArtifact(LOCPLINT->cb->getHero(hid),aid); };
|
||||
buy->addCallback([=]{ LOCPLINT->cb->buyArtifact(LOCPLINT->cb->getHero(hid),aid); });
|
||||
else
|
||||
buy->block(true);
|
||||
|
@ -1,10 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "../widgets/CGarrisonInt.h"
|
||||
#include "../widgets/Images.h"
|
||||
|
||||
#include "CAnimation.h"
|
||||
#include "GUIClasses.h"
|
||||
|
||||
class CAdventureMapButton;
|
||||
class CButton;
|
||||
class CBuilding;
|
||||
class CCastleBuildings;
|
||||
class CCreaturePic;
|
||||
@ -204,8 +203,8 @@ class CCastleInterface : public CWindowObject, public CWindowWithGarrison
|
||||
|
||||
CTownInfo *hall, *fort;
|
||||
|
||||
CAdventureMapButton *exit;
|
||||
CAdventureMapButton *split;
|
||||
CButton *exit;
|
||||
CButton *split;
|
||||
|
||||
std::vector<CCreaInfo*> creainfo;//small icons of creatures (bottom-left corner);
|
||||
|
||||
@ -261,7 +260,7 @@ class CHallInterface : public CWindowObject
|
||||
CLabel *title;
|
||||
CGStatusBar *statusBar;
|
||||
CMinorResDataBar * resdatabar;
|
||||
CAdventureMapButton *exit;
|
||||
CButton *exit;
|
||||
|
||||
public:
|
||||
CHallInterface(const CGTownInstance * Town); //c-tor
|
||||
@ -273,8 +272,8 @@ class CBuildWindow: public CWindowObject
|
||||
const CGTownInstance *town;
|
||||
const CBuilding *building;
|
||||
|
||||
CAdventureMapButton *buy;
|
||||
CAdventureMapButton *cancel;
|
||||
CButton *buy;
|
||||
CButton *cancel;
|
||||
|
||||
std::string getTextForState(int state);
|
||||
void buyFunc();
|
||||
@ -329,7 +328,7 @@ class CFortScreen : public CWindowObject
|
||||
std::vector<RecruitArea*> recAreas;
|
||||
CMinorResDataBar * resdatabar;
|
||||
CGStatusBar *statusBar;
|
||||
CAdventureMapButton *exit;
|
||||
CButton *exit;
|
||||
|
||||
std::string getBgName(const CGTownInstance *town);
|
||||
|
||||
@ -354,7 +353,7 @@ class CMageGuildScreen : public CWindowObject
|
||||
void hover(bool on);
|
||||
};
|
||||
CPicture *window;
|
||||
CAdventureMapButton *exit;
|
||||
CButton *exit;
|
||||
std::vector<Scroll *> spells;
|
||||
CMinorResDataBar * resdatabar;
|
||||
CGStatusBar *statusBar;
|
||||
@ -366,7 +365,7 @@ public:
|
||||
/// The blacksmith window where you can buy available in town war machine
|
||||
class CBlacksmithDialog : public CWindowObject
|
||||
{
|
||||
CAdventureMapButton *buy, *cancel;
|
||||
CButton *buy, *cancel;
|
||||
CPicture *animBG;
|
||||
CCreatureAnim * anim;
|
||||
CLabel * title;
|
871
client/windows/CCreatureWindow.cpp
Normal 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));
|
||||
}
|
||||
}
|
120
client/windows/CCreatureWindow.h
Normal 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();
|
||||
};
|
@ -1,34 +1,34 @@
|
||||
#include "StdInc.h"
|
||||
|
||||
#include "CAnimation.h"
|
||||
#include "CAdvmapInterface.h"
|
||||
#include "../CCallback.h"
|
||||
#include "CGameInfo.h"
|
||||
#include "CHeroWindow.h"
|
||||
#include "CMessage.h"
|
||||
#include "CKingdomInterface.h"
|
||||
|
||||
#include "CAdvmapInterface.h"
|
||||
#include "CCreatureWindow.h"
|
||||
#include "SDL.h"
|
||||
#include "gui/SDL_Extensions.h"
|
||||
#include "CBitmapHandler.h"
|
||||
#include "Graphics.h"
|
||||
#include "CKingdomInterface.h"
|
||||
#include "CSpellWindow.h"
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "CPlayerInterface.h"
|
||||
#include "GUIClasses.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 "CDefHandler.h"
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "../lib/CHeroHandler.h"
|
||||
#include "../lib/mapObjects/CGHeroInstance.h"
|
||||
#include "../lib/NetPacksBase.h"
|
||||
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "gui/CIntObjectClasses.h"
|
||||
#include "CMT.h"
|
||||
|
||||
#undef min
|
||||
|
||||
/*
|
||||
* CHeroWindow.cpp, part of VCMI engine
|
||||
*
|
||||
@ -93,8 +93,11 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero):
|
||||
CWindowObject(PLAYER_COLORED, "HeroScr4"),
|
||||
heroWArt(this, hero)
|
||||
{
|
||||
auto & heroscrn = CGI->generaltexth->heroscrn;
|
||||
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
garr = nullptr;
|
||||
tacticsButton = nullptr;
|
||||
curHero = hero;
|
||||
listSelection = nullptr;
|
||||
|
||||
@ -103,23 +106,32 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero):
|
||||
//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);
|
||||
|
||||
<<<<<<< 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->assignedKeys.insert(SDLK_ESCAPE);
|
||||
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);
|
||||
=======
|
||||
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->addButton(map_list_of(0,CGI->generaltexth->heroscrn[23]),CGI->generaltexth->heroscrn[29], "hsbtns6.def", 481, 483, 0, 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);
|
||||
|
||||
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);
|
||||
formations = new CToggleGroup(0);
|
||||
formations->addToggle(0, new CToggleButton(Point(481, 483), "hsbtns6.def", std::make_pair(heroscrn[23], heroscrn[29]), 0, SDLK_t));
|
||||
formations->addToggle(1, new CToggleButton(Point(481, 519), "hsbtns7.def", std::make_pair(heroscrn[24], heroscrn[30]), 0, SDLK_l));
|
||||
|
||||
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);
|
||||
=======
|
||||
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
|
||||
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)));
|
||||
@ -180,7 +192,9 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero):
|
||||
}
|
||||
|
||||
void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= false*/)
|
||||
{
|
||||
{
|
||||
auto & heroscrn = CGI->generaltexth->heroscrn;
|
||||
|
||||
if(!hero) //something strange... no hero? it shouldn't happen
|
||||
{
|
||||
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;
|
||||
specImage->setFrame(curHero->type->imageIndex);
|
||||
|
||||
tacticsButton->callback.clear();
|
||||
tacticsButton->callback2.clear();
|
||||
delete tacticsButton;
|
||||
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->text = curHero->getBiography();
|
||||
portraitImage->setFrame(curHero->portrait);
|
||||
@ -204,10 +219,17 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
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);
|
||||
<<<<<<< HEAD:client/CHeroWindow.cpp
|
||||
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
|
||||
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);
|
||||
}
|
||||
@ -239,7 +261,7 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
|
||||
secSkillAreas[g]->type = skill;
|
||||
secSkillAreas[g]->bonusValue = level;
|
||||
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);
|
||||
}
|
||||
|
||||
@ -274,14 +296,19 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
|
||||
else
|
||||
{
|
||||
tacticsButton->block(false);
|
||||
tacticsButton->callback = vstd::assigno(curHero->tacticFormationEnabled,true);
|
||||
tacticsButton->callback2 = vstd::assigno(curHero->tacticFormationEnabled,false);
|
||||
tacticsButton->addCallback( [&](bool on) {curHero->tacticFormationEnabled = on;});
|
||||
|
||||
}
|
||||
|
||||
//setting formations
|
||||
<<<<<<< HEAD:client/CHeroWindow.cpp
|
||||
formations->onChange = 0;
|
||||
formations->select(curHero->formation,true);
|
||||
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);
|
||||
luck->set(&heroWArt);
|
||||
@ -328,7 +355,7 @@ void CHeroWindow::commanderWindow()
|
||||
}
|
||||
}
|
||||
else
|
||||
GH.pushInt(new CCreatureWindow (curHero->commander));
|
||||
GH.pushInt(new CStackWindow(curHero->commander, false));
|
||||
|
||||
}
|
||||
|