yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
canvas_interaction_handler.cc
Go to the documentation of this file.
2
3#include <cmath>
4
6#include "imgui/imgui.h"
7
8namespace yaze {
9namespace gui {
10
11namespace {
12
13// Helper function to align position to grid (local version)
14ImVec2 AlignToGridLocal(ImVec2 pos, float grid_step) {
15 return ImVec2(std::floor(pos.x / grid_step) * grid_step,
16 std::floor(pos.y / grid_step) * grid_step);
17}
18
19} // namespace
20
21void CanvasInteractionHandler::Initialize(const std::string& canvas_id) {
22 canvas_id_ = canvas_id;
23 ClearState();
24}
25
27 hover_points_.clear();
28 selected_points_.clear();
29 selected_tiles_.clear();
30 drawn_tile_pos_ = ImVec2(-1, -1);
31 mouse_pos_in_canvas_ = ImVec2(0, 0);
32 selected_tile_pos_ = ImVec2(-1, -1);
33 rect_select_active_ = false;
34}
35
37 ImVec2 canvas_p0, ImVec2 scrolling, float /*global_scale*/,
38 float /*tile_size*/, ImVec2 /*canvas_size*/, bool is_hovered) {
40
41 if (!is_hovered) {
42 hover_points_.clear();
43 return result;
44 }
45
46 const ImGuiIO& imgui_io = ImGui::GetIO();
47 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y);
49 ImVec2(imgui_io.MousePos.x - origin.x, imgui_io.MousePos.y - origin.y);
50
51 // Update based on current mode - each mode is handled by its specific Draw
52 // method This method exists for future state updates if needed
53 (void)current_mode_; // Suppress unused warning
54
55 return result;
56}
57
59 const gfx::Bitmap& bitmap, ImDrawList* draw_list, ImVec2 canvas_p0,
60 ImVec2 scrolling, float global_scale, float tile_size, bool is_hovered) {
61 const ImGuiIO& imgui_io = ImGui::GetIO();
62 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y);
63 const ImVec2 mouse_pos(imgui_io.MousePos.x - origin.x,
64 imgui_io.MousePos.y - origin.y);
65 const auto scaled_size = tile_size * global_scale;
66
67 // Clear hover when not hovering
68 if (!is_hovered) {
69 hover_points_.clear();
70 return false;
71 }
72
73 // Reset previous hover
74 hover_points_.clear();
75
76 // Calculate grid-aligned paint position
77 ImVec2 paint_pos = AlignToGridLocal(mouse_pos, scaled_size);
78 mouse_pos_in_canvas_ = paint_pos;
79 auto paint_pos_end =
80 ImVec2(paint_pos.x + scaled_size, paint_pos.y + scaled_size);
81
82 hover_points_.push_back(paint_pos);
83 hover_points_.push_back(paint_pos_end);
84
85 // Draw preview of tile at hover position
86 if (bitmap.is_active() && draw_list) {
87 draw_list->AddImage(reinterpret_cast<ImTextureID>(bitmap.texture()),
88 ImVec2(origin.x + paint_pos.x, origin.y + paint_pos.y),
89 ImVec2(origin.x + paint_pos.x + scaled_size,
90 origin.y + paint_pos.y + scaled_size));
91 }
92
93 // Check for paint action
94 if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) &&
95 ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
96 drawn_tile_pos_ = paint_pos;
97 return true;
98 }
99
100 return false;
101}
102
104 gfx::Tilemap& tilemap, int current_tile, ImDrawList* draw_list,
105 ImVec2 canvas_p0, ImVec2 scrolling, float global_scale, bool is_hovered) {
106 const ImGuiIO& imgui_io = ImGui::GetIO();
107 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y);
108 const ImVec2 mouse_pos(imgui_io.MousePos.x - origin.x,
109 imgui_io.MousePos.y - origin.y);
110
111 // Safety check
112 if (!tilemap.atlas.is_active() || tilemap.tile_size.x <= 0) {
113 return false;
114 }
115
116 const auto scaled_size = tilemap.tile_size.x * global_scale;
117
118 if (!is_hovered) {
119 hover_points_.clear();
120 return false;
121 }
122
123 hover_points_.clear();
124
125 ImVec2 paint_pos = AlignToGrid(mouse_pos, scaled_size);
126 mouse_pos_in_canvas_ = paint_pos;
127
128 hover_points_.push_back(paint_pos);
129 hover_points_.push_back(
130 ImVec2(paint_pos.x + scaled_size, paint_pos.y + scaled_size));
131
132 // Draw tile preview from atlas
133 if (tilemap.atlas.is_active() && tilemap.atlas.texture() && draw_list) {
134 int tiles_per_row = tilemap.atlas.width() / tilemap.tile_size.x;
135 if (tiles_per_row > 0) {
136 int tile_x = (current_tile % tiles_per_row) * tilemap.tile_size.x;
137 int tile_y = (current_tile / tiles_per_row) * tilemap.tile_size.y;
138
139 if (tile_x >= 0 && tile_x < tilemap.atlas.width() && tile_y >= 0 &&
140 tile_y < tilemap.atlas.height()) {
141 ImVec2 uv0 =
142 ImVec2(static_cast<float>(tile_x) / tilemap.atlas.width(),
143 static_cast<float>(tile_y) / tilemap.atlas.height());
144 ImVec2 uv1 = ImVec2(static_cast<float>(tile_x + tilemap.tile_size.x) /
145 tilemap.atlas.width(),
146 static_cast<float>(tile_y + tilemap.tile_size.y) /
147 tilemap.atlas.height());
148
149 draw_list->AddImage(
150 reinterpret_cast<ImTextureID>(tilemap.atlas.texture()),
151 ImVec2(origin.x + paint_pos.x, origin.y + paint_pos.y),
152 ImVec2(origin.x + paint_pos.x + scaled_size,
153 origin.y + paint_pos.y + scaled_size),
154 uv0, uv1);
155 }
156 }
157 }
158
159 if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) ||
160 ImGui::IsMouseDragging(ImGuiMouseButton_Left)) {
161 drawn_tile_pos_ = paint_pos;
162 return true;
163 }
164
165 return false;
166}
167
169 const ImVec4& color, ImDrawList* draw_list, ImVec2 canvas_p0,
170 ImVec2 scrolling, float global_scale, float tile_size, bool is_hovered) {
171 const ImGuiIO& imgui_io = ImGui::GetIO();
172 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y);
173 const ImVec2 mouse_pos(imgui_io.MousePos.x - origin.x,
174 imgui_io.MousePos.y - origin.y);
175 auto scaled_tile_size = tile_size * global_scale;
176 static bool is_dragging = false;
177 static ImVec2 start_drag_pos;
178
179 if (!is_hovered) {
180 hover_points_.clear();
181 return false;
182 }
183
184 hover_points_.clear();
185
186 ImVec2 paint_pos = AlignToGrid(mouse_pos, scaled_tile_size);
187 mouse_pos_in_canvas_ = paint_pos;
188
189 // Clamp to canvas bounds (assuming canvas_size from Update)
190 // For now, skip clamping as we don't have canvas_size here
191
192 hover_points_.push_back(paint_pos);
193 hover_points_.push_back(
194 ImVec2(paint_pos.x + scaled_tile_size, paint_pos.y + scaled_tile_size));
195
196 if (draw_list) {
197 draw_list->AddRectFilled(
198 ImVec2(origin.x + paint_pos.x + 1, origin.y + paint_pos.y + 1),
199 ImVec2(origin.x + paint_pos.x + scaled_tile_size,
200 origin.y + paint_pos.y + scaled_tile_size),
201 IM_COL32(color.x * 255, color.y * 255, color.z * 255, 255));
202 }
203
204 if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
205 is_dragging = true;
206 start_drag_pos = paint_pos;
207 }
208
209 if (is_dragging && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) {
210 is_dragging = false;
211 drawn_tile_pos_ = start_drag_pos;
212 return true;
213 }
214
215 return false;
216}
217
218bool CanvasInteractionHandler::DrawTileSelector(ImDrawList* /*draw_list*/,
219 ImVec2 canvas_p0,
220 ImVec2 scrolling,
221 float tile_size,
222 bool is_hovered) {
223 const ImGuiIO& imgui_io = ImGui::GetIO();
224 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y);
225 const ImVec2 mouse_pos(imgui_io.MousePos.x - origin.x,
226 imgui_io.MousePos.y - origin.y);
227
228 if (is_hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
229 hover_points_.clear();
230 ImVec2 painter_pos = AlignToGridLocal(mouse_pos, tile_size);
231
232 hover_points_.push_back(painter_pos);
233 hover_points_.push_back(
234 ImVec2(painter_pos.x + tile_size, painter_pos.y + tile_size));
235 mouse_pos_in_canvas_ = painter_pos;
236 }
237
238 if (is_hovered && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
239 return true;
240 }
241
242 return false;
243}
244
246 int current_map, ImDrawList* draw_list, ImVec2 canvas_p0, ImVec2 scrolling,
247 float global_scale, float tile_size, bool is_hovered) {
248 if (!is_hovered) {
249 return false;
250 }
251
252 // Create CanvasGeometry from parameters
253 CanvasGeometry geometry;
254 geometry.canvas_p0 = canvas_p0;
255 geometry.scrolling = scrolling;
256 geometry.scaled_size =
257 ImVec2(tile_size * global_scale, tile_size * global_scale);
258 geometry.canvas_sz =
259 ImVec2(tile_size, tile_size); // Will be updated if needed
260
261 // Call new event-based function
263 geometry, current_map, tile_size, draw_list, ImGuiMouseButton_Right);
264
265 // Update internal state for backward compatibility
266 if (event.is_complete) {
267 selected_tiles_ = event.selected_tiles;
268 selected_points_.clear();
269 selected_points_.push_back(event.start_pos);
270 selected_points_.push_back(event.end_pos);
271 rect_select_active_ = true;
272 return true;
273 }
274
275 if (!event.selected_tiles.empty() && !event.is_complete) {
276 // Single tile selection
277 selected_tile_pos_ = event.selected_tiles[0];
278 selected_points_.clear();
279 rect_select_active_ = false;
280 }
281
282 rect_select_active_ = event.is_active;
283
284 return false;
285}
286
287// Helper methods - these are thin wrappers that could be static but kept as
288// instance methods for potential future state access
289ImVec2 CanvasInteractionHandler::AlignPosToGrid(ImVec2 pos, float grid_step) {
290 return AlignToGridLocal(pos, grid_step);
291}
292
294 ImVec2 scrolling) {
295 const ImGuiIO& imgui_io = ImGui::GetIO();
296 const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y);
297 return ImVec2(imgui_io.MousePos.x - origin.x, imgui_io.MousePos.y - origin.y);
298}
299
300bool CanvasInteractionHandler::IsMouseClicked(ImGuiMouseButton button) {
301 return ImGui::IsMouseClicked(button);
302}
303
305 return ImGui::IsMouseDoubleClicked(button);
306}
307
308bool CanvasInteractionHandler::IsMouseDragging(ImGuiMouseButton button) {
309 return ImGui::IsMouseDragging(button);
310}
311
312bool CanvasInteractionHandler::IsMouseReleased(ImGuiMouseButton button) {
313 return ImGui::IsMouseReleased(button);
314}
315
316} // namespace gui
317} // namespace yaze
Free functions for canvas interaction handling.
Represents a bitmap image optimized for SNES ROM hacking.
Definition bitmap.h:67
TextureHandle texture() const
Definition bitmap.h:380
bool is_active() const
Definition bitmap.h:384
int height() const
Definition bitmap.h:374
int width() const
Definition bitmap.h:373
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)
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)
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)
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 IsMouseDoubleClicked(ImGuiMouseButton button)
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.
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.
Definition tilemap.h:21
int x
X coordinate or width.
Definition tilemap.h:20
Tilemap structure for SNES tile-based graphics management.
Definition tilemap.h:118
Pair tile_size
Size of individual tiles (8x8 or 16x16)
Definition tilemap.h:123
Bitmap atlas
Master bitmap containing all tiles.
Definition tilemap.h:119
Canvas geometry calculated per-frame.
Event payload for rectangle selection operations.
Result of a tile interaction operation.