Xonotic
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  
)

Referenced by ListBox_updateControlTopBottom().

+ Here is the caller graph for this function:

◆ 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  }

◆ 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  }

◆ ListBox_doubleClickListBoxItem()

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

Definition at line 406 of file listbox.qc.

407  {
408  // template method
409  }

◆ ListBox_draw()

void ListBox_draw ( entity  me)

Definition at line 336 of file listbox.qc.

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

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  }
391  draw_ClearClip();
392 
393  draw_shift = oldshift;
394  draw_scale = oldscale;
395  SUPER(ListBox).draw(me);
396  }
const vector eY
Definition: vector.qh:45
float exp(float e)
Definition: mathlib.qc:73
#define SUPER(cname)
Definition: oo.qh:219
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
float frametime
Definition: csprogsdefs.qc:17
vector(float skel, float bonenum) _skel_get_boneabs_hidden
const vector eX
Definition: vector.qh:44
+ Here is the call graph for this function:

◆ ListBox_drawListBoxItem()

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

Definition at line 411 of file listbox.qc.

References draw_Text().

412  {
413  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);
414  }
const vector eY
Definition: vector.qh:45
const vector eX
Definition: vector.qh:44
+ Here is the call graph for this function:

◆ ListBox_focusedItemChangeNotify()

void ListBox_focusedItemChangeNotify ( entity  me)

Definition at line 398 of file listbox.qc.

399  {}

◆ ListBox_focusLeave()

void ListBox_focusLeave ( entity  me)

Definition at line 288 of file listbox.qc.

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

◆ 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  }

◆ ListBox_getItemAtPos()

float ListBox_getItemAtPos ( entity  me,
float  pos 
)

Definition at line 56 of file listbox.qc.

References floor().

57  {
58  return floor(pos / me.itemHeight);
59  }
+ Here is the call graph for this function:

◆ ListBox_getItemHeight()

float ListBox_getItemHeight ( entity  me,
float  i 
)

Definition at line 64 of file listbox.qc.

65  {
66  return me.itemHeight;
67  }

◆ ListBox_getItemStart()

float ListBox_getItemStart ( entity  me,
float  i 
)

Definition at line 60 of file listbox.qc.

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

◆ 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  }

◆ ListBox_getTotalHeight()

float ListBox_getTotalHeight ( entity  me)

Definition at line 52 of file listbox.qc.

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

◆ ListBox_isScrolling()

bool ListBox_isScrolling ( entity  me)

Definition at line 3 of file listbox.qc.

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

◆ ListBox_keyDown()

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

Definition at line 77 of file listbox.qc.

References 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().

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_DOWNARROW
Definition: keycodes.qc:16
float K_HOME
Definition: keycodes.qc:41
float K_KP_DOWNARROW
Definition: keycodes.qc:53
float K_KP_PGDN
Definition: keycodes.qc:55
float K_PGDN
Definition: keycodes.qc:39
float K_END
Definition: keycodes.qc:42
float K_MWHEELDOWN
Definition: keycodes.qc:133
float K_KP_HOME
Definition: keycodes.qc:62
float K_KP_END
Definition: keycodes.qc:51
float K_KP_PGUP
Definition: keycodes.qc:66
float K_PGUP
Definition: keycodes.qc:40
float K_KP_UPARROW
Definition: keycodes.qc:64
float K_MWHEELUP
Definition: keycodes.qc:132
+ Here is the call graph for this function:

◆ ListBox_mouseDrag()

float ListBox_mouseDrag ( entity  me,
vector  pos 
)

Definition at line 177 of file listbox.qc.

References max(), METHOD, min(), pressed, and vector().

178  {
179  float hit;
180  me.updateControlTopBottom(me);
181  me.dragScrollPos = pos;
182  if (me.pressed == 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;
193  d = (pos.y - me.pressOffset) / (1 - (me.controlBottom - me.controlTop)) * (me.getTotalHeight(me) - 1);
194  me.scrollPosTarget = me.previousValue + d;
195  }
196  else
197  {
198  me.scrollPosTarget = me.previousValue;
199  }
200  me.scrollPosTarget = min(me.scrollPosTarget, me.getTotalHeight(me) - 1);
201  me.scrollPosTarget = max(me.scrollPosTarget, 0);
202  }
203  else if (me.pressed == 2)
204  {
205  me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos.y));
206  me.setFocusedItem(me, me.selectedItem);
207  me.mouseMoveOffset = -1;
208  }
209  return 1;
210  }
+ Here is the call graph for this function:

◆ 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  }

◆ ListBox_mouseRelease()

float ListBox_mouseRelease ( entity  me,
vector  pos 
)

Definition at line 259 of file listbox.qc.

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

260  {
261  if (me.pressed == 1)
262  {
263  // slider dragging mode
264  // in that case, nothing happens on releasing
265  }
266  else if (me.pressed == 2)
267  {
268  me.pressed = 3; // do that here, so setSelected can know the mouse has been released
269  // item dragging mode
270  // select current one one last time...
271  me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos.y));
272  me.setFocusedItem(me, me.selectedItem);
273  // and give it a nice click event
274  if (me.nItems > 0)
275  {
276  vector where = globalToBox(pos, eY * (me.getItemStart(me, me.selectedItem) - me.scrollPos), eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, me.selectedItem));
277 
278  if ((me.selectedItem == me.lastClickedItem) && (time < me.lastClickedTime + 0.3)) me.doubleClickListBoxItem(me, me.selectedItem, where);
279  else me.clickListBoxItem(me, me.selectedItem, where);
280 
281  me.lastClickedItem = me.selectedItem;
282  me.lastClickedTime = time;
283  }
284  }
285  me.pressed = 0;
286  return 1;
287  }
const vector eY
Definition: vector.qh:45
vector(float skel, float bonenum) _skel_get_boneabs_hidden
const vector eX
Definition: vector.qh:44
float time
Definition: csprogsdefs.qc:16
+ Here is the call graph for this function:

◆ ListBox_resizeNotify()

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

Definition at line 41 of file listbox.qc.

References SUPER.

42  {
43  SUPER(ListBox).resizeNotify(me, relOrigin, relSize, absOrigin, absSize);
44  me.controlWidth = me.scrollbarWidth / absSize.x;
45  }
#define SUPER(cname)
Definition: oo.qh:219

◆ ListBox_scrollToItem()

void ListBox_scrollToItem ( entity  me,
int  i 
)

Definition at line 8 of file listbox.qc.

References bound().

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  }
+ Here is the call graph for this function:

◆ ListBox_setFocusedItem()

void ListBox_setFocusedItem ( entity  me,
int  item 
)

Definition at line 249 of file listbox.qc.

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

◆ ListBox_setSelected()

void ListBox_setSelected ( entity  me,
float  i 
)

Definition at line 35 of file listbox.qc.

References bound().

36  {
37  i = bound(0, i, me.nItems - 1);
38  me.scrollToItem(me, i);
39  me.selectedItem = i;
40  }
+ Here is the call graph for this function:

◆ ListBox_updateControlTopBottom()

void ListBox_updateControlTopBottom ( entity  me)

Definition at line 297 of file listbox.qc.

References AUTOCVAR(), max(), and min().

298  {
299  float f;
300  // scrollPos is in 0..1 and indicates where the "page" currently shown starts.
301  if (me.getTotalHeight(me) <= 1)
302  {
303  // we don't need no stinkin' scrollbar, we don't need no view control...
304  me.controlTop = 0;
305  me.controlBottom = 1;
306  me.scrollPos = 0;
307  }
308  else
309  {
310  // if scroll pos is below end of list, fix it
311  me.scrollPos = min(me.scrollPos, me.getTotalHeight(me) - 1);
312  // if scroll pos is above beginning of list, fix it
313  me.scrollPos = max(me.scrollPos, 0);
314  // now that we know where the list is scrolled to, find out where to draw the control
315  me.controlTop = max(0, me.scrollPos / me.getTotalHeight(me));
316  me.controlBottom = min((me.scrollPos + 1) / me.getTotalHeight(me), 1);
317 
318  float minfactor;
319  minfactor = 2 * me.controlWidth / me.size.y * me.size.x;
320  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  }
+ Here is the call graph for this function: