Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
listbox.qc File Reference
#include "listbox.qh"
Include dependency graph for listbox.qc:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

 AUTOCVAR (menu_scroll_averaging_time, float, 0.16, "smooth scroll averaging time")
 AUTOCVAR (menu_scroll_averaging_time_pressed, float, 0.06, "smooth scroll averaging time when dragging the scrollbar")
void ListBox_clickListBoxItem (entity me, float i, vector where)
void ListBox_configureListBox (entity me, float theScrollbarWidth, float theItemHeight)
void ListBox_doubleClickListBoxItem (entity me, float i, vector where)
void ListBox_draw (entity me)
void ListBox_drawListBoxItem (entity me, int i, vector absSize, bool isSelected, bool isFocused)
void ListBox_focusedItemChangeNotify (entity me)
void ListBox_focusLeave (entity me)
float ListBox_getFirstFullyVisibleItemAtScrollPos (entity me, float pos)
float ListBox_getItemAtPos (entity me, float pos)
float ListBox_getItemHeight (entity me, float i)
float ListBox_getItemStart (entity me, float i)
float ListBox_getLastFullyVisibleItemAtScrollPos (entity me, float pos)
float ListBox_getTotalHeight (entity me)
bool ListBox_isScrolling (entity me)
float ListBox_keyDown (entity me, float key, float ascii, float shift)
float ListBox_mouseDrag (entity me, vector pos)
float ListBox_mouseMove (entity me, vector pos)
float ListBox_mouseRelease (entity me, vector pos)
void ListBox_resizeNotify (entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
void ListBox_scrollToItem (entity me, int i)
void ListBox_setFocusedItem (entity me, int item)
void ListBox_setSelected (entity me, float i)
void ListBox_updateControlTopBottom (entity me)

Function Documentation

◆ AUTOCVAR() [1/2]

AUTOCVAR ( menu_scroll_averaging_time ,
float ,
0. 16,
"smooth scroll averaging time"  )

◆ AUTOCVAR() [2/2]

AUTOCVAR ( menu_scroll_averaging_time_pressed ,
float ,
0. 06,
"smooth scroll averaging time when dragging the scrollbar"  )

◆ ListBox_clickListBoxItem()

void ListBox_clickListBoxItem ( entity me,
float i,
vector where )

Definition at line 401 of file listbox.qc.

402 {
403 // template method
404 }

References entity(), and vector.

◆ ListBox_configureListBox()

void ListBox_configureListBox ( entity me,
float theScrollbarWidth,
float theItemHeight )

Definition at line 46 of file listbox.qc.

47 {
48 me.scrollbarWidth = theScrollbarWidth;
49 me.itemHeight = theItemHeight;
50 }

References entity().

◆ ListBox_doubleClickListBoxItem()

void ListBox_doubleClickListBoxItem ( entity me,
float i,
vector where )

Definition at line 406 of file listbox.qc.

407 {
408 // template method
409 }

References entity(), and vector.

◆ ListBox_draw()

void ListBox_draw ( entity me)

Definition at line 336 of file listbox.qc.

337 {
338 vector fillSize = '0 0 0';
339
340 // we can't do this in mouseMove as the list can scroll without moving the cursor
341 if (me.mouseMoveOffset != -1) me.setFocusedItem(me, me.getItemAtPos(me, me.scrollPos + me.mouseMoveOffset));
342
343 if (me.needScrollToItem >= 0)
344 {
345 me.scrollToItem(me, me.needScrollToItem);
346 me.needScrollToItem = -1;
347 }
348 if (me.scrollPos != me.scrollPosTarget)
349 {
350 float averaging_time = (me.pressed == 1)
351 ? autocvar_menu_scroll_averaging_time_pressed
352 : autocvar_menu_scroll_averaging_time;
353 // this formula works with whatever framerate
354 float f = averaging_time ? exp(-frametime / averaging_time) : 0;
355 me.scrollPos = me.scrollPos * f + me.scrollPosTarget * (1 - f);
356 if (fabs(me.scrollPos - me.scrollPosTarget) < 0.001) me.scrollPos = me.scrollPosTarget;
357 }
358
359 if (me.pressed == 2) me.mouseDrag(me, me.dragScrollPos); // simulate mouseDrag event
360 me.updateControlTopBottom(me);
361 fillSize.x = (1 - me.controlWidth);
362 if (me.alphaBG) draw_Fill('0 0 0', '0 1 0' + fillSize, me.colorBG, me.alphaBG);
363 if (me.controlWidth)
364 {
365 draw_VertButtonPicture(eX * (1 - me.controlWidth), strcat(me.src, "_s"), eX * me.controlWidth + eY, me.color2, 1);
366 if (me.getTotalHeight(me) > 1)
367 {
368 vector o, s;
369 o = eX * (1 - me.controlWidth) + eY * me.controlTop;
370 s = eX * me.controlWidth + eY * (me.controlBottom - me.controlTop);
371 if (me.pressed == 1) draw_VertButtonPicture(o, strcat(me.src, "_c"), s, me.colorC, 1);
372 else if (me.focused) draw_VertButtonPicture(o, strcat(me.src, "_f"), s, me.colorF, 1);
373 else draw_VertButtonPicture(o, strcat(me.src, "_n"), s, me.color, 1);
374 }
375 }
376 draw_SetClip();
377 vector oldshift = draw_shift;
378 vector oldscale = draw_scale;
379
380 int i = me.getItemAtPos(me, me.scrollPos);
381 float y = me.getItemStart(me, i) - me.scrollPos;
382 for ( ; i < me.nItems && y < 1; ++i)
383 {
384 draw_shift = boxToGlobal(eY * y, oldshift, oldscale);
385 vector relSize = eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, i);
386 vector absSize = boxToGlobalSize(relSize, me.size);
387 draw_scale = boxToGlobalSize(relSize, oldscale);
388 me.drawListBoxItem(me, i, absSize, (me.selectedItem == i), (me.focusedItem == i));
389 y += relSize.y;
390 }
392
393 draw_shift = oldshift;
394 draw_scale = oldscale;
395 SUPER(ListBox).draw(me);
396 }
float frametime
v y
Definition ent_cs.qc:121
float exp(float e)
Definition mathlib.qc:74
void draw_VertButtonPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha)
Definition draw.qc:143
void draw_SetClip()
Definition draw.qc:350
vector boxToGlobalSize(vector v, vector theScale)
Definition draw.qc:53
vector boxToGlobal(vector v, vector theOrigin, vector theScale)
Definition draw.qc:45
void draw_Fill(vector theOrigin, vector theSize, vector theColor, float theAlpha)
Definition draw.qc:97
void draw_ClearClip()
Definition draw.qc:363
vector draw_shift
Definition draw.qh:7
vector draw_scale
Definition draw.qh:8
float fabs(float f)
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
#define SUPER(cname)
Definition oo.qh:231
vector
Definition self.qh:92
const vector eY
Definition vector.qh:45
const vector eX
Definition vector.qh:44

References boxToGlobal(), boxToGlobalSize(), draw_ClearClip(), draw_Fill(), draw_scale, draw_SetClip(), draw_shift, draw_VertButtonPicture(), entity(), eX, exp(), eY, fabs(), frametime, strcat(), SUPER, vector, and y.

◆ ListBox_drawListBoxItem()

void ListBox_drawListBoxItem ( entity me,
int i,
vector absSize,
bool isSelected,
bool isFocused )

Definition at line 411 of file listbox.qc.

412 {
413 // should be overridden
414 draw_Text('0 0 0', sprintf(_("Item %d"), i), eX * (8 / absSize.x) + eY * (8 / absSize.y), (isSelected ? '0 1 0' : '1 1 1'), 1, 0);
415 }
void draw_Text(vector theOrigin, string theText, vector theSize, vector theColor, float theAlpha, float ICanHasKallerz)
Definition draw.qc:282

References draw_Text(), entity(), eX, eY, and vector.

◆ ListBox_focusedItemChangeNotify()

void ListBox_focusedItemChangeNotify ( entity me)

Definition at line 398 of file listbox.qc.

399 {}

References entity().

◆ ListBox_focusLeave()

void ListBox_focusLeave ( entity me)

Definition at line 292 of file listbox.qc.

293 {
294 // Reset the var pressed in case listbox loses focus
295 // by a mouse click on an item of the list
296 // for example showing a dialog on right click
297 me.pressed = 0;
298 me.setFocusedItem(me, -1);
299 me.mouseMoveOffset = -1;
300 }

References entity().

◆ ListBox_getFirstFullyVisibleItemAtScrollPos()

float ListBox_getFirstFullyVisibleItemAtScrollPos ( entity me,
float pos )

Definition at line 73 of file listbox.qc.

74 {
75 return me.getItemAtPos(me, pos + 0.001) + 1;
76 }

References entity().

◆ ListBox_getItemAtPos()

float ListBox_getItemAtPos ( entity me,
float pos )

Definition at line 56 of file listbox.qc.

57 {
58 return floor(pos / me.itemHeight);
59 }
float floor(float f)

References entity(), and floor().

◆ ListBox_getItemHeight()

float ListBox_getItemHeight ( entity me,
float i )

Definition at line 64 of file listbox.qc.

65 {
66 return me.itemHeight;
67 }

References entity().

◆ ListBox_getItemStart()

float ListBox_getItemStart ( entity me,
float i )

Definition at line 60 of file listbox.qc.

61 {
62 return me.itemHeight * i;
63 }

References entity().

◆ ListBox_getLastFullyVisibleItemAtScrollPos()

float ListBox_getLastFullyVisibleItemAtScrollPos ( entity me,
float pos )

Definition at line 69 of file listbox.qc.

70 {
71 return me.getItemAtPos(me, pos + 0.999) - 1;
72 }

References entity().

◆ ListBox_getTotalHeight()

float ListBox_getTotalHeight ( entity me)

Definition at line 52 of file listbox.qc.

53 {
54 return me.nItems * me.itemHeight;
55 }

References entity().

◆ ListBox_isScrolling()

bool ListBox_isScrolling ( entity me)

Definition at line 3 of file listbox.qc.

4 {
5 return me.scrollPos != me.scrollPosTarget;
6 }

References entity().

◆ ListBox_keyDown()

float ListBox_keyDown ( entity me,
float key,
float ascii,
float shift )

Definition at line 77 of file listbox.qc.

78 {
79 if (key == K_MWHEELUP)
80 {
81 me.scrollPosTarget = max(me.scrollPosTarget - 0.5, 0);
82 }
83 else if (key == K_MWHEELDOWN)
84 {
85 me.scrollPosTarget = min(me.scrollPosTarget + 0.5, max(0, me.getTotalHeight(me) - 1));
86 }
87 else if (key == K_PGUP || key == K_KP_PGUP)
88 {
89 if (me.selectionDoesntMatter)
90 {
91 me.scrollPosTarget = max(me.scrollPosTarget - 0.5, 0);
92 return 1;
93 }
94
95 float i = me.selectedItem;
96 float a = me.getItemHeight(me, i);
97 for ( ; ; )
98 {
99 --i;
100 if (i < 0) break;
101 a += me.getItemHeight(me, i);
102 if (a >= 1) break;
103 }
104 me.setSelected(me, i + 1);
105 }
106 else if (key == K_PGDN || key == K_KP_PGDN)
107 {
108 if (me.selectionDoesntMatter)
109 {
110 me.scrollPosTarget = min(me.scrollPosTarget + 0.5, me.nItems * me.itemHeight - 1);
111 return 1;
112 }
113
114 float i = me.selectedItem;
115 float a = me.getItemHeight(me, i);
116 for ( ; ; )
117 {
118 ++i;
119 if (i >= me.nItems) break;
120 a += me.getItemHeight(me, i);
121 if (a >= 1) break;
122 }
123 me.setSelected(me, i - 1);
124 }
125 else if (key == K_UPARROW || key == K_KP_UPARROW)
126 {
127 if (me.selectionDoesntMatter)
128 {
129 me.scrollPosTarget = max(me.scrollPosTarget - me.itemHeight, 0);
130 return 1;
131 }
132
133 me.setSelected(me, me.selectedItem - 1);
134 }
135 else if (key == K_DOWNARROW || key == K_KP_DOWNARROW)
136 {
137 if (me.selectionDoesntMatter)
138 {
139 me.scrollPosTarget = min(me.scrollPosTarget + me.itemHeight, me.nItems * me.itemHeight - 1);
140 return 1;
141 }
142
143 me.setSelected(me, me.selectedItem + 1);
144 }
145 else if (key == K_HOME || key == K_KP_HOME)
146 {
147 me.setSelected(me, 0);
148 }
149 else if (key == K_END || key == K_KP_END)
150 {
151 me.setSelected(me, me.nItems - 1);
152 }
153 else
154 {
155 return 0;
156 }
157 return 1;
158 }
float K_UPARROW
Definition keycodes.qc:15
float K_PGDN
Definition keycodes.qc:39
float K_DOWNARROW
Definition keycodes.qc:16
float K_MWHEELDOWN
Definition keycodes.qc:133
float K_KP_UPARROW
Definition keycodes.qc:64
float K_PGUP
Definition keycodes.qc:40
float K_KP_HOME
Definition keycodes.qc:62
float K_KP_DOWNARROW
Definition keycodes.qc:53
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
float min(float f,...)
float max(float f,...)

References entity(), K_DOWNARROW, K_END, K_HOME, K_KP_DOWNARROW, K_KP_END, K_KP_HOME, K_KP_PGDN, K_KP_PGUP, K_KP_UPARROW, K_MWHEELDOWN, K_MWHEELUP, K_PGDN, K_PGUP, K_UPARROW, max(), and min().

◆ ListBox_mouseDrag()

float ListBox_mouseDrag ( entity me,
vector pos )

Definition at line 177 of file listbox.qc.

178 {
179 float hit;
180 me.updateControlTopBottom(me);
181 me.dragScrollPos = pos;
182 if (me.pressed == 1 && me.getTotalHeight(me) > 1)
183 {
184 hit = 1;
185 if (pos.x < 1 - me.controlWidth - me.tolerance.x * me.controlWidth) hit = 0;
186 if (pos.y < 0 - me.tolerance.y) hit = 0;
187 if (pos.x >= 1 + me.tolerance.x * me.controlWidth) hit = 0;
188 if (pos.y >= 1 + me.tolerance.y) hit = 0;
189 if (hit)
190 {
191 // calculate new pos to v
192 float d = (pos.y - me.pressOffset) / (1 - (me.controlBottom - me.controlTop)) * (me.getTotalHeight(me) - 1);
193 me.scrollPosTarget = me.previousValue + d;
194 }
195 else
196 {
197 me.scrollPosTarget = me.previousValue;
198 }
199 me.scrollPosTarget = min(me.scrollPosTarget, me.getTotalHeight(me) - 1);
200 me.scrollPosTarget = max(me.scrollPosTarget, 0);
201 }
202 else if (me.pressed == 2)
203 {
204 int clickeditem = me.getItemAtPos(me, me.scrollPos + pos.y);
205 me.setSelected(me, clickeditem);
206 me.setFocusedItem(me, clickeditem);
207 me.mouseMoveOffset = -1;
208 }
209 return 1;
210 }

References entity(), max(), min(), and vector.

◆ ListBox_mouseMove()

float ListBox_mouseMove ( entity me,
vector pos )

Definition at line 159 of file listbox.qc.

160 {
161 me.mouseMoveOffset = -1;
162 if (pos_x < 0) return 0;
163 if (pos_y < 0) return 0;
164 if (pos_x >= 1) return 0;
165 if (pos_y >= 1) return 0;
166 if (pos_x < 1 - me.controlWidth)
167 {
168 me.mouseMoveOffset = pos.y;
169 }
170 else
171 {
172 me.setFocusedItem(me, -1);
173 me.mouseMoveOffset = -1;
174 }
175 return 1;
176 }

References entity(), and vector.

◆ ListBox_mouseRelease()

float ListBox_mouseRelease ( entity me,
vector pos )

Definition at line 260 of file listbox.qc.

261 {
262 if (me.pressed == 1)
263 {
264 // slider dragging mode
265 // in that case, nothing happens on releasing
266 }
267 else if (me.pressed == 2)
268 {
269 me.pressed = 3; // do that here, so setSelected can know the mouse has been released
270 // item dragging mode
271 // select current one one last time...
272 int clickeditem = me.getItemAtPos(me, me.scrollPos + pos.y);
273 me.setSelected(me, clickeditem);
274 me.setFocusedItem(me, clickeditem);
275 // and give it a nice click event
276 if (me.nItems > 0)
277 {
278 vector where = globalToBox(pos, eY * (me.getItemStart(me, me.selectedItem) - me.scrollPos), eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, me.selectedItem));
279
280 if ((me.selectedItem == me.lastClickedItem && clickeditem == me.selectedItem) && (time < me.lastClickedTime + 0.3))
281 me.doubleClickListBoxItem(me, me.selectedItem, where);
282 else
283 me.clickListBoxItem(me, me.selectedItem, where);
284
285 me.lastClickedItem = me.selectedItem;
286 me.lastClickedTime = time;
287 }
288 }
289 me.pressed = 0;
290 return 1;
291 }
float time
vector globalToBox(vector v, vector theOrigin, vector theScale)
Definition draw.qc:30

References entity(), eX, eY, globalToBox(), time, and vector.

◆ ListBox_resizeNotify()

void ListBox_resizeNotify ( entity me,
vector relOrigin,
vector relSize,
vector absOrigin,
vector absSize )

Definition at line 41 of file listbox.qc.

42 {
43 SUPER(ListBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
44 me.controlWidth = me.scrollbarWidth / absSize.x;
45 }

References entity(), SUPER, and vector.

◆ ListBox_scrollToItem()

void ListBox_scrollToItem ( entity me,
int i )

Definition at line 8 of file listbox.qc.

9 {
10 // scroll doesn't work properly until itemHeight is set to the correct value
11 // at the first resizeNotify call
12 if (me.itemHeight == 1) // initial temporary value of itemHeight is 1
13 {
14 me.needScrollToItem = i;
15 return;
16 }
17
18 i = bound(0, i, me.nItems - 1);
19
20 // scroll the list to make sure the selected item is visible
21 // (even if the selected item doesn't change).
22 if (i < me.getFirstFullyVisibleItemAtScrollPos(me, me.scrollPos))
23 {
24 // above visible area
25 me.scrollPosTarget = me.getItemStart(me, i);
26 }
27 else if (i > me.getLastFullyVisibleItemAtScrollPos(me, me.scrollPos))
28 {
29 // below visible area
30 if (i == me.nItems - 1) me.scrollPosTarget = me.getTotalHeight(me) - 1;
31 else me.scrollPosTarget = me.getItemStart(me, i + 1) - 1;
32 }
33 }
float bound(float min, float value, float max)

References bound(), and entity().

◆ ListBox_setFocusedItem()

void ListBox_setFocusedItem ( entity me,
int item )

Definition at line 250 of file listbox.qc.

251 {
252 float focusedItem_save = me.focusedItem;
253 me.focusedItem = (item >= 0 && item < me.nItems) ? item : -1;
254 if (focusedItem_save != me.focusedItem)
255 {
256 me.focusedItemChangeNotify(me);
257 if (me.focusedItem >= 0) me.focusedItemAlpha = SKINALPHA_LISTBOX_FOCUSED;
258 }
259 }

References entity().

◆ ListBox_setSelected()

void ListBox_setSelected ( entity me,
float i )

Definition at line 35 of file listbox.qc.

36 {
37 i = bound(0, i, me.nItems - 1);
38 me.scrollToItem(me, i);
39 me.selectedItem = i;
40 }

References bound(), and entity().

◆ ListBox_updateControlTopBottom()

void ListBox_updateControlTopBottom ( entity me)

Definition at line 301 of file listbox.qc.

302 {
303 // scrollPos is in 0..1 and indicates where the "page" currently shown starts.
304 if (me.getTotalHeight(me) <= 1)
305 {
306 // we don't need no stinkin' scrollbar, we don't need no view control...
307 me.controlTop = 0;
308 me.controlBottom = 1;
309 me.scrollPos = 0;
310 }
311 else
312 {
313 // if scroll pos is above beginning or below end of list, fix it
314 me.scrollPos = bound(0, me.scrollPos, me.getTotalHeight(me) - 1);
315 // now that we know where the list is scrolled to, find out where to draw the control
316 me.controlTop = max(0, me.scrollPos / me.getTotalHeight(me));
317 me.controlBottom = min((me.scrollPos + 1) / me.getTotalHeight(me), 1);
318
319 const float minfactor = 2 * me.controlWidth / me.size.y * me.size.x;
320 float f = me.controlBottom - me.controlTop;
321 if (f < minfactor) // FIXME good default?
322 {
323 // f * X + 1 * (1-X) = minfactor
324 // (f - 1) * X + 1 = minfactor
325 // (f - 1) * X = minfactor - 1
326 // X = (minfactor - 1) / (f - 1)
327 f = (minfactor - 1) / (f - 1);
328 me.controlTop = me.controlTop * f + 0 * (1 - f);
329 me.controlBottom = me.controlBottom * f + 1 * (1 - f);
330 }
331 }
332 }

References bound(), entity(), max(), and min().