Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
slider.qc
Go to the documentation of this file.
1#include "slider.qh"
2
3#include "../anim/easing.qh"
4#include "../anim/animhost.qh"
5
6string formatStringSpecial(string formatStr, float value, int decs)
7{
8 /* .formatString is usually in the format of "%sx" to print "2" as "2x".
9 * Special options:
10 * "%": apply ftos_decimals_percentage
11 * Any of "smhdwy": apply time-counting functions
12 * Any of "SMHDWY": apply time-counting functions, allowing decimals
13 */
14 if (strlen(formatStr) == 1)
15 switch (formatStr)
16 {
17 case "%": return ftos_decimals_percentage(value, max(0, decs - 2));
18 case "s": return count_seconds(value);
19 case "m": return count_minutes(value);
20 case "h": return count_hours(value);
21 case "d": return count_days(value);
22 case "w": return count_weeks(value);
23 case "y": return count_years(value);
24 case "S": return count_seconds_decs(value, decs);
25 case "M": return count_minutes_decs(value, decs);
26 case "H": return count_hours_decs(value, decs);
27 case "D": return count_days_decs(value, decs);
28 case "W": return count_weeks_decs(value, decs);
29 case "Y": return count_years_decs(value, decs);
30 default: break;
31 }
32 const string txt = ftos_decimals(value, decs);
33 if (formatStr != "")
34 return sprintf(formatStr, txt);
35 return txt;
36}
37
39
40 void Slider_setValue(entity me, float val, bool allowAnim)
41 {
42 if (allowAnim && me.animated)
43 {
44 const float t = me.pressed ? autocvar_menu_animations * 0.5 : autocvar_menu_animations;
45 if (!me.sliderAnim)
46 me.sliderAnim = makeHostedEasing(me, Slider_setSliderValue, easingQuadOut, t, me.sliderValue, val);
47 else
48 me.sliderAnim.update(me.sliderAnim, t, me.sliderValue, val);
49 }
50 else
51 {
52 me.setSliderValue(me, val);
53 }
54 me.value = val;
55 }
56 void Slider_setSliderValue(entity me, float val)
57 {
58 me.sliderValue = val;
59 }
61 {
62 return sprintf("%d (%s)", me.value, me.valueToText(me, me.value));
63 }
64 void Slider_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
65 {
66 SUPER(Slider).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
67 me.controlWidth = absSize.x == 0 ? 0 : (absSize.y / absSize.x);
68 }
69 string Slider_valueToText(entity me, float val)
70 {
71 if (!almost_in_bounds(me.valueMin, val, me.valueMax))
72 return "";
73 val *= me.valueDisplayMultiplier;
74 return formatStringSpecial(me.formatString, val, me.valueDigits);
75 }
76 void Slider_configureSliderVisuals(entity me, float sz, float theAlign, float theValueSpace, string gfx)
77 {
78 SUPER(Slider).configureLabel(me, string_null, sz, theAlign);
79 me.valueSpace = bound(0, theValueSpace, 1);
80 me.keepspaceLeft = 1 - me.valueSpace;
81 me.src = gfx;
82 }
83 void Slider_configureSliderValues(entity me, float theValueMin, float theValue, float theValueMax, float theValueStep, float theValueKeyStep, float theValuePageStep)
84 {
85 me.value = theValue;
86 me.sliderValue = theValue;
87 me.valueStep = theValueStep;
88 me.valueMin = theValueMin;
89 me.valueMax = theValueMax;
90 me.valueKeyStep = theValueKeyStep;
91 me.valuePageStep = theValuePageStep;
92 me.valueDigits = 3;
93 if (fabs(floor(me.valueStep * 100 + 0.5) - (me.valueStep * 100)) < 0.01) // about a whole number of 100ths
94 me.valueDigits = 2;
95 if (fabs(floor(me.valueStep * 10 + 0.5) - (me.valueStep * 10)) < 0.01) // about a whole number of 10ths
96 me.valueDigits = 1;
97 if (fabs(floor(me.valueStep * 1 + 0.5) - (me.valueStep * 1)) < 0.01) // about a whole number
98 me.valueDigits = 0;
99 }
100 float Slider_keyDown(entity me, float key, float ascii, float shift)
101 {
102 if (me.disabled) return 0;
103 const float inRange = almost_in_bounds(me.valueMin, me.value, me.valueMax);
104 float ret_value = 0;
105 if (key == K_HOME || key == K_KP_HOME
106 || ((shift & S_CTRL) && (key == K_PGDN || key == K_KP_PGDN)))
107 {
108 me.setValue(me, me.valueMin, autocvar_menu_animations > 0);
109 ret_value = 1;
110 }
111 else if (key == K_PGDN || key == K_KP_PGDN || ascii == '-'
112 || key == K_LEFTARROW || key == K_KP_LEFTARROW || key == K_MWHEELDOWN)
113 {
114 if (inRange) me.setValue(me, median(me.valueMin, me.value - me.valuePageStep, me.valueMax), autocvar_menu_animations > 0);
115 else me.setValue(me, me.valueMax, autocvar_menu_animations > 0);
116 ret_value = 1;
117 }
118 else if (key == K_END || key == K_KP_END
119 || ((shift & S_CTRL) && (key == K_PGUP || key == K_KP_PGUP)))
120 {
121 me.setValue(me, me.valueMax, autocvar_menu_animations > 0);
122 ret_value = 1;
123 }
124 else if (key == K_PGUP || key == K_KP_PGUP || ascii == '+'
125 || key == K_RIGHTARROW || key == K_KP_RIGHTARROW || key == K_MWHEELUP)
126 {
127 if (inRange) me.setValue(me, median(me.valueMin, me.value + me.valuePageStep, me.valueMax), autocvar_menu_animations > 0);
128 else me.setValue(me, me.valueMin, autocvar_menu_animations > 0);
129 ret_value = 1;
130 }
131 if(ret_value == 1)
132 if(me.applyButton)
133 me.applyButton.disabled = false;
134 // TODO more keys (NOTE also add them to Slider_keyUp)
135 return ret_value;
136 }
137 float Slider_keyUp(entity me, float key, float ascii, float shift)
138 {
139 if (me.disabled) return 0;
140 switch (key)
141 {
142 case K_LEFTARROW:
143 case K_KP_LEFTARROW:
144 case K_RIGHTARROW:
145 case K_KP_RIGHTARROW:
146 case K_PGUP:
147 case K_KP_PGUP:
148 case K_PGDN:
149 case K_KP_PGDN:
150 case K_HOME:
151 case K_KP_HOME:
152 case K_END:
153 case K_KP_END:
155 }
156 return 0;
157 }
159 {
160 float hit;
161 float v;
162 if (me.disabled) return 0;
163
164 if (me.pressed)
165 {
166 hit = 1;
167 if (pos.x < 0 - me.tolerance.x) hit = 0;
168 if (pos.y < 0 - me.tolerance.y) hit = 0;
169 if (pos.x >= 1 - me.valueSpace + me.tolerance.x) hit = 0;
170 if (pos.y >= 1 + me.tolerance.y) hit = 0;
171 if (hit)
172 {
173 // handle dragging
174 me.pressed = 2;
175
176 float f = bound(0, (pos.x - me.pressOffset - 0.5 * me.controlWidth) / (1 - me.valueSpace - me.controlWidth), 1);
177 v = f * (me.valueMax - me.valueMin) + me.valueMin;
178 // there's no need to round min and max value... also if we did, v could be set
179 // to an out of bounds value due to precision errors
180 if (f > 0 && f < 1 && me.valueStep)
181 v = floor(0.5 + v / me.valueStep) * me.valueStep;
182 me.setValue(me, v, autocvar_menu_animations > 0);
183 if(me.applyButton)
184 if(me.previousValue != me.value)
185 me.applyButton.disabled = false;
186 }
187 else
188 {
189 me.setValue(me, me.previousValue, autocvar_menu_animations > 0);
190 }
191 }
192
193 return 1;
194 }
196 {
197 float controlCenter;
198 if (this.disabled) return false;
199 if (pos.x < 0) return false;
200 if (pos.y < 0) return false;
201 if (pos.x >= 1 - this.valueSpace) return false;
202 if (pos.y >= 1) return false;
203 controlCenter = (this.value - this.valueMin) / (this.valueMax - this.valueMin) * (1 - this.valueSpace - this.controlWidth) + 0.5 * this.controlWidth;
204 if (fabs(pos.x - controlCenter) <= 0.5 * this.controlWidth)
205 {
206 this.pressed = 1;
207 this.pressOffset = pos.x - controlCenter;
208 this.previousValue = this.value;
209 // this.mouseDrag(this, pos);
210 }
211 else
212 {
213 float clickValue, pageValue, inRange;
214 clickValue = median(0, (pos.x - this.pressOffset - 0.5 * this.controlWidth) / (1 - this.valueSpace - this.controlWidth), 1) * (this.valueMax - this.valueMin) + this.valueMin;
215 inRange = (almost_in_bounds(this.valueMin, this.value, this.valueMax));
216 if (pos.x < controlCenter)
217 {
218 pageValue = this.value - this.valuePageStep;
219 if (this.valueStep) clickValue = floor(clickValue / this.valueStep) * this.valueStep;
220 pageValue = max(pageValue, clickValue);
221 }
222 else
223 {
224 pageValue = this.value + this.valuePageStep;
225 if (this.valueStep) clickValue = ceil(clickValue / this.valueStep) * this.valueStep;
226 pageValue = min(pageValue, clickValue);
227 }
228 if (inRange) this.setValue(this, median(this.valueMin, pageValue, this.valueMax), autocvar_menu_animations > 0);
229 else this.setValue(this, this.valueMax, autocvar_menu_animations > 0);
230 if(this.applyButton)
231 this.applyButton.disabled = false;
232 if (pageValue == clickValue)
233 {
234 controlCenter = (this.value - this.valueMin) / (this.valueMax - this.valueMin) * (1 - this.valueSpace - this.controlWidth) + 0.5 * this.controlWidth;
235 this.pressed = 1;
236 this.pressOffset = pos.x - controlCenter;
237 this.previousValue = this.value;
238 // this.mouseDrag(this, pos);
239 }
240 }
241 return true;
242 }
244 {
245 me.pressed = 0;
246 if (me.disabled) return 0;
248 return 1;
249 }
251 {
252 me.focusable = !me.disabled;
253 }
255 {
256 float controlLeft;
257 float save;
258 me.focusable = !me.disabled;
259 save = draw_alpha;
260 if (me.disabled) draw_alpha *= me.disabledAlpha;
261 draw_ButtonPicture('0 0 0', strcat(me.src, "_s"), eX * (1 - me.valueSpace) + eY, me.color2, 1);
262 if (me.valueMax > me.valueMin) // valid?
263 if (almost_in_bounds(me.valueMin, me.sliderValue, me.valueMax))
264 {
265 controlLeft = (me.sliderValue - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.valueSpace - me.controlWidth);
266 if (me.disabled) draw_Picture(eX * controlLeft, strcat(me.src, "_d"), eX * me.controlWidth + eY, me.colorD, 1);
267 else if (me.pressed) draw_Picture(eX * controlLeft, strcat(me.src, "_c"), eX * me.controlWidth + eY, me.colorC, 1);
268 else if (me.focused) draw_Picture(eX * controlLeft, strcat(me.src, "_f"), eX * me.controlWidth + eY, me.colorF, 1);
269 else draw_Picture(eX * controlLeft, strcat(me.src, "_n"), eX * me.controlWidth + eY, me.color, 1);
270 }
271
272 if (me.sliderAnim)
273 if (me.sliderAnim.finished)
274 {
275 anim.removeObjAnim(anim, me);
276 me.sliderAnim = NULL;
277 }
278
279 if (me.valueMax > me.valueMin) // valid?
280 me.setText(me, me.valueToText(me, me.value));
281 draw_alpha = save;
282 if (me.valueSpace > 0)
283 {
284 SUPER(Slider).draw(me);
285 }
286 me.text = string_null; // TEMPSTRING!
287 }
float autocvar_menu_animations
Definition animation.qh:3
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
float disabled
Definition slider.qh:43
float controlWidth
Definition slider.qh:38
float pressOffset
Definition slider.qh:40
virtual void setValue()
float valueStep
Definition slider.qh:31
float valueMax
Definition slider.qh:30
float valueSpace
Definition slider.qh:37
virtual void mousePress()
Definition slider.qc:195
float previousValue
Definition slider.qh:41
float pressed
Definition slider.qh:39
float valuePageStep
Definition slider.qh:34
float valueMin
Definition slider.qh:29
float value
Definition slider.qh:25
#define count_minutes_decs(time, decs)
Definition counting.qh:46
#define count_days_decs(time, decs)
Definition counting.qh:27
#define count_weeks(time)
Definition counting.qh:19
#define count_hours(time)
Definition counting.qh:37
#define count_years_decs(time, decs)
Definition counting.qh:9
#define count_days(time)
Definition counting.qh:28
#define count_weeks_decs(time, decs)
Definition counting.qh:18
#define count_seconds_decs(time, decs)
Definition counting.qh:55
#define count_years(time)
Definition counting.qh:10
#define count_seconds(time)
Definition counting.qh:56
#define count_hours_decs(time, decs)
Definition counting.qh:36
#define count_minutes(time)
Definition counting.qh:47
#define strlen
entity makeHostedEasing(entity obj, void(entity, float) objSetter, float(float, float, float, float) func, float animDuration, float animStartValue, float animEnd)
Definition easing.qc:6
float easingQuadOut(float tickTime, float animDuration, float animStart, float animDelta)
Definition easing.qc:42
const int S_CTRL
Definition hud.qh:130
float Slider_keyDown(entity me, float key, float ascii, float shift)
Definition slider.qc:100
void Slider_showNotify(entity me)
Definition slider.qc:250
float Slider_mouseDrag(entity me, vector pos)
Definition slider.qc:158
void Slider_setValue(entity me, float val, bool allowAnim)
Definition slider.qc:40
void Slider_setSliderValue(entity me, float val)
Definition slider.qc:56
string Slider_valueToText(entity me, float val)
Definition slider.qc:69
entity applyButton
Definition slider.qc:38
float Slider_mouseRelease(entity me, vector pos)
Definition slider.qc:243
string formatStringSpecial(string formatStr, float value, int decs)
Definition slider.qc:6
void Slider_configureSliderVisuals(entity me, float sz, float theAlign, float theValueSpace, string gfx)
Definition slider.qc:76
void Slider_configureSliderValues(entity me, float theValueMin, float theValue, float theValueMax, float theValueStep, float theValueKeyStep, float theValuePageStep)
Definition slider.qc:83
string Slider_toString(entity me)
Definition slider.qc:60
float Slider_keyUp(entity me, float key, float ascii, float shift)
Definition slider.qc:137
void Slider_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
Definition slider.qc:64
void Slider_draw(entity me)
Definition slider.qc:254
float K_KP_RIGHTARROW
Definition keycodes.qc:60
float K_PGDN
Definition keycodes.qc:39
float K_MWHEELDOWN
Definition keycodes.qc:133
float K_RIGHTARROW
Definition keycodes.qc:18
float K_PGUP
Definition keycodes.qc:40
float K_KP_LEFTARROW
Definition keycodes.qc:57
float K_KP_HOME
Definition keycodes.qc:62
float K_LEFTARROW
Definition keycodes.qc:17
float K_HOME
Definition keycodes.qc:41
float K_END
Definition keycodes.qc:42
float K_KP_PGDN
Definition keycodes.qc:55
float K_KP_PGUP
Definition keycodes.qc:66
float K_KP_END
Definition keycodes.qc:51
float K_MWHEELUP
Definition keycodes.qc:132
ERASEABLE float median(float a, float b, float c)
Definition math.qh:213
ERASEABLE float almost_in_bounds(float a, float b, float c)
Definition math.qh:233
void draw_Picture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha)
Definition draw.qc:72
void draw_ButtonPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha)
Definition draw.qc:108
float draw_alpha
Definition draw.qh:9
void m_play_click_sound(string soundfile)
Definition menu.qc:1106
const string MENU_SOUND_SLIDE
Definition menu.qh:55
entity anim
Definition menu.qh:25
float ceil(float f)
float bound(float min, float value, float max)
float min(float f,...)
float fabs(float f)
float floor(float f)
float max(float f,...)
string string_null
Definition nil.qh:9
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
#define SUPER(cname)
Definition oo.qh:231
#define METHOD(cname, name, prototype)
Definition oo.qh:269
#define NULL
Definition post.qh:14
vector
Definition self.qh:92
ERASEABLE string ftos_decimals(float number, int decimals)
converts a number to a string with the indicated number of decimals
Definition string.qh:469
ERASEABLE string ftos_decimals_percentage(float number, int decimals)
converts a percentage to a string with the indicated number of decimals
Definition string.qh:480
const vector eY
Definition vector.qh:45
const vector eX
Definition vector.qh:44