7#include "imgui/imgui.h"
16 return ImVec2(std::floor(pos.x / grid_step) * grid_step,
17 std::floor(pos.y / grid_step) * grid_step);
38 ImVec2 canvas_p0, ImVec2 scrolling,
float ,
39 float , ImVec2 ,
bool is_hovered) {
47 const ImGuiIO& imgui_io = ImGui::GetIO();
48 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y);
50 ImVec2(imgui_io.MousePos.x - origin.x, imgui_io.MousePos.y - origin.y);
60 const gfx::Bitmap& bitmap, ImDrawList* draw_list, ImVec2 canvas_p0,
61 ImVec2 scrolling,
float global_scale,
float tile_size,
bool is_hovered) {
62 const ImGuiIO& imgui_io = ImGui::GetIO();
63 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y);
64 const ImVec2 mouse_pos(imgui_io.MousePos.x - origin.x,
65 imgui_io.MousePos.y - origin.y);
66 const auto scaled_size = tile_size * global_scale;
78 ImVec2 paint_pos = AlignToGridLocal(mouse_pos, scaled_size);
81 ImVec2(paint_pos.x + scaled_size, paint_pos.y + scaled_size);
89 draw_list->AddImage(
reinterpret_cast<ImTextureID
>(bitmap.
texture()),
90 ImVec2(origin.x + paint_pos.x, origin.y + paint_pos.y),
91 ImVec2(origin.x + paint_pos.x + scaled_size,
92 origin.y + paint_pos.y + scaled_size),
93 ImVec2(0, 0), ImVec2(1, 1),
94 ImGui::GetColorU32(ImVec4(1, 1, 1, 1)));
98 if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) &&
99 ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
108 gfx::Tilemap& tilemap,
int current_tile, ImDrawList* draw_list,
109 ImVec2 canvas_p0, ImVec2 scrolling,
float global_scale,
bool is_hovered) {
110 const ImGuiIO& imgui_io = ImGui::GetIO();
111 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y);
112 const ImVec2 mouse_pos(imgui_io.MousePos.x - origin.x,
113 imgui_io.MousePos.y - origin.y);
120 const auto scaled_size = tilemap.
tile_size.
x * global_scale;
129 ImVec2 paint_pos =
AlignToGrid(mouse_pos, scaled_size);
134 ImVec2(paint_pos.x + scaled_size, paint_pos.y + scaled_size));
139 if (tiles_per_row > 0) {
140 int tile_x = (current_tile % tiles_per_row) * tilemap.
tile_size.
x;
141 int tile_y = (current_tile / tiles_per_row) * tilemap.
tile_size.
y;
143 if (tile_x >= 0 && tile_x < tilemap.
atlas.
width() && tile_y >= 0 &&
146 ImVec2(
static_cast<float>(tile_x) / tilemap.
atlas.
width(),
147 static_cast<float>(tile_y) / tilemap.
atlas.
height());
148 ImVec2 uv1 = ImVec2(
static_cast<float>(tile_x + tilemap.
tile_size.
x) /
150 static_cast<float>(tile_y + tilemap.
tile_size.
y) /
156 ImVec2(origin.x + paint_pos.x, origin.y + paint_pos.y),
157 ImVec2(origin.x + paint_pos.x + scaled_size,
158 origin.y + paint_pos.y + scaled_size),
159 uv0, uv1, ImGui::GetColorU32(ImVec4(1, 1, 1, 1)));
164 if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) ||
165 ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
174 const ImVec4& color, ImDrawList* draw_list, ImVec2 canvas_p0,
175 ImVec2 scrolling,
float global_scale,
float tile_size,
bool is_hovered) {
176 const ImGuiIO& imgui_io = ImGui::GetIO();
177 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y);
178 const ImVec2 mouse_pos(imgui_io.MousePos.x - origin.x,
179 imgui_io.MousePos.y - origin.y);
180 auto scaled_tile_size = tile_size * global_scale;
181 static bool is_dragging =
false;
182 static ImVec2 start_drag_pos;
191 ImVec2 paint_pos =
AlignToGrid(mouse_pos, scaled_tile_size);
199 ImVec2(paint_pos.x + scaled_tile_size, paint_pos.y + scaled_tile_size));
202 draw_list->AddRectFilled(
203 ImVec2(origin.x + paint_pos.x + 1, origin.y + paint_pos.y + 1),
204 ImVec2(origin.x + paint_pos.x + scaled_tile_size,
205 origin.y + paint_pos.y + scaled_tile_size),
206 IM_COL32(color.x * 255, color.y * 255, color.z * 255, 255));
209 if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
211 start_drag_pos = paint_pos;
214 if (is_dragging && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) {
228 const ImGuiIO& imgui_io = ImGui::GetIO();
229 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y);
230 const ImVec2 mouse_pos(imgui_io.MousePos.x - origin.x,
231 imgui_io.MousePos.y - origin.y);
233 if (is_hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
235 ImVec2 painter_pos = AlignToGridLocal(mouse_pos, tile_size);
239 ImVec2(painter_pos.x + tile_size, painter_pos.y + tile_size));
243 if (is_hovered && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
251 int current_map, ImDrawList* draw_list, ImVec2 canvas_p0, ImVec2 scrolling,
252 float global_scale,
float tile_size,
bool is_hovered) {
262 ImVec2(tile_size * global_scale, tile_size * global_scale);
264 ImVec2(tile_size, tile_size);
268 geometry, current_map, tile_size, draw_list, ImGuiMouseButton_Right);
271 if (event.is_complete) {
280 if (!event.selected_tiles.empty() && !event.is_complete) {
295 return AlignToGridLocal(pos, grid_step);
300 const ImGuiIO& imgui_io = ImGui::GetIO();
301 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y);
302 return ImVec2(imgui_io.MousePos.x - origin.x, imgui_io.MousePos.y - origin.y);
306 return ImGui::IsMouseClicked(button);
310 return ImGui::IsMouseDoubleClicked(button);
314 return ImGui::IsMouseDragging(button);
318 return ImGui::IsMouseReleased(button);
Free functions for canvas interaction handling.
Represents a bitmap image optimized for SNES ROM hacking.
TextureHandle texture() const
ImVector< ImVec2 > hover_points_
bool DrawSelectRect(int current_map, ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 scrolling, float global_scale, float tile_size, bool is_hovered)
Draw rectangle selector (multi-tile selection)
ImVector< ImVec2 > selected_points_
void ClearState()
Clear all interaction state.
bool DrawTilemapPainter(gfx::Tilemap &tilemap, int current_tile, ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 scrolling, float global_scale, bool is_hovered)
Draw tilemap painter (preview + interaction)
ImVec2 AlignPosToGrid(ImVec2 pos, float grid_step)
ImVec2 selected_tile_pos_
TileInteractionResult Update(ImVec2 canvas_p0, ImVec2 scrolling, float global_scale, float tile_size, ImVec2 canvas_size, bool is_hovered)
Update interaction state (call once per frame)
ImVec2 mouse_pos_in_canvas_
bool DrawTileSelector(ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 scrolling, float tile_size, bool is_hovered)
Draw tile selector (single tile selection)
bool DrawSolidTilePainter(const ImVec4 &color, ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 scrolling, float global_scale, float tile_size, bool is_hovered)
Draw solid color painter.
bool IsMouseClicked(ImGuiMouseButton button)
bool IsMouseDragging(ImGuiMouseButton button)
bool IsMouseReleased(ImGuiMouseButton button)
bool IsMouseDoubleClicked(ImGuiMouseButton button)
std::vector< ImVec2 > selected_tiles_
bool DrawTilePainter(const gfx::Bitmap &bitmap, ImDrawList *draw_list, ImVec2 canvas_p0, ImVec2 scrolling, float global_scale, float tile_size, bool is_hovered)
Draw tile painter (preview + interaction)
ImVec2 GetMousePosition(ImVec2 canvas_p0, ImVec2 scrolling)
void Initialize(const std::string &canvas_id)
Initialize the interaction handler.
TileInteractionMode current_mode_
RAII scope that samples the images drawn inside it with nearest-neighbor filtering.
ImVec2 AlignToGridLocal(ImVec2 pos, float grid_step)
ImVec2 AlignToGrid(ImVec2 pos, float grid_step)
Align position to grid.
RectSelectionEvent HandleRectangleSelection(const CanvasGeometry &geometry, int current_map, float tile_size, ImDrawList *draw_list, ImGuiMouseButton mouse_button)
Handle rectangle selection interaction.
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)
Bitmap atlas
Master bitmap containing all tiles.
Canvas geometry calculated per-frame.
Event payload for rectangle selection operations.
Result of a tile interaction operation.