ardour
tearoff.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 Paul Barton-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  $Id$
19 */
20 
21 #include <cmath>
22 #include <iostream>
23 
24 #include "pbd/xml++.h"
25 
26 #include "gtkmm2ext/tearoff.h"
27 #include "gtkmm2ext/utils.h"
28 
29 #include "i18n.h"
30 
31 using namespace Gtkmm2ext;
32 using namespace Gtk;
33 using namespace Gdk;
34 using namespace Glib;
35 using namespace std;
36 
37 TearOff::TearOff (Widget& c, bool allow_resize)
38  : contents (c)
39  , own_window (Gtk::WINDOW_TOPLEVEL)
40  , tearoff_arrow (ARROW_DOWN, SHADOW_OUT)
41  , close_arrow (ARROW_UP, SHADOW_OUT)
42  , dragging (false)
43  , _visible (true)
44  , _torn (false)
45  , _can_be_torn_off (true)
46 
47 {
48  own_window_width = 0;
50  own_window_xpos = 0;
51  own_window_ypos = 0;
52 
54  tearoff_event_box.set_events (BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK);
55  tearoff_event_box.signal_button_release_event().connect (mem_fun (*this, &TearOff::tearoff_click));
56 
57  tearoff_event_box.set_tooltip_text (_("Click to tear this into its own window"));
58 
60  close_event_box.set_events (BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK);
61  close_event_box.signal_button_release_event().connect (mem_fun (*this, &TearOff::close_click));
62 
63  close_event_box.set_tooltip_text (_("Click to put this back in the main window"));
64 
65  VBox* box1;
66  box1 = manage (new VBox);
67  box1->pack_start (close_event_box, false, false, 2);
68 
69  window_box.pack_end (*box1, false, false, 2);
70 
71  own_window.add_events (KEY_PRESS_MASK|KEY_RELEASE_MASK|BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK|POINTER_MOTION_MASK|POINTER_MOTION_HINT_MASK);
72  own_window.set_resizable (allow_resize);
73  own_window.set_type_hint (WINDOW_TYPE_HINT_UTILITY);
74 
75  own_window.add (window_box);
76 
77  own_window.signal_button_press_event().connect (mem_fun (*this, &TearOff::window_button_press));
78  own_window.signal_button_release_event().connect (mem_fun (*this, &TearOff::window_button_release));
79  own_window.signal_motion_notify_event().connect (mem_fun (*this, &TearOff::window_motion));
80  own_window.signal_delete_event().connect (mem_fun (*this, &TearOff::window_delete_event));
81  own_window.signal_realize().connect (sigc::mem_fun (*this, &TearOff::own_window_realized));
82  own_window.signal_configure_event().connect (sigc::mem_fun (*this, &TearOff::own_window_configured), false);
83 
84  tearoff_arrow.set_name ("TearOffArrow");
85  close_arrow.set_name ("TearOffArrow");
86 
87  VBox* box2;
88  box2 = manage (new VBox);
89  box2->pack_start (tearoff_event_box, false, false);
90 
91  pack_start (contents);
92  pack_start (*box2, false, false);
93 }
94 
96 {
97 }
98 
99 void
101 {
102  if (yn != _can_be_torn_off) {
103  if (yn) {
104  tearoff_arrow.set_no_show_all (false);
105  tearoff_arrow.show ();
106  } else {
107  tearoff_arrow.set_no_show_all (true);
108  tearoff_arrow.hide ();
109  }
110  _can_be_torn_off = yn;
111  }
112 }
113 
114 void
115 TearOff::set_visible (bool yn, bool force)
116 {
117  /* don't change visibility if torn off */
118 
119  if (_torn) {
120  return;
121  }
122 
123  if (_visible != yn || force) {
124  _visible = yn;
125  if (yn) {
126  show_all();
127  Visible ();
128  } else {
129  hide ();
130  Hidden ();
131  }
132  }
133 }
134 
135 gint
136 TearOff::tearoff_click (GdkEventButton* /*ev*/)
137 {
138  tear_it_off ();
139  return true;
140 }
141 
142 void
144 {
145  if (!_can_be_torn_off) {
146  return;
147  }
148 
149  if (torn_off()) {
150  return;
151  }
152 
153  remove (contents);
154  window_box.pack_start (contents);
155  own_window.set_name (get_name());
156  close_event_box.set_name (get_name());
157  if (own_window_width == 0) {
158  own_window.set_position (WIN_POS_MOUSE);
159  }
160  own_window.show_all ();
161  own_window.present ();
162  hide ();
163 
164  _torn = true;
165 
166  Detach ();
167 }
168 
169 gint
170 TearOff::close_click (GdkEventButton* /*ev*/)
171 {
172  put_it_back ();
173  return true;
174 }
175 
176 void
178 {
179  if (!torn_off()) {
180  return;
181  }
182 
183  window_box.remove (contents);
184  pack_start (contents);
185  reorder_child (contents, 0);
186  own_window.hide ();
187  show_all ();
188 
189  _torn = false;
190 
191  Attach ();
192 }
193 
194 gint
195 TearOff::window_button_press (GdkEventButton* ev)
196 {
197  if (dragging || ev->button != 1) {
198  dragging = false;
199  own_window.remove_modal_grab();
200  return true;
201  }
202 
203  dragging = true;
204  drag_x = ev->x_root;
205  drag_y = ev->y_root;
206 
207  own_window.add_modal_grab();
208 
209  return true;
210 }
211 
212 gint
213 TearOff::window_button_release (GdkEventButton* /*ev*/)
214 {
215  dragging = false;
216  own_window.remove_modal_grab();
217  return true;
218 }
219 
220 gint
221 TearOff::window_delete_event (GdkEventAny* /*ev*/)
222 {
223  return close_click(0);
224 }
225 
226 gint
227 TearOff::window_motion (GdkEventMotion* ev)
228 {
229  gint x;
230  gint y;
231  gint mx, my;
232  double x_delta;
233  double y_delta;
234  RefPtr<Gdk::Window> win (own_window.get_window());
235 
236  own_window.get_pointer (mx, my);
237 
238  if (!dragging) {
239  return true;
240  }
241 
242  if (!(ev->state & GDK_BUTTON1_MASK)) {
243  dragging = false;
244  own_window.remove_modal_grab();
245  return true;
246  }
247 
248  x_delta = ev->x_root - drag_x;
249  y_delta = ev->y_root - drag_y;
250 
251  win->get_root_origin (x, y);
252  win->move ((gint) floor (x + x_delta), (gint) floor (y + y_delta));
253 
254  drag_x = ev->x_root;
255  drag_y = ev->y_root;
256 
257  return true;
258 }
259 
260 bool
262 {
263  return _torn;
264 }
265 
266 void
268 {
269  node.add_property ("tornoff", (_torn ? "yes" : "no"));
270 
271  if (own_window_width > 0) {
272  char buf[32];
273 
274  snprintf (buf, sizeof (buf), "%d", own_window_width);
275  node.add_property ("width", buf);
276  snprintf (buf, sizeof (buf), "%d", own_window_height);
277  node.add_property ("height", buf);
278  snprintf (buf, sizeof (buf), "%d", own_window_xpos);
279  node.add_property ("xpos", buf);
280  snprintf (buf, sizeof (buf), "%d", own_window_ypos);
281  node.add_property ("ypos", buf);
282  }
283 }
284 
285 void
287 {
288  Glib::RefPtr<Gdk::Window> win;
289  const XMLProperty* prop;
290 
291  if ((prop = node.property (X_("tornoff"))) == 0) {
292  return;
293  }
294 
295  if (prop->value() == "yes") {
296  tear_it_off ();
297  } else {
298  put_it_back ();
299  }
300 
301  if ((prop = node.property (X_("width"))) != 0) {
302  sscanf (prop->value().c_str(), "%d", &own_window_width);
303  }
304  if ((prop = node.property (X_("height"))) != 0) {
305  sscanf (prop->value().c_str(), "%d", &own_window_height);
306  }
307  if ((prop = node.property (X_("xpos"))) != 0) {
308  sscanf (prop->value().c_str(), "%d", &own_window_xpos);
309  }
310  if ((prop = node.property (X_("ypos"))) != 0) {
311  sscanf (prop->value().c_str(), "%d", &own_window_ypos);
312  }
313 
314  if (own_window.is_realized()) {
315  own_window.set_default_size (own_window_width, own_window_height);
317  }
318  /* otherwise do it once the window is realized, see below */
319 }
320 
321 void
323 {
324  own_window.get_window()->set_decorations (WMDecoration (DECOR_BORDER|DECOR_RESIZEH));
325 
326  if (own_window_width > 0) {
327  own_window.set_default_size (own_window_width, own_window_height);
329  }
330 }
331 
332 bool
333 TearOff::own_window_configured (GdkEventConfigure*)
334 {
335  Glib::RefPtr<const Gdk::Window> win;
336 
337  win = own_window.get_window ();
338 
339  if (win) {
340  win->get_size (own_window_width, own_window_height);
341  win->get_position (own_window_xpos, own_window_ypos);
342  }
343 
344  return false;
345 }
346 
347 void
349 {
350  if (torn_off()) {
351  own_window.hide ();
352  }
353 
354  hide ();
355 }
356 
357 
void set_visible(bool yn, bool force=false)
Definition: tearoff.cc:115
sigc::signal< void > Hidden
Definition: tearoff.h:48
const std::string & value() const
Definition: xml++.h:159
Gtk::HBox window_box
Definition: tearoff.h:64
bool torn_off() const
Definition: tearoff.cc:261
Definition: ardour_ui.h:130
void hide_visible()
Definition: tearoff.cc:348
bool _can_be_torn_off
Definition: tearoff.h:72
void tear_it_off()
Definition: tearoff.cc:143
Definition: Beats.hpp:239
int own_window_height
Definition: tearoff.h:74
gint close_click(GdkEventButton *)
Definition: tearoff.cc:170
void set_can_be_torn_off(bool)
Definition: tearoff.cc:100
Gtk::EventBox tearoff_event_box
Definition: tearoff.h:65
Gtk::Arrow close_arrow
Definition: tearoff.h:63
#define _(Text)
Definition: i18n.h:11
gint tearoff_click(GdkEventButton *)
Definition: tearoff.cc:136
#define X_(Text)
Definition: i18n.h:13
XMLProperty * property(const char *)
Definition: xml++.cc:413
sigc::signal< void > Attach
Definition: tearoff.h:46
gint window_button_release(GdkEventButton *)
Definition: tearoff.cc:213
sigc::signal< void > Detach
Definition: tearoff.h:45
Gtk::Window own_window
Definition: tearoff.h:61
gint window_button_press(GdkEventButton *)
Definition: tearoff.cc:195
bool own_window_configured(GdkEventConfigure *)
Definition: tearoff.cc:333
virtual ~TearOff()
Definition: tearoff.cc:95
XMLProperty * add_property(const char *name, const std::string &value)
gint window_motion(GdkEventMotion *)
Definition: tearoff.cc:227
sigc::signal< void > Visible
Definition: tearoff.h:47
int own_window_width
Definition: tearoff.h:73
Gtk::Arrow tearoff_arrow
Definition: tearoff.h:62
Definition: xml++.h:95
void put_it_back()
Definition: tearoff.cc:177
void add_state(XMLNode &) const
Definition: tearoff.cc:267
Gtk::Widget & contents
Definition: tearoff.h:60
gint window_delete_event(GdkEventAny *)
Definition: tearoff.cc:221
void own_window_realized()
Definition: tearoff.cc:322
TearOff(Gtk::Widget &contents, bool allow_resize=false)
Definition: tearoff.cc:37
Gtk::EventBox close_event_box
Definition: tearoff.h:66
void set_state(const XMLNode &)
Definition: tearoff.cc:286