|
|
@@ -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
|