2014-07-18 09:47:45 -04:00
/*
2019-08-02 22:40:09 -04:00
* Copyright ( C ) 2010 Paul Davis < paul @ linuxaudiosystems . com >
* Copyright ( C ) 2017 Robin Gareus < robin @ gareus . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
2014-07-18 09:47:45 -04:00
# include <iostream>
# include <cmath>
# include <algorithm>
# include <pangomm/layout.h>
# include "pbd/compose.h"
2015-01-02 09:44:54 -05:00
# include "pbd/controllable.h"
2014-07-18 09:47:45 -04:00
# include "pbd/error.h"
# include "pbd/stacktrace.h"
2017-07-17 12:34:35 -04:00
# include "gtkmm2ext/colors.h"
2014-07-18 09:47:45 -04:00
# include "gtkmm2ext/gui_thread.h"
# include "gtkmm2ext/keyboard.h"
2017-07-17 12:34:35 -04:00
# include "gtkmm2ext/rgb_macros.h"
# include "gtkmm2ext/utils.h"
2014-07-18 09:47:45 -04:00
2017-07-15 11:38:28 -04:00
# include "widgets/ardour_knob.h"
# include "widgets/ui_config.h"
2014-07-18 09:47:45 -04:00
2016-07-14 14:44:52 -04:00
# include "pbd/i18n.h"
2014-07-18 09:47:45 -04:00
using namespace Gtkmm2ext ;
2017-07-15 11:38:28 -04:00
using namespace ArdourWidgets ;
2014-07-18 09:47:45 -04:00
using namespace Gtk ;
using namespace Glib ;
using namespace PBD ;
using std : : max ;
using std : : min ;
using namespace std ;
ArdourKnob : : Element ArdourKnob : : default_elements = ArdourKnob : : Element ( ArdourKnob : : Arc ) ;
2015-04-25 10:49:19 -04:00
ArdourKnob : : ArdourKnob ( Element e , Flags flags )
2014-07-18 09:47:45 -04:00
: _elements ( e )
, _hovering ( false )
2015-04-24 20:44:47 -04:00
, _grabbed_x ( 0 )
2015-04-24 20:05:50 -04:00
, _grabbed_y ( 0 )
, _val ( 0 )
2015-04-25 10:49:19 -04:00
, _normal ( 0 )
2015-04-24 23:10:07 -04:00
, _dead_zone_delta ( 0 )
2015-04-25 10:49:19 -04:00
, _flags ( flags )
2015-04-24 19:04:19 -04:00
, _tooltip ( this )
2014-07-18 09:47:45 -04:00
{
2017-07-15 11:38:28 -04:00
UIConfigurationBase : : instance ( ) . ColorsChanged . connect ( sigc : : mem_fun ( * this , & ArdourKnob : : color_handler ) ) ;
2015-04-25 14:20:03 -04:00
// watch automation :(
2016-07-10 21:45:13 -04:00
// TODO only use for GainAutomation
2017-07-15 11:38:28 -04:00
//Timers::rapid_connect (sigc::bind (sigc::mem_fun (*this, &ArdourKnob::controllable_changed), false));
2014-07-18 09:47:45 -04:00
}
ArdourKnob : : ~ ArdourKnob ( )
{
}
void
2017-03-20 12:11:56 -04:00
ArdourKnob : : render ( Cairo : : RefPtr < Cairo : : Context > const & ctx , cairo_rectangle_t * )
2014-07-18 09:47:45 -04:00
{
2017-03-20 12:11:56 -04:00
cairo_t * cr = ctx - > cobj ( ) ;
2014-07-18 09:47:45 -04:00
cairo_pattern_t * shade_pattern ;
2015-10-05 10:17:49 -04:00
2014-07-18 09:47:45 -04:00
float width = get_width ( ) ;
float height = get_height ( ) ;
2015-10-05 10:17:49 -04:00
2014-07-18 09:47:45 -04:00
const float scale = min ( width , height ) ;
const float pointer_thickness = 3.0 * ( scale / 80 ) ; //(if the knob is 80 pixels wide, we want a 3-pix line on it)
2015-10-05 10:17:49 -04:00
2015-04-24 20:05:50 -04:00
const float start_angle = ( ( 180 - 65 ) * G_PI ) / 180 ;
const float end_angle = ( ( 360 + 65 ) * G_PI ) / 180 ;
2015-04-25 10:49:19 -04:00
float zero = 0 ;
if ( _flags & ArcToZero ) {
zero = _normal ;
}
2015-04-24 20:05:50 -04:00
const float value_angle = start_angle + ( _val * ( end_angle - start_angle ) ) ;
2015-04-25 10:49:19 -04:00
const float zero_angle = start_angle + ( zero * ( end_angle - start_angle ) ) ;
2015-10-05 10:17:49 -04:00
2014-07-18 09:47:45 -04:00
float value_x = cos ( value_angle ) ;
float value_y = sin ( value_angle ) ;
float xc = 0.5 + width / 2.0 ;
float yc = 0.5 + height / 2.0 ;
2015-10-05 10:17:49 -04:00
2014-07-18 09:47:45 -04:00
cairo_translate ( cr , xc , yc ) ; //after this, everything is based on the center of the knob
//get the knob color from the theme
2017-07-17 12:34:35 -04:00
Gtkmm2ext : : Color knob_color = UIConfigurationBase : : instance ( ) . color ( string_compose ( " %1 " , get_name ( ) ) ) ;
2014-07-18 09:47:45 -04:00
float center_radius = 0.48 * scale ;
2014-07-22 11:17:09 -04:00
float border_width = 0.8 ;
2015-10-05 10:17:49 -04:00
2014-07-18 09:47:45 -04:00
bool arc = ( _elements & Arc ) = = Arc ;
bool bevel = ( _elements & Bevel ) = = Bevel ;
2014-08-27 12:53:30 -04:00
bool flat = _flat_buttons ;
2015-10-05 10:17:49 -04:00
2014-07-18 09:47:45 -04:00
if ( arc ) {
2015-04-24 16:36:44 -04:00
center_radius = scale * 0.33 ;
2014-07-18 09:47:45 -04:00
2015-04-24 16:36:44 -04:00
float inner_progress_radius = scale * 0.38 ;
2014-07-18 09:47:45 -04:00
float outer_progress_radius = scale * 0.48 ;
float progress_width = ( outer_progress_radius - inner_progress_radius ) ;
float progress_radius = inner_progress_radius + progress_width / 2.0 ;
2015-10-05 10:17:49 -04:00
2014-07-18 09:47:45 -04:00
//dark arc background
cairo_set_source_rgb ( cr , 0.3 , 0.3 , 0.3 ) ;
cairo_set_line_width ( cr , progress_width ) ;
cairo_arc ( cr , 0 , 0 , progress_radius , start_angle , end_angle ) ;
cairo_stroke ( cr ) ;
//look up the arc colors from the config
double red_start , green_start , blue_start , unused ;
2017-07-17 12:34:35 -04:00
Gtkmm2ext : : Color arc_start_color = UIConfigurationBase : : instance ( ) . color ( string_compose ( " %1: arc start " , get_name ( ) ) ) ;
Gtkmm2ext : : color_to_rgba ( arc_start_color , red_start , green_start , blue_start , unused ) ;
2014-07-18 09:47:45 -04:00
double red_end , green_end , blue_end ;
2017-07-17 12:34:35 -04:00
Gtkmm2ext : : Color arc_end_color = UIConfigurationBase : : instance ( ) . color ( string_compose ( " %1: arc end " , get_name ( ) ) ) ;
Gtkmm2ext : : color_to_rgba ( arc_end_color , red_end , green_end , blue_end , unused ) ;
2014-07-18 09:47:45 -04:00
//vary the arc color over the travel of the knob
2015-04-25 10:49:19 -04:00
float intensity = fabsf ( _val - zero ) / std : : max ( zero , ( 1.f - zero ) ) ;
2015-04-24 20:05:50 -04:00
const float intensity_inv = 1.0 - intensity ;
float r = intensity_inv * red_end + intensity * red_start ;
float g = intensity_inv * green_end + intensity * green_start ;
float b = intensity_inv * blue_end + intensity * blue_start ;
2014-07-18 09:47:45 -04:00
//draw the arc
cairo_set_source_rgb ( cr , r , g , b ) ;
cairo_set_line_width ( cr , progress_width ) ;
2015-04-24 20:05:50 -04:00
if ( zero_angle > value_angle ) {
cairo_arc ( cr , 0 , 0 , progress_radius , value_angle , zero_angle ) ;
} else {
cairo_arc ( cr , 0 , 0 , progress_radius , zero_angle , value_angle ) ;
}
2014-07-18 09:47:45 -04:00
cairo_stroke ( cr ) ;
//shade the arc
if ( ! flat ) {
shade_pattern = cairo_pattern_create_linear ( 0.0 , - yc , 0.0 , yc ) ; //note we have to offset the pattern from our centerpoint
cairo_pattern_add_color_stop_rgba ( shade_pattern , 0.0 , 1 , 1 , 1 , 0.15 ) ;
cairo_pattern_add_color_stop_rgba ( shade_pattern , 0.5 , 1 , 1 , 1 , 0.0 ) ;
cairo_pattern_add_color_stop_rgba ( shade_pattern , 1.0 , 1 , 1 , 1 , 0.0 ) ;
cairo_set_source ( cr , shade_pattern ) ;
cairo_arc ( cr , 0 , 0 , outer_progress_radius - 1 , 0 , 2.0 * G_PI ) ;
cairo_fill ( cr ) ;
cairo_pattern_destroy ( shade_pattern ) ;
}
2015-04-24 20:05:50 -04:00
2015-04-24 16:36:44 -04:00
#if 0 //black border
2015-04-24 20:05:50 -04:00
const float start_angle_x = cos ( start_angle ) ;
const float start_angle_y = sin ( start_angle ) ;
const float end_angle_x = cos ( end_angle ) ;
const float end_angle_y = sin ( end_angle ) ;
2014-07-18 09:47:45 -04:00
cairo_set_source_rgb ( cr , 0 , 0 , 0 ) ;
2014-07-22 11:17:09 -04:00
cairo_set_line_width ( cr , border_width ) ;
2014-07-18 09:47:45 -04:00
cairo_move_to ( cr , ( outer_progress_radius * start_angle_x ) , ( outer_progress_radius * start_angle_y ) ) ;
cairo_line_to ( cr , ( inner_progress_radius * start_angle_x ) , ( inner_progress_radius * start_angle_y ) ) ;
cairo_stroke ( cr ) ;
cairo_move_to ( cr , ( outer_progress_radius * end_angle_x ) , ( outer_progress_radius * end_angle_y ) ) ;
cairo_line_to ( cr , ( inner_progress_radius * end_angle_x ) , ( inner_progress_radius * end_angle_y ) ) ;
cairo_stroke ( cr ) ;
cairo_arc ( cr , 0 , 0 , outer_progress_radius , start_angle , end_angle ) ;
cairo_stroke ( cr ) ;
2015-04-24 16:36:44 -04:00
# endif
2014-07-18 09:47:45 -04:00
}
2015-10-05 10:17:49 -04:00
2014-07-18 09:47:45 -04:00
if ( ! flat ) {
//knob shadow
cairo_save ( cr ) ;
cairo_translate ( cr , pointer_thickness + 1 , pointer_thickness + 1 ) ;
cairo_set_source_rgba ( cr , 0 , 0 , 0 , 0.1 ) ;
cairo_arc ( cr , 0 , 0 , center_radius - 1 , 0 , 2.0 * G_PI ) ;
cairo_fill ( cr ) ;
cairo_restore ( cr ) ;
//inner circle
2017-07-17 12:34:35 -04:00
Gtkmm2ext : : set_source_rgba ( cr , knob_color ) ;
2014-07-18 09:47:45 -04:00
cairo_arc ( cr , 0 , 0 , center_radius , 0 , 2.0 * G_PI ) ;
cairo_fill ( cr ) ;
2015-10-05 10:17:49 -04:00
//gradient
2014-07-18 09:47:45 -04:00
if ( bevel ) {
//knob gradient
shade_pattern = cairo_pattern_create_linear ( 0.0 , - yc , 0.0 , yc ) ; //note we have to offset the gradient from our centerpoint
cairo_pattern_add_color_stop_rgba ( shade_pattern , 0.0 , 1 , 1 , 1 , 0.2 ) ;
cairo_pattern_add_color_stop_rgba ( shade_pattern , 0.2 , 1 , 1 , 1 , 0.2 ) ;
cairo_pattern_add_color_stop_rgba ( shade_pattern , 0.8 , 0 , 0 , 0 , 0.2 ) ;
cairo_pattern_add_color_stop_rgba ( shade_pattern , 1.0 , 0 , 0 , 0 , 0.2 ) ;
cairo_set_source ( cr , shade_pattern ) ;
cairo_arc ( cr , 0 , 0 , center_radius , 0 , 2.0 * G_PI ) ;
cairo_fill ( cr ) ;
cairo_pattern_destroy ( shade_pattern ) ;
//flat top over beveled edge
2017-07-17 12:34:35 -04:00
Gtkmm2ext : : set_source_rgb_a ( cr , knob_color , 0.5 ) ;
2014-07-18 09:47:45 -04:00
cairo_arc ( cr , 0 , 0 , center_radius - pointer_thickness , 0 , 2.0 * G_PI ) ;
cairo_fill ( cr ) ;
2015-10-05 10:17:49 -04:00
} else {
2014-07-18 09:47:45 -04:00
//radial gradient
shade_pattern = cairo_pattern_create_radial ( - center_radius , - center_radius , 1 , - center_radius , - center_radius , center_radius * 2.5 ) ; //note we have to offset the gradient from our centerpoint
cairo_pattern_add_color_stop_rgba ( shade_pattern , 0.0 , 1 , 1 , 1 , 0.2 ) ;
cairo_pattern_add_color_stop_rgba ( shade_pattern , 1.0 , 0 , 0 , 0 , 0.3 ) ;
cairo_set_source ( cr , shade_pattern ) ;
cairo_arc ( cr , 0 , 0 , center_radius , 0 , 2.0 * G_PI ) ;
cairo_fill ( cr ) ;
cairo_pattern_destroy ( shade_pattern ) ;
}
2015-10-05 10:17:49 -04:00
2014-07-18 09:47:45 -04:00
} else {
//inner circle
2017-07-17 12:34:35 -04:00
Gtkmm2ext : : set_source_rgba ( cr , knob_color ) ;
2014-07-18 09:47:45 -04:00
cairo_arc ( cr , 0 , 0 , center_radius , 0 , 2.0 * G_PI ) ;
cairo_fill ( cr ) ;
}
2015-10-05 10:17:49 -04:00
2014-07-18 09:47:45 -04:00
//black knob border
2014-07-22 11:17:09 -04:00
cairo_set_line_width ( cr , border_width ) ;
2014-07-18 09:47:45 -04:00
cairo_set_source_rgba ( cr , 0 , 0 , 0 , 1 ) ;
cairo_arc ( cr , 0 , 0 , center_radius , 0 , 2.0 * G_PI ) ;
cairo_stroke ( cr ) ;
2015-10-05 10:17:49 -04:00
2014-07-18 09:47:45 -04:00
//line shadow
if ( ! flat ) {
cairo_save ( cr ) ;
2014-07-22 11:17:09 -04:00
cairo_translate ( cr , 1 , 1 ) ;
cairo_set_source_rgba ( cr , 0 , 0 , 0 , 0.3 ) ;
2014-07-18 09:47:45 -04:00
cairo_set_line_cap ( cr , CAIRO_LINE_CAP_ROUND ) ;
cairo_set_line_width ( cr , pointer_thickness ) ;
cairo_move_to ( cr , ( center_radius * value_x ) , ( center_radius * value_y ) ) ;
cairo_line_to ( cr , ( ( center_radius * 0.4 ) * value_x ) , ( ( center_radius * 0.4 ) * value_y ) ) ;
cairo_stroke ( cr ) ;
cairo_restore ( cr ) ;
}
2015-10-05 10:17:49 -04:00
2014-07-18 09:47:45 -04:00
//line
cairo_set_source_rgba ( cr , 1 , 1 , 1 , 1 ) ;
cairo_set_line_cap ( cr , CAIRO_LINE_CAP_ROUND ) ;
cairo_set_line_width ( cr , pointer_thickness ) ;
cairo_move_to ( cr , ( center_radius * value_x ) , ( center_radius * value_y ) ) ;
cairo_line_to ( cr , ( ( center_radius * 0.4 ) * value_x ) , ( ( center_radius * 0.4 ) * value_y ) ) ;
cairo_stroke ( cr ) ;
//highlight if grabbed or if mouse is hovering over me
2017-07-15 11:38:28 -04:00
if ( _tooltip . dragging ( ) | | ( _hovering & & UIConfigurationBase : : instance ( ) . get_widget_prelight ( ) ) ) {
2014-07-18 09:47:45 -04:00
cairo_set_source_rgba ( cr , 1 , 1 , 1 , 0.12 ) ;
cairo_arc ( cr , 0 , 0 , center_radius , 0 , 2.0 * G_PI ) ;
cairo_fill ( cr ) ;
}
2015-10-05 10:17:49 -04:00
cairo_identity_matrix ( cr ) ;
2014-07-18 09:47:45 -04:00
}
void
ArdourKnob : : on_size_request ( Gtk : : Requisition * req )
{
2015-04-24 19:04:19 -04:00
// see ardour-button VectorIcon size, use font scaling as default
CairoWidget : : on_size_request ( req ) ; // allow to override
// we're square
if ( req - > width < req - > height ) {
req - > width = req - > height ;
}
if ( req - > height < req - > width ) {
req - > height = req - > width ;
}
2014-07-18 09:47:45 -04:00
}
bool
ArdourKnob : : on_scroll_event ( GdkEventScroll * ev )
{
/* mouse wheel */
float scale = 0.05 ; //by default, we step in 1/20ths of the knob travel
if ( ev - > state & Keyboard : : GainFineScaleModifier ) {
if ( ev - > state & Keyboard : : GainExtraFineScaleModifier ) {
scale * = 0.01 ;
} else {
scale * = 0.10 ;
}
}
boost : : shared_ptr < PBD : : Controllable > c = binding_proxy . get_controllable ( ) ;
if ( c ) {
2020-04-06 18:36:59 -04:00
float val = c - > get_interface ( true ) ;
2015-10-05 10:17:49 -04:00
2014-07-18 09:47:45 -04:00
if ( ev - > direction = = GDK_SCROLL_UP )
2015-04-24 23:10:07 -04:00
val + = scale ;
2014-07-18 09:47:45 -04:00
else
2015-10-05 10:17:49 -04:00
val - = scale ;
2014-07-22 11:17:09 -04:00
2020-04-06 18:36:59 -04:00
c - > set_interface ( val , true ) ;
2014-07-18 09:47:45 -04:00
}
return true ;
}
bool
2015-04-24 23:10:07 -04:00
ArdourKnob : : on_motion_notify_event ( GdkEventMotion * ev )
2014-07-18 09:47:45 -04:00
{
2015-04-24 23:10:07 -04:00
if ( ! ( ev - > state & Gdk : : BUTTON1_MASK ) ) {
return true ;
}
boost : : shared_ptr < PBD : : Controllable > c = binding_proxy . get_controllable ( ) ;
if ( ! c ) {
return true ;
}
//scale the adjustment based on keyboard modifiers & GUI size
2017-07-15 11:38:28 -04:00
const float ui_scale = max ( 1.f , UIConfigurationBase : : instance ( ) . get_ui_scale ( ) ) ;
2015-04-25 10:49:19 -04:00
float scale = 0.0025 / ui_scale ;
2015-04-24 23:10:07 -04:00
2014-07-18 09:47:45 -04:00
if ( ev - > state & Keyboard : : GainFineScaleModifier ) {
if ( ev - > state & Keyboard : : GainExtraFineScaleModifier ) {
scale * = 0.01 ;
} else {
scale * = 0.10 ;
}
}
//calculate the travel of the mouse
2015-04-24 23:10:07 -04:00
int delta = ( _grabbed_y - ev - > y ) - ( _grabbed_x - ev - > x ) ;
if ( delta = = 0 ) {
return true ;
2014-07-18 09:47:45 -04:00
}
2015-04-24 23:10:07 -04:00
_grabbed_x = ev - > x ;
_grabbed_y = ev - > y ;
2020-04-06 18:36:59 -04:00
float val = c - > get_interface ( true ) ;
2015-04-24 23:10:07 -04:00
2015-04-25 10:49:19 -04:00
if ( _flags & Detent ) {
const float px_deadzone = 42.f * ui_scale ;
if ( ( val - _normal ) * ( val - _normal + delta * scale ) < 0 ) {
/* detent */
const int tozero = ( _normal - val ) * scale ;
int remain = delta - tozero ;
if ( abs ( remain ) > px_deadzone ) {
/* slow down passing the default value */
remain + = ( remain > 0 ) ? px_deadzone * - .5 : px_deadzone * .5 ;
delta = tozero + remain ;
_dead_zone_delta = 0 ;
} else {
2016-01-02 04:58:23 -05:00
c - > set_value ( c - > normal ( ) , Controllable : : NoGroup ) ;
2015-04-25 10:49:19 -04:00
_dead_zone_delta = remain / px_deadzone ;
return true ;
}
}
if ( fabsf ( rintf ( ( val - _normal ) / scale ) + _dead_zone_delta ) < 1 ) {
2016-01-02 04:58:23 -05:00
c - > set_value ( c - > normal ( ) , Controllable : : NoGroup ) ;
2015-04-25 10:49:19 -04:00
_dead_zone_delta + = delta / px_deadzone ;
2015-04-24 23:10:07 -04:00
return true ;
}
2014-07-18 09:47:45 -04:00
2015-04-25 10:49:19 -04:00
_dead_zone_delta = 0 ;
2015-04-24 23:10:07 -04:00
}
val + = delta * scale ;
2020-04-06 18:36:59 -04:00
c - > set_interface ( val , true ) ;
2015-04-24 23:10:07 -04:00
2014-07-18 09:47:45 -04:00
return true ;
}
bool
ArdourKnob : : on_button_press_event ( GdkEventButton * ev )
{
2015-04-24 20:44:47 -04:00
_grabbed_x = ev - > x ;
2014-07-18 09:47:45 -04:00
_grabbed_y = ev - > y ;
2015-04-24 23:10:07 -04:00
_dead_zone_delta = 0 ;
if ( ev - > type ! = GDK_BUTTON_PRESS ) {
if ( _grabbed ) {
remove_modal_grab ( ) ;
2017-07-23 13:40:20 -04:00
_grabbed = false ;
StopGesture ( ) ;
2015-04-24 23:10:07 -04:00
gdk_pointer_ungrab ( GDK_CURRENT_TIME ) ;
}
return true ;
}
2014-07-18 09:47:45 -04:00
if ( binding_proxy . button_press_handler ( ev ) ) {
return true ;
}
2015-04-24 23:10:07 -04:00
if ( ev - > button ! = 1 & & ev - > button ! = 2 ) {
return false ;
}
2015-10-05 10:17:49 -04:00
2015-04-24 23:10:07 -04:00
set_active_state ( Gtkmm2ext : : ExplicitActive ) ;
_tooltip . start_drag ( ) ;
add_modal_grab ( ) ;
_grabbed = true ;
2017-07-23 13:40:20 -04:00
StartGesture ( ) ;
2015-04-24 23:10:07 -04:00
gdk_pointer_grab ( ev - > window , false ,
GdkEventMask ( Gdk : : POINTER_MOTION_MASK | Gdk : : BUTTON_PRESS_MASK | Gdk : : BUTTON_RELEASE_MASK ) ,
NULL , NULL , ev - > time ) ;
return true ;
2014-07-18 09:47:45 -04:00
}
bool
ArdourKnob : : on_button_release_event ( GdkEventButton * ev )
{
2015-04-24 23:10:07 -04:00
_tooltip . stop_drag ( ) ;
_grabbed = false ;
2017-07-23 13:40:20 -04:00
StopGesture ( ) ;
2015-04-24 23:10:07 -04:00
remove_modal_grab ( ) ;
gdk_pointer_ungrab ( GDK_CURRENT_TIME ) ;
2015-04-24 20:44:47 -04:00
if ( ( _grabbed_y = = ev - > y & & _grabbed_x = = ev - > x ) & & Keyboard : : modifier_state_equals ( ev - > state , Keyboard : : TertiaryModifier ) ) { //no move, shift-click sets to default
2014-07-22 17:05:51 -04:00
boost : : shared_ptr < PBD : : Controllable > c = binding_proxy . get_controllable ( ) ;
if ( ! c ) return false ;
2016-01-02 04:58:23 -05:00
c - > set_value ( c - > normal ( ) , Controllable : : NoGroup ) ;
2015-04-24 23:10:07 -04:00
return true ;
2014-07-22 17:05:51 -04:00
}
2014-07-18 09:47:45 -04:00
unset_active_state ( ) ;
2015-04-24 23:10:07 -04:00
return true ;
2014-07-18 09:47:45 -04:00
}
void
ArdourKnob : : color_handler ( )
{
set_dirty ( ) ;
}
void
ArdourKnob : : on_size_allocate ( Allocation & alloc )
{
CairoWidget : : on_size_allocate ( alloc ) ;
}
void
ArdourKnob : : set_controllable ( boost : : shared_ptr < Controllable > c )
{
2015-04-25 14:20:03 -04:00
watch_connection . disconnect ( ) ; //stop watching the old controllable
2014-07-18 09:47:45 -04:00
if ( ! c ) return ;
binding_proxy . set_controllable ( c ) ;
2016-07-10 21:45:13 -04:00
c - > Changed . connect ( watch_connection , invalidator ( * this ) , boost : : bind ( & ArdourKnob : : controllable_changed , this , false ) , gui_context ( ) ) ;
2014-07-18 09:47:45 -04:00
2015-04-25 10:49:19 -04:00
_normal = c - > internal_to_interface ( c - > normal ( ) ) ;
2015-04-24 20:05:50 -04:00
2014-07-18 09:47:45 -04:00
controllable_changed ( ) ;
}
void
2016-07-10 21:45:13 -04:00
ArdourKnob : : controllable_changed ( bool force_update )
2014-07-18 09:47:45 -04:00
{
2015-04-24 16:16:10 -04:00
boost : : shared_ptr < PBD : : Controllable > c = binding_proxy . get_controllable ( ) ;
2015-04-25 14:20:03 -04:00
if ( ! c ) return ;
2014-07-18 09:47:45 -04:00
2020-04-06 18:36:59 -04:00
float val = c - > get_interface ( true ) ;
2015-04-25 14:20:03 -04:00
val = min ( max ( 0.0f , val ) , 1.0f ) ; // clamp
2016-07-10 21:45:13 -04:00
if ( val = = _val & & ! force_update ) {
2015-04-25 14:20:03 -04:00
return ;
}
2014-07-18 09:47:45 -04:00
2015-04-25 14:20:03 -04:00
_val = val ;
2015-04-24 17:22:15 -04:00
if ( ! _tooltip_prefix . empty ( ) ) {
2017-06-09 08:46:11 -04:00
_tooltip . set_tip ( _tooltip_prefix + c - > get_user_string ( ) ) ;
2015-04-24 17:22:15 -04:00
}
2014-07-18 09:47:45 -04:00
set_dirty ( ) ;
}
void
ArdourKnob : : on_style_changed ( const RefPtr < Gtk : : Style > & )
{
set_dirty ( ) ;
}
void
ArdourKnob : : on_name_changed ( )
{
set_dirty ( ) ;
}
void
ArdourKnob : : set_active_state ( Gtkmm2ext : : ActiveState s )
{
if ( _active_state ! = s )
CairoWidget : : set_active_state ( s ) ;
}
2015-10-05 10:17:49 -04:00
2014-07-18 09:47:45 -04:00
void
ArdourKnob : : set_visual_state ( Gtkmm2ext : : VisualState s )
{
if ( _visual_state ! = s )
CairoWidget : : set_visual_state ( s ) ;
}
2015-10-05 10:17:49 -04:00
2014-07-18 09:47:45 -04:00
bool
ArdourKnob : : on_focus_in_event ( GdkEventFocus * ev )
{
set_dirty ( ) ;
return CairoWidget : : on_focus_in_event ( ev ) ;
}
bool
ArdourKnob : : on_focus_out_event ( GdkEventFocus * ev )
{
set_dirty ( ) ;
return CairoWidget : : on_focus_out_event ( ev ) ;
}
bool
ArdourKnob : : on_enter_notify_event ( GdkEventCrossing * ev )
{
_hovering = true ;
set_dirty ( ) ;
2017-07-02 09:29:57 -04:00
boost : : shared_ptr < PBD : : Controllable > c ( binding_proxy . get_controllable ( ) ) ;
if ( c ) {
PBD : : Controllable : : GUIFocusChanged ( boost : : weak_ptr < PBD : : Controllable > ( c ) ) ;
}
2014-07-18 09:47:45 -04:00
return CairoWidget : : on_enter_notify_event ( ev ) ;
}
bool
ArdourKnob : : on_leave_notify_event ( GdkEventCrossing * ev )
{
_hovering = false ;
set_dirty ( ) ;
2017-07-02 09:29:57 -04:00
if ( binding_proxy . get_controllable ( ) ) {
PBD : : Controllable : : GUIFocusChanged ( boost : : weak_ptr < PBD : : Controllable > ( ) ) ;
}
2014-07-18 09:47:45 -04:00
return CairoWidget : : on_leave_notify_event ( ev ) ;
}
void
ArdourKnob : : set_elements ( Element e )
{
_elements = e ;
}
void
ArdourKnob : : add_elements ( Element e )
{
_elements = ( ArdourKnob : : Element ) ( _elements | e ) ;
}
2015-04-24 19:04:19 -04:00
KnobPersistentTooltip : : KnobPersistentTooltip ( Gtk : : Widget * w )
2015-06-30 07:08:55 -04:00
: PersistentTooltip ( w , true , 3 )
2015-04-24 19:04:19 -04:00
, _dragging ( false )
{
}
void
KnobPersistentTooltip : : start_drag ( )
{
_dragging = true ;
}
void
KnobPersistentTooltip : : stop_drag ( )
{
_dragging = false ;
}
bool
KnobPersistentTooltip : : dragging ( ) const
{
return _dragging ;
}