66
77namespace Pinta . Gui . Widgets ;
88
9- // used in `ColorPickerDialog` for the right hand side sliders
10- // uses a label, scale, and entry
11- // then hides the scale and draws over it
12- // with a drawingarea
139public sealed class ColorPickerSlider : Gtk . Box
1410{
1511 public enum Component
@@ -27,48 +23,24 @@ public enum Component
2723 private const int PADDING_HEIGHT = 10 ;
2824
2925 private readonly Component component ;
30- private readonly Gtk . Scale slider_control ;
31- private readonly Gtk . Entry input_field ;
32- private readonly Gtk . Overlay slider_overlay ;
33- private readonly Gtk . DrawingArea cursor_area ;
3426 private Color color ;
3527
36- public Gtk . DrawingArea Gradient { get ; }
28+ private readonly Gtk . Entry input_field ;
29+ private readonly Gtk . DrawingArea gradient_slider ;
3730
3831 public event EventHandler ? OnColorChanged ;
3932
4033 public ColorPickerSlider ( Component component , Color initialColor , int initialWidth )
4134 {
42- Gtk . Scale sliderControl = new ( ) {
43- WidthRequest = initialWidth ,
44- Opacity = 0 ,
45- } ;
46- sliderControl . SetOrientation ( Gtk . Orientation . Horizontal ) ;
47- sliderControl . SetAdjustment ( Gtk . Adjustment . New ( 0 , 0 , GetMaxValue ( component ) + 1 , 1 , 1 , 1 ) ) ;
48- sliderControl . SetValue ( ExtractValue ( initialColor , component ) ) ;
49- sliderControl . OnChangeValue += OnSliderControlChangeValue ;
50-
51- Gtk . DrawingArea cursorArea = new ( ) ;
52- cursorArea . SetSizeRequest ( initialWidth , this . GetHeight ( ) ) ;
53- cursorArea . SetDrawFunc ( CursorAreaDrawingFunction ) ;
54-
55- Gtk . DrawingArea gradient = new ( ) ;
56- gradient . SetSizeRequest ( initialWidth , this . GetHeight ( ) ) ;
57- gradient . SetDrawFunc ( ( area , context , width , height ) => {
35+ Gtk . DrawingArea gradientSlider = new ( ) ;
36+ gradientSlider . SetSizeRequest ( initialWidth , this . GetHeight ( ) ) ;
37+ gradientSlider . SetDrawFunc ( ( _ , context , width , height ) => {
5838 DrawGradient ( context , width , height , CreateGradient ( color , component ) ) ;
5939 } ) ;
6040
6141 Gtk . Label sliderLabel = new ( ) { WidthRequest = 50 } ;
6242 sliderLabel . SetLabel ( GetLabelText ( component ) ) ;
6343
64- Gtk . Overlay sliderOverlay = new ( ) {
65- WidthRequest = initialWidth ,
66- HeightRequest = this . GetHeight ( ) ,
67- } ;
68- sliderOverlay . AddOverlay ( gradient ) ;
69- sliderOverlay . AddOverlay ( cursorArea ) ;
70- sliderOverlay . AddOverlay ( sliderControl ) ;
71-
7244 Gtk . Entry inputField = new ( ) {
7345 MaxWidthChars = 3 ,
7446 WidthRequest = 50 ,
@@ -77,34 +49,78 @@ public ColorPickerSlider (Component component, Color initialColor, int initialWi
7749 inputField . SetText ( Convert . ToInt32 ( ExtractValue ( initialColor , component ) ) . ToString ( ) ) ;
7850 inputField . OnChanged += OnInputFieldChanged ;
7951
52+ Gtk . GestureDrag dragGesture = Gtk . GestureDrag . New ( ) ;
53+ dragGesture . SetButton ( GtkExtensions . MOUSE_LEFT_BUTTON ) ;
54+ dragGesture . OnDragBegin += ( _ , _ ) => dragGesture . SetState ( Gtk . EventSequenceState . Claimed ) ;
55+ dragGesture . OnDragUpdate += OnDragUpdate ;
56+ dragGesture . OnDragEnd += OnDragEnd ;
57+ gradientSlider . AddController ( dragGesture ) ;
58+
59+ Gtk . EventControllerScroll scrollController = Gtk . EventControllerScroll . New ( Gtk . EventControllerScrollFlags . Vertical ) ;
60+ scrollController . OnScroll += HandleScrollEvent ;
61+ gradientSlider . AddController ( scrollController ) ;
62+
8063 // --- Initialization (Gtk.Box)
8164
8265 Append ( sliderLabel ) ;
83- Append ( sliderOverlay ) ;
66+ Append ( gradientSlider ) ;
8467 Append ( inputField ) ;
8568
8669 // --- References to keep
8770
8871 color = initialColor ;
89- cursor_area = cursorArea ;
90- slider_control = sliderControl ;
91- slider_overlay = sliderOverlay ;
9272 input_field = inputField ;
93-
94- Gradient = gradient ;
73+ gradient_slider = gradientSlider ;
9574
9675 this . component = component ;
9776 }
9877
99- private void CursorAreaDrawingFunction (
100- Gtk . DrawingArea area ,
101- Context context ,
102- int width ,
103- int height )
78+ private void OnDragUpdate ( Gtk . GestureDrag sender , Gtk . GestureDrag . DragUpdateSignalArgs args )
79+ {
80+ sender . GetStartPoint ( out double startX , out _ ) ;
81+ UpdateColorFromDrag ( startX + args . OffsetX ) ;
82+ }
83+
84+ private void OnDragEnd ( Gtk . GestureDrag sender , Gtk . GestureDrag . DragEndSignalArgs args )
85+ {
86+ sender . GetStartPoint ( out double startX , out _ ) ;
87+ UpdateColorFromDrag ( startX + args . OffsetX ) ;
88+ }
89+
90+ private void UpdateColorFromDrag ( double x )
91+ {
92+ x -= PADDING_WIDTH ;
93+ double maxX = gradient_slider . GetWidth ( ) - 2 * PADDING_WIDTH ;
94+ double value = ( x / maxX ) * GetMaxValue ( component ) ;
95+
96+ UpdateColorValue ( value ) ;
97+ }
98+
99+ private void UpdateColorValue ( double value )
100+ {
101+ double clampedValue = Math . Clamp ( Math . Round ( value ) , 0 , GetMaxValue ( component ) ) ;
102+ input_field . SetText ( clampedValue . ToString ( CultureInfo . InvariantCulture ) ) ;
103+
104+ color = UpdateValue ( color , component , clampedValue ) ;
105+ gradient_slider . QueueDraw ( ) ;
106+ OnColorChanged ? . Invoke ( this , EventArgs . Empty ) ;
107+ }
108+
109+ private bool HandleScrollEvent (
110+ Gtk . EventControllerScroll controller ,
111+ Gtk . EventControllerScroll . ScrollSignalArgs args )
112+ {
113+ double value = ExtractValue ( color , component ) ;
114+ UpdateColorValue ( value - args . Dy ) ;
115+ return true ;
116+ }
117+
118+ private void DrawCursor ( Context context , int width , int height )
104119 {
105120 const int OUTLINE_WIDTH = 2 ;
106121
107- double currentPosition = slider_control . GetValue ( ) / GetMaxValue ( component ) * ( width - 2 * PADDING_WIDTH ) + PADDING_WIDTH ;
122+ double value = ExtractValue ( color , component ) ;
123+ double currentPosition = value / GetMaxValue ( component ) * ( width - 2 * PADDING_WIDTH ) + PADDING_WIDTH ;
108124
109125 ReadOnlySpan < PointD > cursorPoly = [
110126 new ( currentPosition , height / 2 ) ,
@@ -127,21 +143,6 @@ private void CursorAreaDrawingFunction (
127143 new Color ( 1 , 1 , 1 ) ) ;
128144 }
129145
130- private bool OnSliderControlChangeValue (
131- Gtk . Range sender ,
132- Gtk . Range . ChangeValueSignalArgs args )
133- {
134- // The provided value is from the scroll action, so we need to clamp to the range!
135- double clampedValue = Math . Clamp ( args . Value , 0 , GetMaxValue ( component ) ) ;
136-
137- input_field . SetText ( clampedValue . ToString ( CultureInfo . InvariantCulture ) ) ;
138-
139- color = UpdateValue ( color , component , clampedValue ) ;
140- OnColorChanged ? . Invoke ( this , new ( ) ) ;
141-
142- return false ;
143- }
144-
145146 private void OnInputFieldChanged ( Gtk . Editable inputField , EventArgs e )
146147 {
147148 string text = inputField . GetText ( ) ;
@@ -166,18 +167,14 @@ private void OnInputFieldChanged (Gtk.Editable inputField, EventArgs e)
166167
167168 public void SetSliderWidth ( int sliderWidth )
168169 {
169- slider_control . WidthRequest = sliderWidth ;
170- Gradient . SetSizeRequest ( sliderWidth , this . GetHeight ( ) ) ;
171- cursor_area . SetSizeRequest ( sliderWidth , this . GetHeight ( ) ) ;
172- slider_overlay . WidthRequest = sliderWidth ;
170+ gradient_slider . WidthRequest = sliderWidth ;
173171 }
174172
175173 public Color Color {
176174 get => color ;
177175 set {
178176 color = value ;
179177 double componentValue = ExtractValue ( value , component ) ;
180- slider_control . SetValue ( componentValue ) ;
181178
182179 if ( ! input_field . IsEditingText ( ) ) {
183180 // Ensure we don't get an infinite loop of "value changed" events
@@ -186,8 +183,7 @@ public Color Color {
186183 input_field . SetText ( newText ) ;
187184 }
188185
189- Gradient . QueueDraw ( ) ;
190- cursor_area . QueueDraw ( ) ;
186+ gradient_slider . QueueDraw ( ) ;
191187 }
192188 }
193189
@@ -257,6 +253,8 @@ private void DrawGradient (Context context, int width, int height, ColorGradient
257253
258254 context . SetSource ( pat ) ;
259255 context . Fill ( ) ;
256+
257+ DrawCursor ( context , width , height ) ;
260258 }
261259
262260 private static double ExtractValue ( Color color , Component component ) => component switch {
0 commit comments