1#include "imgui/imgui_internal.h"
21#include "imgui/imgui.h"
30 auto* hovered = ctx->HoveredWindow;
31 auto* scrolled = ctx->WheelingWindow;
32 if (!hovered || !scrolled ||
33 ctx->WheelingWindowScrolledFrame != ctx->FrameCount ||
35 ctx->FrameCount - 1) {
38 const auto& storage = hovered->StateStorage;
43 if (!viewport.Contains(ctx->IO.MousePos)) {
46 auto* ancestor = hovered;
47 while (ancestor && ancestor != scrolled) {
48 ancestor = ancestor->ParentWindow;
57 const ImVec2 wheel = ctx->IO.MouseWheelRequestAxisSwap
58 ? ImVec2(ctx->IO.MouseWheel, 0)
59 : ImVec2(ctx->IO.MouseWheelH, ctx->IO.MouseWheel);
60 bool scroll_x = wheel.x != 0 && scrolled->ScrollMax.x != 0;
61 bool scroll_y = wheel.y != 0 && scrolled->ScrollMax.y != 0;
64 if (scroll_x && scroll_y) {
65 if (ctx->WheelingAxisAvg.x > ctx->WheelingAxisAvg.y)
71 scrolled->ScrollTarget.x = FLT_MAX;
73 scrolled->ScrollTarget.y = FLT_MAX;
74 ctx->WheelingWindow =
nullptr;
75 ctx->WheelingWindowReleaseTimer = 0;
79 auto* ctx = ImGui::GetCurrentContext();
80 auto* window = ImGui::GetCurrentWindow();
81 ImRect visible = bounds;
82 visible.ClipWith(window->InnerClipRect);
83 auto& storage = window->StateStorage;
89 for (
const auto& hook : ctx->Hooks) {
95 ImGuiContextHook hook;
97 hook.Type = ImGuiContextHookType_NewFramePost;
99 ImGui::AddContextHook(ctx, &hook);
119 for (
auto& label_group :
labels_) {
125 Init(
id, ImVec2(0, 0));
154 Init(
id, ImVec2(0, 0));
229 extensions_ = std::make_unique<CanvasExtensions>();
234using ImGui::GetContentRegionAvail;
235using ImGui::GetCursorScreenPos;
237using ImGui::GetWindowDrawList;
238using ImGui::IsItemActive;
239using ImGui::IsItemHovered;
240using ImGui::IsMouseClicked;
241using ImGui::IsMouseDragging;
248 ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight;
252 return ImVec2(std::floor(pos.x / scale) * scale,
253 std::floor(pos.y / scale) * scale);
312 const float min_scale = old_scale > 0.0f ? std::min(old_scale, 0.25f) : 0.25f;
329 if (old_scale != scale) {
418 ImGui::OpenPopup(
"Canvas Usage Report");
419 if (ImGui::BeginPopupModal(
"Canvas Usage Report",
nullptr,
420 ImGuiWindowFlags_AlwaysAutoResize)) {
421 ImGui::Text(tr(
"Canvas Usage Report"));
423 ImGui::TextWrapped(
"%s", report.c_str());
425 if (ImGui::Button(tr(
"Close"))) {
426 ImGui::CloseCurrentPopup();
436 ext.InitializePaletteEditor();
437 if (ext.palette_editor) {
438 ext.palette_editor->Initialize(
rom);
454 ext.InitializePaletteEditor();
455 if (ext.palette_editor) {
457 ext.palette_editor->ShowPaletteEditor(*mutable_palette,
458 "Canvas Palette Editor");
468 ext.InitializePaletteEditor();
469 if (ext.palette_editor) {
470 ext.palette_editor->ShowColorAnalysis(*
bitmap_,
"Canvas Color Analysis");
507 std::string child_id =
canvas_id_ +
"_TableChild";
512 ImGui::BeginChild(child_id.c_str(), child_size,
514 ImGuiWindowFlags_NoScrollbar);
516 if (!label.empty()) {
517 ImGui::Text(
"%s", label.c_str());
531 if (child_size.x <= 0 || child_size.y <= 0) {
541 std::string child_id =
canvas_id_ +
"_TableChild";
542 ImGuiWindowFlags child_flags = ImGuiWindowFlags_NoScrollbar;
544 child_flags = ImGuiWindowFlags_AlwaysVerticalScrollbar;
546 ImGui::BeginChild(child_id.c_str(), child_size,
true, child_flags);
548 if (!label.empty()) {
549 ImGui::Text(
"%s", label.c_str());
594 return ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(button) &&
602 return ImVec2(-1, -1);
631 if (effective_size.x == 0 && effective_size.y == 0) {
639 ImGuiWindowFlags child_flags = ImGuiWindowFlags_None;
641 child_flags |= ImGuiWindowFlags_AlwaysVerticalScrollbar;
643 ImGui::BeginChild(
canvas_id().c_str(), effective_size,
true, child_flags);
679 const std::function<
void()>& event,
680 int tile_size,
float scale) {
703 std::optional<ImVec2> viewport_size) {
708 const ImVec2 cursor = GetCursorScreenPos();
709 const ImVec2 available = GetContentRegionAvail();
710 ImRect visible_host(cursor,
711 ImVec2(cursor.x + available.x, cursor.y + available.y));
712 visible_host.ClipWith(ImGui::GetCurrentWindow()->InnerClipRect);
716 viewport_size.value_or(ImVec2(std::max(1.0f, visible_host.GetWidth()),
717 std::max(1.0f, visible_host.GetHeight())));
722 const ImVec2 visible(std::max(1.0f, viewport_size->x),
723 std::max(1.0f, viewport_size->y));
747 ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelX);
748 ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY);
749 RegisterViewportWheelOwner(
756 if (IsItemHovered()) {
757 const ImGuiIO& io = GetIO();
770 ImGuiIO& io = GetIO();
771 const float wheel_x = io.MouseWheelH;
772 const float wheel_y = io.MouseWheel;
774 if (wheel_x != 0.0f || wheel_y != 0.0f) {
776 io.MouseWheelH = 0.0f;
777 io.MouseWheel = 0.0f;
779 if (io.KeyCtrl && wheel_y != 0.0f) {
781 constexpr float kMinScale = 0.25f;
782 constexpr float kMaxScale = 8.0f;
784 const float new_scale = std::clamp(unclamped, kMinScale, kMaxScale);
796 constexpr float kTouchWheelToPixels = 10.0f;
798 ImVec2(wheel_x * kTouchWheelToPixels,
799 wheel_y * kTouchWheelToPixels));
808 const ImGuiIO& io = GetIO();
809 const bool is_active = IsItemActive();
812 if (
const float mouse_threshold_for_pan =
815 IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan)) {
824 const ImGuiIO& io = GetIO();
829 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
911 ext.InitializeModals();
922 ext.modals->ShowAdvancedProperties(
canvas_id_, modal_config,
928 ext.InitializeModals();
939 ext.modals->ShowScalingControls(
canvas_id_, modal_config,
963 auto popup_callback = [
this](
const std::string& id,
964 std::function<void()> callback) {
990 last_section.items.push_back(item);
999 std::function<
void()> render_callback) {
1021 if (available.x <= 0 || available.y <= 0)
1022 available = ImGui::GetContentRegionAvail();
1025 const float scale = std::max(0.25f, fit.scale);
1028 (available.y - bitmap.
height() * scale) * 0.5f));
1069 const ImGuiIO& io = GetIO();
1070 const bool is_hovered = IsItemHovered();
1074 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
1075 const auto scaled_size = size * scale;
1089 ImVec2 paint_pos = AlignPosToGrid(mouse_pos, scaled_size);
1091 auto paint_pos_end =
1092 ImVec2(paint_pos.x + scaled_size, paint_pos.y + scaled_size);
1094 points_.push_back(paint_pos_end);
1098 ImVec2(origin.x + paint_pos.x, origin.y + paint_pos.y),
1099 ImVec2(origin.x + paint_pos.x + scaled_size,
1100 origin.y + paint_pos.y + scaled_size),
1101 ImVec2(0, 0), ImVec2(1, 1),
1102 ImGui::GetColorU32(ImVec4(1, 1, 1, 1)));
1105 if (IsMouseClicked(ImGuiMouseButton_Left) &&
1106 ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
1133 const ImGuiIO& io = GetIO();
1136 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
1138 ImVec2 paint_pos = AlignPosToGrid(mouse_pos, scaled_size);
1144 ImVec2(paint_pos.x + scaled_size, paint_pos.y + scaled_size));
1155 const ImGuiIO& io = GetIO();
1156 const bool is_hovered = IsItemHovered();
1160 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
1162 static bool is_dragging =
false;
1163 static ImVec2 start_drag_pos;
1177 ImVec2 paint_pos = AlignPosToGrid(mouse_pos, scaled_tile_size);
1186 ImVec2(paint_pos.x + scaled_tile_size, paint_pos.y + scaled_tile_size));
1189 ImVec2(origin.x + paint_pos.x + 1, origin.y + paint_pos.y + 1),
1190 ImVec2(origin.x + paint_pos.x + scaled_tile_size,
1191 origin.y + paint_pos.y + scaled_tile_size),
1192 IM_COL32(color.x * 255, color.y * 255, color.z * 255, 255));
1194 if (IsMouseClicked(ImGuiMouseButton_Left)) {
1196 start_drag_pos = paint_pos;
1199 if (is_dragging && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) {
1200 is_dragging =
false;
1211 int tile_index_x =
static_cast<int>(position.x /
global_scale_) / tile_size;
1212 int tile_index_y =
static_cast<int>(position.y /
global_scale_) / tile_size;
1214 ImVec2 start_position(tile_index_x * tile_size, tile_index_y * tile_size);
1217 for (
int y = 0; y < tile_size; ++y) {
1218 for (
int x = 0; x < tile_size; ++x) {
1221 (start_position.y + y) * bitmap->
width() + (start_position.x + x);
1239 ImVec2 selected_pos;
1243 if (
is_hovered_ && IsMouseClicked(ImGuiMouseButton_Left)) {
1244 const ImGuiIO& io = GetIO();
1247 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
1248 ImVec2 painter_pos = AlignPosToGrid(mouse_pos,
static_cast<float>(size));
1251 points_.push_back(painter_pos);
1252 points_.push_back(ImVec2(painter_pos.x + size, painter_pos.y + size_y));
1256 return double_clicked;
1325 ImVec2 src_pos, ImVec2 src_size) {
1341 for (
const auto& [key, value] : gfx_bin) {
1343 if (!value || !value->is_active() || !value->texture()) {
1346 int offset = 0x40 * (key + 1);
1351 draw_list_->AddImage((ImTextureID)(intptr_t)value->texture(),
1354 ImVec2(0, 0), ImVec2(1, 1),
1355 ImGui::GetColorU32(ImVec4(1, 1, 1, 1)));
1362 IM_COL32(255, 255, 255, 200), scale);
1368 y, w, h, color, scale);
1378 int tile_size,
float ,
int local_map_size,
1379 ImVec2 total_map_size) {
1384 if (group.empty()) {
1396 bool use_optimized_rendering =
1400 const int small_map = local_map_size;
1401 const float large_map_width = total_map_size.x;
1402 const float large_map_height = total_map_size.y;
1405 const float tile_scale = tile_size * effective_scale;
1414 int start_tile_x =
static_cast<int>(std::floor(rect_top_left.x / tile_size));
1415 int start_tile_y =
static_cast<int>(std::floor(rect_top_left.y / tile_size));
1417 static_cast<int>(std::floor(rect_bottom_right.x / tile_size));
1419 static_cast<int>(std::floor(rect_bottom_right.y / tile_size));
1421 if (start_tile_x > end_tile_x)
1422 std::swap(start_tile_x, end_tile_x);
1423 if (start_tile_y > end_tile_y)
1424 std::swap(start_tile_y, end_tile_y);
1427 int rect_width = (end_tile_x - start_tile_x) * tile_size;
1428 int rect_height = (end_tile_y - start_tile_y) * tile_size;
1430 int tiles_per_row = rect_width / tile_size;
1431 int tiles_per_col = rect_height / tile_size;
1434 for (
int y = 0; y < tiles_per_col + 1; ++y) {
1435 for (
int x = 0; x < tiles_per_row + 1; ++x) {
1437 if (i >=
static_cast<int>(group.size())) {
1441 int tile_id = group[i];
1445 if (tile_id >= 0 && tile_id < tilemap_size) {
1447 int tile_pos_x = (x + start_tile_x) * tile_size * effective_scale;
1448 int tile_pos_y = (y + start_tile_y) * tile_size * effective_scale;
1453 atlas_tiles_per_row > 0) {
1455 (tile_id % atlas_tiles_per_row) * tilemap.
tile_size.
x;
1457 (tile_id / atlas_tiles_per_row) * tilemap.
tile_size.
y;
1460 if (atlas_tile_x >= 0 && atlas_tile_x < tilemap.
atlas.
width() &&
1461 atlas_tile_y >= 0 && atlas_tile_y < tilemap.
atlas.
height()) {
1463 const float atlas_width =
static_cast<float>(tilemap.
atlas.
width());
1464 const float atlas_height =
1467 ImVec2(atlas_tile_x / atlas_width, atlas_tile_y / atlas_height);
1469 ImVec2((atlas_tile_x + tilemap.
tile_size.
x) / atlas_width,
1470 (atlas_tile_y + tilemap.
tile_size.
y) / atlas_height);
1475 float screen_w = tilemap.
tile_size.
x * effective_scale;
1476 float screen_h = tilemap.
tile_size.
y * effective_scale;
1479 uint32_t alpha_color = use_optimized_rendering
1480 ? IM_COL32(255, 255, 255, 200)
1481 : IM_COL32(255, 255, 255, 150);
1486 ImVec2(screen_x, screen_y),
1487 ImVec2(screen_x + screen_w, screen_y + screen_h), uv0, uv1,
1488 ImGui::GetColorU32(alpha_color));
1495 if (i >=
static_cast<int>(group.size())) {
1505 const ImGuiIO& io = GetIO();
1507 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
1512 ImVec2 clamped_mouse_pos = mouse_pos;
1516 int mouse_local_map_x =
static_cast<int>(mouse_pos.x) / small_map;
1517 int mouse_local_map_y =
static_cast<int>(mouse_pos.y) / small_map;
1521 float potential_end_x = mouse_pos.x + rect_width;
1522 float potential_end_y = mouse_pos.y + rect_height;
1525 int potential_end_map_x =
static_cast<int>(potential_end_x) / small_map;
1526 int potential_end_map_y =
static_cast<int>(potential_end_y) / small_map;
1529 if (potential_end_map_x != mouse_local_map_x) {
1531 float max_mouse_x = (mouse_local_map_x + 1) * small_map - rect_width;
1532 clamped_mouse_pos.x = std::min(mouse_pos.x, max_mouse_x);
1535 if (potential_end_map_y != mouse_local_map_y) {
1537 float max_mouse_y = (mouse_local_map_y + 1) * small_map - rect_height;
1538 clamped_mouse_pos.y = std::min(mouse_pos.y, max_mouse_y);
1543 auto new_start_pos_screen =
1544 AlignPosToGrid(clamped_mouse_pos, tile_size * effective_scale);
1547 ImVec2 new_start_pos_world(new_start_pos_screen.x / effective_scale,
1548 new_start_pos_screen.y / effective_scale);
1551 new_start_pos_world.x =
1552 std::clamp(new_start_pos_world.x, 0.0f, large_map_width - rect_width);
1553 new_start_pos_world.y =
1554 std::clamp(new_start_pos_world.y, 0.0f, large_map_height - rect_height);
1559 new_start_pos_world.y + rect_height));
1594 for (
float x = fmodf(
scrolling_.x, grid_step);
1596 for (
float y = fmodf(
scrolling_.y, grid_step);
1600 int tile_id = tile_x + (tile_y * tile_id_offset);
1602 if (tile_id >=
labels_[label_id].size()) {
1605 std::string label =
labels_[label_id][tile_id];
1607 ImVec2(
canvas_p0_.x + x + (grid_step / 2) - tile_id_offset,
1608 canvas_p0_.y + y + (grid_step / 2) - tile_id_offset),
1633 .grid_step = grid_step};
1669 ImDrawList*
draw_list = ImGui::GetWindowDrawList();
1671 Text(tr(
"Blue shape is drawn first: appears in back"));
1672 Text(tr(
"Red shape is drawn after: appears in front"));
1673 ImVec2 p0 = ImGui::GetCursorScreenPos();
1674 draw_list->AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50),
1675 IM_COL32(0, 0, 255, 255));
1676 draw_list->AddRectFilled(ImVec2(p0.x + 25, p0.y + 25),
1677 ImVec2(p0.x + 75, p0.y + 75),
1678 IM_COL32(255, 0, 0, 255));
1679 ImGui::Dummy(ImVec2(75, 75));
1683 Text(tr(
"Blue shape is drawn first, into channel 1: appears in front"));
1684 Text(tr(
"Red shape is drawn after, into channel 0: appears in back"));
1685 ImVec2 p1 = ImGui::GetCursorScreenPos();
1692 draw_list->AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50),
1693 IM_COL32(0, 0, 255, 255));
1695 draw_list->AddRectFilled(ImVec2(p1.x + 25, p1.y + 25),
1696 ImVec2(p1.x + 75, p1.y + 75),
1697 IM_COL32(255, 0, 0, 255));
1703 ImGui::Dummy(ImVec2(75, 75));
1705 tr(
"After reordering, contents of channel 0 appears below channel 1."));
1712 ext.InitializeModals();
1743 if (ImGui::BeginPopupModal(
"Advanced Canvas Properties",
nullptr,
1744 ImGuiWindowFlags_AlwaysAutoResize)) {
1745 ImGui::Text(tr(
"Advanced Canvas Configuration"));
1749 ImGui::Text(tr(
"Canvas Properties"));
1750 ImGui::Text(tr(
"ID: %s"),
canvas_id_.c_str());
1761 ImGui::Text(tr(
"Minimum Size: %.0f x %.0f"), min_size.x, min_size.y);
1762 ImGui::Text(tr(
"Preferred Size: %.0f x %.0f"), preferred_size.x,
1768 ImGui::Text(tr(
"View Settings"));
1775 if (ImGui::Checkbox(tr(
"Enable Custom Labels"),
1779 if (ImGui::Checkbox(tr(
"Enable Context Menu"),
1792 ImGui::Text(tr(
"Grid Configuration"));
1800 ImGui::Text(tr(
"Scale Configuration"));
1808 ImGui::Text(tr(
"Scrolling Configuration"));
1810 if (ImGui::Button(tr(
"Reset Scroll"))) {
1814 if (ImGui::Button(tr(
"Center View"))) {
1825 if (ImGui::Button(tr(
"Close"))) {
1826 ImGui::CloseCurrentPopup();
1837 ext.InitializeModals();
1866 ext.modals->ShowScalingControls(
canvas_id_, modal_config);
1871 if (ImGui::BeginPopupModal(
"Scaling Controls",
nullptr,
1872 ImGuiWindowFlags_AlwaysAutoResize)) {
1873 ImGui::Text(tr(
"Canvas Scaling and Display Controls"));
1884 ImGui::Text(tr(
"Preset Scales:"));
1885 if (ImGui::Button(tr(
"0.25x"))) {
1890 if (ImGui::Button(tr(
"0.5x"))) {
1895 if (ImGui::Button(tr(
"1x"))) {
1900 if (ImGui::Button(tr(
"2x"))) {
1905 if (ImGui::Button(tr(
"4x"))) {
1910 if (ImGui::Button(tr(
"8x"))) {
1917 ImGui::Text(tr(
"Grid Configuration"));
1925 ImGui::Text(tr(
"Grid Presets:"));
1926 if (ImGui::Button(tr(
"8x8"))) {
1931 if (ImGui::Button(tr(
"16x16"))) {
1936 if (ImGui::Button(tr(
"32x32"))) {
1941 if (ImGui::Button(tr(
"64x64"))) {
1948 ImGui::Text(tr(
"Canvas Information"));
1951 ImGui::Text(tr(
"Scaled Size: %.0f x %.0f"),
1955 ImGui::Text(tr(
"Bitmap Size: %d x %d"),
bitmap_->
width(),
1958 tr(
"Effective Scale: %.3f x %.3f"),
1963 if (ImGui::Button(tr(
"Close"))) {
1964 ImGui::CloseCurrentPopup();
1977 if (
bitmap_ && ext.bpp_format_ui) {
1978 ext.bpp_format_ui->RenderFormatSelector(
1990 if (
bitmap_ && ext.bpp_format_ui) {
1999 if (!ext.bpp_conversion_dialog) {
2000 ext.bpp_conversion_dialog = std::make_unique<gui::BppConversionDialog>(
2004 if (
bitmap_ && ext.bpp_conversion_dialog) {
2005 ext.bpp_conversion_dialog->Show(
2008 ConvertBitmapFormat(format);
2012 if (ext.bpp_conversion_dialog) {
2013 ext.bpp_conversion_dialog->Render();
2022 if (current_format == target_format) {
2039 }
catch (
const std::exception& e) {
2040 SDL_Log(
"Failed to convert bitmap format: %s", e.what());
2056 ext.InitializeAutomation(
this);
2057 return ext.automation_api.get();
2072 draw_list_->AddImage(texture, screen_pos, screen_end, ImVec2(0, 0),
2073 ImVec2(1, 1), ImGui::GetColorU32(ImVec4(1, 1, 1, 1)));
2084 draw_list_->AddRectFilled(screen_pos, screen_end, color);
2093 draw_list_->AddText(screen_pos, color, text.c_str());
2101 : canvas_(&canvas), options_(options), active_(true) {
2112 : canvas_(other.canvas_), options_(other.options_), active_(other.active_) {
2113 other.active_ =
false;
2117 if (
this != &other) {
2119 canvas_->
End(options_);
2121 canvas_ = other.canvas_;
2122 options_ = other.options_;
2123 active_ = other.active_;
2124 other.active_ =
false;
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Represents a bitmap image optimized for SNES ROM hacking.
const SnesPalette & palette() const
TextureHandle texture() const
const std::vector< uint8_t > & vector() const
SnesPalette * mutable_palette()
void WriteColor(int position, const ImVec4 &color)
Write a color to a pixel at the given position.
void set_data(const std::vector< uint8_t > &data)
void UpdateTexture()
Updates the underlying SDL_Texture when it already exists.
Defines an abstract interface for all rendering operations.
RAII timer for automatic timing management.
Programmatic interface for controlling canvas operations.
Lightweight RAII guard for existing Canvas instances.
CanvasFrameOptions options_
CanvasFrame & operator=(const CanvasFrame &)=delete
CanvasFrame(Canvas &canvas, CanvasFrameOptions options=CanvasFrameOptions())
void ClearState()
Clear all interaction state.
void Initialize(const std::string &canvas_id)
Initialize the interaction handler.
Modern, robust canvas for drawing and manipulating graphics.
void set_scrolling(ImVec2 scroll)
ImVector< ImVec2 > points_
void DrawBitmap(Bitmap &bitmap, int border_offset, float scale)
PopupRegistry popup_registry_
void ShowScalingControls()
bool WasDoubleClicked(ImGuiMouseButton button=ImGuiMouseButton_Left) const
ImVec2 selected_tile_pos_
auto global_scale() const
gfx::IRenderer * renderer() const
void DrawOutlineWithColor(int x, int y, int w, int h, ImVec4 color)
void SetUsageMode(CanvasUsage usage)
void DrawBitmapGroup(std::vector< int > &group, gfx::Tilemap &tilemap, int tile_size, float scale=1.0f, int local_map_size=0x200, ImVec2 total_map_size=ImVec2(0x1000, 0x1000))
Draw group of bitmaps for multi-tile selection preview.
bool BeginTableCanvas(const std::string &label="")
void InitializeEnhancedComponents()
CanvasRuntime BuildCurrentRuntime() const
void ShowBppConversionDialog()
CanvasAutomationAPI * GetAutomationAPI()
void ShowAdvancedCanvasProperties()
void ApplyScaleSnapshot(const CanvasConfig &snapshot)
void UpdateInfoGrid(ImVec2 bg_size, float grid_size=64.0f, int label_id=0)
void EnsurePerformanceIntegration()
ImVec2 mouse_pos_in_canvas_
bool DrawTilemapPainter(gfx::Tilemap &tilemap, int current_tile)
bool DrawSolidTilePainter(const ImVec4 &color, int size)
bool enable_context_menu_
CanvasMenuDefinition editor_menu_
void ApplyConfigSnapshot(const CanvasConfig &snapshot)
void DrawLayeredElements()
void ReserveTableSpace(const std::string &label="")
bool enable_custom_labels_
void AddTextAt(ImVec2 local_pos, const std::string &text, uint32_t color)
void SetRenderer(gfx::IRenderer *renderer)
ImVec2 GetMinimumSize() const
void AddRectFilledAt(ImVec2 local_top_left, ImVec2 size, uint32_t color)
bool DrawTileSelector(int size, int size_y=0)
bool ConvertBitmapFormat(gfx::BppFormat target_format)
void DrawGridLines(float grid_step)
void SetCustomGridStep(float step)
zelda3::GameData * game_data() const
void ClearContextMenuItems()
void AddImageAt(ImTextureID texture, ImVec2 local_top_left, ImVec2 size)
void SetGameData(zelda3::GameData *game_data)
void DrawRect(int x, int y, int w, int h, ImVec4 color)
bool HasValidSelection() const
bool DrawTilePainter(const Bitmap &bitmap, int size, float scale=1.0f)
ImVector< ImVec2 > selected_points_
ImVec2 GetCurrentSize() const
void UpdateColorPainter(gfx::IRenderer *renderer, gfx::Bitmap &bitmap, const ImVec4 &color, const std::function< void()> &event, int tile_size, float scale=1.0f)
void DrawTileOnBitmap(int tile_size, gfx::Bitmap *bitmap, ImVec4 color)
void DrawCustomHighlight(float grid_step)
std::unique_ptr< CanvasExtensions > extensions_
CanvasGridSize grid_size() const
void AddContextMenuItem(const gui::CanvasMenuItem &item)
ImVec2 GetPreferredSize() const
float GetGridStep() const
CanvasInteractionHandler interaction_handler_
void InitializePaletteEditor(Rom *rom)
void Begin(ImVec2 canvas_size=ImVec2(0, 0))
Begin canvas rendering (ImGui-style)
void SetZoomToFit(const gfx::Bitmap &bitmap)
bool WasClicked(ImGuiMouseButton button=ImGuiMouseButton_Left) const
ImVector< ImVector< std::string > > labels_
gfx::BppFormat GetCurrentBppFormat() const
void ClosePersistentPopup(const std::string &popup_id)
void ShowBppFormatSelector()
void RecordCanvasOperation(const std::string &operation_name, double time_ms)
void RenderPersistentPopups()
void set_global_scale(float scale)
void SetGridSize(CanvasGridSize grid_size)
bool IsAutoResize() const
std::shared_ptr< CanvasUsageTracker > usage_tracker_
void End()
End canvas rendering (ImGui-style)
void EndInTable(CanvasRuntime &runtime, const CanvasFrameOptions &options)
void DrawSelectRect(int current_map, int tile_size=0x10, float scale=1.0f)
std::unique_ptr< CanvasContextMenu > context_menu_
ImVec2 GetLastClickPosition() const
zelda3::GameData * game_data_
void DrawOutline(int x, int y, int w, int h)
void DrawBackground(ImVec2 canvas_size=ImVec2(0, 0), std::optional< ImVec2 > viewport_size=std::nullopt)
void DrawInfoGrid(float grid_step=64.0f, int tile_id_offset=8, int label_id=0)
CanvasSelection selection_
CanvasRuntime BeginInTable(const std::string &label, const CanvasFrameOptions &options)
Begin canvas in table cell with frame options (modern API) Returns CanvasRuntime for stateless helper...
bool enable_hex_tile_labels_
void OpenPersistentPopup(const std::string &popup_id, std::function< void()> render_callback)
void DrawBitmapTable(const BitmapTable &gfx_bin)
void InitializeDefaults()
std::shared_ptr< CanvasPerformanceIntegration > performance_integration_
void Init(const CanvasConfig &config)
Initialize canvas with configuration (post-construction) Preferred over constructor parameters for ne...
void SetGlobalScale(float scale)
void DrawGrid(float grid_step=64.0f, int tile_id_offset=8)
void DrawContextMenuItem(const gui::CanvasMenuItem &item)
void DrawText(const std::string &text, int x, int y)
void SyncLegacyGeometryFromState()
CanvasExtensions & EnsureExtensions()
std::vector< ImVec2 > selected_tiles_
bool ApplyROMPalette(int group_index, int palette_index)
static bool IsTouchDevice()
::yaze::EventBus * event_bus()
Get the current EventBus instance.
BppFormat
BPP format enumeration for SNES graphics.
@ kBpp8
8 bits per pixel (256 colors)
void ReserveCanvasSpace(ImVec2 canvas_size, const std::string &label)
void SetNextCanvasSize(ImVec2 size, bool auto_resize)
void DrawCanvasRect(ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 scrolling, int x, int y, int w, int h, ImVec4 color, float global_scale)
void DrawCanvasLabels(const CanvasRenderContext &ctx, const ImVector< ImVector< std::string > > &labels, int current_labels, int tile_id_offset)
void DrawCanvasOverlay(const CanvasRenderContext &ctx, const ImVector< ImVec2 > &points, const ImVector< ImVec2 > &selected_points)
void DrawCanvasOutlineWithColor(ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 scrolling, int x, int y, int w, int h, ImVec4 color, float global_scale)
void DrawCanvasOutline(ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 scrolling, int x, int y, int w, int h, uint32_t color, float global_scale)
ImVec2 CalculateMinimumCanvasSize(ImVec2 content_size, float global_scale, float padding)
void DrawCanvasGrid(const CanvasRenderContext &ctx, int highlight_tile_id)
ImVec2 CalculatePreferredCanvasSize(ImVec2 content_size, float global_scale, float min_scale)
void DrawCanvasText(ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 scrolling, const std::string &text, int x, int y, float global_scale)
void DrawCustomHighlight(ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 scrolling, int highlight_tile_id, float grid_step)
void DrawCanvasGridLines(ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 canvas_p1, ImVec2 scrolling, float grid_step, float global_scale)
const ImGuiID kViewportWheelOwner
void PreventViewportWheelPropagation(ImGuiContext *ctx, ImGuiContextHook *)
void RegisterViewportWheelOwner(const ImRect &bounds)
ImVec2 AlignPosToGrid(ImVec2 pos, float scale)
Graphical User Interface (GUI) components for the application.
constexpr uint32_t kWhiteColor
constexpr uint32_t kRectangleColor
CanvasUsage
Canvas usage patterns and tracking.
bool DrawTileSelector(const CanvasRuntime &rt, int size, int size_y, ImVec2 *out_selected_pos)
bool DrawTilemapPainter(const CanvasRuntime &rt, gfx::Tilemap &tilemap, int current_tile, ImVec2 *out_drawn_pos)
void ApplyScrollDelta(CanvasGeometry &geometry, ImVec2 delta)
Apply scroll delta to geometry.
ImVec2 ComputeScrollForZoomAtScreenPos(const CanvasGeometry &geometry, float old_scale, float new_scale, ImVec2 mouse_screen_pos)
Compute new scroll offset to keep a canvas point locked under the mouse.
ImVec2 CalculateMouseInCanvas(const CanvasGeometry &geometry, ImVec2 mouse_screen_pos)
Calculate mouse position in canvas space.
void RenderCanvasBackground(ImDrawList *draw_list, const CanvasGeometry &geometry)
Render canvas background and border.
CanvasGeometry CalculateCanvasGeometry(const CanvasConfig &config, ImVec2 requested_size, ImVec2 cursor_screen_pos, ImVec2 content_region_avail)
Calculate canvas geometry from configuration and ImGui context.
ZoomToFitResult ComputeZoomToFit(ImVec2 content_px, ImVec2 canvas_px, float padding_px)
void RenderMenuItem(const CanvasMenuItem &item, std::function< void(const std::string &, std::function< void()>)> popup_opened_callback)
Render a single menu item.
void RenderBitmapOnCanvas(ImDrawList *draw_list, const CanvasGeometry &geometry, gfx::Bitmap &bitmap, int, float scale)
Render bitmap on canvas (border offset variant)
constexpr ImGuiButtonFlags kMouseFlags
void DrawSelectRect(const CanvasRuntime &rt, int current_map, int tile_size, float scale, CanvasSelection &selection)
static ZoomChangedEvent Create(const std::string &src, float old_z, float new_z, size_t session=0)
int y
Y coordinate or height.
int x
X coordinate or width.
Tilemap structure for SNES tile-based graphics management.
Pair tile_size
Size of individual tiles (8x8 or 16x16)
Pair map_size
Size of tilemap in tiles.
Bitmap atlas
Master bitmap containing all tiles.
Unified configuration for canvas display and interaction.
std::function< void(const CanvasConfig &) on_config_changed)
bool clamp_rect_to_local_maps
std::function< void(const CanvasConfig &) on_scale_changed)
bool enable_custom_labels
Optional extension modules for Canvas.
std::optional< ImVec2 > viewport_size
std::optional< float > grid_step
Selection state for canvas interactions.
std::vector< ImVec2 > selected_tiles
std::vector< ImVec2 > selected_points
ImVec2 mouse_pos_in_canvas