X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fgtkmm2ext%2Ftabbable.cc;h=5e4752454e6cfd6c8547b56799f59399b2307165;hb=cf52d6e4b40111eb04b244ec054055a4ec15dbe0;hp=34979d6bbe6f6bd7dd978a53c6d24883cd196c80;hpb=8e144969199bce8008b8d5fa4449a227c207ed62;p=ardour.git diff --git a/libs/gtkmm2ext/tabbable.cc b/libs/gtkmm2ext/tabbable.cc index 34979d6bbe..5e4752454e 100644 --- a/libs/gtkmm2ext/tabbable.cc +++ b/libs/gtkmm2ext/tabbable.cc @@ -27,7 +27,9 @@ #include "gtkmm2ext/utils.h" #include "gtkmm2ext/visibility_tracker.h" -#include "i18n.h" +#include "pbd/stacktrace.h" + +#include "pbd/i18n.h" using namespace Gtkmm2ext; using namespace Gtk; @@ -36,17 +38,9 @@ using std::string; Tabbable::Tabbable (Widget& w, const string& name) : WindowProxy (name) , _contents (w) - , tab_close_image (ArdourIcon::CloseCross, 0xffffffff) + , _parent_notebook (0) + , tab_requested_by_state (true) { - /* make the image about the same size as an actual X */ - set_size_request_to_display_given_text (tab_close_image, "X", 0, 0); - - _tab_box.set_spacing (2); - _tab_box.pack_start (_tab_label, true, true); - _tab_box.pack_start (_tab_close_button, false, false); - _tab_close_button.add (tab_close_image); - - _tab_close_button.signal_clicked().connect (sigc::mem_fun (*this, &Tabbable::tab_close_clicked)); } Tabbable::~Tabbable () @@ -57,36 +51,14 @@ Tabbable::~Tabbable () } } -void -Tabbable::tab_close_clicked () -{ - /* for this to happen, the tab must be visible so we - can assume that the contents are displayed in the - parent notebook - */ - - if (_parent_notebook) { - _parent_notebook->remove_page (_contents); - } -} - void Tabbable::add_to_notebook (Notebook& notebook, const string& tab_title) { - _tab_label.set_text (tab_title); - _tab_box.show_all (); - - notebook.append_page (_contents, _tab_box); - - Gtkmm2ext::UI::instance()->set_tip (_tab_label, - string_compose (_("Drag this tab to the desktop to show %1 in its own window\n\n" - "To put the window back, click on its \"close\" button"), tab_title)); - - notebook.set_tab_detachable (_contents); - notebook.set_tab_reorderable (_contents); - _parent_notebook = ¬ebook; - _tab_title = tab_title; + + if (tab_requested_by_state) { + attach (); + } } Window* @@ -99,7 +71,7 @@ Tabbable::use_own_window (bool and_pack_it) if (parent) { parent->remove (_contents); } - _own_notebook.append_page (_contents, _tab_box); + _own_notebook.append_page (_contents); } return win; @@ -107,13 +79,13 @@ Tabbable::use_own_window (bool and_pack_it) } bool -Tabbable::window_visible () +Tabbable::window_visible () const { - if (!own_window()) { + if (!_window) { return false; } - return visible(); + return _window->is_visible(); } Window* @@ -127,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; } @@ -138,35 +110,50 @@ 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 (false); - + 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; } @@ -182,13 +169,75 @@ Tabbable::show_window () } } -bool -Tabbable::delete_event_handler (GdkEventAny *ev) +/** 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 (_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 (!tab_requested_by_state) { + show_own_window (true); + } else { + show_tab (); + } + } +} + +void +Tabbable::make_invisible () +{ + if (_window && (current_toplevel() == _window)) { + _window->hide (); + } else { + hide_tab (); + } +} + +void +Tabbable::detach () { - Window* toplevel = dynamic_cast (_contents.get_toplevel()); + show_own_window (true); +} + +void +Tabbable::attach () +{ + if (!_parent_notebook) { + return; + } + + if (tabbed()) { + /* already tabbed */ + return; + } - if (_window == toplevel) { + if (_window && current_toplevel() == _window) { /* unpack Tabbable from parent, put it back in the main tabbed * notebook */ @@ -200,48 +249,62 @@ Tabbable::delete_event_handler (GdkEventAny *ev) /* leave the window around */ _window->hide (); - - if (_parent_notebook) { + } - _parent_notebook->append_page (_contents, _tab_box); - _parent_notebook->set_tab_detachable (_contents); - _parent_notebook->set_tab_reorderable (_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(); + + return true; +} - if (_window && (toplevel == _window)) { +bool +Tabbable::tabbed () const +{ + if (_window && (current_toplevel() == _window)) { return false; } - if (_parent_notebook && _contents.get_parent()) { + 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 (); } } @@ -257,11 +320,19 @@ 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; } @@ -270,11 +341,30 @@ Tabbable::set_state (const XMLNode& node, int version) { int ret; - if ((ret = WindowProxy::set_state (node, version)) == 0) { - if (_visible) { - if (use_own_window (true) == 0) { - ret = -1; - } + 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 (); } } @@ -282,11 +372,13 @@ Tabbable::set_state (const XMLNode& node, int version) } void -Tabbable::make_visible () +Tabbable::window_mapped () { - if (_window && (current_toplevel() == _window)) { - _window->present (); - } else { - show_tab (); - } + StateChange (*this); +} + +void +Tabbable::window_unmapped () +{ + StateChange (*this); }