Ok, I worked on my example from above, which surprisingly needed little corrections considering I never attempted to compile it while writing.
There are a few hard-coded numbers in there which are related to the sprites I used. The list window in my example has a fixed width but the height can be adjusted. And because of the border around the window, I have hard-coded offsets. Other than that, it's pretty modular. The list allows for multiple selections and a function will easily return a list of the items selected.
What makes this so much easier to write in AppGameKit rather than DBP, is the pass by reference ability and being able to return arrays from functions.
Type ListItem
label as integer
isSelected as integer
EndType
Type List
items as ListItem[]
x as integer
y as integer
background as integer
top as integer
bottom as integer
middle as integer
shadowtop as integer
shadowbottom as integer
vOffset as float
EndType
mylist as List
mylist = createList(535, 300)
addToList("apples", myList)
addToList("pears", myList)
addToList("peaches", myList)
addToList("pineapple", myList)
addToList("pen", myList)
addToList("mangos", myList)
addToList("watermelon", myList)
addToList("ugly fruit", myList)
addToList("tree star", myList)
// call this at least once before the list is displayed
positionList(mylist, 200, 100)
results as integer[]
do
// handle the list functionality
listListener(mylist)
// get selected items as an array of integers; correspond to indices in items array
results = getSelectedItems(mylist)
// display selected items
for i = 0 to results.length
print(getTextString(mylist.items[results[i]].label))
next i
Sync()
loop
function getSelectedItems(mylist as List)
selected as integer[]
for i = 0 to mylist.items.length
if mylist.items[i].isSelected = 1 then selected.insert(i)
next i
endfunction selected
function listListener(mylist ref as List)
// Calculate the maximum scroll amount for the list
// Determine by the number of items multiplied by their text size
// (because they're offset by text size in the list, which is 40px for this example)
// then subtract what is actually already seen. Which that would be the height of the
// background window minus 60. The 60 comes from offsetting the text from the top by 30
// and allowing it to scroll up beyond the bottom by 30. Those offsets are personal preference
// and I've done so due to the shadow effect I've added.
// 1 is added to list length because AGK is stupid in how it counts array size if you use the 0 index
// This needs to be calculated anytime the list grows.shrinks in size, or the list window is resized
size = (mylist.items.length+1) * 40 - (getSpriteHeight(mylist.background)-60)
oldOffset = mylist.vOffset
// Scroll list using mouse wheel
md = getRawMouseWheelDelta()
if md < 0
mylist.vOffset = mylist.vOffset + 8
if mylist.voffset > size then mylist.voffset = size
elseif md > 0
mylist.vOffset = mylist.vOffset - 8
if mylist.voffset < 0 then mylist.voffset = 0
endif
// Update list items positions
if oldOffset <> mylist.vOffset then positionList(mylist, mylist.x, mylist.y)
mx = getRawMouseX()
my = getRawMouseY()
mc = getRawMouseLeftPressed()
// check that mouse is within the boundaries of the list window
if mx > mylist.x+20 and mx < mylist.x+getSpriteWidth(mylist.background)-15 and my > mylist.y+20 and my < mylist.y+getSpriteHeight(mylist.background)-15
y = mylist.y - mylist.vOffset + 30
for i = 0 to mylist.items.length
// If mouse is within list item's area
if mx > mylist.x+20 and mx < mylist.x+getSpriteWidth(mylist.background)-15 and my > y and my < y+getTextTotalHeight(mylist.items[i].label)
// if mouse left clicked
if mc
// toggle item selection
mylist.items[i].isSelected = 1 - mylist.items[i].isSelected
if mylist.items[i].isSelected = 1
setTextColor(mylist.items[i].label, 200,200,255,255)
else
setTextColor(mylist.items[i].label, 0,0,0,255)
endif
endif
endif
y = y + getTextTotalHeight(mylist.items[i].label)
next i
endif
endfunction
function createList(width as integer, height as integer)
l as List
l.background = createSprite(0)
// semi-transparent background of list window
setSpriteSize(l.background, width, height-10)
setSpriteColor(l.background, 105,150,189,255)
l.shadowTop = createSprite(loadImage("shadow.png"))
l.shadowBottom = cloneSprite(l.shadowTop) : setSpriteFlip(l.shadowBottom, 0, 1)
setSpriteDepth(l.shadowTop, 8)
setSpriteDepth(l.shadowBottom, 8)
l.top = createSprite(loadImage("thing1.png"))
l.bottom = cloneSprite(l.top) : setSpriteFlip(l.bottom, 0, 1)
l.middle = createSprite(loadImage("middle.png"))
setSpriteDepth(l.top, 7)
setSpriteDepth(l.bottom, 7)
setSpriteDepth(l.middle, 7)
endfunction l
function positionList(aList ref as List, x as integer, y as integer)
aList.x = x
aList.y = y
yy = y+getSpriteHeight(aList.background)-90
setSpritePosition(aList.background, x+3, y+5)
setSpritePosition(aList.top, x, y)
setSpritePosition(aList.shadowTop, x, y)
setSpritePosition(aList.bottom, x, yy)
setSpritePosition(aList.shadowBottom, x, yy)
setSpritePosition(aList.middle, x, y+100)
setSpriteSize(aList.middle, 541, yy-y-100)
// position text starting at top of list window minus the scrolled offset amount
ty = y - aList.vOffset + 30
for i = 0 to aList.items.length
setTextPosition(aList.items[i].label, x+20, ty)
// Clip the visible area of the text to only be seen within the list window's area
setTextScissor(aList.items[i].label, x+20, y+16, x+getSpriteWidth(aList.background)-15, y+getSpriteHeight(aList.background)-8)
// Update Y position for next text object. This method allows
// for variable text sizes within the same list
ty = ty + getTextTotalHeight(aList.items[i].label)
next i
endfunction
function addToList(item as string, aList ref as List)
id = createText(item)
setTextColor(id, 0,0,0,255)
setTextSize(id, 40)
setTextDepth(id, 9)
l as ListItem
l.label = id
aList.items.insert(l)
endfunction
function setItemActive(aList ref as List, id as integer)
aList.items[id].isSelected = 1 - aList.items[id].isSelected
if aList.items[id].isSelected = 0
setTextColor(aList.items[id].label, 0,0,0,255)
else
setTextColor(aList.items[id].label, 0,255,0,255)
endif
endfunction