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