Bladeren bron

feat(ui): implement drag-to-select

Added Gtk::GestureDrag handling to allow selecting text regions with the mouse. Dragging updates the cursor position and sets the mark anchor at the drag start.
Bernardo Magri 1 maand geleden
bovenliggende
commit
9a2e3981be
1 gewijzigde bestanden met toevoegingen van 63 en 21 verwijderingen
  1. 63 21
      src/gtk_editor.cpp

+ 63 - 21
src/gtk_editor.cpp

@@ -434,31 +434,47 @@ protected:
                     drawing_area->grab_focus();
                     
                     // 2. Move Cursor
-                    if (line_height_ > 0 && char_width_ > 0) {
-                        int row = static_cast<int>((y - PADDING_TOP) / line_height_);
-                        int col = static_cast<int>((x - PADDING_LEFT) / char_width_);
-                        
-                        if (row < 0) row = 0;
-                        if (col < 0) col = 0;
-                        
-                        auto viewport = window->viewport();
-                        size_t target_line = viewport.scroll_offset + row;
-                        size_t target_col = viewport.horizontal_offset + col;
-                        
-                        // Check boundaries
-                        if (target_line < window->buffer().line_count()) {
-                             window->set_cursor({target_line, target_col});
-                             drawing_area->queue_draw();
-                        } else {
-                             // Clicked past end of buffer, move to end
-                             size_t last_line = window->buffer().line_count() - 1;
-                             window->set_cursor({last_line, window->buffer().line(last_line).length()});
-                             drawing_area->queue_draw();
-                        }
+                    if (auto pos = resolve_screen_pos(window, x, y)) {
+                        window->set_cursor(*pos);
+                        // Clear mark on simple click
+                        window->buffer().deactivate_mark();
+                        drawing_area->queue_draw();
                     }
                 }
             });
             drawing_area->add_controller(click_controller);
+
+            // Add Drag Gesture for Selection
+            auto drag_controller = Gtk::GestureDrag::create();
+            std::weak_ptr<Window> weak_window_drag = node->window;
+            
+            drag_controller->signal_drag_begin().connect([this, weak_window_drag, drawing_area](double x, double y) {
+                if (auto window = weak_window_drag.lock()) {
+                    if (auto pos = resolve_screen_pos(window, x, y)) {
+                        // Set mark at start of drag
+                        window->buffer().set_mark(*pos);
+                        window->set_cursor(*pos);
+                        drawing_area->queue_draw();
+                    }
+                }
+            });
+            
+            drag_controller->signal_drag_update().connect([this, weak_window_drag, drawing_area, drag_controller](double dx, double dy) {
+                if (auto window = weak_window_drag.lock()) {
+                     double start_x, start_y;
+                     if (drag_controller->get_start_point(start_x, start_y)) {
+                         double current_x = start_x + dx;
+                         double current_y = start_y + dy;
+                         
+                         if (auto pos = resolve_screen_pos(window, current_x, current_y)) {
+                             window->set_cursor(*pos);
+                             drawing_area->queue_draw();
+                         }
+                     }
+                }
+            });
+            
+            drawing_area->add_controller(drag_controller);
             
             // Add scroll handling
             auto scroll_controller = Gtk::EventControllerScroll::create();
@@ -889,6 +905,32 @@ protected:
         return key_name;
     }
 
+    // Helper to convert screen coordinates to buffer position
+    std::optional<Position> resolve_screen_pos(std::shared_ptr<Window> window, double x, double y) {
+        if (!window || line_height_ <= 0 || char_width_ <= 0) return std::nullopt;
+
+        int row = static_cast<int>((y - PADDING_TOP) / line_height_);
+        int col = static_cast<int>((x - PADDING_LEFT) / char_width_);
+        
+        if (row < 0) row = 0;
+        if (col < 0) col = 0;
+        
+        auto viewport = window->viewport();
+        size_t target_line = viewport.scroll_offset + row;
+        size_t target_col = viewport.horizontal_offset + col;
+        
+        // Clamp to buffer bounds
+        if (target_line >= window->buffer().line_count()) {
+             target_line = window->buffer().line_count() - 1;
+        }
+        
+        // Clamp column to line length
+        size_t line_len = window->buffer().line(target_line).length();
+        if (target_col > line_len) target_col = line_len;
+        
+        return Position{target_line, target_col};
+    }
+
     // Input
     bool on_key_pressed(guint keyval, guint /*keycode*/, Gdk::ModifierType state) {
         // Safety check - don't process keys if core is destroyed