From 8ca9e6bcdda63632fc55c5a5114af225e3f32a3f Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sat, 2 Nov 2024 21:35:31 +0100 Subject: [PATCH] Tabbable overhaul: consistent toplevel packing --- libs/widgets/tabbable.cc | 134 +++++++++++++++++++++++++++++++- libs/widgets/widgets/tabbable.h | 65 ++++++++++++++-- 2 files changed, 191 insertions(+), 8 deletions(-) diff --git a/libs/widgets/tabbable.cc b/libs/widgets/tabbable.cc index 6957ef2ad1..634c116dd9 100644 --- a/libs/widgets/tabbable.cc +++ b/libs/widgets/tabbable.cc @@ -18,10 +18,12 @@ */ #include +#include #include #include #include +#include "gtkmm2ext/actions.h" #include "gtkmm2ext/gtk_ui.h" #include "gtkmm2ext/utils.h" #include "gtkmm2ext/visibility_tracker.h" @@ -35,12 +37,13 @@ using namespace Gtk; using namespace Gtkmm2ext; using namespace ArdourWidgets; -Tabbable::Tabbable (Widget& w, const string& visible_name, string const & nontranslatable_name, bool tabbed_by_default) +Tabbable::Tabbable (Gtk::Widget& w, const string& visible_name, string const & nontranslatable_name, bool tabbed_by_default) : WindowProxy (visible_name, nontranslatable_name) , _contents (w) , _parent_notebook (0) , tab_requested_by_state (tabbed_by_default) { + default_layout (); } Tabbable::~Tabbable () @@ -51,6 +54,55 @@ Tabbable::~Tabbable () } } +void +Tabbable::default_layout () +{ + left_attachment_button.set_text (_("Left")); + right_attachment_button.set_text (_("Right")); + bottom_attachment_button.set_text (_("Btm")); + + content_attachment_hbox.set_border_width(3); + content_attachment_hbox.set_spacing(3); + content_attachment_hbox.pack_end (right_attachment_button, false, false); + content_attachment_hbox.pack_end (bottom_attachment_button, false, false); + content_attachment_hbox.pack_end (left_attachment_button, false, false); + content_attachments.add (content_attachment_hbox); + + content_header_hbox.pack_start (content_app_bar, true, true); + content_header_hbox.pack_start (content_attachments, false, false); + content_header_hbox.pack_start (content_tabbables, false, false); + + //wrap the header eboxen in a themeable frame + Gtk::Frame *toolbar_frame = manage(new Gtk::Frame); + toolbar_frame->set_name ("TransportFrame"); + toolbar_frame->set_shadow_type (Gtk::SHADOW_NONE); + toolbar_frame->add (content_header_hbox); + + _content_vbox.pack_start (*toolbar_frame, false, false); + _content_vbox.pack_start (content_hbox, true, true); + + content_hbox.pack_start (content_att_left, false, false); + content_hbox.pack_start (content_midlevel_vbox, true, true); + + content_midlevel_vbox.pack_start (content_right_pane, true, true); + content_midlevel_vbox.pack_start (content_att_bottom, false, false); + + content_right_pane.add (content_inner_vbox); + content_right_pane.add (content_right_vbox); + + //TODO: menu switcher here? + content_right_vbox.pack_start (content_att_right, true, true); + + content_inner_vbox.pack_start (content_toolbar, false, false); + content_inner_vbox.pack_start (content_innermost_hbox, true, true); + + content_right_pane.set_child_minsize (content_att_right, 160); /* rough guess at width of notebook tabs */ + content_right_pane.set_check_divider_position (true); + content_right_pane.set_divider (0, 0.85); + + _content_vbox.show_all(); +} + void Tabbable::add_to_notebook (Notebook& notebook) { @@ -343,6 +395,8 @@ Tabbable::get_state() const node.set_property (X_("tabbed"), tabbed()); + node.set_property (string_compose("%1%2", _menu_name, X_("-listpane-pos")).c_str(), content_right_pane.get_divider ()); + return node; } @@ -365,8 +419,14 @@ Tabbable::set_state (const XMLNode& node, int version) if (window_node) { window_node->get_property (X_("tabbed"), tab_requested_by_state); + float fract; + if ( window_node->get_property (string_compose("%1%2", _menu_name, X_("-listpane-pos")).c_str(), fract) ) { + fract = std::max (.05f, std::min (.95f, fract)); + content_right_pane.set_divider (0, fract); + } } + if (!_visible) { if (tab_requested_by_state) { attach (); @@ -391,3 +451,75 @@ Tabbable::window_unmapped () { StateChange (*this); } + +void +Tabbable::showhide_att_right (bool yn) +{ + if (yn) { + content_right_vbox.show (); + } else { + content_right_vbox.hide (); + } +} + +void +Tabbable::att_right_button_toggled () +{ + Glib::RefPtr act = right_attachment_button.get_related_action(); + if (act) { + Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); + if (tact) { + showhide_att_right (tact->get_active()); + } + } else { + showhide_att_right (false); + } +} + +void +Tabbable::showhide_att_left (bool yn) +{ + if (yn) { + content_att_left.show (); + } else { + content_att_left.hide (); + } +} + +void +Tabbable::att_left_button_toggled () +{ + Glib::RefPtr act = left_attachment_button.get_related_action(); + if (act) { + Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); + if (tact) { + showhide_att_left (tact->get_active()); + } + } else { + showhide_att_left (false); + } +} + +void +Tabbable::showhide_att_bottom (bool yn) +{ + if (yn) { + content_att_bottom.show (); + } else { + content_att_bottom.hide (); + } +} + +void +Tabbable::att_bottom_button_toggled () +{ + Glib::RefPtr act = bottom_attachment_button.get_related_action(); + if (act) { + Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); + if (tact) { + showhide_att_bottom (tact->get_active()); + } + } else { + showhide_att_bottom (false); + } +} diff --git a/libs/widgets/widgets/tabbable.h b/libs/widgets/widgets/tabbable.h index 09c58cca20..5a96d10f83 100644 --- a/libs/widgets/widgets/tabbable.h +++ b/libs/widgets/widgets/tabbable.h @@ -20,14 +20,18 @@ #ifndef _WIDGETS_TABBABLE_H_ #define _WIDGETS_TABBABLE_H_ -#include #include #include +#include #include #include #include #include "gtkmm2ext/window_proxy.h" + +#include "widgets/ardour_button.h" +#include "widgets/eventboxext.h" +#include "widgets/pane.h" #include "widgets/visibility.h" namespace Gtk { @@ -56,6 +60,12 @@ public: Gtk::Widget& contents() const { return _contents; } + /* this is where ArdourUI packs the tab switchers + * (record/cues/edit/mix) into my toolbar area, + * in the case where I'm attached to the main window + */ + Gtk::EventBox& tab_btn_box () {return content_tabbables;} + Gtk::Window* get (bool create = false); Gtk::Window* own_window () { return get (false); } virtual Gtk::Window* use_own_window (bool and_pack_it); @@ -68,7 +78,6 @@ public: bool tabbed() const; bool tabbed_by_default () const; - Gtk::Window* current_toplevel () const; Gtk::Notebook* tab_root_drop (); @@ -80,23 +89,65 @@ public: sigc::signal1 StateChange; + void att_left_button_toggled(); + void att_right_button_toggled(); + void att_bottom_button_toggled(); + protected: + virtual void showhide_att_left (bool yn); + virtual void showhide_att_right (bool yn); + virtual void showhide_att_bottom (bool yn); + bool delete_event_handler (GdkEventAny *ev); sigc::signal1 signal_tabbed_changed; -private: - Gtk::Widget& _contents; - Gtk::Notebook _own_notebook; - Gtk::Notebook* _parent_notebook; - bool tab_requested_by_state; + /* This is the heirarchy of a Tabbable's widget packing. + * The end result is to provide 8(ish) event-boxen where the tab can put its contents + * Please maintain the indention here so the hierarchy is visible + */ + /* clang-format off */ + /* _content_vbox * toplevel + * toolbar_frame * the frame is managed in the implementation */ + Gtk::HBox content_header_hbox; + EventBoxExt content_app_bar; /* a placeholder for the transport bar, if you want one */ + Gtk::EventBox content_attachments; /* a placeholder the (strip, list, props) visibility buttons for this tab */ + Gtk::HBox content_attachment_hbox; + EventBoxExt content_tabbables; /* a placeholder for the tabbable switching buttons (used by ArdourUI) */ + Gtk::HBox content_hbox; + EventBoxExt content_att_left; /* a placeholder for the mixer strip, if you want one */ + Gtk::VBox content_midlevel_vbox; + HPane content_right_pane; + Gtk::VBox content_inner_vbox; + EventBoxExt content_toolbar; /* a placeholder for the content-specific toolbar, if you want one */ + Gtk::HBox content_innermost_hbox; /* a placeholder for the innermost content (recorder, cues, editor, mixer) */ + Gtk::VBox content_right_vbox; + EventBoxExt content_att_right; /* a placeholder for the sidebar list, if you want one */ + EventBoxExt content_att_bottom; /* a placeholder for the property box, if you want one */ + /* clang-format on */ + + + /* visibility controls */ + ArdourWidgets::ArdourButton left_attachment_button; + ArdourWidgets::ArdourButton right_attachment_button; + ArdourWidgets::ArdourButton bottom_attachment_button; + +private: + void default_layout (); void show_tab (); void hide_tab (); bool tab_close_clicked (GdkEventButton*); void show_own_window (bool and_pack_it); void window_mapped (); void window_unmapped (); + + Gtk::VBox _content_vbox; /* this is the root widget for a full-featured tabbable, which contains: */ + Gtk::Widget& _contents; /* for most Tabbables this will be content_vbox; but rc_options, for example, does something different. */ + Gtk::Notebook _own_notebook; + Gtk::Notebook* _parent_notebook; + bool tab_requested_by_state; + }; } /* end namespace */