roundabout,
created on Sunday, 23 March 2025, 21:04:51 (1742763891),
received on Sunday, 23 March 2025, 21:04:54 (1742763894)
Author identity: vlad <vlad.muntoiu@gmail.com>
93e8e5734ec398d89985132ce137a361d5dbb726
gpanthera.cc
@@ -9,6 +9,35 @@
#define _(STRING) gettext(STRING) namespace gPanthera { sigc::signal<void(double, double)> add_context_menu(Gtk::Widget &widget) { sigc::signal<void(double, double)> signal; // Add a context menu to a widget auto gesture_click = Gtk::GestureClick::create(); gesture_click->set_button(3); auto gesture_keyboard = Gtk::EventControllerKey::create(); gesture_click->signal_pressed().connect([&widget, signal](int n_press, double x, double y) { if(n_press == 1) { signal.emit(x, y); } }, false); gesture_keyboard->signal_key_pressed().connect([&widget, signal](int keyval, int keycode, Gdk::ModifierType state) { if((keyval == GDK_KEY_F10) && (state == Gdk::ModifierType::SHIFT_MASK) || keyval == GDK_KEY_Menu) { // auto popover = Gtk::make_managed<Gtk::PopoverMenu>(); // popover->set_menu_model(menu); // popover->set_has_arrow(false); // popover->set_halign(Gtk::Align::START); // popover->set_pointing_to(Gdk::Rectangle(0, 0, 1, 1)); // popover->set_parent(widget); // popover->popup(); signal.emit(0, 0); } return true; }, false); widget.add_controller(gesture_click); widget.add_controller(gesture_keyboard); return signal; }std::vector<Gtk::Widget*> collect_children(Gtk::Widget &widget) { // Get a vector of the children of a GTK widget, since the container API was removed in GTK 4 std::vector<Gtk::Widget*> children;
@@ -58,7 +87,6 @@ namespace gPanthera {
} header->add_css_class("gpanthera-dock-titlebar"); auto header_menu_button = Gtk::make_managed<Gtk::MenuButton>(); auto header_menu = Gio::Menu::create();header_menu_button->set_direction(Gtk::ArrowType::NONE); // Pane menu
@@ -610,23 +638,29 @@ namespace gPanthera {
Gtk::Widget *child = nullptr; if(this->get_parent() == paned->get_start_child()) { child = paned->get_end_child(); paned->property_end_child().reset_value();} else if(this->get_parent() == paned->get_end_child()) { child = paned->get_start_child(); paned->property_start_child().reset_value();} else { return; } if(auto parent_paned = dynamic_cast<Gtk::Paned*>(paned->get_parent())) {if(parent_paned->get_start_child() == paned) {parent_paned->set_start_child(*child);} else if(parent_paned->get_end_child() == paned) {parent_paned->set_end_child(*child);g_object_ref(child->gobj()); // Prevent the child from being automatically deleted paned->property_start_child().reset_value(); // Some hacks because the Gtkmm API isn't complete; it doesn't have an unset_start_child() or unset_end_child() paned->property_end_child().reset_value(); if(child) { if(auto parent_paned = dynamic_cast<Gtk::Paned*>(paned->get_parent())) { if(parent_paned->get_start_child() == paned) { parent_paned->set_start_child(*child); } else if(parent_paned->get_end_child() == paned) { parent_paned->set_end_child(*child); } } else if(auto box = dynamic_cast<Gtk::Box*>(paned->get_parent())) { std::cout << child->get_name() << std::endl; child->insert_after(*box, *paned); paned->unparent(); g_object_unref(child->gobj());} } else if(auto box = dynamic_cast<Gtk::Box*>(paned->get_parent())) {child->insert_after(*box, *paned);paned->unparent();} } }
@@ -725,6 +759,39 @@ namespace gPanthera {
this->set_opacity(1); return false; }, false); // Provide a context menu context_menu = Gio::Menu::create(); auto action_group = Gio::SimpleActionGroup::create(); this->insert_action_group("win", action_group); auto close_action = Gio::SimpleAction::create("close"); close_action->signal_activate().connect([this](const Glib::VariantBase&) { if(!this->page->signal_close.emit()) { if(this->page->get_next_sibling()) { this->page->get_stack()->set_visible_child(*this->page->get_next_sibling()); } else if(this->page->get_prev_sibling()) { this->page->get_stack()->set_visible_child(*this->page->get_prev_sibling()); } this->page->redock(nullptr); } }); action_group->add_action(close_action); context_menu->append(_("Close"), "win.close"); // TODO: Add more actions: "New window", "Split left", "Split right", "Split top", "Split bottom", "Close all", "Close others", "Close to the right", "Close to the left" this->insert_action_group("win", action_group); // Attach the context menu to the button auto context_menu_signal = add_context_menu(*this); context_menu_signal.connect([this, action_group](double x, double y) { if(this->context_menu) { auto popover = Gtk::make_managed<Gtk::PopoverMenu>(); popover->set_menu_model(context_menu); popover->set_parent(*this); popover->set_has_arrow(false); popover->set_halign(Gtk::Align::START); popover->set_pointing_to(Gdk::Rectangle(x, y, 1, 1)); popover->popup(); } });} void ContentTab::update_active_style() {
@@ -747,11 +814,28 @@ namespace gPanthera {
return this->tab_widget; } Gtk::Stack *ContentPage::get_stack() const {ContentStack *ContentPage::get_stack() const {return this->stack; } void ContentPage::redock(ContentStack *stack) { if(stack == nullptr) { if(this->stack) { this->stack->remove(*this); if(dynamic_cast<ContentNotebook*>(this->stack->get_parent()) && !this->stack->get_first_child()) { this->stack->remove_with_paned(); } } auto old_stack = this->stack; if(old_stack) { if(!old_stack->get_first_child()) { old_stack->signal_leave_empty.emit(); } } this->stack = nullptr; this->last_stack = nullptr; return; }// Check if the stack is now empty, in which case we should remove it if(this->stack == stack) { return;
gpanthera.hh
@@ -10,6 +10,8 @@
namespace gPanthera { void init(); // Utility function to create a signal that fires when a context menu is requested sigc::signal<void(double, double)> add_context_menu(Gtk::Widget &widget);class DockStack; class DockWindow;
@@ -27,6 +29,7 @@ namespace gPanthera {
Glib::RefPtr<Gio::SimpleActionGroup> action_group; public: std::shared_ptr<LayoutManager> layout; Glib::RefPtr<Gio::Menu> header_menu = Gio::Menu::create();DockStack *last_stack = nullptr; DockablePane(std::shared_ptr<LayoutManager> layout, Gtk::Widget &child, const Glib::ustring &name, const Glib::ustring &label, Gtk::Image *icon, DockStack *stack = nullptr, Gtk::Widget *custom_header = nullptr); Gtk::Stack *get_stack() const;
@@ -119,18 +122,19 @@ namespace gPanthera {
class ContentPage : public Gtk::Box { private: Gtk::Widget *tab_widget; ContentStack *stack;ContentStack *stack = nullptr;Gtk::Widget *child; public: std::shared_ptr<ContentManager> content_manager; ContentStack *last_stack = nullptr; ContentPage(std::shared_ptr<ContentManager> content_manager, ContentStack *stack, Gtk::Widget *child, Gtk::Widget *tab_widget); Gtk::Widget *get_child() const; sigc::signal<bool()> signal_close;Gtk::Widget *get_tab_widget() const; void redock(ContentStack *stack); void set_tab_widget(Gtk::Widget *tab_widget); void set_child(Gtk::Widget *child); Gtk::Stack *get_stack() const;ContentStack *get_stack() const;}; class ContentTab : public Gtk::ToggleButton {
@@ -138,6 +142,7 @@ namespace gPanthera {
std::shared_ptr<Gtk::DragSource> drag_source; std::shared_ptr<Gtk::DropTarget> drop_target; Glib::Value<ContentPage*> value; Glib::RefPtr<Gio::Menu> context_menu = Gio::Menu::create();void update_active_style(); sigc::connection active_style_handler; public: