yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
overworld_sidebar.cc
Go to the documentation of this file.
2#include "util/i18n/tr.h"
3
4#include <algorithm>
5
6#include "absl/strings/str_format.h"
11#include "imgui/imgui.h"
12#include "zelda3/common.h"
15
16namespace yaze {
17namespace editor {
18
19using ImGui::Separator;
20using ImGui::Text;
21
23 MapPropertiesSystem* map_properties_system)
24 : overworld_(overworld),
25 rom_(rom),
26 map_properties_system_(map_properties_system) {}
27
28void OverworldSidebar::Draw(int& current_world, int& current_map,
29 bool& current_map_lock, int& game_state,
30 bool& show_custom_bg_color_editor,
31 bool& show_overlay_editor) {
32 if (!overworld_->is_loaded()) {
33 return;
34 }
35
36 // Use a child window for the sidebar to allow scrolling
37 if (ImGui::BeginChild("OverworldSidebar", ImVec2(0, 0), false,
38 ImGuiWindowFlags_None)) {
39 ImGui::PushID("OverworldSidebar");
40 DrawMapSelection(current_world, current_map, current_map_lock);
41
42 if (overworld_->overworld_map(current_map) == nullptr) {
43 ImGui::Spacing();
44 ImGui::Separator();
45 ImGui::Spacing();
46 ImGui::TextDisabled(tr("Current map selection is invalid."));
47 ImGui::TextDisabled(
48 tr("Hover or jump to a valid overworld map to continue."));
49 ImGui::PopID();
50 ImGui::EndChild();
51 return;
52 }
53
54 ImGui::Spacing();
55 Separator();
56 ImGui::Spacing();
57
58 // Use CollapsingHeader layout for better visibility and configurability
59 if (ImGui::CollapsingHeader(tr("General Settings"),
60 ImGuiTreeNodeFlags_DefaultOpen)) {
61 DrawBasicPropertiesTab(current_map, game_state,
62 show_custom_bg_color_editor, show_overlay_editor);
63 }
64
65 if (ImGui::CollapsingHeader(tr("Graphics"),
66 ImGuiTreeNodeFlags_DefaultOpen)) {
67 DrawGraphicsTab(current_map, game_state);
68 }
69
70 if (ImGui::CollapsingHeader(tr("Sprites"))) {
71 DrawSpritePropertiesTab(current_map, game_state);
72 }
73
74 if (ImGui::CollapsingHeader(tr("Music"))) {
75 DrawMusicTab(current_map);
76 }
77 ImGui::PopID();
78 }
79 ImGui::EndChild();
80}
81
82void OverworldSidebar::DrawBasicPropertiesTab(int current_map, int& game_state,
83 bool& show_custom_bg_color_editor,
84 bool& show_overlay_editor) {
85 ImGui::Spacing();
86 DrawConfiguration(current_map, game_state, show_overlay_editor);
87 ImGui::Spacing();
88 Separator();
89 ImGui::Spacing();
90 DrawPaletteSettings(current_map, game_state, show_custom_bg_color_editor);
91}
92
93void OverworldSidebar::DrawGraphicsTab(int current_map, int game_state) {
94 ImGui::Spacing();
95 DrawGraphicsSettings(current_map, game_state);
96}
97
99 int game_state) {
100 ImGui::Spacing();
101 // Reuse existing logic from MapPropertiesSystem if possible, or reimplement
102 // Here we'll reimplement a simplified version based on what was in MapPropertiesSystem
103
104 ImGui::Text(ICON_MD_PEST_CONTROL_RODENT " Sprite Settings");
105 ImGui::Separator();
106
107 // Sprite Graphics (already in Graphics tab, but useful here too)
108 uint8_t sprite_gfx =
109 overworld_->overworld_map(current_map)->sprite_graphics(game_state);
110 if (gui::InputHexByte("Sprite GFX", &sprite_gfx, kHexByteInputWidth)) {
112 {current_map, OverworldPropertyField::kSpriteGraphics, game_state,
113 sprite_gfx});
114 }
115
116 // Sprite Palette (already in General->Palettes, but useful here too)
117 uint8_t sprite_palette =
118 overworld_->overworld_map(current_map)->sprite_palette(game_state);
119 if (gui::InputHexByte("Sprite Palette", &sprite_palette,
122 {current_map, OverworldPropertyField::kSpritePalette, game_state,
123 sprite_palette});
124 }
125}
126
127void OverworldSidebar::DrawMusicTab(int current_map) {
128 ImGui::Spacing();
129 ImGui::Text(ICON_MD_MUSIC_NOTE " Music Settings");
130 ImGui::Separator();
131
132 for (int i = 0; i < 4; ++i) {
133 uint8_t music = overworld_->overworld_map(current_map)->area_music(i);
134 const std::string label = absl::StrFormat("Music Byte %d", i + 1);
135 if (gui::InputHexByte(label.c_str(), &music, kHexByteInputWidth)) {
137 {current_map, OverworldPropertyField::kMusic, i, music});
138 }
139 }
140}
141
142void OverworldSidebar::DrawMapSelection(int& current_world, int& current_map,
143 bool& current_map_lock) {
144 ImGui::Text(ICON_MD_MAP " Current Map");
145
146 const int clamped_world = std::clamp(current_world, 0, 2);
147 ImGui::TextDisabled(tr("World: %s"), kWorldNames[clamped_world]);
148
149 ImGui::BeginGroup();
150 ImGui::Text(tr("ID: %02X"), current_map);
151 ImGui::SameLine();
152 if (ImGui::Button(current_map_lock ? ICON_MD_LOCK : ICON_MD_LOCK_OPEN)) {
153 current_map_lock = !current_map_lock;
154 }
155 if (ImGui::IsItemHovered()) {
156 ImGui::SetTooltip(current_map_lock ? "Unlock Map" : "Lock Map");
157 }
158 ImGui::EndGroup();
159}
160
161void OverworldSidebar::DrawGraphicsSettings(int current_map, int game_state) {
162 ImGui::Text(ICON_MD_IMAGE " Graphics");
163
164 // Area Graphics
165 uint8_t area_graphics =
166 overworld_->overworld_map(current_map)->area_graphics();
167 if (gui::InputHexByte("Area GFX", &area_graphics, kHexByteInputWidth)) {
169 {current_map, OverworldPropertyField::kAreaGraphics, 0, area_graphics});
170 }
171
172 // Sprite Graphics
173 uint8_t sprite_graphics =
174 overworld_->overworld_map(current_map)->sprite_graphics(game_state);
175 if (gui::InputHexByte("Spr GFX", &sprite_graphics, kHexByteInputWidth)) {
177 {current_map, OverworldPropertyField::kSpriteGraphics, game_state,
178 sprite_graphics});
179 }
180
181 // Animated Graphics (v3+)
184 uint8_t animated_gfx =
185 overworld_->overworld_map(current_map)->animated_gfx();
186 if (gui::InputHexByte("Ani GFX", &animated_gfx, kHexByteInputWidth)) {
189 animated_gfx});
190 }
191 }
192
193 // Custom Tile Graphics (v1+)
195 if (ImGui::TreeNode("Custom Tile Graphics")) {
196 if (ImGui::BeginTable("CustomTileGraphics", 2,
197 ImGuiTableFlags_SizingFixedFit)) {
198 for (int i = 0; i < 8; i++) {
199 ImGui::TableNextColumn();
200 std::string label = absl::StrFormat("Sheet %d", i);
201 uint8_t custom_tileset =
202 overworld_->overworld_map(current_map)->custom_tileset(i);
203 if (gui::InputHexByte(label.c_str(), &custom_tileset,
207 custom_tileset});
208 }
209 if (ImGui::IsItemHovered()) {
210 ImGui::SetTooltip(tr("Custom graphics sheet %d (0x00-0xFF)"), i);
211 }
212 }
213 ImGui::EndTable();
214 }
215 ImGui::TreePop();
216 }
217 }
218}
219
220void OverworldSidebar::DrawPaletteSettings(int current_map, int game_state,
221 bool& show_custom_bg_color_editor) {
222 ImGui::Text(ICON_MD_PALETTE " Palettes");
223
224 // Area Palette
225 uint8_t area_palette = overworld_->overworld_map(current_map)->area_palette();
226 if (gui::InputHexByte("Area Pal", &area_palette, kHexByteInputWidth)) {
228 {current_map, OverworldPropertyField::kAreaPalette, 0, area_palette});
229 }
230
231 // Main Palette (v2+)
234 uint8_t main_palette =
235 overworld_->overworld_map(current_map)->main_palette();
236 if (gui::InputHexByte("Main Pal", &main_palette, kHexByteInputWidth)) {
238 {current_map, OverworldPropertyField::kMainPalette, 0, main_palette});
239 }
240 }
241
242 // Sprite Palette
243 uint8_t sprite_palette =
244 overworld_->overworld_map(current_map)->sprite_palette(game_state);
245 if (gui::InputHexByte("Spr Pal", &sprite_palette, kHexByteInputWidth)) {
247 {current_map, OverworldPropertyField::kSpritePalette, game_state,
248 sprite_palette});
249 }
250
251 // Custom Background Color Button
253 if (ImGui::Button(ICON_MD_FORMAT_COLOR_FILL " Custom BG Color")) {
254 show_custom_bg_color_editor = !show_custom_bg_color_editor;
255 }
256 }
257}
258
259void OverworldSidebar::DrawConfiguration(int current_map, int& game_state,
260 bool& show_overlay_editor) {
261 if (ImGui::BeginTable("ConfigTable", 2, ImGuiTableFlags_SizingFixedFit)) {
262 ImGui::TableSetupColumn("Label", ImGuiTableColumnFlags_WidthFixed, 100.0f);
263 ImGui::TableSetupColumn("Control", ImGuiTableColumnFlags_WidthStretch);
264
265 // Game State
266 ImGui::TableNextColumn();
267 ImGui::Text(ICON_MD_GAMEPAD " Game State");
268 ImGui::TableNextColumn();
269 ImGui::SetNextItemWidth(-1);
270 if (ImGui::Combo("##GameState", &game_state, kGameStateNames, 3)) {
273 }
274
275 // Area Size
276 ImGui::TableNextColumn();
277 ImGui::Text(ICON_MD_PHOTO_SIZE_SELECT_LARGE " Area Size");
278 ImGui::TableNextColumn();
279
281 int current_area_size =
282 static_cast<int>(overworld_->overworld_map(current_map)->area_size());
283
284 ImGui::SetNextItemWidth(-1);
286 if (ImGui::Combo("##AreaSize", &current_area_size, kAreaSizeNames, 4)) {
288 {current_map, OverworldPropertyField::kAreaSize, 0,
289 current_area_size});
290 }
291 } else {
292 const char* limited_names[] = {"Small (1x1)", "Large (2x2)"};
293 int limited_size = (current_area_size == 0 || current_area_size == 1)
294 ? current_area_size
295 : 0;
296 if (ImGui::Combo("##AreaSize", &limited_size, limited_names, 2)) {
297 auto size = (limited_size == 1) ? zelda3::AreaSizeEnum::LargeArea
300 {current_map, OverworldPropertyField::kAreaSize, 0,
301 static_cast<int>(size)});
302 }
303 }
304
305 // Message ID
306 ImGui::TableNextColumn();
307 ImGui::Text(ICON_MD_MESSAGE " Message ID");
308 ImGui::TableNextColumn();
309 ImGui::SetNextItemWidth(-1);
310 uint16_t message_id = overworld_->overworld_map(current_map)->message_id();
311 if (gui::InputHexWordCustom("##MsgID", &message_id, kHexWordInputWidth)) {
313 {current_map, OverworldPropertyField::kMessageId, 0, message_id});
314 }
315
316 ImGui::EndTable();
317 }
318
319 // Visual Effects (Overlay)
321 if (rom_version != zelda3::OverworldVersion::kVanilla) {
322 if (ImGui::Button(ICON_MD_LAYERS " Visual Effects", ImVec2(-1, 0))) {
323 show_overlay_editor = !show_overlay_editor;
324 }
325 }
326
327 // Mosaic Settings
328 ImGui::Separator();
329 ImGui::Text(ICON_MD_GRID_ON " Mosaic");
330
332 auto* current_map_ptr = overworld_->mutable_overworld_map(current_map);
333 std::array<bool, 4> mosaic_expanded = current_map_ptr->mosaic_expanded();
334 const char* direction_names[] = {"North", "South", "East", "West"};
335
336 if (ImGui::BeginTable("MosaicTable", 2)) {
337 for (int i = 0; i < 4; i++) {
338 ImGui::TableNextColumn();
339 if (ImGui::Checkbox(direction_names[i], &mosaic_expanded[i])) {
342 mosaic_expanded[i] ? 1 : 0});
343 }
344 }
345 ImGui::EndTable();
346 }
347 } else {
348 bool mosaic =
349 *overworld_->mutable_overworld_map(current_map)->mutable_mosaic();
350 if (ImGui::Checkbox(tr("Mosaic Effect"), &mosaic)) {
352 {current_map, OverworldPropertyField::kMosaic, 0, mosaic ? 1 : 0});
353 }
354 }
355}
356
357} // namespace editor
358} // namespace yaze
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:28
absl::Status ApplyPropertyEdit(const OverworldPropertyEdit &edit)
void DrawSpritePropertiesTab(int current_map, int game_state)
void Draw(int &current_world, int &current_map, bool &current_map_lock, int &game_state, bool &show_custom_bg_color_editor, bool &show_overlay_editor)
void DrawGraphicsTab(int current_map, int game_state)
void DrawConfiguration(int current_map, int &game_state, bool &show_overlay_editor)
MapPropertiesSystem * map_properties_system_
void DrawBasicPropertiesTab(int current_map, int &game_state, bool &show_custom_bg_color_editor, bool &show_overlay_editor)
void DrawPaletteSettings(int current_map, int game_state, bool &show_custom_bg_color_editor)
OverworldSidebar(zelda3::Overworld *overworld, Rom *rom, MapPropertiesSystem *map_properties_system)
void DrawMapSelection(int &current_world, int &current_map, bool &current_map_lock)
void DrawGraphicsSettings(int current_map, int game_state)
static bool SupportsCustomBGColors(OverworldVersion version)
Check if ROM supports custom background colors per area (v2+)
static OverworldVersion GetVersion(const Rom &rom)
Detect ROM version from ASM marker byte.
static bool SupportsAreaEnum(OverworldVersion version)
Check if ROM supports area enum system (v3+ only)
static bool SupportsAnimatedGFX(OverworldVersion version)
Check if ROM supports animated GFX selection (v3+)
static bool SupportsExpandedSpace(OverworldVersion version)
Check if ROM uses expanded ROM space for overworld data.
Represents the full Overworld data, light and dark world.
Definition overworld.h:389
auto is_loaded() const
Definition overworld.h:728
auto overworld_map(int i) const
Definition overworld.h:662
auto mutable_overworld_map(int i)
Definition overworld.h:668
#define ICON_MD_LOCK_OPEN
Definition icons.h:1142
#define ICON_MD_LOCK
Definition icons.h:1140
#define ICON_MD_PHOTO_SIZE_SELECT_LARGE
Definition icons.h:1459
#define ICON_MD_MAP
Definition icons.h:1173
#define ICON_MD_MESSAGE
Definition icons.h:1201
#define ICON_MD_FORMAT_COLOR_FILL
Definition icons.h:830
#define ICON_MD_MUSIC_NOTE
Definition icons.h:1264
#define ICON_MD_GRID_ON
Definition icons.h:896
#define ICON_MD_LAYERS
Definition icons.h:1068
#define ICON_MD_IMAGE
Definition icons.h:982
#define ICON_MD_PALETTE
Definition icons.h:1370
#define ICON_MD_PEST_CONTROL_RODENT
Definition icons.h:1430
#define ICON_MD_GAMEPAD
Definition icons.h:866
constexpr const char * kAreaSizeNames[]
constexpr const char * kWorldNames[]
constexpr float kHexByteInputWidth
constexpr const char * kGameStateNames[]
Definition ui_constants.h:8
constexpr float kHexWordInputWidth
bool InputHexWordCustom(const char *label, uint16_t *data, float input_width)
Definition input.cc:723
bool InputHexByte(const char *label, uint8_t *data, float input_width, bool no_step)
Definition input.cc:376
@ kVanilla
0xFF in ROM, no ZScream ASM applied