1 ; Copyright 2022 Frank Duncan (frank@consxy.com) under AGPL3. See distributed LICENSE.txt.
2 (in-package #:clnl-gltk)
5 ; - check logic when min is greater than max
6 ; - check logic when value is outside of bounds
7 ; - should make the handle disappear
8 ; - check logic when min or max updates
10 ; - have a hover for handle, when mousedown, do mousedown like the others
11 ; - have a hover for the bar
13 ; - handle "Units" from netlogo sliders
14 ; - have display be dependent on significant digits of min/max/step
16 ; - handle vertical sliders - this is really just the same slider just rotated, nothing special
18 ; Height is constant for slideres in netlogo
19 (defvar *slider-height* 33
32 The default slider height.")
34 (defstruct slider x y width text callback min max increment value dragging)
36 (defun slider (x y width text callback min max increment value)
37 "SLIDER X Y WIDTH TEXT CALLBACK MIN MAX INCREMENT VALUE => SLIDER
41 X: x offset, in pixels
42 Y: y offset, in pixels
43 WIDTH: width, in pixels
44 TEXT: string for the textual display
48 INCREMENT: increment when moving the slider
50 SLIDER: a slider that can later be rendered
54 SLIDER creates a button widget.
56 TODO: The rest of this description needs to be updated!"
58 :x x :y y :width width :text text :callback callback
59 :min min :max max :value value :increment increment :dragging nil))
61 (defun slider-bar-left (slider)
62 (with-slots (min max value width) slider
63 (+ 4 (if (and value min max (/= min max)) (floor (* (- width 12) (/ value (- max min)))) 0))))
65 (defun set-min (slider min)
66 (setf (slider-min slider) min))
68 (defun set-max (slider max)
69 (setf (slider-max slider) max))
71 (defun set-value (slider value)
72 (setf (slider-value slider) value))
74 (defun update-slider-value-from-click (slider x)
76 (< x (+ (slider-x slider) (slider-bar-left slider)))
77 (setf (slider-value slider) (max (slider-min slider) (- (slider-value slider) (slider-increment slider))))
78 (setf (slider-value slider) (min (slider-max slider) (+ (slider-value slider) (slider-increment slider))))))
80 (defun update-slider-value-from-move (slider m-x)
81 (with-slots (x width value min max increment) slider
84 (right (+ x width -8))
85 (portion-left (/ (- m-x left) (- right left)))
92 (* portion-left (- max min))
94 (when (/= value new-value)
95 (setf (slider-value slider) new-value)))))
97 (defun in-slider (m-x m-y slider)
98 (with-slots (x y width) slider
99 (and (< x m-x (+ x width)) (< y m-y (+ y *slider-height*)))))
101 (defun in-slider-handle (m-x m-y slider)
103 (in-slider-bar m-y slider)
105 ((left (+ (slider-x slider) (slider-bar-left slider))))
106 (< left m-x (+ left 6)))))
108 (defun in-slider-bar (m-y slider)
109 (with-slots (y) slider
110 (< (+ y 18) m-y (+ y 30))))
112 ; Uhm, this is currently just pulled from switch, and needs to be changed to slider looking stuffs
113 (defmethod render ((slider slider))
114 (gl:color 1f0 1f0 1f0)
115 (with-slots (x y width text min max value) slider
116 (gl:with-pushed-matrix
119 (gl:color 1f0 1f0 1f0)
121 (gl:vertex 3 26) (gl:vertex (- width 5) 26) (gl:vertex (- width 5) 24) (gl:vertex 3 24)
125 ((left (slider-bar-left slider)))
126 (gl:color 0f0 0f0 0f0)
128 (gl:vertex left 30) (gl:vertex (+ left 4) 30) (gl:vertex (+ left 4) 20) (gl:vertex left 20)
130 (gl:color 1f0 1f0 1f0)
131 (draw-border left 20 (+ left 4) 30))
133 (gl:color 1f0 1f0 1f0)
134 ;(gl:with-pushed-matrix (gl:translate 14 15 0) (font-print "On"))
135 ;(gl:with-pushed-matrix (gl:translate 14 1 0) (font-print "Off"))
137 (draw-border 0 0 width *slider-height*)
139 ; when the value is large enough, value takes precidence and clips off the text, then makes the text disappear
142 ; It also clips off text if too long, and replaces with elipses, so we can do similar
143 ; (this is true for slider and switch!)
144 ; - WE HAVEN"T DONE THIS YET
147 (if (< (* *font-width* (length text)) (- width 46))
149 (format nil "~A..." (subseq text 0 (- (truncate (- width 46) *font-width*) 3))))))
150 (gl:with-pushed-matrix
154 ; Technically netlogo does not clip numbers that are too large, and just draws what it can.
155 ; It's a rare edge case, but maybe we should have something to do with it
156 ; - WE HAVEN"T DONE THIS YET
158 ((value-text (format nil "~A" (or value 0))))
159 (gl:with-pushed-matrix
160 (gl:translate (- width 4 (* (length value-text) *font-width*)) 2 0)
161 (font-print value-text))))))
163 (defmethod reposition ((slider slider) x y)
164 (setf (slider-x slider) x)
165 (setf (slider-y slider) y))
167 (defmethod resize ((slider slider) width height)
168 (declare (ignore height))
169 (setf (slider-width slider) width))
171 (defmethod mousemove ((slider slider) m-x m-y)
173 (and (slider-dragging slider) (update-slider-value-from-move slider m-x))
174 (funcall (slider-callback slider) (slider-value slider))))
176 (defmethod mouseup ((slider slider) m-x m-y)
177 (when (slider-dragging slider)
178 (setf (slider-dragging slider) nil)
179 (funcall (slider-callback slider) (slider-value slider))))
181 (defmethod mousedown ((slider slider) m-x m-y)
183 ((not (in-slider m-x m-y slider)) nil)
184 ((in-slider-handle m-x m-y slider) (setf (slider-dragging slider) t))
186 ; Netlogo recognizes the click even if outside the bar horizontally
187 ((in-slider-bar m-y slider)
188 (update-slider-value-from-click slider m-x)
189 (funcall (slider-callback slider) (slider-value slider)))))