save/restore tabbable state
[ardour.git] / libs / gtkmm2ext / tabbable.cc
1 /*
2     Copyright (C) 2015 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <gtkmm/action.h>
21 #include <gtkmm/notebook.h>
22 #include <gtkmm/window.h>
23
24 #include "gtkmm2ext/tabbable.h"
25 #include "gtkmm2ext/visibility_tracker.h"
26
27 #include "i18n.h"
28
29 using namespace Gtkmm2ext;
30 using namespace Gtk;
31 using std::string;
32
33 Tabbable::Tabbable (Widget& w, const string& name)
34         : WindowProxy (name)
35         , _contents (w)
36 {
37 }
38
39 Tabbable::~Tabbable ()
40 {
41         if (_window) {
42                 delete _window;
43                 _window = 0;
44         }
45 }
46
47 void
48 Tabbable::add_to_notebook (Notebook& notebook, const string& tab_title, int position)
49 {
50         notebook.insert_page (_contents, tab_title, position, false);
51         notebook.set_tab_detachable (_contents);
52         notebook.set_tab_reorderable (_contents);
53
54         _parent_notebook = &notebook;
55         _tab_title = tab_title;
56         _notebook_position = position;
57 }
58
59 Window*
60 Tabbable::use_own_window (bool and_pack_it)
61 {
62         Gtk::Window* win = get (true);
63
64         if (and_pack_it) {
65                 Gtk::Container* parent = _contents.get_parent();
66                 if (parent) {
67                         parent->remove (_contents);
68                 }
69                 _own_notebook.append_page (_contents, _tab_title);
70         }
71
72         return win;
73
74 }
75
76 bool
77 Tabbable::window_visible ()
78 {
79         if (!own_window()) {
80                 return false;
81         }
82
83         return visible();
84 }
85
86 Window*
87 Tabbable::get (bool create)
88 {
89         if (_window) {
90                 return _window;
91         }
92
93         if (!create) {
94                 return 0;
95         }
96
97         /* From here on, we're creating the window 
98          */
99         
100         if ((_window = new Window (WINDOW_TOPLEVEL)) == 0) {
101                 return 0;
102         }
103
104         _window->add (_own_notebook);
105         _own_notebook.show ();
106         _own_notebook.set_show_tabs (false);
107
108         /* do other window-related setup */
109
110         setup ();
111
112         /* window should be ready for derived classes to do something with it */
113         
114         return _window;
115 }
116
117 Gtk::Notebook*
118 Tabbable::tab_root_drop ()
119 {
120         Gtk::Allocation alloc;
121
122         alloc = _contents.get_parent()->get_allocation();
123         
124         (void) use_own_window (false);
125         
126         /* This is called after a drop of a tab onto the root window. Its
127          * responsibility is to return the notebook that this Tabbable's
128          * contents should be packed into before the drop handling is
129          * completed. It is not responsible for actually taking care of this
130          * packing.
131          */
132
133         _window->set_default_size (alloc.get_width(), alloc.get_height());
134         _window->show_all ();
135         _window->present ();
136
137         return &_own_notebook;
138 }
139
140 void
141 Tabbable::show_window ()
142 {
143         Window* toplevel = dynamic_cast<Window*> (_contents.get_toplevel());
144
145         if (toplevel == _window) {
146                 _window->present ();
147         }
148
149         if (!_visible) { /* was hidden, update status */
150                 set_pos_and_size ();
151         }
152
153         if (toplevel != _window) {
154                 /* not in its own window, just switch parent notebook to show
155                    this Tabbable.
156                 */
157                 if (_parent_notebook) {
158                         _parent_notebook->set_current_page (_parent_notebook->page_num (_contents));
159                 }
160         }
161 }
162
163 bool
164 Tabbable::delete_event_handler (GdkEventAny *ev)
165 {
166         Window* toplevel = dynamic_cast<Window*> (_contents.get_toplevel());
167
168         if (_window == toplevel) {
169
170                 /* unpack Tabbable from parent, put it back in the main tabbed
171                  * notebook
172                  */
173
174                 save_pos_and_size ();
175
176                 _contents.get_parent()->remove (_contents);
177
178                 /* leave the window around */
179
180                 _window->hide ();
181                 
182                 if (_parent_notebook) {
183
184                         _parent_notebook->insert_page (_contents, _tab_title, _notebook_position);
185                         _parent_notebook->set_tab_detachable (_contents);
186                         _parent_notebook->set_tab_reorderable (_contents);
187                         _parent_notebook->set_current_page (_parent_notebook->page_num (_contents));
188                 }
189
190                 /* don't let anything else handle this */
191                 
192                 return true;
193         } 
194
195         /* nothing to do */
196         return false;
197 }
198
199 bool
200 Tabbable::is_tabbed () const
201 {
202         Window* toplevel = (Window*) _contents.get_toplevel();
203
204         if (_window && (toplevel == _window)) {
205                 return false;
206         }
207
208         if (_parent_notebook) {
209                 return true;
210         }
211         
212         return false;
213 }
214
215 void
216 Tabbable::show_tab ()
217 {
218         if (!window_visible() && _parent_notebook) {
219                 _parent_notebook->set_current_page (_parent_notebook->page_num (_contents));
220         }
221 }
222
223 Gtk::Window*
224 Tabbable::current_toplevel () const
225 {
226         return dynamic_cast<Gtk::Window*> (contents().get_toplevel());
227 }
228
229 string
230 Tabbable::xml_node_name()
231 {
232         return WindowProxy::xml_node_name();
233 }
234
235 XMLNode&
236 Tabbable::get_state()
237 {
238         XMLNode& node (WindowProxy::get_state());
239
240         return node;
241 }
242
243 int
244 Tabbable::set_state (const XMLNode& node, int version)
245 {
246         int ret;
247
248         if ((ret = WindowProxy::set_state (node, version)) == 0) {
249                 if (_visible) {
250                         if (use_own_window (true) == 0) {
251                                 ret = -1;
252                         }
253                 }
254         }
255
256         return ret;
257 }