feat: bags, spellbook and quest log join the takeover, and their keys follow

Each of this client's panels polls its own keybinding from inside its
own draw, so a panel that is no longer drawn never sees the key —
handing one over made it unopenable, which is worse than not handing it
over at all. The key now reaches the replacement instead: FrameXML's own
ToggleAllBags, ToggleSpellBook, ToggleQuestLog, ToggleCharacter and
ToggleWorldMap.

The character frame's own report from a live session shows all four of
its frames built with sensible rects and hidden only because the sheet
is closed, which is what made the missing key the next thing in the
way.
This commit is contained in:
Kelsi
2026-08-02 08:20:52 -07:00
parent 36861d5bfb
commit cea84e573c
4 changed files with 48 additions and 4 deletions

View File

@@ -47,6 +47,9 @@ enum class UiElement {
QuestTracker,
WorldMap,
CharacterFrame,
Bags,
Spellbook,
QuestLog,
};
/// True when FrameXML is drawing this instead, so the client should not.

View File

@@ -40,6 +40,8 @@
#include "rendering/m2_renderer.hpp"
#include "rendering/minimap.hpp"
#include "rendering/world_map.hpp"
#include "ui/framexml_takeover.hpp"
#include "ui/keybinding_manager.hpp"
#include "rendering/quest_marker_renderer.hpp"
#include "rendering/footprint_renderer.hpp"
#include "rendering/loading_screen.hpp"
@@ -3005,6 +3007,31 @@ void Application::render() {
// is the question that was meant.
const bool overClientUi = ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow);
// The keys that open what FrameXML now owns.
//
// Each of this client's panels polls its own keybinding from
// inside its own draw, so a panel that is no longer drawn never
// sees the key — handing one over made it unopenable. The key has
// to reach the replacement instead, which is FrameXML's own toggle
// for that panel.
{
using ui::UiElement;
using K = ui::KeybindingManager;
struct Route { UiElement element; K::Action action; const char* call; };
static const Route kRoutes[] = {
{UiElement::Bags, K::Action::TOGGLE_BAGS, "ToggleAllBags()"},
{UiElement::Spellbook, K::Action::TOGGLE_SPELLBOOK, "ToggleSpellBook(BOOKTYPE_SPELL)"},
{UiElement::QuestLog, K::Action::TOGGLE_QUESTS, "ToggleQuestLog()"},
{UiElement::CharacterFrame, K::Action::TOGGLE_CHARACTER_SCREEN, "ToggleCharacter(\"PaperDollFrame\")"},
{UiElement::WorldMap, K::Action::TOGGLE_WORLD_MAP, "ToggleWorldMap()"},
};
for (const Route& r : kRoutes) {
if (!ui::frameXmlOwns(r.element)) continue;
if (!K::getInstance().isActionPressed(r.action)) continue;
engine->executeString(r.call);
}
}
// After layout, because the range follows from the rects it just
// resolved, and before the mouse, so a scroll bar enabled by this
// frame's range can be clicked in it.

View File

@@ -14,7 +14,7 @@ namespace {
struct Entry { UiElement element; std::string_view name; };
// One row per element, and the only place a name is written down.
constexpr std::array<Entry, 16> kElements{{
constexpr std::array<Entry, 19> kElements{{
{UiElement::PlayerFrame, "playerframe"},
{UiElement::TargetFrame, "targetframe"},
{UiElement::PetFrame, "petframe"},
@@ -31,6 +31,9 @@ constexpr std::array<Entry, 16> kElements{{
{UiElement::QuestTracker, "questtracker"},
{UiElement::WorldMap, "worldmap"},
{UiElement::CharacterFrame, "characterframe"},
{UiElement::Bags, "bags"},
{UiElement::Spellbook, "spellbook"},
{UiElement::QuestLog, "questlog"},
}};
/// Parsed once. An unknown name is reported rather than dropped: a typo would
@@ -141,6 +144,11 @@ std::vector<std::string> frameXmlCheckFrames() {
"WorldMapZoneMinimapDropDown"},
{UiElement::CharacterFrame, "CharacterFrame PaperDollFrame CharacterModelFrame "
"CharacterNameText CharacterHeadSlot"},
{UiElement::Bags, "ContainerFrame1 ContainerFrame1Item1 "
"ContainerFrame1Name"},
{UiElement::Spellbook, "SpellBookFrame SpellButton1 SpellBookSkillLineTab1"},
{UiElement::QuestLog, "QuestLogFrame QuestLogListScrollFrame "
"QuestLogDetailScrollFrame"},
};
std::vector<std::string> out;

View File

@@ -555,9 +555,13 @@ void GameScreen::render(game::GameHandler& gameHandler) {
renderWorldMap(gameHandler);
questLogScreen.render(gameHandler, inventoryScreen);
if (!frameXmlOwns(UiElement::QuestLog)) {
questLogScreen.render(gameHandler, inventoryScreen);
}
spellbookScreen.render(gameHandler, services_.assetManager);
if (!frameXmlOwns(UiElement::Spellbook)) {
spellbookScreen.render(gameHandler, services_.assetManager);
}
// Insert spell link into chat if player shift-clicked a spellbook entry
{
@@ -625,7 +629,9 @@ void GameScreen::render(game::GameHandler& gameHandler) {
}
inventoryScreen.setGameHandler(&gameHandler);
inventoryScreen.render(gameHandler.getInventory(), gameHandler.getMoneyCopper());
if (!frameXmlOwns(UiElement::Bags)) {
inventoryScreen.render(gameHandler.getInventory(), gameHandler.getMoneyCopper());
}
// Character screen (C key toggle handled inside render())
if (!frameXmlOwns(UiElement::CharacterFrame)) {