X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fgtkmm2ext%2Ftabbable.cc;h=5e4752454e6cfd6c8547b56799f59399b2307165;hb=cf52d6e4b40111eb04b244ec054055a4ec15dbe0;hp=e4c86e838469096110c7e499a71097db616a8182;hpb=a5150d500d44ebda460e10c84daeed206345bb24;p=ardour.git diff --git a/libs/gtkmm2ext/tabbable.cc b/libs/gtkmm2ext/tabbable.cc index e4c86e8384..5e4752454e 100644 --- a/libs/gtkmm2ext/tabbable.cc +++ b/libs/gtkmm2ext/tabbable.cc @@ -20,10 +20,17 @@ #include #include #include +#include #include "gtkmm2ext/tabbable.h" +#include "gtkmm2ext/gtk_ui.h" +#include "gtkmm2ext/utils.h" #include "gtkmm2ext/visibility_tracker.h" +#include "pbd/stacktrace.h" + +#include "pbd/i18n.h" + using namespace Gtkmm2ext; using namespace Gtk; using std::string; @@ -31,6 +38,8 @@ using std::string; Tabbable::Tabbable (Widget& w, const string& name) : WindowProxy (name) , _contents (w) + , _parent_notebook (0) + , tab_requested_by_state (true) { } @@ -43,30 +52,40 @@ Tabbable::~Tabbable () } void -Tabbable::add_to_notebook (Notebook& notebook, const string& tab_title, int position) +Tabbable::add_to_notebook (Notebook& notebook, const string& tab_title) { - notebook.insert_page (_contents, tab_title, position, false); - notebook.set_tab_detachable (_contents); - _parent_notebook = ¬ebook; - _tab_title = tab_title; - _notebook_position = position; + + if (tab_requested_by_state) { + attach (); + } } Window* -Tabbable::use_own_window () +Tabbable::use_own_window (bool and_pack_it) { - return get (true); + Gtk::Window* win = get (true); + + if (and_pack_it) { + Gtk::Container* parent = _contents.get_parent(); + if (parent) { + parent->remove (_contents); + } + _own_notebook.append_page (_contents); + } + + return win; + } bool -Tabbable::window_visible () +Tabbable::window_visible () const { - if (!own_window()) { + if (!_window) { return false; } - return visible(); + return _window->is_visible(); } Window* @@ -80,9 +99,9 @@ Tabbable::get (bool create) return 0; } - /* From here on, we're creating the window + /* From here on, we're creating the window */ - + if ((_window = new Window (WINDOW_TOPLEVEL)) == 0) { return 0; } @@ -91,68 +110,134 @@ Tabbable::get (bool create) _own_notebook.show (); _own_notebook.set_show_tabs (false); + _window->signal_map().connect (sigc::mem_fun (*this, &Tabbable::window_mapped)); + _window->signal_unmap().connect (sigc::mem_fun (*this, &Tabbable::window_unmapped)); + /* do other window-related setup */ setup (); /* window should be ready for derived classes to do something with it */ - + return _window; } -Gtk::Notebook* -Tabbable::tab_root_drop () +void +Tabbable::show_own_window (bool and_pack_it) { + Gtk::Widget* parent = _contents.get_parent(); Gtk::Allocation alloc; - alloc = _contents.get_parent()->get_allocation(); - - (void) use_own_window (); - + if (parent) { + alloc = parent->get_allocation(); + } + + (void) use_own_window (and_pack_it); + + if (parent) { + _window->set_default_size (alloc.get_width(), alloc.get_height()); + } + + tab_requested_by_state = false; + + _window->present (); +} + +Gtk::Notebook* +Tabbable::tab_root_drop () +{ /* This is called after a drop of a tab onto the root window. Its - * responsibility is to return the notebook that this Tabbable's + * responsibility xois to return the notebook that this Tabbable's * contents should be packed into before the drop handling is * completed. It is not responsible for actually taking care of this * packing. */ - _window->set_default_size (alloc.get_width(), alloc.get_height()); - _window->show_all (); - _window->present (); - + show_own_window (false); return &_own_notebook; } void Tabbable::show_window () { - Window* toplevel = dynamic_cast (_contents.get_toplevel()); + make_visible (); - if (toplevel == _window) { - _window->present (); + if (_window && (current_toplevel() == _window)) { + if (!_visible) { /* was hidden, update status */ + set_pos_and_size (); + } + } +} + +/** If this Tabbable is currently parented by a tab, ensure that the tab is the + * current one. If it is parented by a window, then toggle the visibility of + * that window. + */ +void +Tabbable::change_visibility () +{ + if (tabbed()) { + _parent_notebook->set_current_page (_parent_notebook->page_num (_contents)); + return; + } + + if (tab_requested_by_state) { + /* should be tabbed, but currently isn't parented by a notebook */ + return; } - if (!_visible) { /* was hidden, update status */ - set_pos_and_size (); + if (_window && (current_toplevel() == _window)) { + /* Use WindowProxy method which will rotate then hide */ + toggle(); } +} + +void +Tabbable::make_visible () +{ + if (_window && (current_toplevel() == _window)) { + set_pos (); + _window->present (); + } else { - if (toplevel != _window) { - /* not in its own window, just switch parent notebook to show - this Tabbable. - */ - if (_parent_notebook) { - _parent_notebook->set_current_page (_notebook_position); + if (!tab_requested_by_state) { + show_own_window (true); + } else { + show_tab (); } } } -bool -Tabbable::delete_event_handler (GdkEventAny *ev) +void +Tabbable::make_invisible () { - Window* toplevel = dynamic_cast (_contents.get_toplevel()); + if (_window && (current_toplevel() == _window)) { + _window->hide (); + } else { + hide_tab (); + } +} - if (_window == toplevel) { +void +Tabbable::detach () +{ + show_own_window (true); +} +void +Tabbable::attach () +{ + if (!_parent_notebook) { + return; + } + + if (tabbed()) { + /* already tabbed */ + return; + } + + + if (_window && current_toplevel() == _window) { /* unpack Tabbable from parent, put it back in the main tabbed * notebook */ @@ -164,44 +249,62 @@ Tabbable::delete_event_handler (GdkEventAny *ev) /* leave the window around */ _window->hide (); - - if (_parent_notebook) { + } - _parent_notebook->insert_page (_contents, _tab_title, _notebook_position); - _parent_notebook->set_tab_detachable (_contents); - _parent_notebook->set_current_page (_parent_notebook->page_num (_contents)); - } + _parent_notebook->append_page (_contents); + _parent_notebook->set_tab_detachable (_contents); + _parent_notebook->set_tab_reorderable (_contents); + _parent_notebook->set_current_page (_parent_notebook->page_num (_contents)); - /* don't let anything else handle this */ - - return true; - } + /* have to force this on, which is semantically correct, since + * the user has effectively asked for it. + */ - /* nothing to do */ - return false; + tab_requested_by_state = true; + StateChange (*this); } bool -Tabbable::is_tabbed () const +Tabbable::delete_event_handler (GdkEventAny *ev) { - Window* toplevel = (Window*) _contents.get_toplevel(); + _window->hide(); - if (_window && (toplevel == _window)) { + return true; +} + +bool +Tabbable::tabbed () const +{ + if (_window && (current_toplevel() == _window)) { return false; } - if (_parent_notebook) { + if (_parent_notebook && (_parent_notebook->page_num (_contents) >= 0)) { return true; } - + return false; } +void +Tabbable::hide_tab () +{ + if (tabbed()) { + _parent_notebook->remove_page (_contents); + StateChange (*this); + } +} + void Tabbable::show_tab () { if (!window_visible() && _parent_notebook) { + if (_contents.get_parent() == 0) { + tab_requested_by_state = true; + add_to_notebook (*_parent_notebook, _tab_title); + } _parent_notebook->set_current_page (_parent_notebook->page_num (_contents)); + current_toplevel()->present (); } } @@ -210,3 +313,72 @@ Tabbable::current_toplevel () const { return dynamic_cast (contents().get_toplevel()); } + +string +Tabbable::xml_node_name() +{ + return WindowProxy::xml_node_name(); +} + +bool +Tabbable::tabbed_by_default() const +{ + return tab_requested_by_state; +} + +XMLNode& +Tabbable::get_state() +{ + XMLNode& node (WindowProxy::get_state()); + + node.add_property (X_("tabbed"), tabbed() ? X_("yes") : X_("no")); + + return node; +} + +int +Tabbable::set_state (const XMLNode& node, int version) +{ + int ret; + + if ((ret = WindowProxy::set_state (node, version)) != 0) { + return ret; + } + + if (_visible) { + show_own_window (true); + } + + XMLNodeList children = node.children (); + XMLNode* window_node = node.child ("Window"); + + if (window_node) { + XMLProperty const * prop = window_node->property (X_("tabbed")); + if (prop) { + tab_requested_by_state = PBD::string_is_affirmative (prop->value()); + } + } + + if (!_visible) { + if (tab_requested_by_state) { + attach (); + } else { + /* this does nothing if not tabbed */ + hide_tab (); + } + } + + return ret; +} + +void +Tabbable::window_mapped () +{ + StateChange (*this); +} + +void +Tabbable::window_unmapped () +{ + StateChange (*this); +}