1#include "imgui/imgui_internal.h"
22#include "imgui/imgui.h"
31 auto* hovered = ctx->HoveredWindow;
32 auto* scrolled = ctx->WheelingWindow;
33 if (!hovered || !scrolled ||
34 ctx->WheelingWindowScrolledFrame != ctx->FrameCount ||
36 ctx->FrameCount - 1) {
39 const auto& storage = hovered->StateStorage;
44 if (!viewport.Contains(ctx->IO.MousePos)) {
47 auto* ancestor = hovered;
48 while (ancestor && ancestor != scrolled) {
49 ancestor = ancestor->ParentWindow;
58 const ImVec2 wheel = ctx->IO.MouseWheelRequestAxisSwap
59 ? ImVec2(ctx->IO.MouseWheel, 0)
60 : ImVec2(ctx->IO.MouseWheelH, ctx->IO.MouseWheel);
61 bool scroll_x = wheel.x != 0 && scrolled->ScrollMax.x != 0;
62 bool scroll_y = wheel.y != 0 && scrolled->ScrollMax.y != 0;
65 if (scroll_x && scroll_y) {
66 if (ctx->WheelingAxisAvg.x > ctx->WheelingAxisAvg.y)
72 scrolled->ScrollTarget.x = FLT_MAX;
74 scrolled->ScrollTarget.y = FLT_MAX;
75 ctx->WheelingWindow =
nullptr;
76 ctx->WheelingWindowReleaseTimer = 0;
80 auto* ctx = ImGui::GetCurrentContext();
81 auto* window = ImGui::GetCurrentWindow();
82 ImRect visible = bounds;
83 visible.ClipWith(window->InnerClipRect);
84 auto& storage = window->StateStorage;
90 for (
const auto& hook : ctx->Hooks) {
96 ImGuiContextHook hook;
98 hook.Type = ImGuiContextHookType_NewFramePost;
100 ImGui::AddContextHook(ctx, &hook);
120 for (
auto& label_group :
labels_) {
126 Init(
id, ImVec2(0, 0));
155 Init(
id, ImVec2(0, 0));
230 extensions_ = std::make_unique<CanvasExtensions>();
235using ImGui::GetContentRegionAvail;
236using ImGui::GetCursorScreenPos;
238using ImGui::GetWindowDrawList;
239using ImGui::IsItemActive;
240using ImGui::IsItemHovered;
241using ImGui::IsMouseClicked;
242using ImGui::IsMouseDragging;
249 ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight;
253 return ImVec2(std::floor(pos.x / scale) * scale,
254 std::floor(pos.y / scale) * scale);
313 const float min_scale = old_scale > 0.0f ? std::min(old_scale, 0.25f) : 0.25f;
330 if (old_scale != scale) {
419 ImGui::OpenPopup(
"Canvas Usage Report");
420 if (ImGui::BeginPopupModal(
"Canvas Usage Report",
nullptr,
421 ImGuiWindowFlags_AlwaysAutoResize)) {
422 ImGui::Text(tr(
"Canvas Usage Report"));
424 ImGui::TextWrapped(
"%s", report.c_str());
426 if (ImGui::Button(tr(
"Close"))) {
427 ImGui::CloseCurrentPopup();
437 ext.InitializePaletteEditor();
438 if (ext.palette_editor) {
439 ext.palette_editor->Initialize(
rom);
455 ext.InitializePaletteEditor();
456 if (ext.palette_editor) {
458 ext.palette_editor->ShowPaletteEditor(*mutable_palette,
459 "Canvas Palette Editor");
469 ext.InitializePaletteEditor();
470 if (ext.palette_editor) {
471 ext.palette_editor->ShowColorAnalysis(*
bitmap_,
"Canvas Color Analysis");
508 std::string child_id =
canvas_id_ +
"_TableChild";
513 ImGui::BeginChild(child_id.c_str(), child_size,
515 ImGuiWindowFlags_NoScrollbar);
517 if (!label.empty()) {
518 ImGui::Text(
"%s", label.c_str());
532 if (child_size.x <= 0 || child_size.y <= 0) {
542 std::string child_id =
canvas_id_ +
"_TableChild";
543 ImGuiWindowFlags child_flags = ImGuiWindowFlags_NoScrollbar;
545 child_flags = ImGuiWindowFlags_AlwaysVerticalScrollbar;
547 ImGui::BeginChild(child_id.c_str(), child_size,
true, child_flags);
549 if (!label.empty()) {
550 ImGui::Text(
"%s", label.c_str());
595 return ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(button) &&
603 return ImVec2(-1, -1);
632 if (effective_size.x == 0 && effective_size.y == 0) {
640 ImGuiWindowFlags child_flags = ImGuiWindowFlags_None;
642 child_flags |= ImGuiWindowFlags_AlwaysVerticalScrollbar;
644 ImGui::BeginChild(
canvas_id().c_str(), effective_size,
true, child_flags);
680 const std::function<
void()>& event,
681 int tile_size,
float scale) {
704 std::optional<ImVec2> viewport_size) {
709 const ImVec2 cursor = GetCursorScreenPos();
710 const ImVec2 available = GetContentRegionAvail();
711 ImRect visible_host(cursor,
712 ImVec2(cursor.x + available.x, cursor.y + available.y));
713 visible_host.ClipWith(ImGui::GetCurrentWindow()->InnerClipRect);
717 viewport_size.value_or(ImVec2(std::max(1.0f, visible_host.GetWidth()),
718 std::max(1.0f, visible_host.GetHeight())));
723 const ImVec2 visible(std::max(1.0f, viewport_size->x),
724 std::max(1.0f, viewport_size->y));
748 ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelX);
749 ImGui::SetItemKeyOwner(ImGuiKey_MouseWheelY);
750 RegisterViewportWheelOwner(
757 if (IsItemHovered()) {
758 const ImGuiIO& io = GetIO();
771 ImGuiIO& io = GetIO();
772 const float wheel_x = io.MouseWheelH;
773 const float wheel_y = io.MouseWheel;
775 if (wheel_x != 0.0f || wheel_y != 0.0f) {
777 io.MouseWheelH = 0.0f;
778 io.MouseWheel = 0.0f;
780 if (io.KeyCtrl && wheel_y != 0.0f) {
782 constexpr float kMinScale = 0.25f;
783 constexpr float kMaxScale = 8.0f;
785 const float new_scale = std::clamp(unclamped, kMinScale, kMaxScale);
797 constexpr float kTouchWheelToPixels = 10.0f;
799 ImVec2(wheel_x * kTouchWheelToPixels,
800 wheel_y * kTouchWheelToPixels));
809 const ImGuiIO& io = GetIO();
810 const bool is_active = IsItemActive();
813 if (
const float mouse_threshold_for_pan =
816 IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan)) {
825 const ImGuiIO& io = GetIO();
830 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
912 ext.InitializeModals();
923 ext.modals->ShowAdvancedProperties(
canvas_id_, modal_config,
929 ext.InitializeModals();
940 ext.modals->ShowScalingControls(
canvas_id_, modal_config,
964 auto popup_callback = [
this](
const std::string& id,
965 std::function<void()> callback) {
991 last_section.items.push_back(item);
1000 std::function<
void()> render_callback) {
1022 if (available.x <= 0 || available.y <= 0)
1023 available = ImGui::GetContentRegionAvail();
1026 const float scale = std::max(0.25f, fit.scale);
1029 (available.y - bitmap.
height() * scale) * 0.5f));
1070 const ImGuiIO& io = GetIO();
1071 const bool is_hovered = IsItemHovered();
1075 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
1076 const auto scaled_size = size * scale;
1090 ImVec2 paint_pos = AlignPosToGrid(mouse_pos, scaled_size);
1092 auto paint_pos_end =
1093 ImVec2(paint_pos.x + scaled_size, paint_pos.y + scaled_size);
1095 points_.push_back(paint_pos_end);
1100 ImVec2(origin.x + paint_pos.x, origin.y + paint_pos.y),
1101 ImVec2(origin.x + paint_pos.x + scaled_size,
1102 origin.y + paint_pos.y + scaled_size),
1103 ImVec2(0, 0), ImVec2(1, 1),
1104 ImGui::GetColorU32(ImVec4(1, 1, 1, 1)));
1107 if (IsMouseClicked(ImGuiMouseButton_Left) &&
1108 ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
1135 const ImGuiIO& io = GetIO();
1138 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
1140 ImVec2 paint_pos = AlignPosToGrid(mouse_pos, scaled_size);
1146 ImVec2(paint_pos.x + scaled_size, paint_pos.y + scaled_size));
1157 const ImGuiIO& io = GetIO();
1158 const bool is_hovered = IsItemHovered();
1162 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
1164 static bool is_dragging =
false;
1165 static ImVec2 start_drag_pos;
1179 ImVec2 paint_pos = AlignPosToGrid(mouse_pos, scaled_tile_size);
1188 ImVec2(paint_pos.x + scaled_tile_size, paint_pos.y + scaled_tile_size));
1191 ImVec2(origin.x + paint_pos.x + 1, origin.y + paint_pos.y + 1),
1192 ImVec2(origin.x + paint_pos.x + scaled_tile_size,
1193 origin.y + paint_pos.y + scaled_tile_size),
1194 IM_COL32(color.x * 255, color.y * 255, color.z * 255, 255));
1196 if (IsMouseClicked(ImGuiMouseButton_Left)) {
1198 start_drag_pos = paint_pos;
1201 if (is_dragging && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) {
1202 is_dragging =
false;
1213 int tile_index_x =
static_cast<int>(position.x /
global_scale_) / tile_size;
1214 int tile_index_y =
static_cast<int>(position.y /
global_scale_) / tile_size;
1216 ImVec2 start_position(tile_index_x * tile_size, tile_index_y * tile_size);
1219 for (
int y = 0; y < tile_size; ++y) {
1220 for (
int x = 0; x < tile_size; ++x) {
1223 (start_position.y + y) * bitmap->
width() + (start_position.x + x);
1241 ImVec2 selected_pos;
1245 if (
is_hovered_ && IsMouseClicked(ImGuiMouseButton_Left)) {
1246 const ImGuiIO& io = GetIO();
1249 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
1250 ImVec2 painter_pos = AlignPosToGrid(mouse_pos,
static_cast<float>(size));
1253 points_.push_back(painter_pos);
1254 points_.push_back(ImVec2(painter_pos.x + size, painter_pos.y + size_y));
1258 return double_clicked;
1327 ImVec2 src_pos, ImVec2 src_size) {
1344 for (
const auto& [key, value] : gfx_bin) {
1346 if (!value || !value->is_active() || !value->texture()) {
1349 int offset = 0x40 * (key + 1);
1354 draw_list_->AddImage((ImTextureID)(intptr_t)value->texture(),
1357 ImVec2(0, 0), ImVec2(1, 1),
1358 ImGui::GetColorU32(ImVec4(1, 1, 1, 1)));
1365 IM_COL32(255, 255, 255, 200), scale);
1371 y, w, h, color, scale);
1381 int tile_size,
float ,
int local_map_size,
1382 ImVec2 total_map_size) {
1387 if (group.empty()) {
1399 bool use_optimized_rendering =
1403 const int small_map = local_map_size;
1404 const float large_map_width = total_map_size.x;
1405 const float large_map_height = total_map_size.y;
1408 const float tile_scale = tile_size * effective_scale;
1417 int start_tile_x =
static_cast<int>(std::floor(rect_top_left.x / tile_size));
1418 int start_tile_y =
static_cast<int>(std::floor(rect_top_left.y / tile_size));
1420 static_cast<int>(std::floor(rect_bottom_right.x / tile_size));
1422 static_cast<int>(std::floor(rect_bottom_right.y / tile_size));
1424 if (start_tile_x > end_tile_x)
1425 std::swap(start_tile_x, end_tile_x);
1426 if (start_tile_y > end_tile_y)
1427 std::swap(start_tile_y, end_tile_y);
1430 int rect_width = (end_tile_x - start_tile_x) * tile_size;
1431 int rect_height = (end_tile_y - start_tile_y) * tile_size;
1433 int tiles_per_row = rect_width / tile_size;
1434 int tiles_per_col = rect_height / tile_size;
1440 for (
int y = 0; y < tiles_per_col + 1; ++y) {
1441 for (
int x = 0; x < tiles_per_row + 1; ++x) {
1443 if (i >=
static_cast<int>(group.size())) {
1447 int tile_id = group[i];
1451 if (tile_id >= 0 && tile_id < tilemap_size) {
1453 int tile_pos_x = (x + start_tile_x) * tile_size * effective_scale;
1454 int tile_pos_y = (y + start_tile_y) * tile_size * effective_scale;
1459 atlas_tiles_per_row > 0) {
1461 (tile_id % atlas_tiles_per_row) * tilemap.
tile_size.
x;
1463 (tile_id / atlas_tiles_per_row) * tilemap.
tile_size.
y;
1466 if (atlas_tile_x >= 0 && atlas_tile_x < tilemap.
atlas.
width() &&
1467 atlas_tile_y >= 0 && atlas_tile_y < tilemap.
atlas.
height()) {
1469 const float atlas_width =
static_cast<float>(tilemap.
atlas.
width());
1470 const float atlas_height =
1473 ImVec2(atlas_tile_x / atlas_width, atlas_tile_y / atlas_height);
1475 ImVec2((atlas_tile_x + tilemap.
tile_size.
x) / atlas_width,
1476 (atlas_tile_y + tilemap.
tile_size.
y) / atlas_height);
1481 float screen_w = tilemap.
tile_size.
x * effective_scale;
1482 float screen_h = tilemap.
tile_size.
y * effective_scale;
1485 uint32_t alpha_color = use_optimized_rendering
1486 ? IM_COL32(255, 255, 255, 200)
1487 : IM_COL32(255, 255, 255, 150);
1492 ImVec2(screen_x, screen_y),
1493 ImVec2(screen_x + screen_w, screen_y + screen_h), uv0, uv1,
1494 ImGui::GetColorU32(alpha_color));
1501 if (i >=
static_cast<int>(group.size())) {
1511 const ImGuiIO& io = GetIO();
1513 const ImVec2 mouse_pos(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
1518 ImVec2 clamped_mouse_pos = mouse_pos;
1522 int mouse_local_map_x =
static_cast<int>(mouse_pos.x) / small_map;
1523 int mouse_local_map_y =
static_cast<int>(mouse_pos.y) / small_map;
1527 float potential_end_x = mouse_pos.x + rect_width;
1528 float potential_end_y = mouse_pos.y + rect_height;
1531 int potential_end_map_x =
static_cast<int>(potential_end_x) / small_map;
1532 int potential_end_map_y =
static_cast<int>(potential_end_y) / small_map;
1535 if (potential_end_map_x != mouse_local_map_x) {
1537 float max_mouse_x = (mouse_local_map_x + 1) * small_map - rect_width;
1538 clamped_mouse_pos.x = std::min(mouse_pos.x, max_mouse_x);
1541 if (potential_end_map_y != mouse_local_map_y) {
1543 float max_mouse_y = (mouse_local_map_y + 1) * small_map - rect_height;
1544 clamped_mouse_pos.y = std::min(mouse_pos.y, max_mouse_y);
1549 auto new_start_pos_screen =
1550 AlignPosToGrid(clamped_mouse_pos, tile_size * effective_scale);
1553 ImVec2 new_start_pos_world(new_start_pos_screen.x / effective_scale,
1554 new_start_pos_screen.y / effective_scale);
1557 new_start_pos_world.x =
1558 std::clamp(new_start_pos_world.x, 0.0f, large_map_width - rect_width);
1559 new_start_pos_world.y =
1560 std::clamp(new_start_pos_world.y, 0.0f, large_map_height - rect_height);
1565 new_start_pos_world.y + rect_height));
1597 for (
float x = fmodf(
scrolling_.x, grid_step);
1599 for (
float y = fmodf(
scrolling_.y, grid_step);
1603 int tile_id = tile_x + (tile_y * tile_id_offset);
1605 if (tile_id >=
labels_[label_id].size()) {
1608 const std::string& label =
labels_[label_id][tile_id];
1610 ImVec2(
canvas_p0_.x + x + (grid_step / 2) - tile_id_offset,
1611 canvas_p0_.y + y + (grid_step / 2) - tile_id_offset),
1640 .grid_step = grid_step};
1676 ImDrawList*
draw_list = ImGui::GetWindowDrawList();
1678 Text(tr(
"Blue shape is drawn first: appears in back"));
1679 Text(tr(
"Red shape is drawn after: appears in front"));
1680 ImVec2 p0 = ImGui::GetCursorScreenPos();
1681 draw_list->AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50),
1682 IM_COL32(0, 0, 255, 255));
1683 draw_list->AddRectFilled(ImVec2(p0.x + 25, p0.y + 25),
1684 ImVec2(p0.x + 75, p0.y + 75),
1685 IM_COL32(255, 0, 0, 255));
1686 ImGui::Dummy(ImVec2(75, 75));
1690 Text(tr(
"Blue shape is drawn first, into channel 1: appears in front"));
1691 Text(tr(
"Red shape is drawn after, into channel 0: appears in back"));
1692 ImVec2 p1 = ImGui::GetCursorScreenPos();
1699 draw_list->AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50),
1700 IM_COL32(0, 0, 255, 255));
1702 draw_list->AddRectFilled(ImVec2(p1.x + 25, p1.y + 25),
1703 ImVec2(p1.x + 75, p1.y + 75),
1704 IM_COL32(255, 0, 0, 255));
1710 ImGui::Dummy(ImVec2(75, 75));
1712 tr(
"After reordering, contents of channel 0 appears below channel 1."));
1719 ext.InitializeModals();
1750 if (ImGui::BeginPopupModal(
"Advanced Canvas Properties",
nullptr,
1751 ImGuiWindowFlags_AlwaysAutoResize)) {
1752 ImGui::Text(tr(
"Advanced Canvas Configuration"));
1756 ImGui::Text(tr(
"Canvas Properties"));
1757 ImGui::Text(tr(
"ID: %s"),
canvas_id_.c_str());
1768 ImGui::Text(tr(
"Minimum Size: %.0f x %.0f"), min_size.x, min_size.y);
1769 ImGui::Text(tr(
"Preferred Size: %.0f x %.0f"), preferred_size.x,
1775 ImGui::Text(tr(
"View Settings"));
1782 if (ImGui::Checkbox(tr(
"Enable Custom Labels"),
1786 if (ImGui::Checkbox(tr(
"Enable Context Menu"),
1799 ImGui::Text(tr(
"Grid Configuration"));
1807 ImGui::Text(tr(
"Scale Configuration"));
1815 ImGui::Text(tr(
"Scrolling Configuration"));
1817 if (ImGui::Button(tr(
"Reset Scroll"))) {
1821 if (ImGui::Button(tr(
"Center View"))) {
1832 if (ImGui::Button(tr(
"Close"))) {
1833 ImGui::CloseCurrentPopup();
1844 ext.InitializeModals();
1873 ext.modals->ShowScalingControls(
canvas_id_, modal_config);
1878 if (ImGui::BeginPopupModal(
"Scaling Controls",
nullptr,
1879 ImGuiWindowFlags_AlwaysAutoResize)) {
1880 ImGui::Text(tr(
"Canvas Scaling and Display Controls"));
1891 ImGui::Text(tr(
"Preset Scales:"));
1892 if (ImGui::Button(tr(
"0.25x"))) {
1897 if (ImGui::Button(tr(
"0.5x"))) {
1902 if (ImGui::Button(tr(
"1x"))) {
1907 if (ImGui::Button(tr(
"2x"))) {
1912 if (ImGui::Button(tr(
"4x"))) {
1917 if (ImGui::Button(tr(
"8x"))) {
1924 ImGui::Text(tr(
"Grid Configuration"));
1932 ImGui::Text(tr(
"Grid Presets:"));
1933 if (ImGui::Button(tr(
"8x8"))) {
1938 if (ImGui::Button(tr(
"16x16"))) {
1943 if (ImGui::Button(tr(
"32x32"))) {
1948 if (ImGui::Button(tr(
"64x64"))) {
1955 ImGui::Text(tr(
"Canvas Information"));
1958 ImGui::Text(tr(
"Scaled Size: %.0f x %.0f"),
1962 ImGui::Text(tr(
"Bitmap Size: %d x %d"),
bitmap_->
width(),
1965 tr(
"Effective Scale: %.3f x %.3f"),
1970 if (ImGui::Button(tr(
"Close"))) {
1971 ImGui::CloseCurrentPopup();
1984 if (
bitmap_ && ext.bpp_format_ui) {
1985 ext.bpp_format_ui->RenderFormatSelector(
1997 if (
bitmap_ && ext.bpp_format_ui) {
2006 if (!ext.bpp_conversion_dialog) {
2007 ext.bpp_conversion_dialog = std::make_unique<gui::BppConversionDialog>(
2011 if (
bitmap_ && ext.bpp_conversion_dialog) {
2012 ext.bpp_conversion_dialog->Show(
2015 ConvertBitmapFormat(format);
2019 if (ext.bpp_conversion_dialog) {
2020 ext.bpp_conversion_dialog->Render();
2029 if (current_format == target_format) {
2046 }
catch (
const std::exception& e) {
2047 SDL_Log(
"Failed to convert bitmap format: %s", e.what());
2063 ext.InitializeAutomation(
this);
2064 return ext.automation_api.get();
2079 draw_list_->AddImage(texture, screen_pos, screen_end, ImVec2(0, 0),
2080 ImVec2(1, 1), ImGui::GetColorU32(ImVec4(1, 1, 1, 1)));
2091 draw_list_->AddRectFilled(screen_pos, screen_end, color);
2100 draw_list_->AddText(screen_pos, color, text.c_str());
2108 : canvas_(&canvas), options_(options), active_(true) {
2119 : canvas_(other.canvas_), options_(other.options_), active_(other.active_) {
2120 other.active_ =
false;
2124 if (
this != &other) {
2126 canvas_->
End(options_);
2128 canvas_ = other.canvas_;
2129 options_ = other.options_;
2130 active_ = other.active_;
2131 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()
RAII scope that samples the images drawn inside it with nearest-neighbor filtering.
::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