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