the big rework of window management. probably not complete at thsi point, but this...
[ardour.git] / gtk2_ardour / window_manager.cc
1 /*
2     Copyright (C) 2013 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 #include <gtkmm/window.h>
20
21 #include "pbd/xml++.h"
22
23 #include "ardour/session_handle.h"
24
25 #include "gtkmm2ext/visibility_tracker.h"
26
27 #include "actions.h"
28 #include "window_manager.h"
29
30 #include "i18n.h"
31
32 using std::string;
33
34 WindowManager* WindowManager::_instance = 0;
35
36 WindowManager&
37 WindowManager::instance ()
38 {
39         if (!_instance) {
40                 _instance = new WindowManager;
41         }
42         return *_instance;
43 }
44
45 WindowManager::WindowManager ()
46 {
47 }
48
49 void
50 WindowManager::register_window (ProxyBase* info)
51 {
52         _windows.push_back (info);
53
54         if (!info->menu_name().empty()) {
55
56                 if (!window_actions) {
57                         window_actions = Gtk::ActionGroup::create (X_("Window"));
58                         ActionManager::add_action_group (window_actions);
59                 }
60
61                 info->set_action (ActionManager::register_action (window_actions, info->action_name().c_str(), info->menu_name().c_str(), 
62                                                                   sigc::bind (sigc::mem_fun (*this, &WindowManager::toggle_window), info)));
63         }
64 }
65
66 void
67 WindowManager::remove (const ProxyBase* info)
68 {
69         for (Windows::iterator i = _windows.begin(); i != _windows.end(); ++i) {
70                 if ((*i) == info) {
71                         _windows.erase (i);
72                         return;
73                 }
74         }
75 }
76
77 void
78 WindowManager::toggle_window (ProxyBase* proxy)
79 {
80         if (proxy) {
81                 proxy->toggle ();
82         }
83 }
84
85 void
86 WindowManager::show_visible() const
87 {
88         for (Windows::const_iterator i = _windows.begin(); i != _windows.end(); ++i) {
89                 if ((*i)->visible()) {
90                         (*i)->show_all ();
91                         (*i)->present ();
92                 }
93         }
94 }
95
96 void
97 WindowManager::add_state (XMLNode& root) const
98 {
99         for (Windows::const_iterator i = _windows.begin(); i != _windows.end(); ++i) {
100                 root.add_child_nocopy ((*i)->get_state());
101         }
102 }
103
104 void
105 WindowManager::set_session (ARDOUR::Session* s)
106 {
107         for (Windows::const_iterator i = _windows.begin(); i != _windows.end(); ++i) {
108                 ARDOUR::SessionHandlePtr* sp = (*i)->session_handle ();
109                 if (sp) {
110                         sp->set_session (s);
111                 }
112         }
113 }
114
115 /*-----------------------*/
116
117 WindowManager::ProxyBase::ProxyBase (const string& name, const std::string& menu_name)
118         : _name (name)
119         , _menu_name (menu_name)
120         , _window (0)
121         , _visible (false)
122         , _x_off (-1)
123         , _y_off (-1)
124         , _width (-1)
125         , _height (-1) 
126         , vistracker (0)
127 {
128 }
129
130 WindowManager::ProxyBase::ProxyBase (const string& name, const std::string& menu_name, const XMLNode& node)
131         : _name (name)
132         , _menu_name (menu_name)
133         , _window (0)
134         , _visible (false)
135         , _x_off (-1)
136         , _y_off (-1)
137         , _width (-1)
138         , _height (-1) 
139         , vistracker (0)
140 {
141         set_state (node);
142 }
143
144 WindowManager::ProxyBase::~ProxyBase ()
145 {
146         delete vistracker;
147 }
148
149 void
150 WindowManager::ProxyBase::set_state (const XMLNode& node)
151 {
152         XMLNodeList children = node.children ();
153
154         XMLNodeList::const_iterator i = children.begin ();
155
156         while (i != children.end()) {
157                 XMLProperty* prop = (*i)->property (X_("name"));
158                 if ((*i)->name() == X_("Window") && prop && prop->value() == _name) {
159                         break;
160                 }
161
162                 ++i;
163         }
164
165         if (i != children.end()) {
166
167                 XMLProperty* prop;
168
169                 if ((prop = (*i)->property (X_("visible"))) != 0) {
170                         _visible = PBD::string_is_affirmative (prop->value ());
171                 }
172
173                 if ((prop = (*i)->property (X_("x-off"))) != 0) {
174                         _x_off = atoi (prop->value().c_str());
175                 }
176                 if ((prop = (*i)->property (X_("y-off"))) != 0) {
177                         _y_off = atoi (prop->value().c_str());
178                 }
179                 if ((prop = (*i)->property (X_("x-size"))) != 0) {
180                         _width = atoi (prop->value().c_str());
181                 }
182                 if ((prop = (*i)->property (X_("y-size"))) != 0) {
183                         _height = atoi (prop->value().c_str());
184                 }
185         }
186
187         /* if we have a window already, reset its properties */
188
189         if (_window) {
190                 setup ();
191         }
192 }
193
194 void
195 WindowManager::ProxyBase::set_action (Glib::RefPtr<Gtk::Action> act)
196 {
197         _action = act;
198 }
199
200 std::string
201 WindowManager::ProxyBase::action_name() const 
202 {
203         return string_compose (X_("toggle-%1"), _name);
204 }
205
206 void
207 WindowManager::ProxyBase::toggle() 
208 {
209         if (!_window) {
210                 (void) get (true);
211                 assert (_window);
212                 /* XXX this is a hack - the window object should really
213                    ensure its components are all visible. sigh.
214                 */
215                 _window->show_all();
216                 /* we'd like to just call this and nothing else */
217                 _window->present ();
218         } else {
219                 vistracker->cycle_visibility ();
220         }
221 }
222
223 XMLNode&
224 WindowManager::ProxyBase::get_state () const
225 {
226         XMLNode* node = new XMLNode (X_("Window"));
227         char buf[32];   
228
229         node->add_property (X_("name"), _name);
230
231         if (_window && vistracker) {
232                 
233                 /* we have a window, so use current state */
234
235                 _visible = vistracker->partially_visible ();
236                 _window->get_position (_x_off, _y_off);
237                 _window->get_size (_width, _height);
238         }
239
240         node->add_property (X_("visible"), _visible? X_("yes") : X_("no"));
241         
242         snprintf (buf, sizeof (buf), "%d", _x_off);
243         node->add_property (X_("x-off"), buf);
244         snprintf (buf, sizeof (buf), "%d", _y_off);
245         node->add_property (X_("y-off"), buf);
246         snprintf (buf, sizeof (buf), "%d", _width);
247         node->add_property (X_("x-size"), buf);
248         snprintf (buf, sizeof (buf), "%d", _height);
249         node->add_property (X_("y-size"), buf);
250
251         return *node;
252 }
253
254 void
255 WindowManager::ProxyBase::drop_window ()
256 {
257         if (_window) {
258                 _window->hide ();
259                 delete _window;
260                 _window = 0;
261                 delete vistracker;
262                 vistracker = 0;
263         }
264 }
265
266 void
267 WindowManager::ProxyBase::use_window (Gtk::Window& win)
268 {
269         drop_window ();
270         _window = &win;
271         setup ();
272 }
273
274 void
275 WindowManager::ProxyBase::setup ()
276 {
277         assert (_window);
278
279         vistracker = new Gtkmm2ext::VisibilityTracker (*_window);
280
281         if (_width != -1 && _height != -1) {
282                 _window->set_default_size (_width, _height);
283         }
284
285         if (_x_off != -1 && _y_off != -1) {
286                 _window->move (_x_off, _y_off);
287         }
288 }
289         
290 void
291 WindowManager::ProxyBase::show ()
292 {
293         Gtk::Window* win = get (true);
294         win->show ();
295 }
296
297 void
298 WindowManager::ProxyBase::maybe_show ()
299 {
300         if (_visible) {
301                 show ();
302         }
303 }
304
305 void
306 WindowManager::ProxyBase::show_all ()
307 {
308         Gtk::Window* win = get (true);
309         win->show_all ();
310 }
311
312
313 void
314 WindowManager::ProxyBase::present ()
315 {
316         Gtk::Window* win = get (true);
317         win->show_all ();
318         win->present ();
319 }
320
321 void
322 WindowManager::ProxyBase::hide ()
323 {
324         Gtk::Window* win = get (false);
325         if (win) {
326                 win->hide ();
327         }
328 }
329