2 Copyright (C) 2004 Paul Davis
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2 of the License, or
6 (at your option) any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include <pbd/controllable.h>
28 #include <pbd/locale_guard.h>
30 #include "gtkmm2ext/gtk_ui.h"
31 #include "gtkmm2ext/utils.h"
32 #include "gtkmm2ext/keyboard.h"
33 #include "gtkmm2ext/barcontroller.h"
39 using namespace Gtkmm2ext;
41 BarController::BarController (Gtk::Adjustment& adj,
42 boost::shared_ptr<PBD::Controllable> mc)
52 switch_on_release = false;
56 layout = darea.create_pango_layout("");
58 set_shadow_type (SHADOW_NONE);
60 initial_value = adjustment.get_value ();
62 adjustment.signal_value_changed().connect (mem_fun (*this, &Gtk::Widget::queue_draw));
63 adjustment.signal_changed().connect (mem_fun (*this, &Gtk::Widget::queue_draw));
65 darea.add_events (Gdk::BUTTON_RELEASE_MASK|
66 Gdk::BUTTON_PRESS_MASK|
67 Gdk::POINTER_MOTION_MASK|
68 Gdk::ENTER_NOTIFY_MASK|
69 Gdk::LEAVE_NOTIFY_MASK|
72 darea.signal_expose_event().connect (mem_fun (*this, &BarController::expose));
73 darea.signal_motion_notify_event().connect (mem_fun (*this, &BarController::motion));
74 darea.signal_button_press_event().connect (mem_fun (*this, &BarController::button_press), false);
75 darea.signal_button_release_event().connect (mem_fun (*this, &BarController::button_release), false);
76 darea.signal_scroll_event().connect (mem_fun (*this, &BarController::scroll));
78 spinner.signal_activate().connect (mem_fun (*this, &BarController::entry_activated));
79 spinner.signal_focus_out_event().connect (mem_fun (*this, &BarController::entry_focus_out));
80 spinner.signal_input().connect (mem_fun (*this, &BarController::entry_input));
81 spinner.signal_output().connect (mem_fun (*this, &BarController::entry_output));
82 spinner.set_digits (3);
83 spinner.set_numeric (true);
90 BarController::drop_grab ()
94 darea.remove_modal_grab();
100 BarController::button_press (GdkEventButton* ev)
104 if (binding_proxy.button_press_handler (ev)) {
108 switch (ev->button) {
110 if (ev->type == GDK_2BUTTON_PRESS) {
111 switch_on_release = true;
114 switch_on_release = false;
115 darea.add_modal_grab();
118 grab_window = ev->window;
125 fract = ev->x / (darea.get_width() - 2.0);
126 adjustment.set_value (adjustment.get_lower() + fract * (adjustment.get_upper() - adjustment.get_lower()));
140 BarController::button_release (GdkEventButton* ev)
144 switch (ev->button) {
146 if (switch_on_release) {
147 Glib::signal_idle().connect (mem_fun (*this, &BarController::switch_to_spinner));
151 if ((ev->state & (Keyboard::TertiaryModifier|Keyboard::PrimaryModifier)) == Keyboard::TertiaryModifier) {
152 adjustment.set_value (initial_value);
156 if ((ev->state & (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier)) == (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier)) {
158 } else if (ev->state & Keyboard::PrimaryModifier) {
164 mouse_control (ev->x, ev->window, scale);
182 BarController::scroll (GdkEventScroll* ev)
186 if ((ev->state & (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier)) == (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier)) {
188 } else if (ev->state & Keyboard::PrimaryModifier) {
194 switch (ev->direction) {
196 case GDK_SCROLL_RIGHT:
197 adjustment.set_value (adjustment.get_value() + (scale * adjustment.get_step_increment()));
200 case GDK_SCROLL_DOWN:
201 case GDK_SCROLL_LEFT:
202 adjustment.set_value (adjustment.get_value() - (scale * adjustment.get_step_increment()));
210 BarController::motion (GdkEventMotion* ev)
218 if ((ev->state & (Keyboard::TertiaryModifier|Keyboard::PrimaryModifier)) == Keyboard::TertiaryModifier) {
222 if ((ev->state & (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier)) == (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier)) {
224 } else if (ev->state & Keyboard::PrimaryModifier) {
230 return mouse_control (ev->x, ev->window, scale);
234 BarController::mouse_control (double x, GdkWindow* window, double scaling)
239 if (window != grab_window) {
241 grab_window = window;
251 fract = scaling * (delta / (darea.get_width() - 2));
252 fract = min (1.0, fract);
253 fract = max (-1.0, fract);
254 adjustment.set_value (adjustment.get_value() + fract * (adjustment.get_upper() - adjustment.get_lower()));
266 BarController::expose (GdkEventExpose* /*event*/)
268 Glib::RefPtr<Gdk::Window> win (darea.get_window());
270 gint x1=0, x2=0, y1=0, y2=0;
274 fract = ((adjustment.get_value() - adjustment.get_lower()) /
275 (adjustment.get_upper() - adjustment.get_lower()));
279 w = darea.get_width() - 1;
280 h = darea.get_height();
281 x1 = (gint) floor (w * fract);
287 parent = get_parent();
290 win->draw_rectangle (parent->get_style()->get_fg_gc (parent->get_state()),
292 0, 0, darea.get_width(), darea.get_height());
297 win->draw_rectangle (get_style()->get_bg_gc (get_state()),
299 0, 0, darea.get_width() - ((darea.get_width()+1) % 2), darea.get_height());
302 win->draw_line (get_style()->get_fg_gc (get_state()), x1, 0, x1, h);
310 w = darea.get_width() - 2;
311 h = darea.get_height() - 2;
314 x2 = (gint) floor (w * fract);
318 win->draw_rectangle (get_style()->get_bg_gc (get_state()),
320 0, 0, darea.get_width() - 1, darea.get_height() - 1);
322 /* draw active box */
324 win->draw_rectangle (get_style()->get_fg_gc (get_state()),
331 /* draw inactive box */
333 win->draw_rectangle (get_style()->get_fg_gc (STATE_INSENSITIVE),
353 std::string const label = get_label (xpos);
355 if (!label.empty()) {
357 layout->set_text (label);
360 layout->get_pixel_size (width, height);
363 xpos = max (3, 1 + (x2 - (width/2)));
364 xpos = min (darea.get_width() - width - 3, xpos);
367 win->draw_layout (get_style()->get_text_gc (get_state()),
369 (darea.get_height()/2) - (height/2),
377 BarController::set_style (barStyle s)
384 BarController::switch_to_bar ()
392 if (get_child() == &darea) {
405 BarController::switch_to_spinner ()
413 if (get_child() == &spinner) {
420 spinner.select_region (0, spinner.get_text_length());
421 spinner.grab_focus ();
428 BarController::entry_activated ()
434 BarController::entry_focus_out (GdkEventFocus* /*ev*/)
441 BarController::set_use_parent (bool yn)
448 BarController::set_sensitive (bool yn)
450 Frame::set_sensitive (yn);
451 darea.set_sensitive (yn);
455 This is called when we need to update the adjustment with the value
456 from the spinner's text entry.
458 We need to use Gtk::Entry::get_text to avoid recursive nastiness :)
460 If we're not in logarithmic mode we can return false to use the
463 In theory we should check for conversion errors but set numeric
464 mode to true on the spinner prevents invalid input.
467 BarController::entry_input (double* new_value)
473 // extract a double from the string and take its log
474 Entry *entry = dynamic_cast<Entry *>(&spinner);
478 // Switch to user's preferred locale so that
479 // if they use different LC_NUMERIC conventions,
480 // we will honor them.
482 PBD::LocaleGuard lg ("");
483 sscanf (entry->get_text().c_str(), "%lf", &value);
486 *new_value = log(value);
492 This is called when we need to update the spinner's text entry
493 with the value of the adjustment.
495 We need to use Gtk::Entry::set_text to avoid recursive nastiness :)
497 If we're not in logarithmic mode we can return false to use the
501 BarController::entry_output ()
507 // generate the exponential and turn it into a string
508 // convert to correct locale.
516 // Switch to user's preferred locale so that
517 // if they use different LC_NUMERIC conventions,
518 // we will honor them.
520 PBD::LocaleGuard lg ("");
521 snprintf (buf, sizeof (buf), "%g", exp (spinner.get_adjustment()->get_value()));
524 Entry *entry = dynamic_cast<Entry *>(&spinner);
525 entry->set_text(buf);