2 Copyright (C) 2008 Paul Davis
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.
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.
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.
21 #include <gtkmm2ext/scroomer.h>
23 using namespace Gtkmm2ext;
28 Scroomer::Scroomer(Gtk::Adjustment& adjustment)
33 position[TopBase] = 0;
34 position[Handle1] = 0;
36 position[Handle2] = 0;
37 position[BottomBase] = 0;
40 add_events (Gdk::BUTTON_PRESS_MASK |
41 Gdk::BUTTON_RELEASE_MASK |
42 Gdk::POINTER_MOTION_MASK |
45 adjustment.signal_value_changed().connect (mem_fun (*this, &Scroomer::adjustment_changed));
46 //adjustment.signal_changed().connect (mem_fun (*this, &Scroomer::adjustment_changed));
49 Scroomer::~Scroomer() {
53 Scroomer::on_motion_notify_event (GdkEventMotion* ev) {
54 double range = adj.get_upper() - adj.get_lower();
55 double pixel2val = range / get_height();
56 double val_at_pointer = ((get_height() - ev->y) * pixel2val) + adj.get_lower();
57 double delta_y = ev->y - grab_y;
58 double half_min_page = min_page_size / 2;
59 double fract = delta_y / position[Total];
60 double scale, temp, zoom;
63 if(grab_comp == None || grab_comp == Total) {
67 if (ev->window != grab_window) {
69 grab_window = ev->window;
75 if (ev->state & GDK_CONTROL_MASK) {
76 if (ev->state & GDK_MOD1_MASK) {
85 fract = min (1.0, fract);
86 fract = max (-1.0, fract);
92 unzoomed_val += scale * fract * range;
93 unzoomed_val = min(unzoomed_val, adj.get_upper() - unzoomed_page);
94 unzoomed_val = max(unzoomed_val, adj.get_lower());
97 unzoomed_val += scale * fract * range;
98 unzoomed_val = min(unzoomed_val, adj.get_upper() - unzoomed_page);
99 unzoomed_val = max(unzoomed_val, adj.get_lower());
102 unzoomed_page += scale * fract * range;
103 unzoomed_page = min(unzoomed_page, adj.get_upper() - unzoomed_val);
104 unzoomed_page = max(unzoomed_page, min_page_size);
107 temp = unzoomed_val + unzoomed_page;
108 unzoomed_val += scale * fract * range;
109 unzoomed_val = min(unzoomed_val, temp - min_page_size);
110 unzoomed_val = max(unzoomed_val, adj.get_lower());
112 unzoomed_page = temp - unzoomed_val;
113 unzoomed_page = max(unzoomed_page, min_page_size);
120 * Then we handle zoom, which is dragging horizontally. We zoom around the area that is
121 * the current y pointer value, not from the area that was the start of the drag.
122 * the point of zoom must have the same
125 if(ev->x > get_width()) {
126 zoom = ev->x - get_width();
128 double higher = unzoomed_val + unzoomed_page - half_min_page - val_at_pointer;
129 double lower = val_at_pointer - (unzoomed_val + half_min_page);
131 higher *= zoom / 128;
134 val = unzoomed_val + lower;
135 page = unzoomed_page - higher - lower;
137 page = max(page, min_page_size);
140 val = max(val, val_at_pointer - half_min_page);
143 val = min(val, val_at_pointer - half_min_page);
146 val = min(val, adj.get_upper() - min_page_size);
147 page = min(page, adj.get_upper() - val);
149 else if (ev->x < 0) {
150 /* on zoom out increase the page size as well as moving the range towards the mouse pos*/
153 /*double higher = unzoomed_val + unzoomed_page - half_min_page - val_at_pointer;
154 double lower = val_at_pointer - (unzoomed_val + half_min_page);
156 higher *= zoom / 128;
159 val = unzoomed_val + lower;
160 page = unzoomed_page - higher - lower;
162 page = max(page, min_page_size);
165 val = max(val, val_at_pointer - half_min_page);
168 val = min(val, val_at_pointer - half_min_page);
171 val = min(val, adj.get_upper() - min_page_size);
172 page = min(page, adj.get_upper() - val);*/
175 page = unzoomed_page;
179 page = unzoomed_page;
182 adj.set_page_size(page);
184 if(val == adj.get_value()) {
187 if(val < adj.get_lower()) {
190 else if(val > adj.get_upper()) {
201 Scroomer::on_button_press_event (GdkEventButton* ev) {
202 if(ev->button == 1) {
203 Component comp = point_in(ev->y);
205 cerr << get_comp_name(comp) << " pressed" << endl;
207 if(comp == Total || comp == None) {
214 unzoomed_val = adj.get_value();
215 unzoomed_page = adj.get_page_size();
216 grab_window = ev->window;
222 Scroomer::on_button_release_event (GdkEventButton* ev) {
223 if(grab_comp == None || grab_comp == Total) {
227 if (ev->window != grab_window) {
229 grab_window = ev->window;
233 if (ev->button != 1) {
259 Scroomer::on_scroll_event (GdkEventScroll*) {
264 Scroomer::on_size_allocate (Allocation& a) {
265 Gtk::DrawingArea::on_size_allocate(a);
267 cerr << "allocate" << endl;
269 position[Total] = a.get_height();
270 set_min_page_size(min_page_size);
275 * assumes that x and width are correct, and they will not be altered
278 Scroomer::set_comp_rect(GdkRectangle& r, Component c) const {
286 r.height = position[Total];
289 r.y = position[index];
290 r.height = position[index+1] - position[index];
296 Scroomer::point_in(double point) const {
297 for(int i = 0; i < Total; ++i) {
298 if(position[i+1] >= point) {
299 return (Component) i;
307 Scroomer::set_min_page_size(double ps) {
308 double coeff = ((double)position[Total]) / (adj.get_upper() - adj.get_lower());
311 handle_size = (int) floor((ps * coeff) / 2);
316 double range = adj.get_upper() - adj.get_lower();
317 double value = adj.get_value() - adj.get_lower();
318 int height = position[Total];
319 double coeff = ((double) height) / range;
321 /* save the old positions to calculate update regions later*/
322 for(int i = Handle1; i < Total; ++i) {
323 old_pos[i] = position[i];
326 position[BottomBase] = (int) floor(height - (adj.get_value() * coeff));
327 position[Handle2] = position[BottomBase] - handle_size;
329 position[Handle1] = (int) floor(height - ((adj.get_value() + adj.get_page_size()) * coeff));
330 position[Slider] = position[Handle1] + handle_size;
334 Scroomer::adjustment_changed() {
335 //cerr << floor(adj.get_value()) << " " << floor(adj.get_value() + adj.get_page_size()) << endl;
337 Glib::RefPtr<Gdk::Window> win = get_window();
346 rect.set_width(get_width());
348 if(position[Handle1] < old_pos[Handle1]) {
349 rect.set_y(position[Handle1]);
350 rect.set_height(old_pos[Slider] - position[Handle1]);
351 win->invalidate_rect(rect, false);
353 else if(position[Handle1] > old_pos[Handle1]) {
354 rect.set_y(old_pos[Handle1]);
355 rect.set_height(position[Slider] - old_pos[Handle1]);
356 win->invalidate_rect(rect, false);
359 if(position[Handle2] < old_pos[Handle2]) {
360 rect.set_y(position[Handle2]);
361 rect.set_height(old_pos[BottomBase] - position[Handle2]);
362 win->invalidate_rect(rect, false);
364 else if(position[Handle2] > old_pos[Handle2]) {
365 rect.set_y(old_pos[Handle2]);
366 rect.set_height(position[BottomBase] - old_pos[Handle2]);
367 win->invalidate_rect(rect, false);
370 win->process_updates(false);
374 Scroomer::get_comp_name(Component c) {