X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fmenu%2Fitem%2Flistbox.c;h=1087c347943df0273fb1116d3032ade90c60c92a;hp=9664e93765575014aab68a8198ee3fc22bb3ca14;hb=ac828a4561855509c384c8d589b04c6f0115a837;hpb=406b13f464e47f8ca373b6bbe8ebe3bfc0f6be44 diff --git a/qcsrc/menu/item/listbox.c b/qcsrc/menu/item/listbox.c index 9664e93765..1087c34794 100644 --- a/qcsrc/menu/item/listbox.c +++ b/qcsrc/menu/item/listbox.c @@ -38,6 +38,15 @@ CLASS(ListBox) EXTENDS(Item) 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 @@ -56,23 +65,75 @@ void ListBox_configureListBox(entity me, float theScrollbarWidth, float theItemH 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); + { + float i = me.selectedItem; + float a = me.getItemHeight(me, i); + for(;;) + { + --i; + if (i < 0) + break; + a += me.getItemHeight(me, i); + if (a >= 1) + break; + } + me.setSelected(me, i + 1); + } else if(key == K_PGDN || key == K_KP_PGDN) - me.setSelected(me, me.selectedItem + 1 / me.itemHeight); + { + float i = me.selectedItem; + float a = me.getItemHeight(me, i); + for(;;) + { + ++i; + if (i >= me.nItems) + break; + a += me.getItemHeight(me, i); + if (a >= 1) + break; + } + me.setSelected(me, i - 1); + } else if(key == K_UPARROW || key == K_KP_UPARROW) me.setSelected(me, me.selectedItem - 1); else if(key == K_DOWNARROW || key == K_KP_DOWNARROW) @@ -84,7 +145,7 @@ float ListBox_keyDown(entity me, float key, float ascii, float shift) } 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 @@ -108,20 +169,20 @@ float ListBox_mouseDrag(entity me, vector pos) { // 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; } @@ -141,13 +202,13 @@ float ListBox_mousePress(entity me, vector pos) { // 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 { @@ -161,13 +222,12 @@ float ListBox_mousePress(entity me, vector pos) // 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; } float ListBox_mouseRelease(entity me, vector pos) { - vector absSize; if(me.pressed == 1) { // slider dragging mode @@ -178,12 +238,11 @@ float ListBox_mouseRelease(entity me, vector pos) 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) { - absSize = boxToGlobalSize(me.size, eX * (1 - me.controlWidth) + eY * me.itemHeight); - 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; @@ -200,7 +259,7 @@ void ListBox_updateControlTopBottom(entity me) { 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; @@ -216,20 +275,20 @@ void ListBox_updateControlTopBottom(entity me) 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; @@ -249,7 +308,7 @@ void ListBox_updateControlTopBottom(entity me) void ListBox_draw(entity me) { float i; - vector absSize, fillSize; + vector absSize, fillSize = '0 0 0'; vector oldshift, oldscale; if(me.pressed == 2) me.mouseDrag(me, me.dragScrollPos); // simulate mouseDrag event @@ -260,7 +319,7 @@ void ListBox_draw(entity me) 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; @@ -276,18 +335,23 @@ void ListBox_draw(entity me) 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 += relSize_y; } draw_ClearClip(); + + draw_shift = oldshift; + draw_scale = oldscale; + SUPER(ListBox).draw(me); } void ListBox_clickListBoxItem(entity me, float i, vector where)