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