1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-09-16 09:26:28 +02:00

Merge pull request #4210 from Laserlicht/graphics_improvements

[1.6] Graphics improvements
This commit is contained in:
Ivan Savenko
2024-07-16 12:17:39 +03:00
committed by GitHub
4 changed files with 137 additions and 66 deletions

View File

@@ -402,7 +402,7 @@ void OptionsTab::CPlayerOptionTooltipBox::genBonusWindow()
textBonusDescription = std::make_shared<CTextBox>(getDescription(), Rect(10, 100, pos.w - 20, 70), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
}
OptionsTab::SelectionWindow::SelectionWindow(const PlayerColor & color, SelType _type)
OptionsTab::SelectionWindow::SelectionWindow(const PlayerColor & color, SelType _type, int sliderPos)
: CWindowObject(BORDERED), color(color)
{
addUsedEvents(LCLICK | SHOW_POPUP);
@@ -434,15 +434,18 @@ OptionsTab::SelectionWindow::SelectionWindow(const PlayerColor & color, SelType
if(initialFaction.isValid())
allowedBonus.push_back(PlayerStartingBonus::RESOURCE);
recreate();
recreate(sliderPos);
}
int OptionsTab::SelectionWindow::calcLines(FactionID faction)
std::tuple<int, int> OptionsTab::SelectionWindow::calcLines(FactionID faction)
{
double additionalItems = 1; // random
int additionalItems = 1; // random
if(!faction.isValid())
return std::ceil(((double)allowedFactions.size() + additionalItems) / elementsPerLine);
return std::make_tuple(
std::ceil(((double)allowedFactions.size() + additionalItems) / MAX_ELEM_PER_LINES),
(allowedFactions.size() + additionalItems) % MAX_ELEM_PER_LINES
);
int count = 0;
for(auto & elemh : allowedHeroes)
@@ -452,7 +455,10 @@ int OptionsTab::SelectionWindow::calcLines(FactionID faction)
count++;
}
return std::ceil(std::max((double)count + additionalItems, (double)allowedFactions.size() + additionalItems) / (double)elementsPerLine);
return std::make_tuple(
std::ceil(((double)count + additionalItems) / MAX_ELEM_PER_LINES),
(count + additionalItems) % MAX_ELEM_PER_LINES
);
}
void OptionsTab::SelectionWindow::apply()
@@ -482,13 +488,17 @@ void OptionsTab::SelectionWindow::setSelection()
void OptionsTab::SelectionWindow::reopen()
{
auto window = std::shared_ptr<SelectionWindow>(new SelectionWindow(color, type));
close();
if(CSH->isMyColor(color) || CSH->isHost())
GH.windows().pushWindow(window);
if(type == SelType::HERO && SEL->getStartInfo()->playerInfos.find(color)->second.castle == FactionID::RANDOM)
close();
else{
auto window = std::shared_ptr<SelectionWindow>(new SelectionWindow(color, type, slider ? slider->getValue() : 0));
close();
if(CSH->isMyColor(color) || CSH->isHost())
GH.windows().pushWindow(window);
}
}
void OptionsTab::SelectionWindow::recreate()
void OptionsTab::SelectionWindow::recreate(int sliderPos)
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
@@ -497,32 +507,19 @@ void OptionsTab::SelectionWindow::recreate()
elementsPerLine = allowedBonus.size();
else
{
// try to make squarish
if(type == SelType::TOWN)
elementsPerLine = floor(sqrt(allowedFactions.size()));
if(type == SelType::HERO)
{
int count = 0;
for(auto & elem : allowedHeroes)
{
const CHero * type = elem.toHeroType();
if(type->heroClass->faction == selectedFaction)
{
count++;
}
}
elementsPerLine = floor(sqrt(count));
}
amountLines = calcLines((type > SelType::TOWN) ? selectedFaction : FactionID::RANDOM);
std::tie(amountLines, elementsPerLine) = calcLines((type > SelType::TOWN) ? selectedFaction : FactionID::RANDOM);
if(amountLines > 1 || elementsPerLine == 0)
elementsPerLine = MAX_ELEM_PER_LINES;
}
int x = (elementsPerLine) * (ICON_BIG_WIDTH-1);
int y = (amountLines) * (ICON_BIG_HEIGHT-1);
int y = (std::min(amountLines, MAX_LINES)) * (ICON_BIG_HEIGHT-1);
pos = Rect(0, 0, x, y);
int sliderWidth = ((amountLines > MAX_LINES) ? 16 : 0);
backgroundTexture = std::make_shared<FilledTexturePlayerColored>(ImagePath::builtin("DiBoxBck"), pos);
pos = Rect(pos.x, pos.y, x + sliderWidth, y);
backgroundTexture = std::make_shared<FilledTexturePlayerColored>(ImagePath::builtin("DiBoxBck"), Rect(0, 0, pos.w - sliderWidth, pos.h));
backgroundTexture->playerColored(PlayerColor(1));
updateShadow();
@@ -532,7 +529,15 @@ void OptionsTab::SelectionWindow::recreate()
genContentHeroes();
if(type == SelType::BONUS)
genContentBonus();
genContentGrid(amountLines);
genContentGrid(std::min(amountLines, MAX_LINES));
if(!slider && amountLines > MAX_LINES)
{
slider = std::make_shared<CSlider>(Point(x, 0), y, std::bind(&OptionsTab::SelectionWindow::sliderMove, this, _1), MAX_LINES, amountLines, 0, Orientation::VERTICAL, CSlider::BLUE);
slider->setPanningStep(ICON_BIG_HEIGHT);
slider->setScrollBounds(Rect(-pos.w + slider->pos.w, 0, x + slider->pos.w, y));
slider->scrollTo(sliderPos);
}
center();
}
@@ -570,22 +575,26 @@ void OptionsTab::SelectionWindow::genContentFactions()
if(selectedFaction == FactionID::RANDOM)
components.push_back(std::make_shared<CPicture>(ImagePath::builtin("lobby/townBorderSmallActivated"), 6, (ICON_SMALL_HEIGHT/2)));
factions.clear();
for(auto & elem : allowedFactions)
{
int x = i % elementsPerLine;
int y = i / elementsPerLine;
int y = (i / elementsPerLine) - (slider ? slider->getValue() : 0);
PlayerSettings set = PlayerSettings();
set.castle = elem;
CPlayerSettingsHelper helper = CPlayerSettingsHelper(set, SelType::TOWN);
factions.push_back(elem);
i++;
if(y < 0 || y > MAX_LINES - 1)
continue;
components.push_back(std::make_shared<CAnimImage>(helper.getImageName(true), helper.getImageIndex(true), 0, x * (ICON_BIG_WIDTH-1), y * (ICON_BIG_HEIGHT-1)));
components.push_back(std::make_shared<CPicture>(ImagePath::builtin(selectedFaction == elem ? "lobby/townBorderBigActivated" : "lobby/townBorderBig"), x * (ICON_BIG_WIDTH-1), y * (ICON_BIG_HEIGHT-1)));
drawOutlinedText(x * (ICON_BIG_WIDTH-1) + TEXT_POS_X, y * (ICON_BIG_HEIGHT-1) + TEXT_POS_Y, (selectedFaction == elem) ? Colors::YELLOW : Colors::WHITE, helper.getName());
factions.push_back(elem);
i++;
}
}
@@ -602,33 +611,36 @@ void OptionsTab::SelectionWindow::genContentHeroes()
if(selectedHero == HeroTypeID::RANDOM)
components.push_back(std::make_shared<CPicture>(ImagePath::builtin("lobby/townBorderSmallActivated"), 6, (ICON_SMALL_HEIGHT/2)));
heroes.clear();
for(auto & elem : allowedHeroes)
{
const CHero * type = elem.toHeroType();
if(type->heroClass->faction == selectedFaction)
{
if(type->heroClass->faction != selectedFaction)
continue;
int x = i % elementsPerLine;
int y = i / elementsPerLine;
int x = i % elementsPerLine;
int y = (i / elementsPerLine) - (slider ? slider->getValue() : 0);
PlayerSettings set = PlayerSettings();
set.hero = elem;
PlayerSettings set = PlayerSettings();
set.hero = elem;
CPlayerSettingsHelper helper = CPlayerSettingsHelper(set, SelType::HERO);
CPlayerSettingsHelper helper = CPlayerSettingsHelper(set, SelType::HERO);
components.push_back(std::make_shared<CAnimImage>(helper.getImageName(true), helper.getImageIndex(true), 0, x * (ICON_BIG_WIDTH-1), y * (ICON_BIG_HEIGHT-1)));
drawOutlinedText(x * (ICON_BIG_WIDTH-1) + TEXT_POS_X, y * (ICON_BIG_HEIGHT-1) + TEXT_POS_Y, (selectedHero == elem) ? Colors::YELLOW : Colors::WHITE, helper.getName());
ImagePath image = ImagePath::builtin("lobby/townBorderBig");
if(selectedHero == elem)
image = ImagePath::builtin("lobby/townBorderBigActivated");
if(unusableHeroes.count(elem))
image = ImagePath::builtin("lobby/townBorderBigGrayedOut");
components.push_back(std::make_shared<CPicture>(image, x * (ICON_BIG_WIDTH-1), y * (ICON_BIG_HEIGHT-1)));
heroes.push_back(elem);
heroes.push_back(elem);
i++;
i++;
}
if(y < 0 || y > MAX_LINES - 1)
continue;
components.push_back(std::make_shared<CAnimImage>(helper.getImageName(true), helper.getImageIndex(true), 0, x * (ICON_BIG_WIDTH-1), y * (ICON_BIG_HEIGHT-1)));
drawOutlinedText(x * (ICON_BIG_WIDTH-1) + TEXT_POS_X, y * (ICON_BIG_HEIGHT-1) + TEXT_POS_Y, (selectedHero == elem) ? Colors::YELLOW : Colors::WHITE, helper.getName());
ImagePath image = ImagePath::builtin("lobby/townBorderBig");
if(selectedHero == elem)
image = ImagePath::builtin("lobby/townBorderBigActivated");
if(unusableHeroes.count(elem))
image = ImagePath::builtin("lobby/townBorderBigGrayedOut");
components.push_back(std::make_shared<CPicture>(image, x * (ICON_BIG_WIDTH-1), y * (ICON_BIG_HEIGHT-1)));
}
}
@@ -659,7 +671,7 @@ void OptionsTab::SelectionWindow::genContentBonus()
int OptionsTab::SelectionWindow::getElement(const Point & cursorPosition)
{
int x = (cursorPosition.x - pos.x) / (ICON_BIG_WIDTH-1);
int y = (cursorPosition.y - pos.y) / (ICON_BIG_HEIGHT-1);
int y = (cursorPosition.y - pos.y) / (ICON_BIG_HEIGHT-1) + (slider ? slider->getValue() : 0);
return x + y * elementsPerLine;
}
@@ -741,6 +753,14 @@ void OptionsTab::SelectionWindow::setElement(int elem, bool doApply)
apply();
}
void OptionsTab::SelectionWindow::sliderMove(int slidPos)
{
if(!slider)
return; // ignore spurious call when slider is being created
recreate();
redraw();
}
bool OptionsTab::SelectionWindow::receiveEvent(const Point & position, int eventType) const
{
return true; // capture click also outside of window
@@ -748,6 +768,9 @@ bool OptionsTab::SelectionWindow::receiveEvent(const Point & position, int event
void OptionsTab::SelectionWindow::clickReleased(const Point & cursorPosition)
{
if(slider && slider->pos.isInside(cursorPosition))
return;
if(!pos.isInside(cursorPosition))
{
close();
@@ -761,7 +784,7 @@ void OptionsTab::SelectionWindow::clickReleased(const Point & cursorPosition)
void OptionsTab::SelectionWindow::showPopupWindow(const Point & cursorPosition)
{
if(!pos.isInside(cursorPosition))
if(!pos.isInside(cursorPosition) || (slider && slider->pos.isInside(cursorPosition)))
return;
int elem = getElement(cursorPosition);

View File

@@ -26,6 +26,7 @@ class CAnimImage;
class CComponentBox;
class CTextBox;
class CButton;
class CSlider;
class FilledTexturePlayerColored;
@@ -105,8 +106,13 @@ private:
const int TEXT_POS_X = 29;
const int TEXT_POS_Y = 56;
const int MAX_LINES = 5;
const int MAX_ELEM_PER_LINES = 5;
int elementsPerLine;
std::shared_ptr<CSlider> slider;
PlayerColor color;
SelType type;
@@ -134,13 +140,15 @@ private:
void genContentBonus();
void drawOutlinedText(int x, int y, ColorRGBA color, std::string text);
int calcLines(FactionID faction);
std::tuple<int, int> calcLines(FactionID faction);
void apply();
void recreate();
void recreate(int sliderPos = 0);
void setSelection();
int getElement(const Point & cursorPosition);
void setElement(int element, bool doApply);
void sliderMove(int slidPos);
bool receiveEvent(const Point & position, int eventType) const override;
void clickReleased(const Point & cursorPosition) override;
void showPopupWindow(const Point & cursorPosition) override;
@@ -148,7 +156,7 @@ private:
public:
void reopen();
SelectionWindow(const PlayerColor & color, SelType _type);
SelectionWindow(const PlayerColor & color, SelType _type, int sliderPos = 0);
};
/// Image with current town/hero/bonus

View File

@@ -669,15 +669,50 @@ CTavernWindow::HeroSelector::HeroSelector(std::map<HeroTypeID, CGHeroInstance*>
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
pos = Rect(0, 0, 16 * 48, (inviteableHeroes.size() / 16 + (inviteableHeroes.size() % 16 != 0)) * 32);
pos = Rect(
pos.x,
pos.y,
ELEM_PER_LINES * 48,
std::min((int)(inviteableHeroes.size() / ELEM_PER_LINES + (inviteableHeroes.size() % ELEM_PER_LINES != 0)), MAX_LINES) * 32
);
background = std::make_shared<CFilledTexture>(ImagePath::builtin("DIBOXBCK"), Rect(0, 0, pos.w, pos.h));
if(inviteableHeroes.size() / ELEM_PER_LINES > MAX_LINES)
{
pos.w += 16;
slider = std::make_shared<CSlider>(Point(pos.w - 16, 0), pos.h, std::bind(&CTavernWindow::HeroSelector::sliderMove, this, _1), MAX_LINES, std::ceil((double)inviteableHeroes.size() / ELEM_PER_LINES), 0, Orientation::VERTICAL, CSlider::BROWN);
slider->setPanningStep(32);
slider->setScrollBounds(Rect(-pos.w + slider->pos.w, 0, pos.w, pos.h));
}
recreate();
center();
}
void CTavernWindow::HeroSelector::sliderMove(int slidPos)
{
if(!slider)
return; // ignore spurious call when slider is being created
recreate();
redraw();
}
void CTavernWindow::HeroSelector::recreate()
{
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
int sliderLine = slider ? slider->getValue() : 0;
int x = 0;
int y = 0;
int y = -sliderLine;
portraits.clear();
portraitAreas.clear();
for(auto & h : inviteableHeroes)
{
portraits.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsSmall"), (*CGI->heroh)[h.first]->imageIndex, 0, x * 48, y * 32));
portraitAreas.push_back(std::make_shared<LRClickableArea>(Rect(x * 48, y * 32, 48, 32), [this, h](){ close(); onChoose(inviteableHeroes[h.first]); }, [this, h](){ GH.windows().createAndPushWindow<CRClickPopupInt>(std::make_shared<CHeroWindow>(inviteableHeroes[h.first])); }));
if(y >= 0 && y <= MAX_LINES - 1)
{
portraits.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsSmall"), (*CGI->heroh)[h.first]->imageIndex, 0, x * 48, y * 32));
portraitAreas.push_back(std::make_shared<LRClickableArea>(Rect(x * 48, y * 32, 48, 32), [this, h](){ close(); onChoose(inviteableHeroes[h.first]); }, [this, h](){ GH.windows().createAndPushWindow<CRClickPopupInt>(std::make_shared<CHeroWindow>(inviteableHeroes[h.first])); }));
}
if(x > 0 && x % 15 == 0)
{
@@ -687,8 +722,6 @@ CTavernWindow::HeroSelector::HeroSelector(std::map<HeroTypeID, CGHeroInstance*>
else
x++;
}
center();
}
CShipyardWindow::CShipyardWindow(const TResources & cost, int state, BoatId boatType, const std::function<void()> & onBuy)

View File

@@ -238,6 +238,10 @@ public:
{
public:
std::shared_ptr<CFilledTexture> background;
std::shared_ptr<CSlider> slider;
const int MAX_LINES = 18;
const int ELEM_PER_LINES = 16;
HeroSelector(std::map<HeroTypeID, CGHeroInstance*> InviteableHeroes, std::function<void(CGHeroInstance*)> OnChoose);
@@ -247,6 +251,9 @@ public:
std::vector<std::shared_ptr<CAnimImage>> portraits;
std::vector<std::shared_ptr<LRClickableArea>> portraitAreas;
void recreate();
void sliderMove(int slidPos);
};
//recruitable heroes