]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/menu/item/slider.qc
Increase Hagar and Crylink damage
[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                 if (me.disabled) return 0;
122                 inRange = (almost_in_bounds(me.valueMin, me.value, me.valueMax));
123                 if (key == K_LEFTARROW || key == K_KP_LEFTARROW || key == K_MWHEELDOWN)
124                 {
125                         if (inRange) me.setValue(me, median(me.valueMin, me.value - me.valueKeyStep, me.valueMax));
126                         else me.setValue(me, me.valueMax);
127                         return 1;
128                 }
129                 if (key == K_RIGHTARROW || key == K_KP_RIGHTARROW || key == K_MWHEELUP)
130                 {
131                         if (inRange) me.setValue(me, median(me.valueMin, me.value + me.valueKeyStep, me.valueMax));
132                         else me.setValue(me, me.valueMin);
133                         return 1;
134                 }
135                 if (key == K_PGDN || key == K_KP_PGDN)
136                 {
137                         if (inRange) me.setValue(me, median(me.valueMin, me.value - me.valuePageStep, me.valueMax));
138                         else me.setValue(me, me.valueMax);
139                         return 1;
140                 }
141                 if (key == K_PGUP || key == K_KP_PGUP)
142                 {
143                         if (inRange) me.setValue(me, median(me.valueMin, me.value + me.valuePageStep, me.valueMax));
144                         else me.setValue(me, me.valueMin);
145                         return 1;
146                 }
147                 if (key == K_HOME || key == K_KP_HOME)
148                 {
149                         me.setValue(me, me.valueMin);
150                         return 1;
151                 }
152                 if (key == K_END || key == K_KP_END)
153                 {
154                         me.setValue(me, me.valueMax);
155                         return 1;
156                 }
157                 // TODO more keys (NOTE also add them to Slider_keyUp)
158                 return 0;
159         }
160         float Slider_keyUp(entity me, float key, float ascii, float shift)
161         {
162                 if (me.disabled) return 0;
163                 switch (key)
164                 {
165                         case K_LEFTARROW:
166                         case K_KP_LEFTARROW:
167                         case K_RIGHTARROW:
168                         case K_KP_RIGHTARROW:
169                         case K_PGUP:
170                         case K_KP_PGUP:
171                         case K_PGDN:
172                         case K_KP_PGDN:
173                         case K_HOME:
174                         case K_KP_HOME:
175                         case K_END:
176                         case K_KP_END:
177                                 m_play_click_sound(MENU_SOUND_SLIDE);
178                 }
179                 return 0;
180         }
181         float Slider_mouseDrag(entity me, vector pos)
182         {
183                 float hit;
184                 float v;
185                 if (me.disabled) return 0;
186
187                 if (me.pressed)
188                 {
189                         hit = 1;
190                         if (pos.x < 0 - me.tolerance.x) hit = 0;
191                         if (pos.y < 0 - me.tolerance.y) hit = 0;
192                         if (pos.x >= 1 - me.textSpace + me.tolerance.x) hit = 0;
193                         if (pos.y >= 1 + me.tolerance.y) hit = 0;
194                         if (hit)
195                         {
196                                 // handle dragging
197                                 me.pressed = 2;
198
199                                 v = median(0, (pos.x - me.pressOffset - 0.5 * me.controlWidth) / (1 - me.textSpace - me.controlWidth), 1) * (me.valueMax - me.valueMin) + me.valueMin;
200                                 if (me.valueStep) v = floor(0.5 + v / me.valueStep) * me.valueStep;
201                                 me.setValue_noAnim(me, v);
202                         }
203                         else
204                         {
205                                 me.setValue(me, me.previousValue);
206                         }
207                 }
208
209                 return 1;
210         }
211         float Slider_mousePress(entity me, vector pos)
212         {
213                 float controlCenter;
214                 if (me.disabled) 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) clickValue = floor(clickValue / me.valueStep) * me.valueStep;
236                                 pageValue = max(pageValue, clickValue);
237                                 if (inRange) me.setValue(me, median(me.valueMin, pageValue, me.valueMax));
238                                 else me.setValue(me, me.valueMax);
239                         }
240                         else
241                         {
242                                 pageValue = me.value + me.valuePageStep;
243                                 if (me.valueStep) clickValue = ceil(clickValue / me.valueStep) * me.valueStep;
244                                 pageValue = min(pageValue, clickValue);
245                                 if (inRange) me.setValue(me, median(me.valueMin, pageValue, me.valueMax));
246                                 else me.setValue(me, me.valueMax);
247                         }
248                         if (pageValue == clickValue)
249                         {
250                                 controlCenter = (me.value - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth) + 0.5 * me.controlWidth;
251                                 me.pressed = 1;
252                                 me.pressOffset = pos.x - controlCenter;
253                                 me.previousValue = me.value;
254                                 // me.mouseDrag(me, pos);
255                         }
256                 }
257                 return 1;
258         }
259         float Slider_mouseRelease(entity me, vector pos)
260         {
261                 me.pressed = 0;
262                 if (me.disabled) return 0;
263                 m_play_click_sound(MENU_SOUND_SLIDE);
264                 return 1;
265         }
266         void Slider_showNotify(entity me)
267         {
268                 me.focusable = !me.disabled;
269         }
270         void Slider_draw(entity me)
271         {
272                 float controlLeft;
273                 float save;
274                 me.focusable = !me.disabled;
275                 save = draw_alpha;
276                 if (me.disabled) draw_alpha *= me.disabledAlpha;
277                 draw_ButtonPicture('0 0 0', strcat(me.src, "_s"), eX * (1 - me.textSpace) + eY, me.color2, 1);
278                 if (me.valueMax > me.valueMin) // valid?
279                 if (almost_in_bounds(me.valueMin, me.sliderValue, me.valueMax))
280                 {
281                         controlLeft = (me.sliderValue - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth);
282                         if (me.disabled) draw_Picture(eX * controlLeft, strcat(me.src, "_d"), eX * me.controlWidth + eY, me.colorD, 1);
283                         else if (me.pressed) draw_Picture(eX * controlLeft, strcat(me.src, "_c"), eX * me.controlWidth + eY, me.colorC, 1);
284                         else if (me.focused) draw_Picture(eX * controlLeft, strcat(me.src, "_f"), eX * me.controlWidth + eY, me.colorF, 1);
285                         else draw_Picture(eX * controlLeft, strcat(me.src, "_n"), eX * me.controlWidth + eY, me.color, 1);
286                 }
287
288                 if (me.sliderAnim)
289                         if (me.sliderAnim.isFinished(me.sliderAnim))
290                         {
291                                 anim.removeObjAnim(anim, me);
292                                 me.sliderAnim = NULL;
293                         }
294
295                 if (me.valueMax > me.valueMin) // valid?
296                         me.setText(me, me.valueToText(me, me.value));
297                 draw_alpha = save;
298                 SUPER(Slider).draw(me);
299                 me.text = string_null;  // TEMPSTRING!
300         }
301 #endif