4 #include "imgui_impl_sdl.h"
5 #include "imgui_impl_sdlrenderer.h"
13 #include "../engine/ResourcesManager.hxx"
20 auto main_button = [
this](
const char *tx,
const char *id)
22 m_buttons.emplace_back(std::make_shared<BuildMenuButton>(tx,
id));
27 auto constrution = main_button(
"Button_ConstructionMenu",
"Construction");
28 constrution->addActionButton(
"Button_ConstructionMenu_Demolish",
"Demolish",
"Demolish");
29 constrution->addActionButton(
"Button_ConstructionMenu_RaiseTerrain",
"RaiseTerrain",
"Raise Terrain");
30 constrution->addActionButton(
"Button_ConstructionMenu_LowerTerrain",
"LowerTerrain",
"Lower Terrain");
31 constrution->addActionButton(
"Button_ConstructionMenu_LevelTerrain",
"LevelTerrain",
"Level Terrain");
32 constrution->addActionButton(
"Button_ConstructionMenu_DeZone",
"DeZone",
"De-zone");
33 constrution->addActionButton(
"Button_ConstructionMenu_Water",
"Water",
"Water");
36 main_button(
"Button_NatureMenu",
"Nature");
37 main_button(
"Button_RoadsMenu",
"Roads");
38 main_button(
"Button_ZonesMenu",
"Zones");
39 main_button(
"Button_RecreationMenu",
"Recreation");
40 main_button(
"Button_PowerMenu",
"Power");
41 main_button(
"Button_WaterMenu",
"Waterworks");
42 main_button(
"Button_EmergencyMenu",
"Emergency");
43 main_button(
"Button_DebugMenu",
"Debug");
47 SDL_QueryTexture(
m_buttons.front()->m_tex,
nullptr,
nullptr, &size.w, &size.h);
55 float getItemSpan(
int deep) {
return deep == 0 ? 16.f : 6.f; }
59 template <
class Holder>
void drawSubmenu(ImVec2 pos,
float categoryOffset,
const Holder &holder,
BuildMenu *menu,
int deep)
61 if (holder.getButtons().empty())
64 const ImVec2 &frameSize = holder.getButtons().front()->getBtnSize();
66 ImVec2 screenSize = ui::GetIO().DisplaySize;
73 ImVec2 nextOffset{0, 0};
77 windowSize = verticalMenu ? ImVec2(frameSize.x, frameFullWidth * (
float)holder.getButtons().size())
78 : ImVec2(frameFullWidth * (
float)holder.getButtons().size(), frameSize.y);
80 switch (uiManager.buildMenuLayout())
83 nextOffset.y = -categoryOffset;
86 nextOffset.y = +categoryOffset;
89 nextOffset.x = categoryOffset;
92 nextOffset.x = -categoryOffset;
95 const auto &layout = uiManager.getLayouts()[
"BuildMenuButtons"];
97 ui::SetNextWindowPos(pos);
98 ui::SetNextWindowSize(windowSize);
101 ui::PushFont(layout.font);
102 ui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
103 ui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2{0, 0});
104 ui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{0, 0});
105 ui::PushStyleVar(ImGuiStyleVar_ItemSpacing, itemSpacing);
111 ui::Begin(wId.c_str(), &open,
112 ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoScrollbar |
113 ImGuiWindowFlags_NoScrollWithMouse);
116 ui::PushClipRect(ImVec2{0, 0}, screenSize,
false);
121 std::array<char, 128> id_str = {0};
122 for (
auto btn : holder.getButtons())
124 snprintf(id_str.data(), 128,
"%s_%d", holder.getId().c_str(), ++idx);
126 ImVec2 imgPos{btn->m_destRect.x, btn->m_destRect.y};
127 ImVec2 imgSize{btn->m_destRect.z, btn->m_destRect.w};
130 ImGuiButtonFlags flags = btn->m_open ? ImGuiButtonFlags_ForcePressed : 0;
131 flags |= btn->m_background ? 0 : ImGuiButtonFlags_NoBackground;
133 if (ui::ImageButtonCt(btn->m_tex, flags, frameSize, imgPos, imgSize, btn->m_uv0, btn->m_uv1, -1, ImVec4(0, 0, 0, 0)))
135 btn->m_open = !btn->m_open;
140 if (ui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && ui::GetHoveredTimer() > menu->
getTooltipDelay())
142 ui::SetTooltip(btn->getId().c_str());
146 if (btn->m_open && !btn->getButtons().empty())
149 const ImVec2 &nextFrameSize = btn->getButtons().front()->getBtnSize();
150 const float nextFrameFullWidth = (verticalMenu ? nextFrameSize.y : nextFrameSize.x) +
detail::getItemSpan(deep + 1);
151 const float nextCategoryOffset = (nextFrameFullWidth * (float)btn->getButtons().size()) / 2;
153 switch (uiManager.buildMenuLayout())
156 nextPos.x = ui::GetCursorScreenPos().x + ((float)(idx - 1) * frameFullWidth) - nextCategoryOffset + frameFullWidth / 2;
157 nextPos.y = pos.y - nextFrameFullWidth;
160 nextPos.x = ui::GetCursorScreenPos().x + ((float)(idx - 1) * frameFullWidth) - nextCategoryOffset + frameFullWidth / 2;
165 nextPos.y = ui::GetCursorScreenPos().y - nextCategoryOffset - frameFullWidth / 2;
168 nextPos.x = pos.x - nextFrameFullWidth;
169 nextPos.y = ui::GetCursorScreenPos().y - nextCategoryOffset - frameFullWidth / 2;
189 drawSubmenu(nextPos, frameSize.y + 10.f, *nextMenuLevel, menu, deep + 1);
195 ImVec2 screenSize = ui::GetIO().DisplaySize;
196 auto _self =
const_cast<BuildMenu *
>(
this);
201 const float buttonsSize = (float)
m_buttons.size();
203 switch (uiManager.buildMenuLayout())
206 pos = {(screenSize.x - buttonsSize * frameSize) / 2, screenSize.y -
m_btnSize.y};
209 pos = ImVec2{(screenSize.x - buttonsSize * frameSize) / 2, 0};
212 pos = ImVec2{0, (screenSize.y - buttonsSize * frameSize) / 2};
215 pos = {screenSize.x -
m_btnSize.x, (screenSize.y - buttonsSize * frameSize) / 2};
223 auto debugBtnIt = std::find_if(
m_buttons.begin(),
m_buttons.end(), [](
auto &btn) { return btn->getId() ==
"Debug"; });
229 std::map<std::string, BuildMenuButton::Ptr> categories;
232 categories[btn->getId()] = btn;
239 (tileData.subCategory == tileData.category) ? (tileData.category +
"_" + tileData.subCategory) : tileData.subCategory;
241 const std::string &tooltip = !title.empty() ? title : subCategory.empty() ? category : subCategory;
244 if (category ==
"Water" || category ==
"Terrain")
249 if (!subCategory.empty())
251 auto it = categories.find(subCategory);
252 if (it == categories.end())
254 auto category_it = categories.find(category);
256 if (category_it == categories.end())
258 btn = (*debugBtnIt)->addCategoryButton(tx, tooltip, tileData);
259 categories[category] = btn;
263 btn = category_it->second;
266 auto subBtn = btn->addCategoryButton(tx, tooltip, tileData);
267 categories[subCategory] = subBtn;
269 subBtn->addTileButton(tx, tooltip, tileData);
273 it->second->addTileButton(tx, tooltip, tileData);
278 auto it = categories.find(category);
279 if (it == categories.end())
281 auto btn = (*debugBtnIt)->addTileButton(tx, tooltip, tileData);
282 categories[category] = btn;
286 it->second->addTileButton(tx, tooltip, tileData);
296 for (
auto it : btn->getButtons())
321 if (!btn->m_action.empty())
323 onAction(btn->m_action, btn->m_open);
326 const bool hasAction = !btn->m_tiletype.empty();
327 const bool isCategoryButton = btn->getButtons().size() > 0;
328 if (hasAction && !isCategoryButton)
336 if (action ==
"Demolish")
347 else if (action ==
"LowerTerrain")
352 else if (action ==
"RaiseTerrain")
357 else if (action ==
"LevelTerrain")
362 else if (action ==
"DeZone")
372 else if (action ==
"underground_pipes")
376 else if (action ==
"Water")
391 if (actionParameter.empty())
416 case +TileType::AUTOTILE:
417 case +TileType::POWERLINE:
421 case +TileType::GROUNDDECORATION:
466 : m_background(true), m_texstr(tx), m_id(id), m_tiletype(tx)
480 m_destRect = ImVec4((
float)destRect.x, (
float)destRect.y, (
float)destRect.w, (
float)destRect.h);
486 auto btn = std::make_shared<BuildMenuButton>(tx, action);
488 btn->m_background =
true;
489 btn->m_parent =
this;
490 btn->m_action = action;
497 auto btn = std::make_shared<BuildMenuButton>(tx,
id, tile);
498 btn->m_parent =
this;
507 float ratio = (float)imgH / (
float)imgW;
509 ret.h =
static_cast<int>(ceil((
float)btnH * ratio));
511 ret.y = btnH - ret.h;
515 float ratio = (float)imgW / (
float)imgH;
516 ret.w =
static_cast<int>(ceil((
float)btnW * ratio));
518 ret.x =
static_cast<int>(ceil(((
float)(btnW - ret.w)) / 2));