remove unused lines
[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 #include <gtkmm/stock.h>
24
25 #include "gtkmm2ext/tabbable.h"
26 #include "gtkmm2ext/gtk_ui.h"
27 #include "gtkmm2ext/utils.h"
28 #include "gtkmm2ext/visibility_tracker.h"
29
30 #include "i18n.h"
31
32 using namespace Gtkmm2ext;
33 using namespace Gtk;
34 using std::string;
35
36 Tabbable::Tabbable (Widget& w, const string& name)
37         : WindowProxy (name)
38         , _contents (w)
39         , tab_close_image (ArdourIcon::CloseCross, 0xffffffff)
40         , tab_requested_by_state (true)
41 {
42         tab_close_image.set_size_request (15,15);
43         
44         _tab_box.set_spacing (2);
45         _tab_box.pack_start (_tab_label, true, true);
46         _tab_box.pack_start (_tab_close_button, false, false);
47         _tab_close_button.add (tab_close_image);
48         
49         _tab_close_button.signal_clicked().connect (sigc::mem_fun (*this, &Tabbable::tab_close_clicked));
50 }
51
52 Tabbable::~Tabbable ()
53 {
54         if (_window) {
55                 delete _window;
56                 _window = 0;
57         }
58 }
59
60 void
61 Tabbable::tab_close_clicked ()
62 {
63         hide_tab ();
64 }
65
66 void
67 Tabbable::add_to_notebook (Notebook& notebook, const string& tab_title)
68 {
69         _parent_notebook = &notebook;
70         _tab_title = tab_title;
71         _tab_label.set_text (tab_title);
72         _tab_box.show_all ();
73
74         if (tab_requested_by_state) {
75                 attach ();
76         }
77 }
78
79 Window*
80 Tabbable::use_own_window (bool and_pack_it)
81 {
82         Gtk::Window* win = get (true);
83
84         if (and_pack_it) {
85                 Gtk::Container* parent = _contents.get_parent();
86                 if (parent) {
87                         parent->remove (_contents);
88                 }
89                 _own_notebook.append_page (_contents, _tab_box);
90         }
91
92         return win;
93
94 }
95
96 bool
97 Tabbable::window_visible ()
98 {
99         if (!own_window()) {
100                 return false;
101         }
102
103         return _window->is_visible();
104 }
105
106 Window*
107 Tabbable::get (bool create)
108 {
109         if (_window) {
110                 return _window;
111         }
112
113         if (!create) {
114                 return 0;
115         }
116
117         /* From here on, we're creating the window 
118          */
119         
120         if ((_window = new Window (WINDOW_TOPLEVEL)) == 0) {
121                 return 0;
122         }
123
124         _window->add (_own_notebook);
125         _own_notebook.show ();
126         _own_notebook.set_show_tabs (false);
127
128         _window->signal_map().connect (sigc::mem_fun (*this, &Tabbable::window_mapped));
129         _window->signal_unmap().connect (sigc::mem_fun (*this, &Tabbable::window_unmapped));
130         
131         /* do other window-related setup */
132
133         setup ();
134
135         /* window should be ready for derived classes to do something with it */
136         
137         return _window;
138 }
139
140 void
141 Tabbable::show_own_window (bool and_pack_it)
142 {
143         Gtk::Widget* parent = _contents.get_parent();
144         Gtk::Allocation alloc;
145
146         if (parent) {
147                 alloc = parent->get_allocation();
148         }
149         
150         (void) use_own_window (and_pack_it);
151         
152         if (parent) {
153                 _window->set_default_size (alloc.get_width(), alloc.get_height());
154         }
155
156         _window->show_all ();
157         _window->present ();
158 }
159
160 Gtk::Notebook*
161 Tabbable::tab_root_drop ()
162 {
163         /* This is called after a drop of a tab onto the root window. Its
164          * responsibility xois to return the notebook that this Tabbable's
165          * contents should be packed into before the drop handling is
166          * completed. It is not responsible for actually taking care of this
167          * packing.
168          */
169
170         show_own_window (false);
171         return &_own_notebook;
172 }
173
174 void
175 Tabbable::show_window ()
176 {
177         make_visible ();
178
179         if (_window && (current_toplevel() == _window)) {
180                 if (!_visible) { /* was hidden, update status */
181                         set_pos_and_size ();
182                 }
183         }
184 }
185
186 void
187 Tabbable::make_visible ()
188 {
189         if (_window && (current_toplevel() == _window)) {
190                 _window->present ();
191         } else {
192
193                 if (!tab_requested_by_state) {
194                         show_own_window (true);
195                 } else {
196                         show_tab ();
197                 }
198         }
199 }
200
201 void
202 Tabbable::make_invisible ()
203 {
204         if (_window && (current_toplevel() == _window)) {
205                 _window->hide ();
206         } else {
207                 hide_tab ();
208         }
209 }
210         
211 void
212 Tabbable::detach ()
213 {
214         show_own_window (true);
215 }
216
217 void
218 Tabbable::attach ()
219 {
220         if (!_parent_notebook) {
221                 return;
222         }
223         
224         if (tabbed()) {
225                 /* already tabbed */
226                 return;
227         }
228
229
230         if (_window && current_toplevel() == _window) {
231                 /* unpack Tabbable from parent, put it back in the main tabbed
232                  * notebook
233                  */
234                 
235                 save_pos_and_size ();
236                 
237                 _contents.get_parent()->remove (_contents);
238         
239                 /* leave the window around */
240                 
241                 _window->hide ();
242         }
243         
244         _parent_notebook->append_page (_contents, _tab_box);
245         _parent_notebook->set_tab_detachable (_contents);
246         _parent_notebook->set_tab_reorderable (_contents);
247         _parent_notebook->set_current_page (_parent_notebook->page_num (_contents));
248
249         Gtkmm2ext::UI::instance()->set_tip (_tab_label,
250                                             string_compose (_("Drag this tab to the desktop to show %1 in its own window\n\n"
251                                                               "To put the window back, click on its \"close\" button"), _tab_title));
252
253
254         /* have to force this on, which is semantically correct, since
255          * the user has effectively asked for it.
256          */
257
258         tab_requested_by_state = true;
259         StateChange (*this);
260 }
261
262 bool
263 Tabbable::delete_event_handler (GdkEventAny *ev)
264 {
265         _window->hide();
266
267         return true;
268 }
269
270 bool
271 Tabbable::is_tabbed () const
272 {
273         Window* toplevel = (Window*) _contents.get_toplevel();
274
275         if (_window && (toplevel == _window)) {
276                 return false;
277         }
278
279         if (_parent_notebook && _contents.get_parent()) {
280                 return true;
281         }
282         
283         return false;
284 }
285
286 void
287 Tabbable::hide_tab ()
288 {
289         if (tabbed()) {
290                 _parent_notebook->remove_page (_contents);
291                 StateChange (*this);
292         }
293 }
294
295 void
296 Tabbable::show_tab ()
297 {
298         if (!window_visible() && _parent_notebook) {
299                 if (_contents.get_parent() == 0) {
300                         tab_requested_by_state = true;
301                         add_to_notebook (*_parent_notebook, _tab_title);
302                 }
303                 _parent_notebook->set_current_page (_parent_notebook->page_num (_contents));
304         }
305 }
306
307 Gtk::Window*
308 Tabbable::current_toplevel () const
309 {
310         return dynamic_cast<Gtk::Window*> (contents().get_toplevel());
311 }
312
313 string
314 Tabbable::xml_node_name()
315 {
316         return WindowProxy::xml_node_name();
317 }
318
319 bool
320 Tabbable::tabbed () const
321 {
322         return _parent_notebook && (_parent_notebook->page_num (_contents) >= 0);
323 }
324
325 XMLNode&
326 Tabbable::get_state()
327 {
328         XMLNode& node (WindowProxy::get_state());
329
330         node.add_property (X_("tabbed"),  tabbed() ? X_("yes") : X_("no"));
331         
332         return node;
333 }
334
335 int
336 Tabbable::set_state (const XMLNode& node, int version)
337 {
338         int ret;
339
340         if ((ret = WindowProxy::set_state (node, version)) == 0) {
341                 if (_visible) {
342                         if (use_own_window (true) == 0) {
343                                 ret = -1;
344                         }
345                 }
346         }
347
348         XMLNodeList children = node.children ();
349         XMLNode* window_node = node.child ("Window");
350
351         if (window_node) {
352                 const XMLProperty* prop = window_node->property (X_("tabbed"));
353                 if (prop) {
354                         tab_requested_by_state = PBD::string_is_affirmative (prop->value());
355                 }
356         }
357
358         if (tab_requested_by_state) {
359
360                 std::cerr << name() << " pn " << _parent_notebook << std::endl;
361                 if (_parent_notebook) {
362                         std::cerr << "\t page " << _parent_notebook->page_num (_contents) << std::endl;
363                 }
364
365                 attach ();
366         } else {
367                 /* this does nothing if not tabbed */
368                 hide_tab ();
369         }
370         
371         return ret;
372 }
373
374 void
375 Tabbable::window_mapped ()
376 {
377         StateChange (*this);
378 }
379
380 void
381 Tabbable::window_unmapped ()
382 {
383         StateChange (*this);
384 }
385