From ee13be56d77191d0f10ec064c2a4bb809a65d323 Mon Sep 17 00:00:00 2001 From: shweet Date: Fri, 13 Nov 2026 00:11:24 -0500 Subject: [PATCH] Select screen with a centered preview and a portrait taskbar --- MODDING.md | 2 +- resources/common/gfx/ui/icons.anm2 | 3 +- resources/common/gfx/ui/icons.png | Bin 14846 -> 15733 bytes src/character.cpp | 2 - src/character.h | 2 + src/main.cpp | 1 + src/ui.cpp | 308 ++++++++++++++--------------- src/ui.h | 11 +- 8 files changed, 168 insertions(+), 161 deletions(-) diff --git a/MODDING.md b/MODDING.md index bd5007c..8dea5d9 100644 --- a/MODDING.md +++ b/MODDING.md @@ -32,7 +32,7 @@ There's two folders inside resources; "characters" and "font". "font" holds the one font the whole game uses (Mali, under the SIL Open Font License; see its LICENSE.txt). -"common" holds files characters share (sounds, particles, the cursor and so on). Whenever a character names a file, the game looks in the character's folder first, then in "common", so a character can use anything there as is, or replace it by having its own file at the same path. This includes the taskbar's icons, `gfx/ui/icons.anm2`: one region per icon, named after its button (`talk`, `mood`, `spawn`, `autofeed`, `home`, `stats`, `catalog`, `settings`, `cheats`, `help`, plus whatever `icon`s the interaction types name). A character with its own `gfx/ui/icons.anm2` gets its own icons. +"common" holds files characters share (sounds, particles, the cursor and so on). Whenever a character names a file, the game looks in the character's folder first, then in "common", so a character can use anything there as is, or replace it by having its own file at the same path. This includes the taskbar's icons, `gfx/ui/icons.anm2`: one region per icon, named after its button (`talk`, `mood`, `spawn`, `autofeed`, `home`, `stats`, `catalog`, `settings`, `cheats`, `help`, `credits`, plus whatever `icon`s the interaction types name). A character with its own `gfx/ui/icons.anm2` gets its own icons. EVERYTHING ELSE is stored inside character folders in the "characters" folder; one folder per character, named however you like (the folder name is also the name of its save file). This has all data associated with characters. Think of characters more as tailored game experiences rather than literally being just the characters. Not only is there the character graphics, but backgrounds, items, parameters, etc. These are intensely customizable to suit whatever experience you'd like (within the confines of the engine, of course). diff --git a/resources/common/gfx/ui/icons.anm2 b/resources/common/gfx/ui/icons.anm2 index d461948..29c68f4 100644 --- a/resources/common/gfx/ui/icons.anm2 +++ b/resources/common/gfx/ui/icons.anm2 @@ -18,7 +18,8 @@ {"name": "settings", "crop": [195, 65], "size": [64, 64], "origin": "center"}, {"name": "help", "crop": [260, 65], "size": [64, 64], "origin": "center"}, {"name": "close", "crop": [325, 65], "size": [64, 64], "origin": "center"}, - {"name": "cheats", "crop": [390, 65], "size": [64, 64], "origin": "center"} + {"name": "cheats", "crop": [390, 65], "size": [64, 64], "origin": "center"}, + {"name": "credits", "crop": [455, 65], "size": [64, 64], "origin": "center"} ] } ], diff --git a/resources/common/gfx/ui/icons.png b/resources/common/gfx/ui/icons.png index 65396ec9c1cd2a83f5ca1e73a6737254417f72b9..516af139ec97f9412287194eae8911a7634a3c26 100644 GIT binary patch literal 15733 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 : nullptr; + Anm2* icons = character && character->icons ? character->icons : &iconsDefault; const Anm2Region* region = icons ? icons->region_get(0, name) : nullptr; Texture* sheet = region && !icons->sheets.empty() ? icons->sheets[0] : nullptr; if (!sheet) @@ -446,10 +450,10 @@ static void cooldown_draw(float progress) } } -void Ui::window_open(Play& play, Panel next) +void Ui::sound_play(SoundId id) { - panel = next; - play.audio->play(play.character->sounds[SOUND_OPEN]); + if (character) + audio->play(character->sounds[id]); } // The bar along the bottom: the character's name and body at a glance, then a button for everything. A thin bar above @@ -618,7 +622,7 @@ void Ui::taskbar_draw(Play& play, ImVec2 screen) continue; ImGui::SameLine(); if (icon_button(PANEL_ICONS[each], PANEL_NAMES[each], BUTTON_NORMAL)) - window_open(play, each); + panel = each; } ImGui::SameLine(); if (icon_button("help", "Help", state_get(dialogue.is_hook(HOOK_HELP)))) @@ -946,49 +950,46 @@ void Ui::catalog_draw(Play& play) style_pop(); } -// The open window (stats, catalog, settings or cheats): one at a time, fixed in size above the taskbar, closed by its -// X, escape or a click off it, and holding the mouse while open. -void Ui::window_draw(Play& play, Settings& settings, ImVec2 screen) +// Starts the open window (one at a time, from the taskbar), fixed in size above the bottom inset. Its contents follow, +// then window_end. +bool Ui::window_begin(ImVec2 screen, float inset) { - if (play.text.isScene) - panel = PANEL_NONE; - play.isBlocked = panel != PANEL_NONE; if (panel == PANEL_NONE) - return; + return false; const char* title = PANEL_NAMES[panel]; - float above = screen.y - play.inset - TOGGLE_HEIGHT; + float above = screen.y - inset - TOGGLE_HEIGHT; ImVec2 size = {std::min(WINDOW_WIDTH, screen.x * WINDOW_FIT), std::min(WINDOW_HEIGHT, above * WINDOW_FIT)}; ImGui::SetNextWindowSize(size); ImGui::SetNextWindowPos({screen.x / 2, above / 2}, ImGuiCond_Always, {0.5f, 0.5f}); if (!ImGui::IsPopupOpen(title)) - ImGui::OpenPopup(title); - bool isOpen = true; - if (ImGui::BeginPopupModal(title, &isOpen, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove)) { - if (panel == PANEL_STATS) - stats_draw(play); - else if (panel == PANEL_CATALOG) - catalog_draw(play); - else if (panel == PANEL_CHEATS) - cheats_draw(play); - else - settings_draw(settings); - ImVec2 min = ImGui::GetWindowPos(); - ImVec2 max = {min.x + ImGui::GetWindowWidth(), min.y + ImGui::GetWindowHeight()}; - bool isFocused = ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy); - bool isClickedOff = - isFocused && ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGui::IsMouseHoveringRect(min, max, false); - if (ImGui::IsKeyPressed(ImGuiKey_Escape) || isClickedOff) - { - isOpen = false; - ImGui::CloseCurrentPopup(); - } - ImGui::EndPopup(); + ImGui::OpenPopup(title); + sound_play(SOUND_OPEN); } - if (isOpen) - return; + isWindowOpen = true; + if (ImGui::BeginPopupModal(title, &isWindowOpen, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove)) + return true; panel = PANEL_NONE; - play.audio->play(play.character->sounds[SOUND_CLOSE]); + return false; +} + +// Ends the open window, closing it on its X, escape or a click off it. +void Ui::window_end() +{ + ImVec2 min = ImGui::GetWindowPos(); + ImVec2 max = {min.x + ImGui::GetWindowWidth(), min.y + ImGui::GetWindowHeight()}; + bool isFocused = ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy); + bool isClickedOff = + isFocused && ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGui::IsMouseHoveringRect(min, max, false); + if (ImGui::IsKeyPressed(ImGuiKey_Escape) || isClickedOff) + isWindowOpen = false; + if (!isWindowOpen) + { + ImGui::CloseCurrentPopup(); + panel = PANEL_NONE; + sound_play(SOUND_CLOSE); + } + ImGui::EndPopup(); } void Ui::play_update(Play& play, Settings& settings) @@ -1004,15 +1005,29 @@ void Ui::play_update(Play& play, Settings& settings) taskbar_draw(play, screen); toasts_draw(play); text_draw(play, screen); - window_draw(play, settings, screen); + if (play.text.isScene) + panel = PANEL_NONE; + play.isBlocked = panel != PANEL_NONE; + if (!window_begin(screen, play.inset)) + return; + if (panel == PANEL_STATS) + stats_draw(play); + else if (panel == PANEL_CATALOG) + catalog_draw(play); + else if (panel == PANEL_CHEATS) + cheats_draw(play); + else + settings_draw(settings); + window_end(); } void Ui::select_update(std::vector& characters, Settings& settings) { ImGuiStyle& style = ImGui::GetStyle(); ImVec2 screen = ImGui::GetIO().DisplaySize; - ImVec2 half = {screen.x / 2 - style.WindowPadding.x * 2, screen.y / 2 - style.WindowPadding.y * 2}; character = nullptr; + measurement = &settings.measurement; + buttonSize = SELECT_BUTTON_SIZE; characterIndex = characters.empty() ? -1 : std::clamp(characterIndex, 0, (int)characters.size() - 1); Character* selected = characterIndex >= 0 ? &characters[characterIndex] : nullptr; if (selected && selectedIndex != characterIndex) @@ -1022,88 +1037,111 @@ void Ui::select_update(std::vector& characters, Settings& settings) selectedIndex = characterIndex; } + int count = (int)characters.size() + SELECT_BUTTONS_FIXED; + float width = count * buttonSize + (count - 1) * style.ItemSpacing.x + style.ItemSpacing.x * INFO_GAP + + style.WindowPadding.x * 2; + float height = buttonSize + style.WindowPadding.y * 2; + ImGui::SetNextWindowPos({(screen.x - width) / 2, screen.y - height}); + ImGui::SetNextWindowSize({width, height}); + if (ImGui::Begin("##Select Bar", nullptr, BAR_FLAGS)) + { + for (int i = 0; i < (int)characters.size(); i++) + { + Character& entry = characters[i]; + ImGui::PushID(i); + style_push(entry.color); + bool isCurrent = i == characterIndex; + if (isCurrent) + ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered)); + ImVec2 size = {buttonSize, buttonSize}; + bool isPressed = entry.portrait + ? ImGui::ImageButton("##Portrait", texture_id_get(*entry.portrait), + {size.x - style.FramePadding.x * 2, size.y - style.FramePadding.y * 2}) + : ImGui::Button(entry.name.c_str(), size); + if (is_fx(isPressed)) + characterIndex = i; + if (isCurrent) + ImGui::PopStyleColor(); + ImGui::SetItemTooltip("%s", entry.name.c_str()); + style_pop(); + ImGui::PopID(); + ImGui::SameLine(); + } + ImGui::SameLine(0, style.ItemSpacing.x * INFO_GAP / 2); + ImVec2 cursor = ImGui::GetCursorScreenPos(); + ImGui::GetWindowDrawList()->AddLine({cursor.x, cursor.y}, {cursor.x, cursor.y + buttonSize}, + ImGui::GetColorU32(ImGuiCol_Separator)); + ImGui::SameLine(0, style.ItemSpacing.x * INFO_GAP / 2); + ImGui::BeginDisabled(!selected); + if (icon_button("credits", "Credits", BUTTON_NORMAL)) + panel = PANEL_CREDITS; + ImGui::EndDisabled(); + ImGui::SameLine(); + if (icon_button("settings", "Settings", BUTTON_NORMAL)) + panel = PANEL_SETTINGS; + } + ImGui::End(); + if (selected) { + float above = screen.y - height; + ImVec2 size = {std::min(PREVIEW_WIDTH, screen.x * WINDOW_FIT), above * WINDOW_FIT}; style_push(selected->color); - ImGui::SetNextWindowSize(half); - ImGui::SetNextWindowPos({style.WindowPadding.x, style.WindowPadding.y}); - if (ImGui::Begin("##Preview", nullptr, PANEL_FLAGS) && ImGui::BeginTabBar("##Preview Tabs")) + ImGui::SetNextWindowSize(size); + ImGui::SetNextWindowPos({screen.x / 2, above / 2}, ImGuiCond_Always, {0.5f, 0.5f}); + if (ImGui::Begin("##Preview", nullptr, PANEL_FLAGS)) { - ImVec2 available = ImGui::GetContentRegionAvail(); - if (is_fx(ImGui::BeginTabItem("Render"))) + if (ImGui::BeginTabBar("##Preview Tabs")) { - if (Texture* render = selected->render) + if (is_fx(ImGui::BeginTabItem("In Game"))) { - float scale = std::min(available.x / render->width, available.y / render->height); - ImVec2 size = {render->width * scale, render->height * scale}; - ImGui::SetCursorPos({ImGui::GetCursorPosX() + (available.x - size.x) / 2, - ImGui::GetCursorPosY() + (available.y - size.y) / 2}); - ImGui::Image(texture_id_get(*render), size); + isPreviewRender = false; + ImGui::EndTabItem(); } - else - ImGui::TextWrapped("%s\n%s", selected->name.c_str(), selected->description.c_str()); - ImGui::EndTabItem(); + if (is_fx(ImGui::BeginTabItem("Render"))) + { + isPreviewRender = true; + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); } - if (is_fx(ImGui::BeginTabItem("In Game"))) + ImVec2 available = {ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y * PREVIEW_FRACTION}; + ImVec2 shown = {}; + ImTextureID texture = {}; + if (isPreviewRender && selected->render) + { + Texture& render = *selected->render; + float scale = std::min(available.x / render.width, available.y / render.height); + shown = {render.width * scale, render.height * scale}; + texture = texture_id_get(render); + } + else { Anm2* anm2 = selected->anm2_get(ANM2_PATH, *renderer, *audio); if (previewActor.anm2 != anm2 || !anm2) previewActor = Actor(anm2); previewActor.update(*audio); - ImVec2 size = canvas_draw(*renderer, previewCanvas, previewActor, available); - ImGui::SetCursorPos({ImGui::GetCursorPosX() + (available.x - size.x) / 2, - ImGui::GetCursorPosY() + (available.y - size.y) / 2}); - ImGui::Image(texture_id_get(previewCanvas.texture), size); - ImGui::EndTabItem(); + shown = canvas_draw(*renderer, previewCanvas, previewActor, available); + texture = texture_id_get(previewCanvas.texture); } - ImGui::EndTabBar(); - } - ImGui::End(); + ImVec2 start = ImGui::GetCursorPos(); + ImGui::SetCursorPos({start.x + (available.x - shown.x) / 2, start.y + (available.y - shown.y) / 2}); + if (shown.x > 0) + ImGui::Image(texture, shown); + ImGui::SetCursorPos({start.x, start.y + available.y}); + ImGui::Separator(); - ImGui::SetNextWindowSize(half); - ImGui::SetNextWindowPos({style.WindowPadding.x, screen.y / 2 + style.WindowPadding.y}); - if (ImGui::Begin("##Info", nullptr, PANEL_FLAGS)) - { - float footer = ImGui::GetTextLineHeightWithSpacing() + style.WindowPadding.y + style.ItemSpacing.y; - ImGui::PushFont(nullptr, FONT_HEADER_3); - if (ImGui::BeginChild("##Info Child", {0, ImGui::GetContentRegionAvail().y - footer})) - { - ImGui::TextUnformatted(selected->name.c_str()); - ImGui::PushFont(nullptr, FONT_NORMAL); - if (ImGui::BeginTabBar("##Info Tabs")) - { - ImGui::PushFont(nullptr, FONT_HEADER_2); - if (ImGui::BeginTabItem("Overview")) - { - ImGui::Separator(); - if (!selected->description.empty()) - { - ImGui::PushStyleColor(ImGuiCol_Text, imvec4_get(GRAY)); - ImGui::TextWrapped("%s", selected->description.c_str()); - ImGui::PopStyleColor(); - ImGui::Separator(); - } - float weight = isSelectedSaved ? selectedStats.weight : selected->traits.weight; - ImGui::Text("Weight: %s", weight_format(weight, settings.measurement).c_str()); - ImGui::Text("Stages: %i", (int)selected->stages.size() + 1); - ImGui::EndTabItem(); - } - if (ImGui::BeginTabItem("Credits")) - { - ImGui::Separator(); - ImGui::PushStyleColor(ImGuiCol_Text, imvec4_get(GRAY)); - ImGui::TextWrapped("%s", selected->credits.empty() ? "No credits listed." - : selected->credits.c_str()); - ImGui::PopStyleColor(); - ImGui::EndTabItem(); - } - ImGui::PopFont(); - ImGui::EndTabBar(); - } - ImGui::PopFont(); - } - ImGui::EndChild(); + ImGui::PushFont(nullptr, FONT_HEADER_2); + ImGui::TextUnformatted(selected->name.c_str()); + ImGui::PopFont(); + ImGui::PushStyleColor(ImGuiCol_Text, imvec4_get(GRAY)); + ImGui::TextWrapped("%s", selected->description.c_str()); + ImGui::PopStyleColor(); + float weight = isSelectedSaved ? selectedStats.weight : selected->traits.weight; + ImGui::Text("Weight: %s Stages: %i", weight_format(weight, settings.measurement).c_str(), + (int)selected->stages.size() + 1); + ImGui::SetCursorPosY(ImGui::GetWindowHeight() - style.WindowPadding.y - ImGui::GetFrameHeight()); ImVec2 buttonSize = {row_width_get(isSelectedSaved ? 2 : 1), 0}; if (isSelectedSaved) { @@ -1121,9 +1159,8 @@ void Ui::select_update(std::vector& characters, Settings& settings) isNewGameWarning = isSelectedSaved; } tooltip_set("Start a new game.\nThis will delete progress!"); - ImGui::PopFont(); - ImGui::SetNextWindowSize({screen.x / 2, 0}); + ImGui::SetNextWindowSize({size.x, 0}); ImGui::SetNextWindowPos({screen.x / 2, screen.y / 2}, ImGuiCond_Always, {0.5f, 0.5f}); if (ImGui::BeginPopupModal("New Game Warning", &isNewGameWarning, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize)) @@ -1142,53 +1179,16 @@ void Ui::select_update(std::vector& characters, Settings& settings) style_pop(); } - ImGui::SetNextWindowSize({screen.x / 2 - style.WindowPadding.x, screen.y - style.WindowPadding.y * 2}); - ImGui::SetNextWindowPos({screen.x / 2, style.WindowPadding.y}); - if (ImGui::Begin("##Main Menu", nullptr, PANEL_FLAGS) && ImGui::BeginTabBar("##Main Tabs")) + if (window_begin(screen, height)) { - if (is_fx(ImGui::BeginTabItem("Characters"))) + if (panel == PANEL_CREDITS && selected) { - if (ImGui::BeginPopupContextWindow("##Characters Context")) - { - if (ImGui::MenuItem("Refresh")) - { - command_add(COMMAND_RELOAD); - selectedIndex = -1; - } - ImGui::EndPopup(); - } - float side = ImGui::GetContentRegionAvail().x / 4; - float right = ImGui::GetCursorScreenPos().x + ImGui::GetContentRegionAvail().x; - for (int i = 0; i < (int)characters.size(); i++) - { - Character& entry = characters[i]; - ImGui::PushID(i); - style_push(entry.color); - bool isCurrent = i == characterIndex; - if (isCurrent) - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBgHovered)); - bool isPressed = entry.portrait ? ImGui::ImageButton(entry.name.c_str(), - texture_id_get(*entry.portrait), {side, side}) - : ImGui::Button(entry.name.c_str(), {side, side}); - if (is_fx(isPressed)) - characterIndex = i; - if (isCurrent) - ImGui::PopStyleColor(); - ImGui::SetItemTooltip("%s", entry.name.c_str()); - style_pop(); - float next = ImGui::GetItemRectMax().x + style.ItemSpacing.x + side; - if (i + 1 < (int)characters.size() && next < right) - ImGui::SameLine(); - ImGui::PopID(); - } - ImGui::EndTabItem(); + ImGui::PushStyleColor(ImGuiCol_Text, imvec4_get(GRAY)); + ImGui::TextWrapped("%s", selected->credits.empty() ? "No credits listed." : selected->credits.c_str()); + ImGui::PopStyleColor(); } - if (is_fx(ImGui::BeginTabItem("Settings"))) - { + else settings_draw(settings); - ImGui::EndTabItem(); - } - ImGui::EndTabBar(); + window_end(); } - ImGui::End(); } diff --git a/src/ui.h b/src/ui.h index a42d396..b1559bf 100644 --- a/src/ui.h +++ b/src/ui.h @@ -23,7 +23,8 @@ enum Panel PANEL_STATS, PANEL_CATALOG, PANEL_SETTINGS, - PANEL_CHEATS + PANEL_CHEATS, + PANEL_CREDITS }; enum ButtonState @@ -61,6 +62,7 @@ public: std::vector itemCanvases; std::vector itemSizes; Actor previewActor; + Anm2 iconsDefault; Canvas previewCanvas; Stats selectedStats; Audio* audio = nullptr; @@ -77,7 +79,9 @@ public: Panel panel = PANEL_NONE; bool isFullscreen = false; bool isNewGameWarning = false; + bool isPreviewRender = false; bool isSelectedSaved = false; + bool isWindowOpen = false; void play_update(Play& play, Settings& settings); void select_update(std::vector& characters, Settings& settings); @@ -87,9 +91,10 @@ private: bool icon_button(const char* icon, const char* tooltip, ButtonState state); void icon_draw(const char* name, ImVec2 position, float size, ImU32 tint); void command_add(CommandType type, const std::string& key = ""); - void window_open(Play& play, Panel next); + void sound_play(SoundId id); void taskbar_draw(Play& play, ImVec2 screen); - void window_draw(Play& play, Settings& settings, ImVec2 screen); + bool window_begin(ImVec2 screen, float inset); + void window_end(); void stats_draw(Play& play); void cheats_draw(Play& play); void catalog_draw(Play& play);