midi_clock_slave: enable debugging output
[ardour.git] / libs / gtkmm2ext / pixscroller.cc
1 /*
2     Copyright (C) 2005 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     $Id$
19 */
20 #include <iostream>
21 #include <algorithm>
22 #include <cmath>
23
24 #include <gtkmm.h>
25
26 #include "gtkmm2ext/pixscroller.h"
27 #include "gtkmm2ext/keyboard.h"
28
29 using namespace std;
30 using namespace Gtk;
31 using namespace Gtkmm2ext;
32
33 PixScroller::PixScroller (Adjustment& a, 
34                           Glib::RefPtr<Gdk::Pixbuf> s,
35                           Glib::RefPtr<Gdk::Pixbuf> r)
36         : adj (a),
37           rail (r),
38           slider (s)
39 {
40         dragging = false;
41         add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK);
42
43         adj.signal_value_changed().connect (mem_fun (*this, &PixScroller::adjustment_changed));
44         default_value = adj.get_value();
45
46         sliderrect.set_width(slider->get_width());
47         sliderrect.set_height(slider->get_height());
48         railrect.set_width(rail->get_width());
49         railrect.set_height(rail->get_height());
50
51         railrect.set_y(sliderrect.get_height() / 2);
52         sliderrect.set_x(0);
53
54         overall_height = railrect.get_height() + sliderrect.get_height();
55
56         sliderrect.set_y((int) rint ((overall_height - sliderrect.get_height()) * (adj.get_upper() - adj.get_value())));
57         railrect.set_x((sliderrect.get_width() / 2) - 2);
58 }
59
60 void
61 PixScroller::on_size_request (GtkRequisition* requisition)
62 {
63         requisition->width = sliderrect.get_width();
64         requisition->height = overall_height;
65 }
66
67 bool
68 PixScroller::on_expose_event (GdkEventExpose* ev)
69 {
70         GdkRectangle intersect;
71         Glib::RefPtr<Gdk::Window> win (get_window());
72
73         win->draw_rectangle (get_style()->get_bg_gc(get_state()), TRUE, 
74                             ev->area.x,
75                             ev->area.y,
76                             ev->area.width,
77                             ev->area.height);
78
79         if (gdk_rectangle_intersect (railrect.gobj(), &ev->area, &intersect)) {
80                 Glib::RefPtr<Gdk::GC> gc(get_style()->get_bg_gc(get_state()));
81                 win->draw_pixbuf (gc, rail, 
82                                   intersect.x - railrect.get_x(),
83                                   intersect.y - railrect.get_y(),
84                                   intersect.x, 
85                                   intersect.y, 
86                                   intersect.width,
87                                   intersect.height,
88                                   Gdk::RGB_DITHER_NONE, 0, 0);
89         }
90         
91         if (gdk_rectangle_intersect (sliderrect.gobj(), &ev->area, &intersect)) {
92                 Glib::RefPtr<Gdk::GC> gc(get_style()->get_fg_gc(get_state()));
93                 // Glib::RefPtr<Gdk::Bitmap> mask (slider_mask);
94
95                 GdkGCValues values;
96                 gdk_gc_get_values(gc->gobj(), &values);
97                 gc->set_clip_origin (sliderrect.get_x(), sliderrect.get_y());
98                 // gc->set_clip_mask (mask);
99                 win->draw_pixbuf (gc, slider, 
100                                   intersect.x - sliderrect.get_x(),
101                                   intersect.y - sliderrect.get_y(),
102                                   intersect.x, 
103                                   intersect.y, 
104                                   intersect.width,
105                                   intersect.height,
106                                   Gdk::RGB_DITHER_NONE, 0, 0);
107                 gc->set_clip_origin (values.clip_x_origin, values.clip_y_origin);
108                 // gdk_gc_set_clip_mask (gc->gobj(), values.clip_mask);
109         }
110
111
112         return true;
113 }
114
115 bool
116 PixScroller::on_button_press_event (GdkEventButton* ev)
117 {
118         switch (ev->button) {
119         case 1:
120                 if (!(ev->state & Keyboard::TertiaryModifier)) {
121                         add_modal_grab();
122                         grab_y = ev->y;
123                         grab_start = ev->y;
124                         grab_window = ev->window;
125                         dragging = true;
126                 }
127                 break;
128         default:
129                 break;
130         } 
131                                
132
133         return false;
134 }
135
136 bool
137 PixScroller::on_button_release_event (GdkEventButton* ev)
138 {
139         double scale;
140         
141         if (ev->state & Keyboard::PrimaryModifier) {
142                 if (ev->state & Keyboard::SecondaryModifier) {
143                         scale = 0.05;
144                 } else {
145                         scale = 0.1;
146                 }
147         } else {
148                 scale = 1.0;
149         }
150
151         switch (ev->button) {
152         case 1:
153                 if (dragging) {
154                         remove_modal_grab();
155                         dragging = false;
156
157                         if (ev->y == grab_start) {
158                                 /* no motion - just a click */
159                                 double fract;
160
161                                 if (ev->y < sliderrect.get_height()/2) {
162                                         /* near the top */
163                                         fract = 1.0;
164                                 } else {
165                                         fract = 1.0 - (ev->y - sliderrect.get_height()/2) / railrect.get_height();
166                                 }
167
168                                 fract = min (1.0, fract);
169                                 fract = max (0.0, fract);
170
171                                 adj.set_value (scale * fract * (adj.get_upper() - adj.get_lower()));
172                         }
173                 } else {
174                         if (ev->state & Keyboard::TertiaryModifier) {
175                                 adj.set_value (default_value);
176                                 cerr << "default value = " << default_value << endl;
177                         }
178                 }
179                 break;
180         default:
181                 break;
182         }
183         return false;
184 }
185
186 bool
187 PixScroller::on_scroll_event (GdkEventScroll* ev)
188 {
189         double scale;
190         
191         if (ev->state & Keyboard::PrimaryModifier) {
192                 if (ev->state & Keyboard::SecondaryModifier) {
193                         scale = 0.05;
194                 } else {
195                         scale = 0.1;
196                 }
197         } else {
198                 scale = 0.5;
199         }
200
201         switch (ev->direction) {
202
203         case GDK_SCROLL_UP:
204                 /* wheel up */
205                 adj.set_value (adj.get_value() + (adj.get_page_increment() * scale));
206                 break;
207         case GDK_SCROLL_DOWN:
208                 /* wheel down */
209                 adj.set_value (adj.get_value() - (adj.get_page_increment() * scale));
210                 break;
211         default:
212                 break;
213         }
214         return false;
215 }
216
217 bool
218 PixScroller::on_motion_notify_event (GdkEventMotion* ev)
219 {
220         if (dragging) {
221                 double fract;
222                 double delta;
223                 double scale;
224
225                 if (ev->window != grab_window) {
226                         grab_y = ev->y;
227                         grab_window = ev->window;
228                         return true;
229                 }
230                 
231                 if (ev->state & Keyboard::PrimaryModifier) {
232                         if (ev->state & Keyboard::SecondaryModifier) {
233                                 scale = 0.05;
234                         } else {
235                                 scale = 0.1;
236                         }
237                 } else {
238                         scale = 1.0;
239                 }
240
241                 delta = ev->y - grab_y;
242                 grab_y = ev->y;
243
244                 fract = (delta / railrect.get_height());
245
246                 fract = min (1.0, fract);
247                 fract = max (-1.0, fract);
248                 
249                 fract = -fract;
250
251                 adj.set_value (adj.get_value() + scale * fract * (adj.get_upper() - adj.get_lower()));
252         }
253
254         return true;
255 }
256
257 void
258 PixScroller::adjustment_changed ()
259 {
260         int y = (int) rint ((overall_height - sliderrect.get_height()) * (adj.get_upper() - adj.get_value()));
261
262         if (y != sliderrect.get_y()) {
263                 sliderrect.set_y(y);
264                 queue_draw ();
265         }
266 }