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) {
402 SpinnerActive (false); /* EMIT SIGNAL */
408 BarController::switch_to_spinner ()
416 if (get_child() == &spinner) {
423 spinner.select_region (0, spinner.get_text_length());
424 spinner.grab_focus ();
428 SpinnerActive (true); /* EMIT SIGNAL */
434 BarController::entry_activated ()
440 BarController::entry_focus_out (GdkEventFocus* /*ev*/)
447 BarController::set_use_parent (bool yn)
454 BarController::set_sensitive (bool yn)
456 Frame::set_sensitive (yn);
457 darea.set_sensitive (yn);
461 This is called when we need to update the adjustment with the value
462 from the spinner's text entry.
464 We need to use Gtk::Entry::get_text to avoid recursive nastiness :)
466 If we're not in logarithmic mode we can return false to use the
469 In theory we should check for conversion errors but set numeric
470 mode to true on the spinner prevents invalid input.
473 BarController::entry_input (double* new_value)
479 // extract a double from the string and take its log
480 Entry *entry = dynamic_cast<Entry *>(&spinner);
484 // Switch to user's preferred locale so that
485 // if they use different LC_NUMERIC conventions,
486 // we will honor them.
488 PBD::LocaleGuard lg ("");
489 sscanf (entry->get_text().c_str(), "%lf", &value);
492 *new_value = log(value);
498 This is called when we need to update the spinner's text entry
499 with the value of the adjustment.
501 We need to use Gtk::Entry::set_text to avoid recursive nastiness :)
503 If we're not in logarithmic mode we can return false to use the
507 BarController::entry_output ()
513 // generate the exponential and turn it into a string
514 // convert to correct locale.
522 // Switch to user's preferred locale so that
523 // if they use different LC_NUMERIC conventions,
524 // we will honor them.
526 PBD::LocaleGuard lg ("");
527 snprintf (buf, sizeof (buf), "%g", exp (spinner.get_adjustment()->get_value()));
530 Entry *entry = dynamic_cast<Entry *>(&spinner);
531 entry->set_text(buf);