df9f046004695543dc12601a1c0a2578533374a3
[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 <gtkmm2ext/tearoff.h>
23 #include <gtkmm2ext/utils.h>
24
25 using namespace Gtkmm2ext;
26 using namespace Gtk;
27 using namespace std;
28
29 TearOff::TearOff (Gtk::Widget& c)
30         : contents (c),
31           tearoff_arrow (Gtk::ARROW_DOWN, Gtk::SHADOW_OUT),
32           close_arrow (Gtk::ARROW_UP, Gtk::SHADOW_OUT)
33 {
34         dragging = false;
35
36         tearoff_event_box.add (tearoff_arrow);
37         tearoff_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
38         tearoff_event_box.signal_button_release_event().connect (mem_fun (*this, &TearOff::tearoff_click));
39
40         close_event_box.add (close_arrow);
41         close_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
42         close_event_box.signal_button_release_event().connect (mem_fun (*this, &TearOff::close_click));
43         
44         own_window = new Gtk::Window (Gtk::WINDOW_TOPLEVEL);
45         own_window->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::POINTER_MOTION_HINT_MASK);
46         own_window->set_resizable (false);
47         
48         VBox* box1;
49         box1 = manage (new VBox);
50         box1->pack_start (close_event_box, false, false, 5);
51         
52         window_box.pack_end (*box1, false, false, 2);
53         own_window->add (window_box);
54         
55         own_window->signal_button_press_event().connect (mem_fun (*this, &TearOff::window_button_press));
56         own_window->signal_button_release_event().connect (mem_fun (*this, &TearOff::window_button_release));
57         own_window->signal_motion_notify_event().connect (mem_fun (*this, &TearOff::window_motion));
58         own_window->signal_delete_event().connect (mem_fun (*this, &TearOff::window_delete_event));
59         own_window->signal_realize().connect (bind (sigc::ptr_fun (Gtkmm2ext::set_decoration), own_window, Gdk::WMDecoration (Gdk::DECOR_BORDER|Gdk::DECOR_RESIZEH)));
60
61         tearoff_arrow.set_name ("TearOffArrow");
62         close_arrow.set_name ("TearOffArrow");
63
64         VBox* box2;
65         box2 = manage (new VBox);
66         box2->pack_start (tearoff_event_box, false, false, 5);
67
68         pack_start (contents);
69         pack_start (*box2, false, false, 2);
70
71 }
72
73 TearOff::~TearOff ()
74 {
75         delete own_window;
76 }
77
78 gint
79 TearOff::tearoff_click (GdkEventButton* ev)
80 {
81         remove (contents);
82         window_box.pack_start (contents);
83         own_window->set_name (get_name());
84         close_event_box.set_name (get_name());
85         own_window->show_all ();
86 //      own_window->realize ();
87         hide ();
88         Detach ();
89         return TRUE;
90 }
91
92 gint
93 TearOff::close_click (GdkEventButton* ev)
94 {
95         window_box.remove (contents);
96         pack_start (contents);
97         reorder_child (contents, 0);
98         own_window->hide ();
99         show_all ();
100         Attach ();
101         return TRUE;
102 }               
103
104 gint
105 TearOff::window_button_press (GdkEventButton* ev)
106 {
107         dragging = true;
108         drag_x = ev->x_root;
109         drag_y = ev->y_root;
110
111         own_window->add_modal_grab();
112
113         return TRUE;
114 }
115
116 gint
117 TearOff::window_button_release (GdkEventButton* ev)
118 {
119         dragging = false;
120         own_window->remove_modal_grab();
121         return TRUE;
122 }
123
124 gint
125 TearOff::window_delete_event (GdkEventAny* ev)
126 {
127         return close_click(0);
128 }
129
130 gint
131 TearOff::window_motion (GdkEventMotion* ev)
132 {
133         gint x;
134         gint y;
135         gint mx, my;
136         double x_delta;
137         double y_delta;
138         Glib::RefPtr<Gdk::Window> win (own_window->get_window());
139         
140         own_window->get_pointer (mx, my);
141
142         if (!dragging) {
143                 return TRUE;
144         }
145
146         x_delta = ev->x_root - drag_x;
147         y_delta = ev->y_root - drag_y;
148
149         win->get_root_origin (x, y);
150         win->move ((gint) floor (x + x_delta), (gint) floor (y + y_delta));
151         
152         drag_x = ev->x_root;
153         drag_y = ev->y_root;
154         
155         return TRUE;
156 }
157
158 bool
159 TearOff::torn_off() const
160 {
161         return own_window->is_visible();
162 }