@@ -95,38 +95,65 @@ struct Slider{T<:Number} <: InputWidget{T}
95
95
observable:: Observable{T}
96
96
widget:: GtkScaleLeaf
97
97
id:: Culong
98
+ snap_handler_id:: Ref{Culong}
98
99
preserved:: Vector{Any}
99
100
100
- function Slider {T} (observable:: Observable{T} , widget, id, preserved) where T
101
- obj = new {T} (observable, widget, id, preserved)
101
+ function Slider {T} (observable:: Observable{T} , widget, id, snap_id, preserved) where T
102
+ obj = new {T} (observable, widget, id, snap_id, preserved)
102
103
gc_preserve (widget, obj)
103
104
obj
104
105
end
105
106
end
106
- Slider (observable:: Observable{T} , widget:: GtkScale , id, preserved) where {T} =
107
- Slider {T} (observable, widget, id, preserved)
107
+ Slider (observable:: Observable{T} , widget:: GtkScale , id, snap_id, preserved) where {T} =
108
+ Slider {T} (observable, widget, id, snap_id, preserved)
108
109
109
110
medianidx (r) = (ax = axes (r)[1 ]; return (first (ax)+ last (ax))÷ 2 )
110
111
# differs from median(r) in that it always returns an element of the range
111
112
medianelement (r:: AbstractRange ) = r[medianidx (r)]
112
113
113
- slider (observable:: Observable , widget:: GtkScale , id, preserved = []) =
114
- Slider (observable, widget, id, preserved)
114
+ # simplified version of function in https://github.com/joshday/SearchSortedNearest.jl
115
+ function searchsortednearest (a, x)
116
+ i = searchsortedfirst (a, x)
117
+ if i == 1
118
+ elseif i > length (a)
119
+ i = length (a)
120
+ elseif a[i] == x
121
+ else
122
+ i = isless (abs (a[i] - x), abs (a[i - 1 ] - x)) ? i : i - 1
123
+ end
124
+ return i
125
+ end
126
+
127
+ @guarded Cint (0 ) function slider_changevalue_cb (ptr:: Ptr , scroll, value:: Float64 , user_data)
128
+ scale = convert (GtkScale, ptr)
129
+ r, idr = user_data
130
+ i = searchsortednearest (r, value)
131
+ signal_handler_block (scale, idr[])
132
+ signal_emit (scale, " change-value" , Bool, Gtk4. ScrollType (scroll), Float64 (r[i]))
133
+ signal_handler_unblock (scale, idr[])
134
+ return Cint (1 )
135
+ end
136
+
137
+
138
+ slider (observable:: Observable , widget:: GtkScale , id, snap_id, preserved = []) =
139
+ Slider (observable, widget, id, snap_id, preserved)
115
140
116
141
"""
117
- slider(range; widget=nothing, value=nothing, observable=nothing, orientation="horizontal")
142
+ slider(range; widget=nothing, value=nothing, observable=nothing, orientation="horizontal", snap=false )
118
143
119
144
Create a slider widget with the specified `range`. Optionally provide:
120
145
- the GtkScale `widget` (by default, creates a new one)
121
146
- the starting `value` (defaults to the median of `range`)
122
147
- the (Observables.jl) `observable` coupled to this slider (by default, creates a new observable)
123
148
- the `orientation` of the slider.
149
+ - whether to `snap` the slider value to an element of `range`.
124
150
"""
125
151
function slider (range:: AbstractRange ;
126
152
widget= nothing ,
127
153
value= nothing ,
128
154
observable= nothing ,
129
155
orientation= " horizontal" ,
156
+ snap= false ,
130
157
syncsig= true ,
131
158
own= nothing )
132
159
obsin = observable
@@ -155,6 +182,11 @@ function slider(range::AbstractRange;
155
182
observable[] = defaultgetter (w)
156
183
end
157
184
185
+ ref_snap_id = Ref {Culong} (0 )
186
+ if snap
187
+ ref_snap_id[] = Gtk4. on_change_value (slider_changevalue_cb, widget, (range,ref_snap_id))
188
+ end
189
+
158
190
# # observable -> widget
159
191
preserved = []
160
192
if syncsig
@@ -164,7 +196,7 @@ function slider(range::AbstractRange;
164
196
ondestroy (widget, preserved)
165
197
end
166
198
167
- Slider (observable, widget, id, preserved)
199
+ Slider (observable, widget, id, ref_snap_id, preserved)
168
200
end
169
201
170
202
# Adjust the range on a slider
0 commit comments