yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
canvas_context_menu.cc
Go to the documentation of this file.
2#include "util/i18n/tr.h"
3
12#include "imgui/imgui.h"
13
14namespace yaze {
15namespace gui {
16
17namespace {
18inline void Dispatch(const std::function<void(CanvasContextMenu::Command,
19 const CanvasConfig&)>& handler,
21 if (handler) {
22 handler(command, config);
23 }
24}
25} // namespace
26
27void CanvasContextMenu::Initialize(const std::string& canvas_id) {
28 canvas_id_ = canvas_id;
29 enabled_ = true;
31 palette_editor_ = std::make_unique<PaletteEditorWidget>();
32
33 // Initialize canvas state
34 canvas_size_ = ImVec2(0, 0);
35 content_size_ = ImVec2(0, 0);
36 global_scale_ = 1.0F;
37 grid_step_ = 32.0F;
38 enable_grid_ = true;
39 enable_hex_labels_ = false;
42 is_draggable_ = false;
43 auto_resize_ = false;
44 scrolling_ = ImVec2(0, 0);
45
46 // Create default menu items
48}
49
53
55 global_items_.push_back(item);
56}
57
59 CanvasUsage usage) {
60 usage_specific_items_[usage].push_back(item);
61}
62
67
69 const std::string& context_id, const ImVec2& /* mouse_pos */, Rom* rom,
70 const gfx::Bitmap* bitmap, const gfx::SnesPalette* /* palette */,
71 const std::function<void(Command, const CanvasConfig&)>& command_handler,
72 CanvasConfig current_config, Canvas* canvas) {
73 if (!enabled_)
74 return;
75
76 // Context menu (under default mouse threshold)
77 if (ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right);
78 enable_context_menu_ && drag_delta.x == 0.0F && drag_delta.y == 0.0F) {
79 ImGui::OpenPopupOnItemClick(context_id.c_str(),
80 ImGuiPopupFlags_MouseButtonRight);
81 }
82
83 // Phase 4: Popup callback for automatic popup management
84 auto popup_callback = [canvas](const std::string& id,
85 std::function<void()> callback) {
86 if (canvas) {
87 canvas->GetPopupRegistry().Open(id, callback);
88 }
89 };
90
91 // Contents of the Context Menu (Phase 4: Priority-based ordering)
92 if (ImGui::BeginPopup(context_id.c_str())) {
93 // PRIORITY 0: Editor-specific items (from Canvas::editor_menu_)
94 if (canvas && !canvas->editor_menu().sections.empty()) {
95 RenderCanvasMenu(canvas->editor_menu(), popup_callback);
96 }
97
98 // Only show built-in menu items if show_builtin_context_menu is true
99 if (current_config.show_builtin_context_menu) {
100 // Also render usage-specific items (legacy support)
102 RenderUsageSpecificMenu(popup_callback);
103 ImGui::Separator();
104 }
105
106 // Shared built-in canvas tools. Bitmap and palette mutation entries
107 // ("Pixel Format", "Edit Palette") would corrupt the underlying data
108 // for read-only roles (kPreviewOnly, kSelectionSource) whose bitmap
109 // is a shared view (gfx-group sheets, sprite atlas thumbnails). Gate
110 // them on the canvas role; view controls below stay unconditional so
111 // read-only canvases keep pan/zoom/reset.
112 if (bitmap && RoleAllowsBitmapMutation(current_config.role)) {
113 RenderBitmapOperationsMenu(const_cast<gfx::Bitmap*>(bitmap));
114 ImGui::Separator();
115
116 RenderPaletteOperationsMenu(rom, const_cast<gfx::Bitmap*>(bitmap));
117 ImGui::Separator();
118 }
119
120 RenderViewControlsMenu(command_handler, current_config);
121
122 // PRIORITY 30: Debug/Performance
123 if (ImGui::GetIO().KeyCtrl) { // Only show when Ctrl is held
124 ImGui::Separator();
126 }
127
128 // Render global menu items (if any)
129 if (!global_items_.empty()) {
130 ImGui::Separator();
131 RenderMenuSection("Custom Actions", global_items_, popup_callback);
132 }
133 }
134
135 ImGui::EndPopup();
136 }
137}
138
142
144 const ImVec2& canvas_size, const ImVec2& content_size, float global_scale,
145 float grid_step, bool enable_grid, bool enable_hex_labels,
146 bool enable_custom_labels, bool enable_context_menu, bool is_draggable,
147 bool auto_resize, const ImVec2& scrolling) {
148 canvas_size_ = canvas_size;
149 content_size_ = content_size;
150 global_scale_ = global_scale;
151 grid_step_ = grid_step;
152 enable_grid_ = enable_grid;
153 enable_hex_labels_ = enable_hex_labels;
154 enable_custom_labels_ = enable_custom_labels;
155 enable_context_menu_ = enable_context_menu;
156 is_draggable_ = is_draggable;
157 auto_resize_ = auto_resize;
158 scrolling_ = scrolling;
159}
160
162 const CanvasMenuItem& item,
163 std::function<void(const std::string&, std::function<void()>)>
164 popup_callback) {
165 // Phase 4: Delegate to canvas_menu.h implementation
166 gui::RenderMenuItem(item, popup_callback);
167}
168
170 const std::string& title, const std::vector<CanvasMenuItem>& items,
171 std::function<void(const std::string&, std::function<void()>)>
172 popup_callback) {
173 if (items.empty())
174 return;
175
176 ImGui::TextColored(ImVec4(0.7F, 0.7F, 0.7F, 1.0F), "%s", title.c_str());
177 for (const auto& item : items) {
178 RenderMenuItem(item, popup_callback);
179 }
180}
181
183 std::function<void(const std::string&, std::function<void()>)>
184 popup_callback) {
186 if (it == usage_specific_items_.end() || it->second.empty()) {
187 return;
188 }
189
190 std::string usage_name = GetUsageModeName(current_usage_);
191 ImVec4 usage_color = GetUsageModeColor(current_usage_);
192
193 ImGui::TextColored(usage_color, tr("%s %s Mode"), ICON_MD_COLOR_LENS,
194 usage_name.c_str());
195 ImGui::Separator();
196
197 for (const auto& item : it->second) {
198 RenderMenuItem(item, popup_callback);
199 }
200}
201
203 const std::function<void(Command, const CanvasConfig&)>& command_handler,
204 CanvasConfig current_config) {
205 if (ImGui::BeginMenu(ICON_MD_VISIBILITY " View Controls")) {
206 if (ImGui::MenuItem(tr("Reset View"), "Ctrl+R")) {
207 Dispatch(command_handler, Command::kResetView, current_config);
208 }
209 if (ImGui::MenuItem(tr("Zoom to Fit"), "Ctrl+F")) {
210 Dispatch(command_handler, Command::kZoomToFit, current_config);
211 }
212 if (ImGui::BeginMenu(ICON_MD_ZOOM_IN " Zoom")) {
213 if (ImGui::MenuItem(tr("Zoom In"), "Ctrl++")) {
214 CanvasConfig updated = current_config;
215 updated.global_scale *= 1.25F;
216 Dispatch(command_handler, Command::kSetScale, updated);
217 }
218 if (ImGui::MenuItem(tr("Zoom Out"), "Ctrl+-")) {
219 CanvasConfig updated = current_config;
220 updated.global_scale *= 0.8F;
221 Dispatch(command_handler, Command::kSetScale, updated);
222 }
223
224 const struct ScaleOption {
225 const char* label;
226 float value;
227 } scale_options[] = {{"0.25x", 0.25F}, {"0.5x", 0.5F}, {"1x", 1.0F},
228 {"2x", 2.0F}, {"4x", 4.0F}, {"8x", 8.0F}};
229
230 ImGui::Separator();
231 for (const auto& option : scale_options) {
232 const bool selected = current_config.global_scale == option.value;
233 if (ImGui::MenuItem(option.label, nullptr, selected)) {
234 CanvasConfig updated = current_config;
235 updated.global_scale = option.value;
236 Dispatch(command_handler, Command::kSetScale, updated);
237 }
238 }
239 ImGui::EndMenu();
240 }
241
242 ImGui::Separator();
243 if (ImGui::MenuItem(tr("Show Grid"), nullptr, enable_grid_)) {
244 CanvasConfig updated = current_config;
245 updated.enable_grid = !enable_grid_;
246 Dispatch(command_handler, Command::kToggleGrid, updated);
247 }
248 if (ImGui::MenuItem(tr("Show Hex Labels"), nullptr, enable_hex_labels_)) {
249 CanvasConfig updated = current_config;
251 Dispatch(command_handler, Command::kToggleHexLabels, updated);
252 }
253 if (ImGui::MenuItem(tr("Show Custom Labels"), nullptr,
255 CanvasConfig updated = current_config;
257 Dispatch(command_handler, Command::kToggleCustomLabels, updated);
258 }
259
260 if (ImGui::BeginMenu(ICON_MD_GRID_ON " Grid")) {
261 const struct GridOption {
262 const char* label;
263 float value;
264 } grid_options[] = {
265 {"8x8", 8.0F}, {"16x16", 16.0F}, {"32x32", 32.0F}, {"64x64", 64.0F}};
266
267 for (const auto& option : grid_options) {
268 const bool selected = grid_step_ == option.value;
269 if (ImGui::MenuItem(option.label, nullptr, selected)) {
270 CanvasConfig updated = current_config;
271 updated.grid_step = option.value;
272 Dispatch(command_handler, Command::kSetGridStep, updated);
273 }
274 }
275 ImGui::EndMenu();
276 }
277
278 ImGui::Separator();
279 ImGui::TextDisabled(tr("Canvas %.0f x %.0f"), canvas_size_.x,
280 canvas_size_.y);
281 ImGui::TextDisabled(tr("Content %.0f x %.0f"), content_size_.x,
282 content_size_.y);
283 ImGui::TextDisabled(tr("Scale %.2f"), global_scale_);
284 ImGui::TextDisabled(tr("Grid %.1f"), grid_step_);
285
286 ImGui::Separator();
287 if (ImGui::MenuItem(tr("Advanced Properties..."))) {
288 CanvasConfig updated = current_config;
289 updated.enable_grid = enable_grid_;
293 updated.is_draggable = is_draggable_;
294 updated.auto_resize = auto_resize_;
295 updated.grid_step = grid_step_;
296 updated.canvas_size = canvas_size_;
297 updated.content_size = content_size_;
298 updated.scrolling = scrolling_;
299 Dispatch(command_handler, Command::kOpenAdvancedProperties, updated);
300 }
301 ImGui::EndMenu();
302 }
303}
304
306 if (!bitmap)
307 return;
308
309 if (ImGui::BeginMenu(ICON_MD_IMAGE " Bitmap")) {
310 ImGui::TextDisabled(tr("Size %d x %d"), bitmap->width(), bitmap->height());
311 if (auto* surface = bitmap->surface()) {
312 ImGui::TextDisabled(tr("Pitch %d"), surface->pitch);
313 ImGui::TextDisabled(tr("BPP %d / %d bytes"),
316 }
317
318 if (ImGui::BeginMenu(tr("Pixel Format"))) {
319 if (ImGui::MenuItem(tr("Indexed"))) {
321 // Queue texture update via Arena's deferred system
324 }
325 if (ImGui::MenuItem(tr("4BPP"))) {
327 // Queue texture update via Arena's deferred system
330 }
331 if (ImGui::MenuItem(tr("8BPP"))) {
333 // Queue texture update via Arena's deferred system
336 }
337 ImGui::EndMenu();
338 }
339
340 if (ImGui::BeginMenu(tr("Format Tools"))) {
341 if (ImGui::MenuItem(tr("Format Analysis..."))) {
342 // Open BPP analysis
343 }
344 if (ImGui::MenuItem(tr("Convert Format..."))) {
345 // Open BPP conversion dialog
346 }
347 if (ImGui::MenuItem(tr("Format Comparison..."))) {
348 // Open format comparison tool
349 }
350 ImGui::EndMenu();
351 }
352
353 ImGui::EndMenu();
354 }
355}
356
358 gfx::Bitmap* bitmap) {
359 if (!bitmap)
360 return;
361
362 if (ImGui::BeginMenu(ICON_MD_PALETTE " Palette")) {
363 if (ImGui::MenuItem(tr("Edit Palette..."))) {
364 palette_editor_->ShowPaletteEditor(*bitmap->mutable_palette(),
365 "Palette Editor");
366 }
367 if (ImGui::MenuItem(tr("Color Analysis..."))) {
368 palette_editor_->ShowColorAnalysis(*bitmap, "Color Analysis");
369 }
370
371 if (rom && ImGui::BeginMenu(tr("ROM Palette Selection"))) {
372 palette_editor_->Initialize(rom);
373
374 // Render palette selector inline
375 ImGui::Text(tr("Group:"));
376 ImGui::SameLine();
377 ImGui::InputScalar("##group", ImGuiDataType_U64,
379 ImGui::Text(tr("Palette:"));
380 ImGui::SameLine();
381 ImGui::InputScalar("##palette", ImGuiDataType_U64, &edit_palette_index_);
382
383 if (ImGui::Button(tr("Apply to Canvas"))) {
384 palette_editor_->ApplyROMPalette(bitmap, edit_palette_group_name_index_,
386 }
387 ImGui::EndMenu();
388 }
389
390 if (ImGui::BeginMenu(tr("View Palette"))) {
391 DisplayEditablePalette(*bitmap->mutable_palette(), "Palette", true, 8);
392 ImGui::EndMenu();
393 }
394
395 ImGui::Separator();
396
397 // Palette Help submenu
398 if (ImGui::BeginMenu(ICON_MD_HELP " Palette Help")) {
399 ImGui::TextColored(ImVec4(0.7F, 0.9F, 1.0F, 1.0F), tr("Bitmap Metadata"));
400 ImGui::Separator();
401
402 const auto& meta = bitmap->metadata();
403 ImGui::Text(tr("Source BPP: %d"), meta.source_bpp);
404 ImGui::Text(tr("Palette Format: %s"),
405 meta.palette_format == 0 ? "Full" : "Sub-palette");
406 ImGui::Text(tr("Source Type: %s"), meta.source_type.c_str());
407 ImGui::Text(tr("Expected Colors: %d"), meta.palette_colors);
408 ImGui::Text(tr("Actual Palette Size: %zu"), bitmap->palette().size());
409
410 ImGui::Separator();
411 ImGui::TextColored(ImVec4(1.0F, 0.9F, 0.6F, 1.0F),
412 tr("Palette Application Method"));
413 if (meta.palette_format == 0) {
414 ImGui::TextWrapped(
415 tr("Full palette (SetPalette) - all colors applied directly"));
416 } else {
417 ImGui::TextWrapped(tr(
418 "Sub-palette (SetPaletteWithTransparent) - color 0 is transparent, "
419 "1-7 from palette"));
420 }
421
422 ImGui::Separator();
423 ImGui::TextColored(ImVec4(0.6F, 1.0F, 0.6F, 1.0F), tr("Documentation"));
424 if (ImGui::MenuItem(tr("Palette System Architecture"))) {
425 ImGui::SetClipboardText("yaze/docs/palette-system-architecture.md");
426 // TODO: Open file in system viewer
427 }
428 if (ImGui::MenuItem(tr("User Palette Guide"))) {
429 ImGui::SetClipboardText("yaze/docs/user-palette-guide.md");
430 // TODO: Open file in system viewer
431 }
432
433 ImGui::EndMenu();
434 }
435
436 ImGui::EndMenu();
437 }
438}
439
441 if (!palette_editor_)
442 return;
443
444 palette_editor_->DrawROMPaletteSelector();
445}
446
448 if (ImGui::BeginMenu(ICON_MD_TRENDING_UP " Performance")) {
449 auto& profiler = gfx::PerformanceProfiler::Get();
450 auto canvas_stats = profiler.GetStats("canvas_operations");
451 auto draw_stats = profiler.GetStats("canvas_draw");
452
453 ImGui::Text(tr("Canvas Operations: %zu"), canvas_stats.sample_count);
454 ImGui::Text(tr("Average Time: %.2f ms"), draw_stats.avg_time_us / 1000.0);
455
456 if (ImGui::MenuItem(tr("Performance Dashboard..."))) {
458 }
459 if (ImGui::MenuItem(tr("Usage Report..."))) {
460 // Open usage report
461 }
462
463 ImGui::EndMenu();
464 }
465}
466
467void CanvasContextMenu::RenderMaterialIcon(const std::string& icon_name,
468 const ImVec4& color) {
469 // Simple material icon rendering using Unicode symbols
470 static std::unordered_map<std::string, const char*> icon_map = {
471 {"grid_on", ICON_MD_GRID_ON},
472 {"label", ICON_MD_LABEL},
473 {"edit", ICON_MD_EDIT},
474 {"menu", ICON_MD_MENU},
475 {"drag_indicator", ICON_MD_DRAG_INDICATOR},
476 {"fit_screen", ICON_MD_FIT_SCREEN},
477 {"zoom_in", ICON_MD_ZOOM_IN},
478 {"speed", ICON_MD_SPEED},
479 {"timer", ICON_MD_TIMER},
480 {"functions", ICON_MD_FUNCTIONS},
481 {"schedule", ICON_MD_SCHEDULE},
482 {"refresh", ICON_MD_REFRESH},
483 {"settings", ICON_MD_SETTINGS},
484 {"info", ICON_MD_INFO},
485 {"view", ICON_MD_VISIBILITY},
486 {"properties", ICON_MD_SETTINGS},
487 {"bitmap", ICON_MD_IMAGE},
488 {"palette", ICON_MD_PALETTE},
489 {"bpp", ICON_MD_SWAP_HORIZ},
490 {"performance", ICON_MD_TRENDING_UP},
491 {"grid", ICON_MD_GRID_ON},
492 {"scaling", ICON_MD_ZOOM_IN}};
493
494 auto it = icon_map.find(icon_name);
495 if (it != icon_map.end()) {
496 ImGui::TextColored(color, "%s", it->second);
497 }
498}
499
501 switch (usage) {
503 return "Tile Painting";
505 return "Tile Selecting";
507 return "Rectangle Selection";
509 return "Color Painting";
511 return "Bitmap Editing";
513 return "Palette Editing";
515 return "BPP Conversion";
517 return "Performance Mode";
519 return "Entity Manipulation";
521 return "Unknown";
522 default:
523 return "Unknown";
524 }
525}
526
528 switch (usage) {
530 return ImVec4(0.2F, 1.0F, 0.2F, 1.0F); // Green
532 return ImVec4(0.2F, 0.8F, 1.0F, 1.0F); // Blue
534 return ImVec4(1.0F, 0.8F, 0.2F, 1.0F); // Yellow
536 return ImVec4(1.0F, 0.2F, 1.0F, 1.0F); // Magenta
538 return ImVec4(1.0F, 0.5F, 0.2F, 1.0F); // Orange
540 return ImVec4(0.8F, 0.2F, 1.0F, 1.0F); // Purple
542 return ImVec4(0.2F, 1.0F, 1.0F, 1.0F); // Cyan
544 return ImVec4(1.0F, 0.2F, 0.2F, 1.0F); // Red
546 return ImVec4(0.4F, 0.8F, 1.0F, 1.0F); // Light Blue
548 return ImVec4(0.7F, 0.7F, 0.7F, 1.0F); // Gray
549 default:
550 return ImVec4(0.7F, 0.7F, 0.7F, 1.0F); // Gray
551 }
552}
553
555 // The shared canvas should not invent placeholder actions like "Paint Tile"
556 // or "Select Tile". Callers can inject real usage-specific items when a
557 // given editor has concrete actions to expose.
558}
559
560} // namespace gui
561} // 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
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
Definition arena.cc:36
static Arena & Get()
Definition arena.cc:21
Represents a bitmap image optimized for SNES ROM hacking.
Definition bitmap.h:67
const SnesPalette & palette() const
Definition bitmap.h:389
void Reformat(int format)
Reformat the bitmap to use a different pixel format.
Definition bitmap.cc:277
BitmapMetadata & metadata()
Definition bitmap.h:391
SnesPalette * mutable_palette()
Definition bitmap.h:390
int height() const
Definition bitmap.h:395
int width() const
Definition bitmap.h:394
SDL_Surface * surface() const
Definition bitmap.h:400
static PerformanceDashboard & Get()
void SetVisible(bool visible)
Show/hide the dashboard.
static PerformanceProfiler & Get()
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
void Initialize(const std::string &canvas_id)
std::unique_ptr< PaletteEditorWidget > palette_editor_
void SetUsageMode(CanvasUsage usage)
std::unordered_map< CanvasUsage, std::vector< CanvasMenuItem > > usage_specific_items_
void RenderMenuItem(const CanvasMenuItem &item, std::function< void(const std::string &, std::function< void()>)> popup_callback)
void SetCanvasState(const ImVec2 &canvas_size, const ImVec2 &content_size, float global_scale, float grid_step, bool enable_grid, bool enable_hex_labels, bool enable_custom_labels, bool enable_context_menu, bool is_draggable, bool auto_resize, const ImVec2 &scrolling)
void RenderMaterialIcon(const std::string &icon_name, const ImVec4 &color=ImVec4(1, 1, 1, 1))
void RenderUsageSpecificMenu(std::function< void(const std::string &, std::function< void()>)> popup_callback)
void RenderViewControlsMenu(const std::function< void(Command, const CanvasConfig &)> &command_handler, CanvasConfig current_config)
std::string GetUsageModeName(CanvasUsage usage) const
ImVec4 GetUsageModeColor(CanvasUsage usage) const
void RenderMenuSection(const std::string &title, const std::vector< CanvasMenuItem > &items, std::function< void(const std::string &, std::function< void()>)> popup_callback)
std::vector< CanvasMenuItem > global_items_
void RenderPaletteOperationsMenu(Rom *rom, gfx::Bitmap *bitmap)
void AddMenuItem(const CanvasMenuItem &item)
void Render(const std::string &context_id, const ImVec2 &mouse_pos, Rom *rom, const gfx::Bitmap *bitmap, const gfx::SnesPalette *palette, const std::function< void(Command, const CanvasConfig &)> &command_handler, CanvasConfig current_config, Canvas *canvas)
void RenderBitmapOperationsMenu(gfx::Bitmap *bitmap)
Modern, robust canvas for drawing and manipulating graphics.
Definition canvas.h:64
PopupRegistry & GetPopupRegistry()
Definition canvas.h:217
CanvasMenuDefinition & editor_menu()
Definition canvas.h:203
void Open(const std::string &popup_id, std::function< void()> render_callback)
Open a persistent popup.
#define ICON_MD_FUNCTIONS
Definition icons.h:863
#define ICON_MD_SETTINGS
Definition icons.h:1699
#define ICON_MD_INFO
Definition icons.h:993
#define ICON_MD_FIT_SCREEN
Definition icons.h:781
#define ICON_MD_TRENDING_UP
Definition icons.h:2016
#define ICON_MD_SWAP_HORIZ
Definition icons.h:1896
#define ICON_MD_REFRESH
Definition icons.h:1572
#define ICON_MD_SCHEDULE
Definition icons.h:1652
#define ICON_MD_LABEL
Definition icons.h:1053
#define ICON_MD_DRAG_INDICATOR
Definition icons.h:624
#define ICON_MD_VISIBILITY
Definition icons.h:2101
#define ICON_MD_EDIT
Definition icons.h:645
#define ICON_MD_SPEED
Definition icons.h:1817
#define ICON_MD_GRID_ON
Definition icons.h:896
#define ICON_MD_TIMER
Definition icons.h:1982
#define ICON_MD_IMAGE
Definition icons.h:982
#define ICON_MD_ZOOM_IN
Definition icons.h:2194
#define ICON_MD_MENU
Definition icons.h:1196
#define ICON_MD_PALETTE
Definition icons.h:1370
#define ICON_MD_COLOR_LENS
Definition icons.h:440
#define ICON_MD_HELP
Definition icons.h:933
@ kIndexed
Definition bitmap.h:36
@ k8bpp
Definition bitmap.h:38
@ k4bpp
Definition bitmap.h:37
void Dispatch(const std::function< void(CanvasContextMenu::Command, const CanvasConfig &)> &handler, CanvasContextMenu::Command command, CanvasConfig config)
CanvasUsage
Canvas usage patterns and tracking.
void RenderCanvasMenu(const CanvasMenuDefinition &menu, std::function< void(const std::string &, std::function< void()>)> popup_opened_callback)
Render a complete menu definition.
constexpr bool RoleAllowsBitmapMutation(CanvasRole role)
void RenderMenuItem(const CanvasMenuItem &item, std::function< void(const std::string &, std::function< void()>)> popup_opened_callback)
Render a single menu item.
Definition canvas_menu.cc:6
absl::Status DisplayEditablePalette(gfx::SnesPalette &palette, const std::string &title, bool show_color_picker, int colors_per_row, ImGuiColorEditFlags flags)
Definition color.cc:357
int GetSurfaceBitsPerPixel(SDL_Surface *surface)
Get bits per pixel from a surface.
Definition sdl_compat.h:455
int GetSurfaceBytesPerPixel(SDL_Surface *surface)
Get bytes per pixel from a surface.
Definition sdl_compat.h:530
SDL2/SDL3 compatibility layer.
Unified configuration for canvas display and interaction.
std::vector< CanvasMenuSection > sections
Declarative menu item definition.
Definition canvas_menu.h:64