X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fshuttle_control.cc;h=4616b7673473fdf06ff15cbc943a7dc51daad0b9;hb=bb090c0012340b637508e0930376b3d5afba5f5c;hp=3f18c26feb5050995f4cbb83dbba79a7f09f96c2;hpb=6b06923a5d53b9d535709fe0b11340ceb365b5f0;p=ardour.git diff --git a/gtk2_ardour/shuttle_control.cc b/gtk2_ardour/shuttle_control.cc index 3f18c26feb..4616b76734 100644 --- a/gtk2_ardour/shuttle_control.cc +++ b/gtk2_ardour/shuttle_control.cc @@ -18,7 +18,7 @@ #include -#include +#include #include "ardour/ardour.h" #include "ardour/audioengine.h" @@ -27,16 +27,21 @@ #include "gtkmm2ext/keyboard.h" #include "gtkmm2ext/gui_thread.h" +#include "gtkmm2ext/cairocell.h" +#include "gtkmm2ext/utils.h" +#include "gtkmm2ext/rgb_macros.h" -#include "ardour_ui.h" +#include "actions.h" #include "rgb_macros.h" #include "shuttle_control.h" +#include "tooltips.h" #include "i18n.h" using namespace Gtk; using namespace Gtkmm2ext; using namespace ARDOUR; +using namespace ARDOUR_UI_UTILS; using std::min; using std::max; @@ -49,9 +54,10 @@ ShuttleControl::ShuttleControl () : _controllable (new ShuttleControllable (*this)) , binding_proxy (_controllable) { - ARDOUR_UI::instance()->set_tip (*this, _("Shuttle speed control (Context-click for options)")); + set_tooltip (*this, _("Shuttle speed control (Context-click for options)")); pattern = 0; + shine_pattern = 0; last_shuttle_request = 0; last_speed_displayed = -99999999; shuttle_grabbed = false; @@ -61,12 +67,22 @@ ShuttleControl::ShuttleControl () shuttle_style_menu = 0; shuttle_unit_menu = 0; shuttle_context_menu = 0; + _hovering = false; set_flags (CAN_FOCUS); add_events (Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::POINTER_MOTION_MASK|Gdk::SCROLL_MASK); - set_size_request (100, 15); + set_size_request (85, 20); set_name (X_("ShuttleControl")); + shuttle_max_speed = Config->get_shuttle_max_speed(); + + if (shuttle_max_speed >= 8.f) { shuttle_max_speed = 8.0f; } + else if (shuttle_max_speed >= 6.f) { shuttle_max_speed = 6.0f; } + else if (shuttle_max_speed >= 4.f) { shuttle_max_speed = 4.0f; } + else if (shuttle_max_speed >= 3.f) { shuttle_max_speed = 3.0f; } + else if (shuttle_max_speed >= 2.f) { shuttle_max_speed = 2.0f; } + else { shuttle_max_speed = 1.5f; } + Config->ParameterChanged.connect (parameter_connection, MISSING_INVALIDATOR, boost::bind (&ShuttleControl::parameter_changed, this, _1), gui_context()); /* gtkmm 2.4: the C++ wrapper doesn't work */ @@ -77,6 +93,7 @@ ShuttleControl::ShuttleControl () ShuttleControl::~ShuttleControl () { cairo_pattern_destroy (pattern); + cairo_pattern_destroy (shine_pattern); } void @@ -98,22 +115,26 @@ ShuttleControl::on_size_allocate (Gtk::Allocation& alloc) if (pattern) { cairo_pattern_destroy (pattern); pattern = 0; + cairo_pattern_destroy (shine_pattern); + shine_pattern = 0; } - pattern = cairo_pattern_create_linear (0, 0, alloc.get_width(), alloc.get_height()); - - /* add 3 color stops */ - - uint32_t col = ARDOUR_UI::config()->canvasvar_Shuttle.get(); + CairoWidget::on_size_allocate ( alloc); + //background + pattern = cairo_pattern_create_linear (0, 0, 0, alloc.get_height()); + uint32_t col = UIConfiguration::instance().color ("shuttle"); int r,b,g,a; UINT_TO_RGBA(col, &r, &g, &b, &a); - - cairo_pattern_add_color_stop_rgb (pattern, 0.0, 0, 0, 0); - cairo_pattern_add_color_stop_rgb (pattern, 0.5, r/255.0, g/255.0, b/255.0); - cairo_pattern_add_color_stop_rgb (pattern, 1.0, 0, 0, 0); - - DrawingArea::on_size_allocate (alloc); + cairo_pattern_add_color_stop_rgb (pattern, 0.0, r/400.0, g/400.0, b/400.0); + cairo_pattern_add_color_stop_rgb (pattern, 0.4, r/255.0, g/255.0, b/255.0); + cairo_pattern_add_color_stop_rgb (pattern, 1.0, r/512.0, g/512.0, b/512.0); + + //reflection + shine_pattern = cairo_pattern_create_linear (0.0, 0.0, 0.0, 10); + cairo_pattern_add_color_stop_rgba (shine_pattern, 0, 1,1,1,0.0); + cairo_pattern_add_color_stop_rgba (shine_pattern, 0.2, 1,1,1,0.4); + cairo_pattern_add_color_stop_rgba (shine_pattern, 1, 1,1,1,0.1); } void @@ -121,6 +142,15 @@ ShuttleControl::map_transport_state () { float speed = _session->transport_speed (); + if ( (fabsf( speed - last_speed_displayed) < 0.005f) // dead-zone + && !( speed == 1.f && last_speed_displayed != 1.f) + && !( speed == 0.f && last_speed_displayed != 0.f) + ) + { + return; // nothing to see here, move along. + } + + // Q: is there a good reason why we re-calculate this every time? if (fabs(speed) <= (2*DBL_EPSILON)) { shuttle_fract = 0; } else { @@ -205,6 +235,8 @@ ShuttleControl::build_shuttle_context_menu () items.push_back (MenuElem (_("Maximum speed"), *speed_menu)); + items.push_back (SeparatorElem ()); + items.push_back (MenuElem (_("Reset to 100%"), sigc::mem_fun (*this, &ShuttleControl::reset_speed))); } void @@ -217,10 +249,22 @@ ShuttleControl::show_shuttle_context_menu () shuttle_context_menu->popup (1, gtk_get_current_event_time()); } +void +ShuttleControl::reset_speed () +{ + if (_session->transport_rolling()) { + _session->request_transport_speed (1.0, true); + } else { + _session->request_transport_speed (0.0, true); + } +} + void ShuttleControl::set_shuttle_max_speed (float speed) { + Config->set_shuttle_max_speed (speed); shuttle_max_speed = speed; + last_speed_displayed = -99999999; } bool @@ -250,6 +294,9 @@ ShuttleControl::on_button_press_event (GdkEventButton* ev) shuttle_grabbed = true; shuttle_speed_on_grab = _session->transport_speed (); mouse_shuttle (ev->x, true); + gdk_pointer_grab(ev->window,false, + GdkEventMask( Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK |Gdk::BUTTON_RELEASE_MASK), + NULL,NULL,ev->time); } break; @@ -274,9 +321,14 @@ ShuttleControl::on_button_release_event (GdkEventButton* ev) if (shuttle_grabbed) { shuttle_grabbed = false; remove_modal_grab (); - + gdk_pointer_ungrab (GDK_CURRENT_TIME); + if (Config->get_shuttle_behaviour() == Sprung) { - _session->request_transport_speed (shuttle_speed_on_grab); + if (shuttle_speed_on_grab == 0 ) { + _session->request_stop (); + } else { + _session->request_transport_speed (shuttle_speed_on_grab); + } } else { mouse_shuttle (ev->x, true); } @@ -345,7 +397,7 @@ ShuttleControl::on_scroll_event (GdkEventScroll* ev) default: return false; } - + if (semis) { float lower_side_of_dead_zone = semitones_as_fract (-24, true); @@ -410,10 +462,10 @@ ShuttleControl::mouse_shuttle (double x, bool force) } void -ShuttleControl::set_shuttle_fract (double f) +ShuttleControl::set_shuttle_fract (double f, bool zero_ok) { shuttle_fract = f; - use_shuttle_fract (false); + use_shuttle_fract (false, zero_ok); } int @@ -455,7 +507,7 @@ ShuttleControl::fract_as_semitones (float fract, bool& reverse) } void -ShuttleControl::use_shuttle_fract (bool force) +ShuttleControl::use_shuttle_fract (bool force, bool zero_ok) { microseconds_t now = get_microseconds(); @@ -486,24 +538,22 @@ ShuttleControl::use_shuttle_fract (bool force) speed = shuttle_max_speed * shuttle_fract; } - _session->request_transport_speed_nonzero (speed, true); + if (zero_ok) { + _session->request_transport_speed (speed, Config->get_shuttle_behaviour() == Wheel); + } else { + _session->request_transport_speed_nonzero (speed, Config->get_shuttle_behaviour() == Wheel); + } } -bool -ShuttleControl::on_expose_event (GdkEventExpose*) +void +ShuttleControl::render (cairo_t* cr, cairo_rectangle_t*) { cairo_text_extents_t extents; - Glib::RefPtr win (get_window()); - Glib::RefPtr style (get_style()); - - cairo_t* cr = gdk_cairo_create (win->gobj()); - - cairo_set_source (cr, pattern); - cairo_rectangle (cr, 0.0, 0.0, get_width(), get_height()); - cairo_fill_preserve (cr); - cairo_set_source_rgb (cr, 0, 0, 0.0); - cairo_stroke (cr); + //black border + cairo_set_source_rgb (cr, 0, 0.0, 0.0); + rounded_rectangle (cr, 0, 0, get_width(), get_height(), 4); + cairo_fill (cr); float speed = 0.0; @@ -512,12 +562,22 @@ ShuttleControl::on_expose_event (GdkEventExpose*) } /* Marker */ - - double visual_fraction = std::min (1.0f, speed/shuttle_max_speed); - double x = (get_width() / 2.0) + (0.5 * (get_width() * visual_fraction)); - cairo_move_to (cr, x, 1); - cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); - cairo_line_to (cr, x, get_height()-1); + float visual_fraction = std::min (1.0f, speed / shuttle_max_speed); + float marker_size = get_height() - 5.0; + float avail_width = get_width() - marker_size - 4; + float x = get_width() * 0.5 + visual_fraction * avail_width * 0.5; +// cairo_set_source_rgb (cr, 0, 1, 0.0); + cairo_set_source (cr, pattern); + if (speed == 1.0) { + cairo_move_to( cr, x, 2.5); + cairo_line_to( cr, x + marker_size * .577, 2.5 + marker_size * 0.5); + cairo_line_to( cr, x, 2.5 + marker_size); + cairo_close_path(cr); + } else if ( speed ==0.0 ) + rounded_rectangle (cr, x, 2.5, marker_size, marker_size, 1); + else + cairo_arc (cr, x, 2.5 + marker_size * .5, marker_size * 0.47, 0, 2.0 * M_PI); + cairo_set_line_width (cr, 1.75); cairo_stroke (cr); /* speed text */ @@ -532,9 +592,9 @@ ShuttleControl::on_expose_event (GdkEventExpose*) snprintf (buf, sizeof (buf), "%s", _("Playing")); } else { if (speed < 0.0) { - snprintf (buf, sizeof (buf), "<<< %d%%", (int) round (-speed * 100)); + snprintf (buf, sizeof (buf), "<<< %.1f%%", -speed * 100.f); } else { - snprintf (buf, sizeof (buf), ">>> %d%%", (int) round (speed * 100)); + snprintf (buf, sizeof (buf), ">>> %.1f%%", speed * 100.f); } } @@ -556,9 +616,13 @@ ShuttleControl::on_expose_event (GdkEventExpose*) last_speed_displayed = speed; - cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); - cairo_text_extents (cr, buf, &extents); - cairo_move_to (cr, 10, extents.height + 2); + // TODO use a proper pango layout, scale font + cairo_set_source_rgb (cr, 0.6, 0.6, 0.6); + cairo_set_font_size (cr, 13.0); + cairo_text_extents (cr, "0|", &extents); // note the descender + const float text_ypos = (get_height() + extents.height - 1.) * .5; + + cairo_move_to (cr, 10, text_ypos); cairo_show_text (cr, buf); /* style text */ @@ -574,13 +638,16 @@ ShuttleControl::on_expose_event (GdkEventExpose*) } cairo_text_extents (cr, buf, &extents); - - cairo_move_to (cr, get_width() - (fabs(extents.x_advance) + 5), extents.height + 2); + cairo_move_to (cr, get_width() - (fabs(extents.x_advance) + 5), text_ypos); cairo_show_text (cr, buf); - cairo_destroy (cr); - - return true; + if (UIConfiguration::instance().get_widget_prelight()) { + if (_hovering) { + rounded_rectangle (cr, 1, 1, get_width()-2, get_height()-2, 4.0); + cairo_set_source_rgba (cr, 1, 1, 1, 0.2); + cairo_fill (cr); + } + } } void @@ -604,14 +671,6 @@ ShuttleControl::set_shuttle_units (ShuttleUnits s) Config->set_shuttle_units (s); } -void -ShuttleControl::update_speed_display () -{ - if (_session->transport_speed() != last_speed_displayed) { - queue_draw (); - } -} - ShuttleControl::ShuttleControllable::ShuttleControllable (ShuttleControl& s) : PBD::Controllable (X_("Shuttle")) , sc (s) @@ -619,27 +678,15 @@ ShuttleControl::ShuttleControllable::ShuttleControllable (ShuttleControl& s) } void -ShuttleControl::ShuttleControllable::set_value (double val) +ShuttleControl::ShuttleControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/) { - double fract; - - if (val == 0.5) { - fract = 0.0; - } else { - if (val < 0.5) { - fract = -((0.5 - val)/0.5); - } else { - fract = ((val - 0.5)/0.5); - } - } - - sc.set_shuttle_fract (fract); + sc.set_shuttle_fract ((val - lower()) / (upper() - lower()), true); } double ShuttleControl::ShuttleControllable::get_value () const { - return sc.get_shuttle_fract (); + return lower() + (sc.get_shuttle_fract () * (upper() - lower())); } void @@ -676,3 +723,28 @@ ShuttleControl::parameter_changed (std::string p) queue_draw (); } } + + +bool +ShuttleControl::on_enter_notify_event (GdkEventCrossing* ev) +{ + _hovering = true; + + if (UIConfiguration::instance().get_widget_prelight()) { + queue_draw (); + } + + return CairoWidget::on_enter_notify_event (ev); +} + +bool +ShuttleControl::on_leave_notify_event (GdkEventCrossing* ev) +{ + _hovering = false; + + if (UIConfiguration::instance().get_widget_prelight()) { + queue_draw (); + } + + return CairoWidget::on_leave_notify_event (ev); +}