Skip to content

Commit 27e3a50

Browse files
committed
Remove the hidden Gtk.Scale from the color picker slider
Instead, just attach suitable event handlers for the gesture interactions. This is much simpler, and also lets us change the behaviour so that clicking elsewhere on the slider moves the color to that position, rather than incrementing the value by one step Bug: #1791
1 parent f7ad8c9 commit 27e3a50

1 file changed

Lines changed: 65 additions & 67 deletions

File tree

Pinta.Gui.Widgets/Widgets/ColorPickerSlider.cs

Lines changed: 65 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@
66

77
namespace 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
139
public 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

Comments
 (0)