浏览代码

feat(ui): implement context menu (initial)

Added basic right-click context menu functionality with Gtk::Popover. Includes mocked Copy/Cut/Paste (Copy/Cut now use clipboard but Cut's erase is temporarily disabled due to compiler ambiguity), Set Mark, Kill Line, and Quit actions. Marked Buffer::erase for future disambiguation.
Bernardo Magri 1 月之前
父节点
当前提交
00022c537b
共有 1 个文件被更改,包括 88 次插入1 次删除
  1. 88 1
      src/gtk_editor.cpp

+ 88 - 1
src/gtk_editor.cpp

@@ -5,11 +5,14 @@
 #include <iostream>
 #include <filesystem>
 #include <vector>
-#include <algorithm>
+#include <functional> // For std::function
 
 // Check if GTK is enabled in build
 #ifdef LUMACS_WITH_GTK
 #include <gtkmm.h>
+#include <gtkmm/popover.h> // For Gtk::Popover
+#include <gtkmm/box.h>     // For Gtk::Box
+#include <gtkmm/button.h>  // For Gtk::Button
 #include <pangomm.h>
 
 namespace lumacs {
@@ -495,6 +498,90 @@ protected:
             }, true);
             drawing_area->add_controller(scroll_controller);
             
+            // Add secondary click handling for context menus
+            auto context_menu_controller = Gtk::GestureClick::create();
+            context_menu_controller->set_button(GDK_BUTTON_SECONDARY);
+            std::weak_ptr<Window> weak_window_context = node->window;
+            context_menu_controller->signal_pressed().connect([this, weak_window_context, drawing_area](int, double x, double y) {
+                if (auto window = weak_window_context.lock()) {
+                    // Activate window if not already
+                    if (core_ && core_->active_window() != window) {
+                        core_->set_active_window(window);
+                    }
+                    drawing_area->grab_focus(); // Ensure focus for context
+                    
+                    // Create and populate context menu
+                    auto popover = Gtk::make_managed<Gtk::Popover>();
+                    auto box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL);
+                    box->set_spacing(5); // Add some spacing between buttons
+                    popover->set_child(*box);
+
+                    auto add_menu_item = [&](const Glib::ustring& label, std::function<void()> callback) {
+                        auto button = Gtk::make_managed<Gtk::Button>();
+                        button->set_label(label);
+                        button->signal_clicked().connect(callback);
+                        box->append(*button);
+                    };
+
+                    // Sample items (will be replaced by actual logic later)
+                    if (window->buffer().has_active_mark()) {
+                        add_menu_item("Copy", [this, window, drawing_area](){ // Keep drawing_area captured as it's used below
+                            if (auto region = window->buffer().get_region(window->cursor())) {
+                                std::string text = window->buffer().get_text_in_range(*region);
+                                if (auto clipboard = drawing_area->get_clipboard()) {
+                                    clipboard->set_text(text);
+                                    message_line_ = "Copied region.";
+                                } else {
+                                    message_line_ = "Failed to get clipboard.";
+                                }
+                                if (content_widget_) queue_redraw_all_windows(content_widget_);
+                            } else {
+                                message_line_ = "No region to copy.";
+                                if (content_widget_) queue_redraw_all_windows(content_widget_);
+                            }
+                        });
+                        add_menu_item("Cut", [this, window, drawing_area](){ // Keep drawing_area captured
+                            if (auto region = window->buffer().get_region(window->cursor())) {
+                                std::string text = window->buffer().get_text_in_range(*region);
+                                                                if (auto clipboard = drawing_area->get_clipboard()) {
+                                                                    clipboard->set_text(text);
+                                                                    // TODO: Fix ambiguity with std::erase. For now, just copy to clipboard.
+                                                                    // window->buffer().Buffer::erase(region->start, region->end);
+                                                                    window->buffer().deactivate_mark(); // Deactivate mark after cut
+                                                                    drawing_area->queue_draw();
+                                                                    message_line_ = "Cut region.";
+                                                                } else {                                    message_line_ = "Failed to get clipboard.";
+                                }
+                                if (content_widget_) queue_redraw_all_windows(content_widget_);
+                            } else {
+                                message_line_ = "No region to cut.";
+                                if (content_widget_) queue_redraw_all_windows(content_widget_);
+                            }
+                        });
+                    }
+                    add_menu_item("Paste", [this](){
+                        message_line_ = "Paste not implemented!";
+                        if (content_widget_) queue_redraw_all_windows(content_widget_);
+                    });
+                    add_menu_item("Set Mark", [this, window, x, y, drawing_area](){ // Explicitly capture drawing_area
+                        if (auto pos = resolve_screen_pos(window, x, y)) {
+                            window->buffer().set_mark(*pos);
+                            drawing_area->queue_draw(); // Used here
+                            if (content_widget_) queue_redraw_all_windows(content_widget_);
+                        }
+                    });
+                    add_menu_item("Kill Line", [this](){
+                        core_->kill_line();
+                        if (content_widget_) queue_redraw_all_windows(content_widget_);
+                    });
+                    add_menu_item("Quit", [this](){ app_->quit(); });
+
+                    popover->set_parent(*drawing_area);
+                    popover->popup(); // Shows at the mouse position
+                }
+            });
+            drawing_area->add_controller(context_menu_controller);
+            
             // Store reference for single-window compatibility
             if (!drawing_area_) {
                 drawing_area_ = drawing_area;