]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/menu/item/slider.qc
348addbb8984d1f7ba18fff6d54a5662051deed7
[xonotic/xonotic-data.pk3dir.git] / qcsrc / menu / item / slider.qc
1 #include "slider.qh"
2 // Note:
3 //   to use this, you FIRST call configureSliderVisuals, then configureSliderValues
4 #ifndef ITEM_SLIDER_H
5         #define ITEM_SLIDER_H
6         #include "label.qc"
7         CLASS(Slider, Label)
8                 METHOD(Slider, resizeNotify, void(entity, vector, vector, vector, vector));
9                 METHOD(Slider, configureSliderVisuals, void(entity, float, float, float, string));
10                 METHOD(Slider, configureSliderValues, void(entity, float, float, float, float, float, float));
11                 METHOD(Slider, draw, void(entity));
12                 METHOD(Slider, keyDown, float(entity, float, float, float));
13                 METHOD(Slider, keyUp, float(entity, float, float, float));
14                 METHOD(Slider, mousePress, float(entity, vector));
15                 METHOD(Slider, mouseDrag, float(entity, vector));
16                 METHOD(Slider, mouseRelease, float(entity, vector));
17                 METHOD(Slider, valueToText, string(entity, float));
18                 METHOD(Slider, toString, string(entity));
19                 METHOD(Slider, setValue_allowAnim, void(entity, float, bool));
20                 METHOD(Slider, setValue_noAnim, void(entity, float));
21                 METHOD(Slider, setValue, void(entity, float));
22                 METHOD(Slider, setSliderValue, void(entity, float));
23                 METHOD(Slider, showNotify, void(entity));
24                 ATTRIB(Slider, src, string, string_null)
25                 ATTRIB(Slider, focusable, float, 1)
26                 ATTRIB(Slider, allowFocusSound, float, 1)
27                 ATTRIB(Slider, value, float, 0)
28                 ATTRIB(Slider, animated, float, 1)
29                 ATTRIB(Slider, sliderValue, float, 0)
30                 ATTRIB(Slider, sliderAnim, entity, NULL)
31                 ATTRIB(Slider, valueMin, float, 0)
32                 ATTRIB(Slider, valueMax, float, 0)
33                 ATTRIB(Slider, valueStep, float, 0)
34                 ATTRIB(Slider, valueDigits, float, 0)
35                 ATTRIB(Slider, valueKeyStep, float, 0)
36                 ATTRIB(Slider, valuePageStep, float, 0)
37                 ATTRIB(Slider, valueDisplayMultiplier, float, 1.0)
38                 ATTRIB(Slider, textSpace, float, 0)
39                 ATTRIB(Slider, controlWidth, float, 0)
40                 ATTRIB(Slider, pressed, float, 0)
41                 ATTRIB(Slider, pressOffset, float, 0)
42                 ATTRIB(Slider, previousValue, float, 0)
43                 ATTRIB(Slider, tolerance, vector, '0 0 0')
44                 ATTRIB(Slider, disabled, float, 0)
45                 ATTRIB(Slider, color, vector, '1 1 1')
46                 ATTRIB(Slider, color2, vector, '1 1 1')
47                 ATTRIB(Slider, colorD, vector, '1 1 1')
48                 ATTRIB(Slider, colorC, vector, '1 1 1')
49                 ATTRIB(Slider, colorF, vector, '1 1 1')
50                 ATTRIB(Slider, disabledAlpha, float, 0.3)
51         ENDCLASS(Slider)
52 #endif
53
54 #ifdef IMPLEMENTATION
55         void Slider_setValue_allowAnim(entity me, float val, bool allowAnim)
56         {
57                 if (allowAnim && me.animated)
58                 {
59                         float t = 0.5;
60                         if (!me.sliderAnim) me.sliderAnim = makeHostedEasing(me, Slider_setSliderValue, easingQuadOut, t, me.sliderValue, val);
61                         else me.sliderAnim.update(me.sliderAnim, t, me.sliderValue, val);
62                 }
63                 else
64                 {
65                         me.setSliderValue(me, val);
66                 }
67                 me.value = val;
68         }
69         void Slider_setValue_noAnim(entity me, float val)
70         {
71                 Slider_setValue_allowAnim(me, val, false);
72         }
73         void Slider_setValue(entity me, float val)
74         {
75                 Slider_setValue_allowAnim(me, val, true);
76         }
77         void Slider_setSliderValue(entity me, float val)
78         {
79                 me.sliderValue = val;
80         }
81         string Slider_toString(entity me)
82         {
83                 return sprintf("%d (%s)", me.value, me.valueToText(me, me.value));
84         }
85         void Slider_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
86         {
87                 SUPER(Slider).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
88                 me.controlWidth = absSize.x == 0 ? 0 : (absSize.y / absSize.x);
89         }
90         string Slider_valueToText(entity me, float val)
91         {
92                 if (almost_in_bounds(me.valueMin, val, me.valueMax)) return ftos_decimals(val * me.valueDisplayMultiplier, me.valueDigits);
93                 return "";
94         }
95         void Slider_configureSliderVisuals(entity me, float sz, float theAlign, float theTextSpace, string gfx)
96         {
97                 SUPER(Slider).configureLabel(me, string_null, sz, theAlign);
98                 me.textSpace = theTextSpace;
99                 me.keepspaceLeft = (theTextSpace == 0) ? 0 : (1 - theTextSpace);
100                 me.src = gfx;
101         }
102         void Slider_configureSliderValues(entity me, float theValueMin, float theValue, float theValueMax, float theValueStep, float theValueKeyStep, float theValuePageStep)
103         {
104                 me.value = theValue;
105                 me.sliderValue = theValue;
106                 me.valueStep = theValueStep;
107                 me.valueMin = theValueMin;
108                 me.valueMax = theValueMax;
109                 me.valueKeyStep = theValueKeyStep;
110                 me.valuePageStep = theValuePageStep;
111                 me.valueDigits = 3;
112                 if (fabs(floor(me.valueStep * 100 + 0.5) - (me.valueStep * 100)) < 0.01) // about a whole number of 100ths
113                         me.valueDigits = 2;
114                 if (fabs(floor(me.valueStep * 10 + 0.5) - (me.valueStep * 10)) < 0.01)   // about a whole number of 10ths
115                         me.valueDigits = 1;
116                 if (fabs(floor(me.valueStep * 1 + 0.5) - (me.valueStep * 1)) < 0.01)     // about a whole number
117                         me.valueDigits = 0;
118         }
119         float Slider_keyDown(entity me, float key, float ascii, float shift)
120         {
121                 float inRange;
122                 float ret_value = 0;
123                 if (me.disabled) return 0;
124                 inRange = (almost_in_bounds(me.valueMin, me.value, me.valueMax));
125                 if (key == K_LEFTARROW || key == K_KP_LEFTARROW || key == K_MWHEELDOWN)
126                 {
127                         if (inRange) me.setValue(me, median(me.valueMin, me.value - me.valueKeyStep, me.valueMax));
128                         else me.setValue(me, me.valueMax);
129                         ret_value = 1;
130                 }
131                 if (key == K_RIGHTARROW || key == K_KP_RIGHTARROW || key == K_MWHEELUP)
132                 {
133                         if (inRange) me.setValue(me, median(me.valueMin, me.value + me.valueKeyStep, me.valueMax));
134                         else me.setValue(me, me.valueMin);
135                         ret_value = 1;
136                 }
137                 if (key == K_PGDN || key == K_KP_PGDN)
138                 {
139                         if (inRange) me.setValue(me, median(me.valueMin, me.value - me.valuePageStep, me.valueMax));
140                         else me.setValue(me, me.valueMax);
141                         ret_value = 1;
142                 }
143                 if (key == K_PGUP || key == K_KP_PGUP)
144                 {
145                         if (inRange) me.setValue(me, median(me.valueMin, me.value + me.valuePageStep, me.valueMax));
146                         else me.setValue(me, me.valueMin);
147                         ret_value = 1;
148                 }
149                 if (key == K_HOME || key == K_KP_HOME)
150                 {
151                         me.setValue(me, me.valueMin);
152                         ret_value = 1;
153                 }
154                 if (key == K_END || key == K_KP_END)
155                 {
156                         me.setValue(me, me.valueMax);
157                         ret_value = 1;
158                 }
159                 if(ret_value == 1)
160                 {
161                         if(me.applyButton)
162                                 me.applyButton.disabled = false;
163                         return 1;
164                 }
165                 // TODO more keys (NOTE also add them to Slider_keyUp)
166                 return 0;
167         }
168         float Slider_keyUp(entity me, float key, float ascii, float shift)
169         {
170                 if (me.disabled) return 0;
171                 switch (key)
172                 {
173                         case K_LEFTARROW:
174                         case K_KP_LEFTARROW:
175                         case K_RIGHTARROW:
176                         case K_KP_RIGHTARROW:
177                         case K_PGUP:
178                         case K_KP_PGUP:
179                         case K_PGDN:
180                         case K_KP_PGDN:
181                         case K_HOME:
182                         case K_KP_HOME:
183                         case K_END:
184                         case K_KP_END:
185                                 m_play_click_sound(MENU_SOUND_SLIDE);
186                 }
187                 return 0;
188         }
189         float Slider_mouseDrag(entity me, vector pos)
190         {
191                 float hit;
192                 float v;
193                 if (me.disabled) return 0;
194
195                 if (me.pressed)
196                 {
197                         hit = 1;
198                         if (pos.x < 0 - me.tolerance.x) hit = 0;
199                         if (pos.y < 0 - me.tolerance.y) hit = 0;
200                         if (pos.x >= 1 - me.textSpace + me.tolerance.x) hit = 0;
201                         if (pos.y >= 1 + me.tolerance.y) hit = 0;
202                         if (hit)
203                         {
204                                 // handle dragging
205                                 me.pressed = 2;
206
207                                 v = median(0, (pos.x - me.pressOffset - 0.5 * me.controlWidth) / (1 - me.textSpace - me.controlWidth), 1) * (me.valueMax - me.valueMin) + me.valueMin;
208                                 if (me.valueStep) v = floor(0.5 + v / me.valueStep) * me.valueStep;
209                                 me.setValue_noAnim(me, v);
210                                 if(me.applyButton)
211                                 if(me.previousValue != me.value)
212                                         me.applyButton.disabled = false;
213                         }
214                         else
215                         {
216                                 me.setValue(me, me.previousValue);
217                         }
218                 }
219
220                 return 1;
221         }
222         float Slider_mousePress(entity me, vector pos)
223         {
224                 float controlCenter;
225                 if (me.disabled) return 0;
226                 if (pos.x < 0) return 0;
227                 if (pos.y < 0) return 0;
228                 if (pos.x >= 1 - me.textSpace) return 0;
229                 if (pos.y >= 1) return 0;
230                 controlCenter = (me.value - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth) + 0.5 * me.controlWidth;
231                 if (fabs(pos.x - controlCenter) <= 0.5 * me.controlWidth)
232                 {
233                         me.pressed = 1;
234                         me.pressOffset = pos.x - controlCenter;
235                         me.previousValue = me.value;
236                         // me.mouseDrag(me, pos);
237                 }
238                 else
239                 {
240                         float clickValue, pageValue, inRange;
241                         clickValue = median(0, (pos.x - me.pressOffset - 0.5 * me.controlWidth) / (1 - me.textSpace - me.controlWidth), 1) * (me.valueMax - me.valueMin) + me.valueMin;
242                         inRange = (almost_in_bounds(me.valueMin, me.value, me.valueMax));
243                         if (pos.x < controlCenter)
244                         {
245                                 pageValue = me.value - me.valuePageStep;
246                                 if (me.valueStep) clickValue = floor(clickValue / me.valueStep) * me.valueStep;
247                                 pageValue = max(pageValue, clickValue);
248                         }
249                         else
250                         {
251                                 pageValue = me.value + me.valuePageStep;
252                                 if (me.valueStep) clickValue = ceil(clickValue / me.valueStep) * me.valueStep;
253                                 pageValue = min(pageValue, clickValue);
254                         }
255                         if (inRange) me.setValue(me, median(me.valueMin, pageValue, me.valueMax));
256                         else me.setValue(me, me.valueMax);
257                         if(me.applyButton)
258                                 me.applyButton.disabled = false;
259                         if (pageValue == clickValue)
260                         {
261                                 controlCenter = (me.value - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth) + 0.5 * me.controlWidth;
262                                 me.pressed = 1;
263                                 me.pressOffset = pos.x - controlCenter;
264                                 me.previousValue = me.value;
265                                 // me.mouseDrag(me, pos);
266                         }
267                 }
268                 return 1;
269         }
270         float Slider_mouseRelease(entity me, vector pos)
271         {
272                 me.pressed = 0;
273                 if (me.disabled) return 0;
274                 m_play_click_sound(MENU_SOUND_SLIDE);
275                 return 1;
276         }
277         void Slider_showNotify(entity me)
278         {
279                 me.focusable = !me.disabled;
280         }
281         void Slider_draw(entity me)
282         {
283                 float controlLeft;
284                 float save;
285                 me.focusable = !me.disabled;
286                 save = draw_alpha;
287                 if (me.disabled) draw_alpha *= me.disabledAlpha;
288                 draw_ButtonPicture('0 0 0', strcat(me.src, "_s"), eX * (1 - me.textSpace) + eY, me.color2, 1);
289                 if (me.valueMax > me.valueMin) // valid?
290                 if (almost_in_bounds(me.valueMin, me.sliderValue, me.valueMax))
291                 {
292                         controlLeft = (me.sliderValue - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth);
293                         if (me.disabled) draw_Picture(eX * controlLeft, strcat(me.src, "_d"), eX * me.controlWidth + eY, me.colorD, 1);
294                         else if (me.pressed) draw_Picture(eX * controlLeft, strcat(me.src, "_c"), eX * me.controlWidth + eY, me.colorC, 1);
295                         else if (me.focused) draw_Picture(eX * controlLeft, strcat(me.src, "_f"), eX * me.controlWidth + eY, me.colorF, 1);
296                         else draw_Picture(eX * controlLeft, strcat(me.src, "_n"), eX * me.controlWidth + eY, me.color, 1);
297                 }
298
299                 if (me.sliderAnim)
300                         if (me.sliderAnim.isFinished(me.sliderAnim))
301                         {
302                                 anim.removeObjAnim(anim, me);
303                                 me.sliderAnim = NULL;
304                         }
305
306                 if (me.valueMax > me.valueMin) // valid?
307                         me.setText(me, me.valueToText(me, me.value));
308                 draw_alpha = save;
309                 SUPER(Slider).draw(me);
310                 me.text = string_null;  // TEMPSTRING!
311         }
312 #endif