METHOD(ListBox, drawListBoxItem, void(entity, float, vector, float)) // item number, width/height, selected
METHOD(ListBox, clickListBoxItem, void(entity, float, vector)) // item number, relative clickpos
METHOD(ListBox, setSelected, void(entity, float))
+
+ METHOD(ListBox, getLastFullyVisibleItemAtScrollPos, float(entity, float))
+ METHOD(ListBox, getFirstFullyVisibleItemAtScrollPos, float(entity, float))
+
+ // NOTE: override these four methods if you want variable sized list items
+ METHOD(ListBox, getTotalHeight, float(entity))
+ METHOD(ListBox, getItemAtPos, float(entity, float))
+ METHOD(ListBox, getItemStart, float(entity, float))
+ METHOD(ListBox, getItemHeight, float(entity, float))
ENDCLASS(ListBox)
#endif
me.scrollbarWidth = theScrollbarWidth;
me.itemHeight = theItemHeight;
}
+
+float ListBox_getTotalHeight(entity me)
+{
+ return me.nItems * me.itemHeight;
+}
+float ListBox_getItemAtPos(entity me, float pos)
+{
+ return floor(pos / me.itemHeight);
+}
+float ListBox_getItemStart(entity me, float i)
+{
+ return me.itemHeight * i;
+}
+float ListBox_getItemHeight(entity me, float i)
+{
+ return me.itemHeight;
+}
+
+float ListBox_getLastFullyVisibleItemAtScrollPos(entity me, float pos)
+{
+ return me.getItemAtPos(me, pos + 1.001) - 1;
+}
+float ListBox_getFirstFullyVisibleItemAtScrollPos(entity me, float pos)
+{
+ return me.getItemAtPos(me, pos - 0.001) + 1;
+}
float ListBox_keyDown(entity me, float key, float ascii, float shift)
{
me.dragScrollTimer = time;
if(key == K_MWHEELUP)
{
me.scrollPos = max(me.scrollPos - 0.5, 0);
- me.setSelected(me, min(me.selectedItem, floor((me.scrollPos + 1) / me.itemHeight - 1)));
+ me.setSelected(me, min(me.selectedItem, me.getLastFullyVisibleItemAtScrollPos(me, me.scrollPos)));
}
else if(key == K_MWHEELDOWN)
{
- me.scrollPos = min(me.scrollPos + 0.5, me.nItems * me.itemHeight - 1);
- me.setSelected(me, max(me.selectedItem, ceil(me.scrollPos / me.itemHeight)));
+ me.scrollPos = min(me.scrollPos + 0.5, me.getTotalHeight(me) - 1);
+ me.setSelected(me, max(me.selectedItem, me.getFirstFullyVisibleItemAtScrollPos(me, me.scrollPos)));
}
else if(key == K_PGUP || key == K_KP_PGUP)
- me.setSelected(me, me.selectedItem - 1 / me.itemHeight);
+ {
+ me.scrollPos = max(me.scrollPos - 1, 0);
+ me.setSelected(me, min(me.selectedItem, me.getLastFullyVisibleItemAtScrollPos(me, me.scrollPos)));
+ }
else if(key == K_PGDN || key == K_KP_PGDN)
- me.setSelected(me, me.selectedItem + 1 / me.itemHeight);
+ {
+ me.scrollPos = min(me.scrollPos + 1, me.getTotalHeight(me) - 1);
+ me.setSelected(me, max(me.selectedItem, me.getFirstFullyVisibleItemAtScrollPos(me, me.scrollPos)));
+ }
else if(key == K_UPARROW || key == K_KP_UPARROW)
me.setSelected(me, me.selectedItem - 1);
else if(key == K_DOWNARROW || key == K_KP_DOWNARROW)
}
else if(key == K_END || key == K_KP_END)
{
- me.scrollPos = max(0, me.nItems * me.itemHeight - 1);
+ me.scrollPos = max(0, me.getTotalHeight(me) - 1);
me.setSelected(me, me.nItems - 1);
}
else
{
// calculate new pos to v
float d;
- d = (pos_y - me.pressOffset) / (1 - (me.controlBottom - me.controlTop)) * (me.nItems * me.itemHeight - 1);
+ d = (pos_y - me.pressOffset) / (1 - (me.controlBottom - me.controlTop)) * (me.getTotalHeight(me) - 1);
me.scrollPos = me.previousValue + d;
}
else
me.scrollPos = me.previousValue;
- me.scrollPos = min(me.scrollPos, me.nItems * me.itemHeight - 1);
+ me.scrollPos = min(me.scrollPos, me.getTotalHeight(me) - 1);
me.scrollPos = max(me.scrollPos, 0);
- i = min(me.selectedItem, floor((me.scrollPos + 1) / me.itemHeight - 1));
- i = max(i, ceil(me.scrollPos / me.itemHeight));
+ i = min(me.selectedItem, me.getLastFullyVisibleItemAtScrollPos(me, me.scrollPos));
+ i = max(i, ListBox_getFirstFullyVisibleItemAtScrollPos(me, me.scrollPos));
me.setSelected(me, i);
}
else if(me.pressed == 2)
{
- me.setSelected(me, floor((me.scrollPos + pos_y) / me.itemHeight));
+ me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos_y));
}
return 1;
}
{
// page up
me.scrollPos = max(me.scrollPos - 1, 0);
- me.setSelected(me, min(me.selectedItem, floor((me.scrollPos + 1) / me.itemHeight - 1)));
+ me.setSelected(me, min(me.selectedItem, ListBox_getLastFullyVisibleItemAtScrollPos(me, me.scrollPos)));
}
else if(pos_y > me.controlBottom)
{
// page down
- me.scrollPos = min(me.scrollPos + 1, me.nItems * me.itemHeight - 1);
- me.setSelected(me, max(me.selectedItem, ceil(me.scrollPos / me.itemHeight)));
+ me.scrollPos = min(me.scrollPos + 1, me.getTotalHeight(me) - 1);
+ me.setSelected(me, max(me.selectedItem, ListBox_getFirstFullyVisibleItemAtScrollPos(me, me.scrollPos)));
}
else
{
// continue doing that while dragging (even when dragging outside). When releasing, forward the click to the then selected item.
me.pressed = 2;
// an item has been clicked. Select it, ...
- me.setSelected(me, floor((me.scrollPos + pos_y) / me.itemHeight));
+ me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos_y));
}
return 1;
}
me.pressed = 3; // do that here, so setSelected can know the mouse has been released
// item dragging mode
// select current one one last time...
- me.setSelected(me, floor((me.scrollPos + pos_y) / me.itemHeight));
+ me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos_y));
// and give it a nice click event
if(me.nItems > 0)
{
- me.clickListBoxItem(me, me.selectedItem, globalToBox(pos, eY * (me.selectedItem * me.itemHeight - me.scrollPos), eX * (1 - me.controlWidth) + eY * me.itemHeight));
+ me.clickListBoxItem(me, me.selectedItem, globalToBox(pos, eY * (me.getItemStart(me, me.selectedItem) - me.scrollPos), eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, me.selectedItem)));
}
}
me.pressed = 0;
{
float f;
// scrollPos is in 0..1 and indicates where the "page" currently shown starts.
- if(me.nItems * me.itemHeight <= 1)
+ if(me.getTotalHeight(me) <= 1)
{
// we don't need no stinkin' scrollbar, we don't need no view control...
me.controlTop = 0;
float save;
save = me.scrollPos;
// if selected item is below listbox, increase scrollpos so it is in
- me.scrollPos = max(me.scrollPos, me.selectedItem * me.itemHeight - 1 + me.itemHeight);
+ me.scrollPos = max(me.scrollPos, me.getItemStart(me, me.selectedItem) + me.getItemHeight(me, me.selectedItem) - 1);
// if selected item is above listbox, decrease scrollpos so it is in
- me.scrollPos = min(me.scrollPos, me.selectedItem * me.itemHeight);
+ me.scrollPos = min(me.scrollPos, me.getItemStart(me, me.selectedItem));
if(me.scrollPos != save)
me.dragScrollTimer = time + 0.2;
}
}
// if scroll pos is below end of list, fix it
- me.scrollPos = min(me.scrollPos, me.nItems * me.itemHeight - 1);
+ me.scrollPos = min(me.scrollPos, me.getTotalHeight(me) - 1);
// if scroll pos is above beginning of list, fix it
me.scrollPos = max(me.scrollPos, 0);
// now that we know where the list is scrolled to, find out where to draw the control
- me.controlTop = max(0, me.scrollPos / (me.nItems * me.itemHeight));
- me.controlBottom = min((me.scrollPos + 1) / (me.nItems * me.itemHeight), 1);
+ me.controlTop = max(0, me.scrollPos / me.getTotalHeight(me));
+ me.controlBottom = min((me.scrollPos + 1) / me.getTotalHeight(me), 1);
float minfactor;
minfactor = 1 * me.controlWidth / me.size_y * me.size_x;
if(me.controlWidth)
{
draw_VertButtonPicture(eX * (1 - me.controlWidth), strcat(me.src, "_s"), eX * me.controlWidth + eY, me.color2, 1);
- if(me.nItems * me.itemHeight > 1)
+ if(me.getTotalHeight(me) > 1)
{
vector o, s;
o = eX * (1 - me.controlWidth) + eY * me.controlTop;
draw_SetClip();
oldshift = draw_shift;
oldscale = draw_scale;
- absSize = boxToGlobalSize(me.size, eX * (1 - me.controlWidth) + eY * me.itemHeight);
- draw_scale = boxToGlobalSize(eX * (1 - me.controlWidth) + eY * me.itemHeight, oldscale);
- for(i = floor(me.scrollPos / me.itemHeight); i < me.nItems; ++i)
+ float y;
+ i = me.getItemAtPos(me, me.scrollPos);
+ y = me.getItemStart(me, i) - me.scrollPos;
+ for(; i < me.nItems && y < 1; ++i)
{
- float y;
- y = i * me.itemHeight - me.scrollPos;
- if(y >= 1)
- break;
draw_shift = boxToGlobal(eY * y, oldshift, oldscale);
+ vector relSize = eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, i);
+ absSize = boxToGlobalSize(relSize, me.size);
+ draw_scale = boxToGlobalSize(relSize, oldscale);
me.drawListBoxItem(me, i, absSize, (me.selectedItem == i));
+ y += absSize_y;
}
draw_ClearClip();