6#include "absl/strings/str_format.h"
29 "Entrances (3)\nOnly entrances respond to hover and drag"},
31 "Exits (4)\nOnly exits respond to hover and drag"},
33 "Items (5)\nOnly items respond to hover and drag.\n"
34 "Arrows nudge the selected item (Shift = 16px), Cmd/Ctrl+D duplicates"},
36 "Sprites (6)\nOnly sprites respond to hover and drag"},
39bool ToolButton(
const char* label,
const char* tooltip,
bool active,
40 const char* automation_id =
nullptr) {
44 std::string(
"OverworldToolbar/button:") + automation_id,
"button",
47 if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
48 ImGui::SetTooltip(
"%s", tooltip);
54 ImGui::SameLine(0, 6.0f);
55 const ImVec2 pos = ImGui::GetCursorScreenPos();
56 const float height = ImGui::GetFrameHeight();
57 ImGui::GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + 3.0f),
58 ImVec2(pos.x, pos.y + height - 3.0f),
59 ImGui::GetColorU32(ImGuiCol_Separator));
60 ImGui::Dummy(ImVec2(1.0f, 0.0f));
61 ImGui::SameLine(0, 6.0f);
67 const char* shortcut_name)
const {
76 std::string result = text;
77 const size_t newline = result.find(
'\n');
78 const std::string hint =
" (" + keys +
")";
79 if (newline == std::string::npos) {
82 return result.insert(newline, hint);
86 const auto toggle = [&](
const char* icon,
const char* label,
87 const char* shortcut,
const std::function<bool()>& on,
88 const std::function<void()>& flip) {
92 const std::string tip =
WithHint(label, shortcut);
94 const std::string keys =
96 const std::string title =
97 std::string(label).substr(0, std::string(label).find(
'\n'));
98 const std::string item = absl::StrFormat(
"%s %s", icon, title);
99 if (ImGui::MenuItem(item.c_str(), keys.empty() ?
nullptr : keys.c_str(),
103 if (ImGui::IsItemHovered()) {
104 ImGui::SetTooltip(
"%s", tip.c_str());
111 ImGui::SameLine(0, 2);
113 const auto action = [&](
const char* icon,
const char* label,
114 const char* shortcut,
115 const std::function<void()>& run) {
120 const std::string keys =
122 const std::string title =
123 std::string(label).substr(0, std::string(label).find(
'\n'));
124 const std::string item = absl::StrFormat(
"%s %s", icon, title);
125 if (ImGui::MenuItem(item.c_str(),
126 keys.empty() ?
nullptr : keys.c_str())) {
129 if (ImGui::IsItemHovered()) {
130 ImGui::SetTooltip(
"%s",
WithHint(label, shortcut).c_str());
134 const std::string tip =
WithHint(label, shortcut);
138 ImGui::SameLine(0, 2);
143 toggle(
ICON_MD_PLACE,
"Entities\nShow entrances, exits, items and sprites",
153 ImGui::AlignTextToFramePadding();
154 ImGui::TextDisabled(
"%3.0f%%",
get_zoom() * 100.0f);
155 ImGui::SameLine(0, 2);
171 const std::function<
void()>& draw_appearance) {
172 if (!overworld || !overworld->
is_loaded() || !window_manager || !rom) {
179 const float avail = ImGui::GetContentRegionAvail().x;
180 const float right_edge = ImGui::GetCursorScreenPos().x + avail;
181 const bool tiny = avail < ImGui::GetFontSize() * 38.0f;
184 {{ImGuiStyleVar_FramePadding, ImVec2(4.0f, 3.0f)},
185 {ImGuiStyleVar_ItemSpacing, ImVec2(4.0f, 4.0f)}});
186 ImGui::PushID(
"OverworldToolbar");
189 static constexpr const char* kWorldButtons[] = {
"LW",
"DW",
"SW"};
190 static constexpr const char* kWorldShortcuts[] = {
"overworld.world_light",
191 "overworld.world_dark",
192 "overworld.world_special"};
193 for (
int world_index = 0; !tiny && world_index < 3; ++world_index) {
194 if (world_index > 0) {
195 ImGui::SameLine(0, 2);
198 current_world == world_index, ImVec2(30.0f, 0.0f)) &&
202 if (ImGui::IsItemHovered()) {
213 current_map, game_state);
217 if (ImGui::IsItemHovered()) {
219 "%s\n%s\nClick this button or double-click the canvas map for "
221 "%s / %s: adjacent map",
222 metadata.map_title.c_str(), metadata.area_size_label.c_str(),
223 WithHint(
"Previous",
"overworld.map_left").c_str(),
224 WithHint(
"Next",
"overworld.map_right").c_str());
226 ImGui::SameLine(0, 2);
227 const std::string pin_tip =
229 ?
WithHint(
"Unpin map\nResume following the cursor",
230 "overworld.toggle_lock")
231 :
WithHint(
"Pin map\nKeep properties on this map while navigating",
232 "overworld.toggle_lock");
236 ImVec2(ImGui::GetFrameHeight(), ImGui::GetFrameHeight()),
238 current_map_lock = !current_map_lock;
242 ImGui::SameLine(0, 4);
243 const std::string story_label = absl::StrFormat(
"Story %d", game_state);
244 ImGui::SetNextItemWidth(ImGui::CalcTextSize(
"Story 0").x +
245 ImGui::GetFrameHeight() + 8.0f);
246 const bool story_open = ImGui::BeginCombo(
"##Story", story_label.c_str());
248 "OverworldToolbar/combo:Story",
"combobox", ImGui::GetItemID());
249 if (ImGui::IsItemHovered()) {
251 "Story part to preview. Changes the active sprite set, "
252 "sprite graphics and sprite palettes. "
253 "Shared item placements stay the same.");
256 for (
int state = 0; state < 3; ++state) {
257 const std::string label =
259 if (ImGui::Selectable(label.c_str(), game_state == state) &&
264 absl::StrFormat(
"OverworldToolbar/story:%d", state),
"selectable",
269 if (draw_appearance) {
270 ImGui::SameLine(0, 4);
274 const char* entity_label =
"Entities";
275 for (
const auto& button : kEntityModeButtons) {
276 if (entity_edit_mode == button.mode) {
277 entity_label = button.label;
280 const auto button_width = [](
const char* label) {
281 return ImGui::CalcTextSize(label,
nullptr,
true).x +
282 ImGui::GetStyle().FramePadding.x * 2.0f;
286 const float drawing_width =
290 const auto tools_width = [&](
bool compact_labels) {
291 return 3.0f * 13.0f + drawing_width +
292 button_width(compact_labels ?
ICON_MD_PLACE : entity_label) +
296 const float remaining = right_edge - ImGui::GetItemRectMax().x;
297 const bool compact = tools_width(
false) > remaining;
299 const bool overflow = tiny || tools_width(
true) > remaining;
301 ImGui::SameLine(0, 4);
304 ImGui::OpenPopup(
"ToolsOverflow");
306 if (!ImGui::BeginPopup(
"ToolsOverflow")) {
311 for (
int world = 0; world < 3; ++world) {
313 current_world == world) &&
332 "Select (1)\nLeft-drag empty map: pan Middle-drag: pan\n"
333 "Drag entities to move them Right-click: map menu\n"
334 "Double-click a map: Map Properties",
338 ImGui::SameLine(0, 2);
339 const std::string brush_tip =
WithHint(
340 "Brush (2)\nLeft-drag: paint the selected tile16\n"
341 "Right-click: sample tile16 (or I) Right-drag: capture a brush\n"
342 "[ / ]: previous / next tile16 Shift+Right-click: map menu",
343 "overworld.brush_toggle");
348 ImGui::SameLine(0, 2);
349 const std::string fill_tip =
WithHint(
350 "Fill screen\nClick fills the 32x32 screen under the cursor\n"
351 "Right-click: sample tile16 Shift+Right-click: map menu",
357 ImGui::SameLine(0, 2);
359 "Pick an item from the list, then click the map to place it",
360 false,
"Insert Item")) {
369 ImGui::OpenPopup(
"EntityTools");
372 "OverworldToolbar/button:Entities",
"button", ImGui::GetItemID());
373 if (ImGui::IsItemHovered()) {
375 "Choose which entities respond to hover and drag.\n"
376 "Entrances (3), exits (4), items (5), sprites (6).");
378 if (ImGui::BeginPopup(
"EntityTools")) {
383 entity_edit_mode = mode;
386 if (ImGui::MenuItem(
"All entities",
nullptr,
390 for (
const auto& button : kEntityModeButtons) {
391 if (ImGui::MenuItem(button.label,
nullptr,
392 entity_edit_mode == button.mode)) {
395 if (ImGui::IsItemHovered()) {
396 ImGui::SetTooltip(
"%s", button.tooltip);
406 "Grid, entities, overlay and zoom",
false,
"View")) {
407 ImGui::OpenPopup(
"OverworldViewMenu");
409 if (ImGui::BeginPopup(
"OverworldViewMenu")) {
413 ImGui::SameLine(0, 2);
415 "Open overworld editing windows",
false,
"Windows")) {
416 ImGui::OpenPopup(
"OverworldWindowsPopup");
418 if (ImGui::BeginPopup(
"OverworldWindowsPopup")) {
419 const auto item = [&](
const char* label,
const char* panel_id,
420 const char* shortcut_name) {
421 const std::string keys =
shortcuts && shortcut_name
424 if (ImGui::MenuItem(label, keys.empty() ?
nullptr : keys.c_str(),
426 const bool opening = !window_manager->
IsWindowOpen(panel_id);
439 "overworld.toggle_tile16_editor");
446 "overworld.toggle_item_list");
456 " Upgrade to ZSCustomOverworld v3...")) {
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
std::string GetDisplayString(const std::string &name) const
Live, platform-formatted binding for a shortcut name.
Central registry for all editor cards with session awareness and dependency injection.
size_t GetActiveSessionId() const
bool IsWindowOpen(size_t session_id, const std::string &base_window_id) const
bool ToggleWindow(size_t session_id, const std::string &base_window_id)
RAII guard for ImGui style vars.
static OverworldVersion GetVersion(const Rom &rom)
Detect ROM version from ASM marker byte.
auto overworld_map(int i) const
#define ICON_MD_GRID_VIEW
#define ICON_MD_CENTER_FOCUS_STRONG
#define ICON_MD_FIT_SCREEN
#define ICON_MD_GPS_FIXED
#define ICON_MD_VISIBILITY
#define ICON_MD_FORMAT_COLOR_FILL
#define ICON_MD_MORE_HORIZ
#define ICON_MD_AUTO_FIX_HIGH
#define ICON_MD_ANALYTICS
Editors are the view controllers for the application.
constexpr const char * kWorldNames[]
OverworldMapMetadata BuildOverworldMapMetadata(const zelda3::Overworld &overworld, const Rom *rom, const project::YazeProject *project, int map_id, int game_state)
constexpr const char * kGameStateNames[]
bool ThemedIconButton(const char *icon, const char *tooltip, const ImVec2 &size, bool is_active, bool is_disabled, const char *panel_id, const char *anim_id)
Draw a standard icon button with theme-aware colors.
bool ToggleButton(const char *label, bool active, const ImVec2 &size)
bool ToolbarIconButton(const char *icon, const char *tooltip, bool is_active)
Convenience wrapper for toolbar-sized icon buttons.
@ kVanilla
0xFF in ROM, no ZScream ASM applied
static constexpr const char * kMapProperties
static constexpr const char * kTile8Selector
static constexpr const char * kAreaGraphics
static constexpr const char * kItemList
static constexpr const char * kScratchSpace
static constexpr const char * kTile16Editor
static constexpr const char * kTile16Selector
static constexpr const char * kGfxGroups
static constexpr const char * kUsageStats
Modern project structure with comprehensive settings consolidation.