midi_clock_slave: enable debugging output
[ardour.git] / libs / gtkmm2ext / tearoff.cc
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 #include <gtkmm2ext/tearoff.h>
24 #include <gtkmm2ext/utils.h>
25
26 using namespace Gtkmm2ext;
27 using namespace Gtk;
28 using namespace Gdk;
29 using namespace Glib;
30 using namespace std;
31
32 TearOff::TearOff (Widget& c, bool allow_resize)
33         : contents (c),
34           own_window (Gtk::WINDOW_TOPLEVEL),
35           tearoff_arrow (ARROW_DOWN, SHADOW_OUT),
36           close_arrow (ARROW_UP, SHADOW_OUT)
37 {
38         dragging = false;
39         _visible = true;
40         _can_be_torn_off = true;
41
42         tearoff_event_box.add (tearoff_arrow);
43         tearoff_event_box.set_events (BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK);
44         tearoff_event_box.signal_button_release_event().connect (mem_fun (*this, &TearOff::tearoff_click));
45
46         close_event_box.add (close_arrow);
47         close_event_box.set_events (BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK);
48         close_event_box.signal_button_release_event().connect (mem_fun (*this, &TearOff::close_click));
49         
50         own_window.add_events (KEY_PRESS_MASK|KEY_RELEASE_MASK|BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK|POINTER_MOTION_MASK|POINTER_MOTION_HINT_MASK);
51         own_window.set_resizable (allow_resize);
52         own_window.set_type_hint (WINDOW_TYPE_HINT_TOOLBAR);
53         
54         VBox* box1;
55         box1 = manage (new VBox);
56         box1->pack_start (close_event_box, false, false, 2);
57         
58         window_box.pack_end (*box1, false, false, 2);
59         own_window.add (window_box);
60         
61         own_window.signal_button_press_event().connect (mem_fun (*this, &TearOff::window_button_press));
62         own_window.signal_button_release_event().connect (mem_fun (*this, &TearOff::window_button_release));
63         own_window.signal_motion_notify_event().connect (mem_fun (*this, &TearOff::window_motion));
64         own_window.signal_delete_event().connect (mem_fun (*this, &TearOff::window_delete_event));
65         own_window.signal_realize().connect (bind (sigc::ptr_fun (Gtkmm2ext::set_decoration), &own_window, WMDecoration (DECOR_BORDER|DECOR_RESIZEH)));
66
67         tearoff_arrow.set_name ("TearOffArrow");
68         close_arrow.set_name ("TearOffArrow");
69
70         VBox* box2;
71         box2 = manage (new VBox);
72         box2->pack_start (tearoff_event_box, false, false, 2);
73
74         pack_start (contents);
75         pack_start (*box2, false, false, 2);
76
77 }
78
79 TearOff::~TearOff ()
80 {
81 }
82
83 void
84 TearOff::set_can_be_torn_off (bool yn)
85 {
86         if (yn != _can_be_torn_off) {
87                 if (yn) {
88                         tearoff_arrow.set_no_show_all (false);
89                         tearoff_arrow.show ();
90                 } else {
91                         tearoff_arrow.set_no_show_all (true);
92                         tearoff_arrow.hide ();
93                 }
94                 _can_be_torn_off = yn;
95         }
96 }
97
98 void
99 TearOff::set_visible (bool yn)
100 {
101         /* don't change visibility if torn off */
102
103         if (own_window.is_visible()) {
104                 return;
105         }
106
107         if (_visible != yn) {
108                 _visible = yn;
109                 if (yn) {
110                         show_all();
111                         Visible ();
112                 } else {
113                         hide ();
114                         Hidden ();
115                 }
116         }
117 }
118
119 gint
120 TearOff::tearoff_click (GdkEventButton* /*ev*/)
121 {
122         if (_can_be_torn_off) {
123                 remove (contents);
124                 window_box.pack_start (contents);
125                 own_window.set_name (get_name());
126                 close_event_box.set_name (get_name());
127                 own_window.show_all ();
128                 own_window.present ();
129                 std::cerr << "own window should be visible\n";
130                 hide ();
131                 Detach ();
132         }
133
134         return true;
135 }
136
137 gint
138 TearOff::close_click (GdkEventButton* /*ev*/)
139 {
140         window_box.remove (contents);
141         pack_start (contents);
142         reorder_child (contents, 0);
143         own_window.hide ();
144         show_all ();
145         Attach ();
146         return true;
147 }               
148
149 gint
150 TearOff::window_button_press (GdkEventButton* ev)
151 {
152         if (dragging || ev->button != 1) {
153                 dragging = false;
154                 own_window.remove_modal_grab();
155                 return true;
156         }
157
158         dragging = true;
159         drag_x = ev->x_root;
160         drag_y = ev->y_root;
161
162         own_window.add_modal_grab();
163
164         return true;
165 }
166
167 gint
168 TearOff::window_button_release (GdkEventButton* /*ev*/)
169 {
170         dragging = false;
171         own_window.remove_modal_grab();
172         return true;
173 }
174
175 gint
176 TearOff::window_delete_event (GdkEventAny* /*ev*/)
177 {
178         return close_click(0);
179 }
180
181 gint
182 TearOff::window_motion (GdkEventMotion* ev)
183 {
184         gint x;
185         gint y;
186         gint mx, my;
187         double x_delta;
188         double y_delta;
189         RefPtr<Gdk::Window> win (own_window.get_window());
190         
191         own_window.get_pointer (mx, my);
192
193         if (!dragging) {
194                 return true;
195         }
196
197         if (!(ev->state & GDK_BUTTON1_MASK)) {
198                 dragging = false;
199                 own_window.remove_modal_grab();
200                 return true;
201         }
202
203         x_delta = ev->x_root - drag_x;
204         y_delta = ev->y_root - drag_y;
205
206         win->get_root_origin (x, y);
207         win->move ((gint) floor (x + x_delta), (gint) floor (y + y_delta));
208         
209         drag_x = ev->x_root;
210         drag_y = ev->y_root;
211         
212         return true;
213 }
214
215 bool
216 TearOff::torn_off() const
217 {
218         return own_window.is_visible();
219 }