yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
selection_properties_panel.cc
Go to the documentation of this file.
2#include "util/i18n/tr.h"
3
4#include <cstdio>
5
6#include "absl/strings/str_cat.h"
7#include "absl/strings/str_format.h"
14#include "imgui/imgui.h"
15#include "rom/rom.h"
16#include "zelda3/dungeon/room.h"
19
20namespace yaze {
21namespace editor {
22
24 switch (type) {
26 return "None";
28 return "Dungeon Room";
30 return "Dungeon Object";
32 return "Dungeon Sprite";
34 return "Dungeon Entrance";
36 return "Overworld Map";
38 return "Overworld Tile";
40 return "Overworld Sprite";
42 return "Overworld Entrance";
44 return "Overworld Exit";
46 return "Overworld Item";
48 return "Graphics Sheet";
50 return "Palette";
51 default:
52 return "Unknown";
53 }
54}
55
59
63
67 ImGui::Spacing();
68 }
69
70 switch (selection_.type) {
73 break;
76 break;
79 break;
82 break;
85 break;
88 break;
91 break;
94 break;
97 break;
100 break;
103 break;
106 break;
109 break;
110 }
111
112 // Advanced options toggle
113 ImGui::Spacing();
114 ImGui::Separator();
115 ImGui::Spacing();
116 ImGui::Checkbox(tr("Show Advanced"), &show_advanced_);
117 ImGui::SameLine();
118 ImGui::Checkbox(tr("Raw Data"), &show_raw_data_);
119}
120
122 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
123
124 gui::ColoredText(ICON_MD_TOUCH_APP " Select an Item",
126
127 ImGui::Spacing();
128 ImGui::TextWrapped(
129 tr("Click on an object in the editor to view and edit its properties."));
130
131 ImGui::Spacing();
132 ImGui::Separator();
133 ImGui::Spacing();
134
135 // Show quick reference for what can be selected
136 ImGui::TextDisabled(tr("Selectable Items:"));
137 ImGui::BulletText(tr("Dungeon: Rooms, Objects, Sprites"));
138 ImGui::BulletText(tr("Overworld: Maps, Tiles, Entities"));
139 ImGui::BulletText(tr("Graphics: Sheets, Palettes"));
140}
141
143 const char* title) {
144 std::string full_title = absl::StrFormat("%s %s", icon, title);
145 if (!selection_.display_name.empty()) {
146 absl::StrAppend(&full_title, " - ", selection_.display_name);
147 }
148 if (selection_.read_only) {
149 absl::StrAppend(&full_title, " (Read Only)");
150 }
151
152 gui::SectionHeader(full_title.c_str());
153 ImGui::Spacing();
154}
155
158 ImGui::Separator();
159
160 ImGui::Text(tr("Type: %s"), GetSelectionTypeName(selection_.type));
161 if (!selection_.display_name.empty()) {
162 ImGui::Text(tr("Name: %s"), selection_.display_name.c_str());
163 }
164 if (selection_.id >= 0) {
165 ImGui::Text(tr("ID: %d (0x%X)"), selection_.id, selection_.id);
166 }
167 if (selection_.secondary_id >= 0) {
168 ImGui::Text(tr("Secondary: %d (0x%X)"), selection_.secondary_id,
170 }
171 if (selection_.read_only) {
172 ImGui::TextDisabled(tr("Read Only"));
173 }
174
175 ImGui::Spacing();
176 bool wrote_action = false;
177 if (selection_.id >= 0) {
178 if (gui::ThemedButton("Copy ID")) {
179 char buffer[32];
180 std::snprintf(buffer, sizeof(buffer), "%d", selection_.id);
181 ImGui::SetClipboardText(buffer);
182 }
183 wrote_action = true;
184 }
185 if (selection_.id >= 0) {
186 if (wrote_action)
187 ImGui::SameLine();
188 if (gui::ThemedButton("Copy Hex")) {
189 char buffer[32];
190 std::snprintf(buffer, sizeof(buffer), "0x%X", selection_.id);
191 ImGui::SetClipboardText(buffer);
192 }
193 wrote_action = true;
194 }
195 if (!selection_.display_name.empty()) {
196 if (wrote_action)
197 ImGui::SameLine();
198 if (gui::ThemedButton("Copy Name")) {
199 ImGui::SetClipboardText(selection_.display_name.c_str());
200 }
201 wrote_action = true;
202 }
203
205
206 if (show_raw_data_) {
207 ImGui::Spacing();
208 ImGui::TextDisabled(tr("Data Ptr: %p"), selection_.data);
209 }
210}
211
213 if (!send_to_agent_) {
214 return;
215 }
216
217 ImGui::Spacing();
218 ImGui::Separator();
219 ImGui::Spacing();
220
221 ImGui::TextDisabled(tr("%s Agent Actions"), ICON_MD_SMART_TOY);
222 bool no_selection = (selection_.type == SelectionType::kNone);
223 ImGui::BeginDisabled(no_selection);
224 if (gui::ThemedButton("Explain")) {
225 SendAgentPrompt("Explain this selection and how to edit it safely.");
226 }
227 ImGui::SameLine();
228 if (gui::ThemedButton("Suggest Fixes")) {
229 SendAgentPrompt("Suggest improvements or checks for this selection.");
230 }
231 ImGui::SameLine();
232 if (gui::ThemedButton("Audit")) {
233 SendAgentPrompt("Audit this selection for possible issues or conflicts.");
234 }
235 ImGui::EndDisabled();
236 if (no_selection &&
237 ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
238 ImGui::SetTooltip(tr("Select an object first to use agent actions"));
239 }
240}
241
243 std::string context = absl::StrFormat("Selection Type: %s",
245 if (!selection_.display_name.empty()) {
246 context += absl::StrFormat("\nName: %s", selection_.display_name);
247 }
248 if (selection_.id >= 0) {
249 context += absl::StrFormat("\nID: 0x%X", selection_.id);
250 }
251 if (selection_.secondary_id >= 0) {
252 context += absl::StrFormat("\nSecondary ID: 0x%X", selection_.secondary_id);
253 }
254 if (selection_.read_only) {
255 context += "\nRead Only: true";
256 }
257 return context;
258}
259
261 const char* intent) const {
262 std::string prompt = intent ? intent : "Review this selection.";
263 prompt += "\n\n";
264 prompt += BuildSelectionContext();
265 prompt += "\n\nProvide actionable steps inside Yaze where possible.";
266 return prompt;
267}
268
270 if (!send_to_agent_) {
271 return;
272 }
274 if (focus_agent_panel_) {
276 }
277}
278
279bool SelectionPropertiesPanel::DrawPositionEditor(const char* label, int* x,
280 int* y, int min_val,
281 int max_val) {
282 bool changed = false;
283 ImGui::PushID(label);
284
285 ImGui::Text("%s", label);
286 ImGui::PushItemWidth(80);
287
288 ImGui::Text(tr("X:"));
289 ImGui::SameLine();
290 if (ImGui::InputInt("##X", x, 1, 8)) {
291 *x = std::clamp(*x, min_val, max_val);
292 changed = true;
293 }
294
295 ImGui::SameLine();
296 ImGui::Text(tr("Y:"));
297 ImGui::SameLine();
298 if (ImGui::InputInt("##Y", y, 1, 8)) {
299 *y = std::clamp(*y, min_val, max_val);
300 changed = true;
301 }
302
303 ImGui::PopItemWidth();
304 ImGui::PopID();
305
306 return changed;
307}
308
309bool SelectionPropertiesPanel::DrawSizeEditor(const char* label, int* width,
310 int* height) {
311 bool changed = false;
312 ImGui::PushID(label);
313
314 ImGui::Text("%s", label);
315 ImGui::PushItemWidth(80);
316
317 ImGui::Text(tr("W:"));
318 ImGui::SameLine();
319 if (ImGui::InputInt("##W", width, 1, 8)) {
320 *width = std::max(1, *width);
321 changed = true;
322 }
323
324 ImGui::SameLine();
325 ImGui::Text(tr("H:"));
326 ImGui::SameLine();
327 if (ImGui::InputInt("##H", height, 1, 8)) {
328 *height = std::max(1, *height);
329 changed = true;
330 }
331
332 ImGui::PopItemWidth();
333 ImGui::PopID();
334
335 return changed;
336}
337
339 uint8_t* value,
340 const char* tooltip) {
341 bool changed = false;
342 int val = *value;
343
344 ImGui::PushItemWidth(80);
345 if (ImGui::InputInt(label, &val, 1, 16)) {
346 *value = static_cast<uint8_t>(std::clamp(val, 0, 255));
347 changed = true;
348 }
349 ImGui::PopItemWidth();
350
351 if (tooltip && ImGui::IsItemHovered()) {
352 ImGui::SetTooltip("%s", tooltip);
353 }
354
355 return changed;
356}
357
359 uint16_t* value,
360 const char* tooltip) {
361 bool changed = false;
362 int val = *value;
363
364 ImGui::PushItemWidth(100);
365 if (ImGui::InputInt(label, &val, 1, 256)) {
366 *value = static_cast<uint16_t>(std::clamp(val, 0, 65535));
367 changed = true;
368 }
369 ImGui::PopItemWidth();
370
371 if (tooltip && ImGui::IsItemHovered()) {
372 ImGui::SetTooltip("%s", tooltip);
373 }
374
375 return changed;
376}
377
379 int* current_item,
380 const char* const items[],
381 int items_count) {
382 return ImGui::Combo(label, current_item, items, items_count);
383}
384
386 uint8_t* flags,
387 const char* const flag_names[],
388 int flag_count) {
389 bool changed = false;
390
391 if (ImGui::TreeNode(label)) {
392 for (int i = 0; i < flag_count && i < 8; ++i) {
393 bool bit_set = (*flags >> i) & 1;
394 if (ImGui::Checkbox(flag_names[i], &bit_set)) {
395 if (bit_set) {
396 *flags |= (1 << i);
397 } else {
398 *flags &= ~(1 << i);
399 }
400 changed = true;
401 }
402 }
403 ImGui::TreePop();
404 }
405
406 return changed;
407}
408
410 const char* value) {
411 ImGui::Text("%s:", label);
412 ImGui::SameLine();
413 ImGui::TextDisabled("%s", value);
414}
415
417 uint32_t value, int digits) {
418 ImGui::Text("%s:", label);
419 ImGui::SameLine();
420 char fmt[16];
421 snprintf(fmt, sizeof(fmt), "0x%%0%dX", digits);
422 ImGui::TextDisabled(fmt, value);
423}
424
430
431// ============================================================================
432// Type-specific property editors
433// ============================================================================
434
436 DrawPropertyHeader(ICON_MD_GRID_VIEW, "Dungeon Room");
437
438 if (!selection_.data) {
439 ImGui::TextDisabled(tr("No room data available."));
440 return;
441 }
442
443 auto* room = static_cast<zelda3::Room*>(selection_.data);
444
445 if (ImGui::CollapsingHeader(tr("Identity"), ImGuiTreeNodeFlags_DefaultOpen)) {
446 DrawReadOnlyHex("Room ID", selection_.id, 4);
448 }
449
450 if (ImGui::CollapsingHeader(tr("Graphics & Layout"),
451 ImGuiTreeNodeFlags_DefaultOpen)) {
452 uint8_t blockset = room->blockset();
453 if (DrawByteProperty("Blockset", &blockset,
454 "Tile graphics and layout definition")) {
455 room->SetBlockset(blockset);
456 NotifyChange();
457 }
458
459 uint8_t palette = room->palette();
460 if (DrawByteProperty("Palette", &palette, "Room color scheme")) {
461 room->SetPalette(palette);
462 NotifyChange();
463 }
464
465 uint8_t spriteset = room->spriteset();
466 if (DrawByteProperty("Spriteset", &spriteset,
467 "Enemy graphics and behavior")) {
468 room->SetSpriteset(spriteset);
469 NotifyChange();
470 }
471 }
472
473 if (show_advanced_ &&
474 ImGui::CollapsingHeader(tr("Advanced Settings"),
475 ImGuiTreeNodeFlags_DefaultOpen)) {
476
477 // Room Tags with manifest integration
478 auto draw_tag_combo = [&](const char* label, zelda3::TagKey current,
479 std::function<void(zelda3::TagKey)> setter) {
480 std::string current_label =
481 zelda3::GetRoomTagLabel(static_cast<int>(current));
482 if (ImGui::BeginCombo(label, current_label.c_str())) {
483 const auto& vanilla_tags = zelda3::Zelda3Labels::GetRoomTagNames();
484 for (int i = 0; i < static_cast<int>(vanilla_tags.size()); ++i) {
485 std::string item_label = zelda3::GetRoomTagLabel(i);
486 if (ImGui::Selectable(item_label.c_str(),
487 static_cast<int>(current) == i)) {
488 setter(static_cast<zelda3::TagKey>(i));
489 NotifyChange();
490 }
491 }
492 ImGui::EndCombo();
493 }
494 };
495
496 draw_tag_combo("Tag 1", room->tag1(),
497 [&](zelda3::TagKey val) { room->SetTag1(val); });
498 draw_tag_combo("Tag 2", room->tag2(),
499 [&](zelda3::TagKey val) { room->SetTag2(val); });
500
501 // Room Effect
502 int effect = static_cast<int>(room->effect());
503 const auto& effects = zelda3::Zelda3Labels::GetRoomEffectNames();
504 std::vector<const char*> effect_ptrs;
505 for (const auto& s : effects)
506 effect_ptrs.push_back(s.c_str());
507
508 if (ImGui::Combo(tr("Effect"), &effect, effect_ptrs.data(),
509 static_cast<int>(effect_ptrs.size()))) {
510 room->SetEffect(static_cast<zelda3::EffectKey>(effect));
511 NotifyChange();
512 }
513 }
514}
515
517 DrawPropertyHeader(ICON_MD_CATEGORY, "Dungeon Object");
518
519 if (ImGui::CollapsingHeader(tr("Transform"),
520 ImGuiTreeNodeFlags_DefaultOpen)) {
521 // Placeholder for actual object data
522 int x = 0, y = 0;
523 if (DrawPositionEditor("Position", &x, &y, 0, 63)) {
524 NotifyChange();
525 }
526
527 int w = 1, h = 1;
528 if (DrawSizeEditor("Size", &w, &h)) {
529 NotifyChange();
530 }
531 }
532
533 if (ImGui::CollapsingHeader(tr("Object Type"),
534 ImGuiTreeNodeFlags_DefaultOpen)) {
535 ImGui::TextDisabled(tr("Object ID: --"));
536 ImGui::TextDisabled(tr("Subtype: --"));
537 ImGui::TextDisabled(tr("Layer: --"));
538 }
539
540 if (show_raw_data_ &&
541 ImGui::CollapsingHeader(tr("Raw Data"), ImGuiTreeNodeFlags_None)) {
542 ImGui::TextDisabled(tr("Byte 1: 0x00"));
543 ImGui::TextDisabled(tr("Byte 2: 0x00"));
544 ImGui::TextDisabled(tr("Byte 3: 0x00"));
545 }
546}
547
549 DrawPropertyHeader(ICON_MD_PEST_CONTROL, "Dungeon Sprite");
550
551 if (ImGui::CollapsingHeader(tr("Position"), ImGuiTreeNodeFlags_DefaultOpen)) {
552 int x = 0, y = 0;
553 if (DrawPositionEditor("Position", &x, &y, 0, 255)) {
554 NotifyChange();
555 }
556 }
557
558 if (ImGui::CollapsingHeader(tr("Sprite Data"),
559 ImGuiTreeNodeFlags_DefaultOpen)) {
560 ImGui::TextDisabled(tr("Sprite ID: --"));
561 ImGui::TextDisabled(tr("Subtype: --"));
562 ImGui::TextDisabled(tr("Overlord: No"));
563 }
564}
565
567 DrawPropertyHeader(ICON_MD_DOOR_FRONT, "Dungeon Entrance");
568
569 if (ImGui::CollapsingHeader(tr("Target"), ImGuiTreeNodeFlags_DefaultOpen)) {
570 ImGui::TextDisabled(tr("Target Room: --"));
571 ImGui::TextDisabled(tr("Entry Position: --"));
572 }
573
574 if (ImGui::CollapsingHeader(tr("Properties"),
575 ImGuiTreeNodeFlags_DefaultOpen)) {
576 ImGui::TextDisabled(tr("Door Type: --"));
577 ImGui::TextDisabled(tr("Direction: --"));
578 }
579}
580
582 DrawPropertyHeader(ICON_MD_MAP, "Overworld Map");
583
584 if (ImGui::CollapsingHeader(tr("Identity"), ImGuiTreeNodeFlags_DefaultOpen)) {
585 DrawReadOnlyHex("Map ID", selection_.id, 2);
587 }
588
589 if (ImGui::CollapsingHeader(tr("Graphics"), ImGuiTreeNodeFlags_DefaultOpen)) {
590 ImGui::TextDisabled(tr("GFX Set: --"));
591 ImGui::TextDisabled(tr("Palette: --"));
592 ImGui::TextDisabled(tr("Sprite GFX: --"));
593 ImGui::TextDisabled(tr("Sprite Palette: --"));
594 }
595
596 if (ImGui::CollapsingHeader(tr("Properties"),
597 ImGuiTreeNodeFlags_DefaultOpen)) {
598 ImGui::TextDisabled(tr("Large Map: No"));
599 ImGui::TextDisabled(tr("Area Size: 1x1"));
600 ImGui::TextDisabled(tr("Parent ID: --"));
601 }
602}
603
605 DrawPropertyHeader(ICON_MD_GRID_ON, "Overworld Tile");
606
607 if (ImGui::CollapsingHeader(tr("Tile Info"),
608 ImGuiTreeNodeFlags_DefaultOpen)) {
609 DrawReadOnlyHex("Tile16 ID", selection_.id, 4);
610 ImGui::TextDisabled(tr("Position: --"));
611 }
612
613 if (show_advanced_ &&
614 ImGui::CollapsingHeader(tr("Tile16 Data"), ImGuiTreeNodeFlags_None)) {
615 ImGui::TextDisabled(tr("TL: 0x0000"));
616 ImGui::TextDisabled(tr("TR: 0x0000"));
617 ImGui::TextDisabled(tr("BL: 0x0000"));
618 ImGui::TextDisabled(tr("BR: 0x0000"));
619 }
620}
621
623 DrawPropertyHeader(ICON_MD_PEST_CONTROL, "Overworld Sprite");
624
625 if (ImGui::CollapsingHeader(tr("Position"), ImGuiTreeNodeFlags_DefaultOpen)) {
626 int x = 0, y = 0;
627 if (DrawPositionEditor("Position", &x, &y, 0, 8191)) {
628 NotifyChange();
629 }
630 }
631
632 if (ImGui::CollapsingHeader(tr("Sprite"), ImGuiTreeNodeFlags_DefaultOpen)) {
633 ImGui::TextDisabled(tr("Sprite ID: --"));
634 ImGui::TextDisabled(tr("Map ID: --"));
635 }
636}
637
639 DrawPropertyHeader(ICON_MD_DOOR_FRONT, "Overworld Entrance");
640
641 if (ImGui::CollapsingHeader(tr("Position"), ImGuiTreeNodeFlags_DefaultOpen)) {
642 int x = 0, y = 0;
643 if (DrawPositionEditor("Position", &x, &y)) {
644 NotifyChange();
645 }
646 }
647
648 if (ImGui::CollapsingHeader(tr("Target"), ImGuiTreeNodeFlags_DefaultOpen)) {
649 ImGui::TextDisabled(tr("Entrance ID: --"));
650 ImGui::TextDisabled(tr("Target Room: --"));
651 }
652}
653
655 DrawPropertyHeader(ICON_MD_EXIT_TO_APP, "Overworld Exit");
656
657 if (ImGui::CollapsingHeader(tr("Exit Point"),
658 ImGuiTreeNodeFlags_DefaultOpen)) {
659 ImGui::TextDisabled(tr("Exit ID: --"));
660 int x = 0, y = 0;
661 if (DrawPositionEditor("Position", &x, &y)) {
662 NotifyChange();
663 }
664 }
665
666 if (ImGui::CollapsingHeader(tr("Target Map"),
667 ImGuiTreeNodeFlags_DefaultOpen)) {
668 ImGui::TextDisabled(tr("Room ID: --"));
669 ImGui::TextDisabled(tr("Target Map: --"));
670 }
671}
672
674 DrawPropertyHeader(ICON_MD_STAR, "Overworld Item");
675
676 if (ImGui::CollapsingHeader(tr("Position"), ImGuiTreeNodeFlags_DefaultOpen)) {
677 int x = 0, y = 0;
678 if (DrawPositionEditor("Position", &x, &y)) {
679 NotifyChange();
680 }
681 }
682
683 if (ImGui::CollapsingHeader(tr("Item Data"),
684 ImGuiTreeNodeFlags_DefaultOpen)) {
685 ImGui::TextDisabled(tr("Item ID: --"));
686 ImGui::TextDisabled(tr("Map ID: --"));
687 }
688}
689
691 DrawPropertyHeader(ICON_MD_IMAGE, "Graphics Sheet");
692
693 if (ImGui::CollapsingHeader(tr("Sheet Info"),
694 ImGuiTreeNodeFlags_DefaultOpen)) {
695 DrawReadOnlyHex("Sheet ID", selection_.id, 2);
696 ImGui::TextDisabled(tr("Size: 128x32"));
697 ImGui::TextDisabled(tr("BPP: 4"));
698 }
699
700 if (show_advanced_ &&
701 ImGui::CollapsingHeader(tr("ROM Location"), ImGuiTreeNodeFlags_None)) {
702 ImGui::TextDisabled(tr("Address: --"));
703 ImGui::TextDisabled(tr("Compressed: Yes"));
704 ImGui::TextDisabled(tr("Original Size: --"));
705 }
706}
707
710
711 if (ImGui::CollapsingHeader(tr("Palette Info"),
712 ImGuiTreeNodeFlags_DefaultOpen)) {
713 DrawReadOnlyHex("Palette ID", selection_.id, 2);
714 ImGui::TextDisabled(tr("Colors: 16"));
715 }
716
717 if (ImGui::CollapsingHeader(tr("Colors"), ImGuiTreeNodeFlags_DefaultOpen)) {
718 // Would show color swatches in actual implementation
719 ImGui::TextDisabled(tr("Color editing not yet implemented"));
720 }
721}
722
723} // namespace editor
724} // namespace yaze
bool DrawByteProperty(const char *label, uint8_t *value, const char *tooltip=nullptr)
bool DrawFlagsProperty(const char *label, uint8_t *flags, const char *const flag_names[], int flag_count)
std::string BuildAgentPrompt(const char *intent) const
bool DrawPositionEditor(const char *label, int *x, int *y, int min_val=0, int max_val=512)
std::function< void(const std::string &) send_to_agent_)
void DrawReadOnlyText(const char *label, const char *value)
bool DrawSizeEditor(const char *label, int *width, int *height)
bool DrawWordProperty(const char *label, uint16_t *value, const char *tooltip=nullptr)
bool DrawComboProperty(const char *label, int *current_item, const char *const items[], int items_count)
void ClearSelection()
Clear the current selection.
void Draw()
Draw the properties panel content.
void DrawReadOnlyHex(const char *label, uint32_t value, int digits=4)
void DrawPropertyHeader(const char *icon, const char *title)
void SetSelection(const SelectionContext &context)
Set the current selection to display/edit.
const Theme & GetCurrentTheme() const
static ThemeManager & Get()
#define ICON_MD_GRID_VIEW
Definition icons.h:897
#define ICON_MD_EXIT_TO_APP
Definition icons.h:699
#define ICON_MD_INFO
Definition icons.h:993
#define ICON_MD_STAR
Definition icons.h:1848
#define ICON_MD_MAP
Definition icons.h:1173
#define ICON_MD_GRID_ON
Definition icons.h:896
#define ICON_MD_DOOR_FRONT
Definition icons.h:613
#define ICON_MD_IMAGE
Definition icons.h:982
#define ICON_MD_PEST_CONTROL
Definition icons.h:1429
#define ICON_MD_TOUCH_APP
Definition icons.h:2000
#define ICON_MD_PALETTE
Definition icons.h:1370
#define ICON_MD_CATEGORY
Definition icons.h:382
#define ICON_MD_SMART_TOY
Definition icons.h:1781
const char * GetSelectionTypeName(SelectionType type)
Get a human-readable name for a selection type.
SelectionType
Types of entities that can be selected and edited.
void ColoredText(const char *text, const ImVec4 &color)
bool ThemedButton(const char *label, const ImVec2 &size, const char *panel_id, const char *anim_id)
Draw a standard text button with theme colors.
ImVec4 GetPrimaryVec4()
void SectionHeader(const char *icon, const char *label, const ImVec4 &color)
ImVec4 GetTextDisabledVec4()
void ColoredTextF(const ImVec4 &color, const char *fmt,...)
std::string GetRoomTagLabel(int id)
Convenience function to get a room tag label.
Holds information about the current selection.
static const std::vector< std::string > & GetRoomEffectNames()
static const std::vector< std::string > & GetRoomTagNames()