METHOD(ListBox, mouseRelease, float(entity, vector))
METHOD(ListBox, focusLeave, void(entity))
ATTRIB(ListBox, focusable, float, 1)
+ ATTRIB(ListBox, allowFocusSound, float, 1)
ATTRIB(ListBox, selectedItem, float, 0)
ATTRIB(ListBox, size, vector, '0 0 0')
ATTRIB(ListBox, origin, vector, '0 0 0')
ATTRIB(ListBox, itemHeight, float, 0)
ATTRIB(ListBox, colorBG, vector, '0 0 0')
ATTRIB(ListBox, alphaBG, float, 0)
+
+ ATTRIB(ListBox, lastClickedItem, float, -1)
+ ATTRIB(ListBox, lastClickedTime, float, 0)
+
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, doubleClickListBoxItem, void(entity, float, vector)) // item number, relative clickpos
METHOD(ListBox, setSelected, void(entity, float))
METHOD(ListBox, getLastFullyVisibleItemAtScrollPos, float(entity, float))
METHOD(ListBox, getItemAtPos, float(entity, float))
METHOD(ListBox, getItemStart, float(entity, float))
METHOD(ListBox, getItemHeight, float(entity, float))
+ // NOTE: if getItemAt* are overridden, it may make sense to cache the
+ // start and height of the last item returned by getItemAtPos and fast
+ // track returning their properties for getItemStart and getItemHeight.
+ // The "hot" code path calls getItemAtPos first, then will query
+ // getItemStart and getItemHeight on it soon.
+ // When overriding, the following consistency rules must hold:
+ // getTotalHeight() == SUM(getItemHeight(i), i, 0, me.nItems-1)
+ // getItemStart(i+1) == getItemStart(i) + getItemHeight(i)
+ // for 0 <= i < me.nItems-1
+ // getItemStart(0) == 0
+ // getItemStart(getItemAtPos(p)) <= p
+ // if p >= 0
+ // getItemAtPos(p) == 0
+ // if p < 0
+ // getItemStart(getItemAtPos(p)) + getItemHeight(getItemAtPos(p)) > p
+ // if p < getTotalHeigt()
+ // getItemAtPos(p) == me.nItems - 1
+ // if p >= getTotalHeight()
ENDCLASS(ListBox)
#endif
#ifdef IMPLEMENTATION
void ListBox_setSelected(entity me, float i)
{
- me.selectedItem = floor(0.5 + bound(0, i, me.nItems - 1));
+ me.selectedItem = bound(0, i, me.nItems - 1);
}
void ListBox_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
{
// and give it a nice click event
if(me.nItems > 0)
{
- 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)));
+ vector where = globalToBox(pos, eY * (me.getItemStart(me, me.selectedItem) - me.scrollPos), eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, me.selectedItem));
+
+ if((me.selectedItem == me.lastClickedItem) && (time < me.lastClickedTime + 0.3))
+ me.doubleClickListBoxItem(me, me.selectedItem, where);
+ else
+ me.clickListBoxItem(me, me.selectedItem, where);
+
+ me.lastClickedItem = me.selectedItem;
+ me.lastClickedTime = time;
}
}
me.pressed = 0;
me.controlBottom = min((me.scrollPos + 1) / me.getTotalHeight(me), 1);
float minfactor;
- minfactor = 1 * me.controlWidth / me.size_y * me.size_x;
+ minfactor = 2 * me.controlWidth / me.size_y * me.size_x;
f = me.controlBottom - me.controlTop;
if(f < minfactor) // FIXME good default?
{
void ListBox_clickListBoxItem(entity me, float i, vector where)
{
- // itemclick, itemclick, does whatever itemclick does
+ // template method
+}
+
+void ListBox_doubleClickListBoxItem(entity me, float i, vector where)
+{
+ // template method
}
void ListBox_drawListBoxItem(entity me, float i, vector absSize, float selected)