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>
29 #include "gtkmm2ext/gtk_ui.h"
30 #include "gtkmm2ext/utils.h"
31 #include "gtkmm2ext/keyboard.h"
32 #include "gtkmm2ext/barcontroller.h"
38 using namespace Gtkmm2ext
;
40 BarController::BarController (Gtk::Adjustment
& adj
,
41 boost::shared_ptr
<PBD::Controllable
> mc
)
51 switch_on_release
= false;
55 layout
= darea
.create_pango_layout("");
57 set_shadow_type (SHADOW_NONE
);
59 initial_value
= adjustment
.get_value ();
61 adjustment
.signal_value_changed().connect (mem_fun (*this, &Gtk::Widget::queue_draw
));
62 adjustment
.signal_changed().connect (mem_fun (*this, &Gtk::Widget::queue_draw
));
64 darea
.add_events (Gdk::BUTTON_RELEASE_MASK
|
65 Gdk::BUTTON_PRESS_MASK
|
66 Gdk::POINTER_MOTION_MASK
|
67 Gdk::ENTER_NOTIFY_MASK
|
68 Gdk::LEAVE_NOTIFY_MASK
|
71 darea
.signal_expose_event().connect (mem_fun (*this, &BarController::expose
));
72 darea
.signal_motion_notify_event().connect (mem_fun (*this, &BarController::motion
));
73 darea
.signal_button_press_event().connect (mem_fun (*this, &BarController::button_press
), false);
74 darea
.signal_button_release_event().connect (mem_fun (*this, &BarController::button_release
), false);
75 darea
.signal_scroll_event().connect (mem_fun (*this, &BarController::scroll
));
77 spinner
.signal_activate().connect (mem_fun (*this, &BarController::entry_activated
));
78 spinner
.signal_focus_out_event().connect (mem_fun (*this, &BarController::entry_focus_out
));
79 spinner
.signal_input().connect (mem_fun (*this, &BarController::entry_input
));
80 spinner
.signal_output().connect (mem_fun (*this, &BarController::entry_output
));
81 spinner
.set_digits (3);
82 spinner
.set_numeric (true);
89 BarController::drop_grab ()
93 darea
.remove_modal_grab();
99 BarController::button_press (GdkEventButton
* ev
)
103 if (binding_proxy
.button_press_handler (ev
)) {
107 switch (ev
->button
) {
109 if (ev
->type
== GDK_2BUTTON_PRESS
) {
110 switch_on_release
= true;
113 switch_on_release
= false;
114 darea
.add_modal_grab();
117 grab_window
= ev
->window
;
124 fract
= ev
->x
/ (darea
.get_width() - 2.0);
125 adjustment
.set_value (adjustment
.get_lower() + fract
* (adjustment
.get_upper() - adjustment
.get_lower()));
139 BarController::button_release (GdkEventButton
* ev
)
143 switch (ev
->button
) {
145 if (switch_on_release
) {
146 Glib::signal_idle().connect (mem_fun (*this, &BarController::switch_to_spinner
));
150 if ((ev
->state
& (Keyboard::TertiaryModifier
|Keyboard::PrimaryModifier
)) == Keyboard::TertiaryModifier
) {
151 adjustment
.set_value (initial_value
);
155 if ((ev
->state
& (Keyboard::PrimaryModifier
|Keyboard::TertiaryModifier
)) == (Keyboard::PrimaryModifier
|Keyboard::TertiaryModifier
)) {
157 } else if (ev
->state
& Keyboard::PrimaryModifier
) {
163 mouse_control (ev
->x
, ev
->window
, scale
);
181 BarController::scroll (GdkEventScroll
* ev
)
185 if ((ev
->state
& (Keyboard::PrimaryModifier
|Keyboard::TertiaryModifier
)) == (Keyboard::PrimaryModifier
|Keyboard::TertiaryModifier
)) {
187 } else if (ev
->state
& Keyboard::PrimaryModifier
) {
193 switch (ev
->direction
) {
195 case GDK_SCROLL_RIGHT
:
196 adjustment
.set_value (adjustment
.get_value() + (scale
* adjustment
.get_step_increment()));
199 case GDK_SCROLL_DOWN
:
200 case GDK_SCROLL_LEFT
:
201 adjustment
.set_value (adjustment
.get_value() - (scale
* adjustment
.get_step_increment()));
209 BarController::motion (GdkEventMotion
* ev
)
217 if ((ev
->state
& (Keyboard::TertiaryModifier
|Keyboard::PrimaryModifier
)) == Keyboard::TertiaryModifier
) {
221 if ((ev
->state
& (Keyboard::PrimaryModifier
|Keyboard::TertiaryModifier
)) == (Keyboard::PrimaryModifier
|Keyboard::TertiaryModifier
)) {
223 } else if (ev
->state
& Keyboard::PrimaryModifier
) {
229 return mouse_control (ev
->x
, ev
->window
, scale
);
233 BarController::mouse_control (double x
, GdkWindow
* window
, double scaling
)
238 if (window
!= grab_window
) {
240 grab_window
= window
;
250 fract
= scaling
* (delta
/ (darea
.get_width() - 2));
251 fract
= min (1.0, fract
);
252 fract
= max (-1.0, fract
);
253 adjustment
.set_value (adjustment
.get_value() + fract
* (adjustment
.get_upper() - adjustment
.get_lower()));
265 BarController::expose (GdkEventExpose
* /*event*/)
267 Glib::RefPtr
<Gdk::Window
> win (darea
.get_window());
269 gint x1
=0, x2
=0, y1
=0, y2
=0;
273 fract
= ((adjustment
.get_value() - adjustment
.get_lower()) /
274 (adjustment
.get_upper() - adjustment
.get_lower()));
278 w
= darea
.get_width() - 1;
279 h
= darea
.get_height();
280 x1
= (gint
) floor (w
* fract
);
286 parent
= get_parent();
289 win
->draw_rectangle (parent
->get_style()->get_fg_gc (parent
->get_state()),
291 0, 0, darea
.get_width(), darea
.get_height());
296 win
->draw_rectangle (get_style()->get_bg_gc (get_state()),
298 0, 0, darea
.get_width() - ((darea
.get_width()+1) % 2), darea
.get_height());
301 win
->draw_line (get_style()->get_fg_gc (get_state()), x1
, 0, x1
, h
);
309 w
= darea
.get_width() - 2;
310 h
= darea
.get_height() - 2;
313 x2
= (gint
) floor (w
* fract
);
317 win
->draw_rectangle (get_style()->get_bg_gc (get_state()),
319 0, 0, darea
.get_width() - 1, darea
.get_height() - 1);
321 /* draw active box */
323 win
->draw_rectangle (get_style()->get_fg_gc (get_state()),
330 /* draw inactive box */
332 win
->draw_rectangle (get_style()->get_fg_gc (STATE_INSENSITIVE
),
352 std::string
const label
= get_label (xpos
);
354 if (!label
.empty()) {
356 layout
->set_text (label
);
359 layout
->get_pixel_size (width
, height
);
362 xpos
= max (3, 1 + (x2
- (width
/2)));
363 xpos
= min (darea
.get_width() - width
- 3, xpos
);
366 win
->draw_layout (get_style()->get_text_gc (get_state()),
368 (darea
.get_height()/2) - (height
/2),
376 BarController::set_style (barStyle s
)
383 BarController::switch_to_bar ()
391 if (get_child() == &darea
) {
404 BarController::switch_to_spinner ()
412 if (get_child() == &spinner
) {
419 spinner
.select_region (0, spinner
.get_text_length());
420 spinner
.grab_focus ();
427 BarController::entry_activated ()
433 BarController::entry_focus_out (GdkEventFocus
* /*ev*/)
440 BarController::set_use_parent (bool yn
)
447 BarController::set_sensitive (bool yn
)
449 Frame::set_sensitive (yn
);
450 darea
.set_sensitive (yn
);
454 This is called when we need to update the adjustment with the value
455 from the spinner's text entry.
457 We need to use Gtk::Entry::get_text to avoid recursive nastiness :)
459 If we're not in logarithmic mode we can return false to use the
462 In theory we should check for conversion errors but set numeric
463 mode to true on the spinner prevents invalid input.
466 BarController::entry_input (double* new_value
)
472 // extract a double from the string and take its log
473 Entry
*entry
= dynamic_cast<Entry
*>(&spinner
);
474 stringstream
stream(entry
->get_text());
475 stream
.imbue(std::locale(""));
480 *new_value
= log(value
);
485 This is called when we need to update the spinner's text entry
486 with the value of the adjustment.
488 We need to use Gtk::Entry::set_text to avoid recursive nastiness :)
490 If we're not in logarithmic mode we can return false to use the
494 BarController::entry_output ()
500 // generate the exponential and turn it into a string
501 // convert to correct locale.
507 // Gtk.Entry does not like the thousands separator, so we have to
508 // remove it after conversion from float to string.
510 stream
.imbue(std::locale(""));
511 stream
.precision(spinner
.get_digits());
513 stream
<< fixed
<< exp(spinner
.get_adjustment()->get_value());
517 // find thousands separators, remove them
518 found
= str
.find(use_facet
<numpunct
<char> >(std::locale("")).thousands_sep());
519 while(found
!= str
.npos
) {
523 found
= str
.find(use_facet
<numpunct
<char> >(std::locale("")).thousands_sep());
526 Entry
*entry
= dynamic_cast<Entry
*>(&spinner
);
527 entry
->set_text(str
);