Here's a dropdown/flyout menu, just call HandleHomeMenu() on a press event it's straight from my project so you'll need to make modifications for missing media and functions (I have some "override" functions in there like CreateText2). The basics are there though so you can see how I handle it.
function CreateHomeMenu()
gHomeMenuLoaded = 1
pxH# = 100.0 / gDevH#
pxW# = 100.0 / gDevW#
numBtns = 6
dim btnTxt$[numBtns]
btnTxt$[1] = "View WS Friends"
btnTxt$[2] = "Settings"
btnTxt$[3] = "How To Play"
btnTxt$[4] = "FAQ"
btnTxt$[5] = "Feedback / Support"
btnTxt$[6] = "Clear Finished Games"
txtDepth = TOPBAR_DEPTH + 1
dim homeMenuUI#[numBtns+1 , 6]
`0,0 = array size
`i,0 = text object id
`i,1 = BG sprite id
`i,2 = separator sprite id
`i,3 = final button x position
`i,4 = final button y position
`i,5 = final text x position
`i,6 = final text y position
homeMenuUI#[0,0] = numBtns
`Calculate font sizes
fontSizePct# = 0.6 * gBarH#
tmpTxt = CreateText("X")
SetTextFontImage(tmpTxt , menuElements[4])
SetTextSize(tmpTxt , fontSizePct#)
chW# = GetTextTotalWidth(tmpTxt)
DeleteText(tmpTxt)
minLeftRightPadding# = chW#
minPaddingPct# = chW#
for i = 1 to numBtns
txtID = Createtext2(btnTxt$[i] , "TEXT_CHAT_OPTION_MENU")
homeMenuUI#[i,0] = txtID
SetTextColor2(txtID)
SetTextFontImage(txtID , menuElements[4])
SetTextDepth(txtID , txtDepth)
SetTextSize(txtID , fontSizePct#)
thisTextWidth# = GetTextTotalWidth(txtID)
if textMaxWidth# < thisTextWidth#
textMaxWidth# = thisTextWidth#
biggestTextIndex = i
endif
next i
undim btnTxt$[]
if textMaxWidth# > 100
repeat
fontSizePct# = fontSizePct# - 0.01
SetTextSize(round(homeMenuUI#[biggestTextIndex,0]) , fontSizePct#)
until GetTextTotalWidth(round(homeMenuUI#[biggestTextIndex,0])) < 100
for i = 1 to numBtns
SetTextSize(round(homeMenuUI#[i,0]) , fontSizePct#)
next i
endif
`Create menu item backgrounds and separators , set size , position offscreen
btnWPct# = 2 * minPaddingPct# + textMaxWidth# + chW#
btnHPct# = 2.0 * fontSizePct#
for i = 1 to numBtns
`Menu item BGs
homeMenuUI#[i,1] = CloneSprite2(menuElements[5] , "MENU_ITEM_BG")
SetSpriteSize(round(homeMenuUI#[i,1]) , btnWPct# , btnHPct#)
SetSpriteDepth(round(homeMenuUI#[i,1]) , GetSpriteDepth(menuElements[1])+3*i)
SetSpritePosition(round(homeMenuUI#[i,1]) , -100 , 0)
`Separators
homeMenuUI#[i,2] = CloneSprite2(menuElements[6] , "SEPARATOR")
SetSpriteSize(round(homeMenuUI#[i,2]) , btnWPct# - 100.0 / gDevW# , 100.0 / (1.0*gDevH#))
SetSpriteDepth(round(homeMenuUI#[i,2]) , GetSpriteDepth(round(homeMenuUI#[i,1]))-1)
SetSpritePosition(round(homeMenuUI#[i,2]) , -100 , 0)
`Position text offscreen
SetTextPosition(round(homeMenuUI#[i,0]) , -100 , 0)
SetTextDepth(round(homeMenuUI#[i,0]), GetSpriteDepth(round(homeMenuUI#[i,1]))-1)
next i
` Calculate final positions
buttonX# = 100 - GetSpriteWidth(round(homeMenuUI#[1,1]))
textX# = buttonX# + minPaddingPct#
yAdjustment# = 3.0 / gDevH# * 100.0
for i = 1 to numBtns
homeMenuUI#[i,3] = buttonX#
buttonY# = GetSpriteHeight(menuElements[1]) + (i-1) * btnHPct#
homeMenuUI#[i,4] = buttonY#
homeMenuUI#[i,5] = textX#
textY# = 0.25 * btnHPct# + buttonY#
homeMenuUI#[i,6] = textY#
next i
bg = CreateSprite(0)
FixSpriteToScreen(bg , 1)
homeMenuUI#[numBtns+1 , 1] = bg
SetSpriteColor(bg , 0 , 0 , 0 , 200)
SetSpriteSize(bg , btnWPct# + pxW# , numBtns * btnHPct# + pxH#)
SetSpriteDepth(bg ,GetSpriteDepth(round(homeMenuUI#[numBtns , 1])) + 1)
SetSpriteOffset(bg , pxW# , GetSpriteHeight(bg) - 2.0 * pxH# - btnHPct#)
SetSpritePosition(bg , -200 , -200)
SetSpriteSnap(bg , 1)
endfunction
//tb implemented
function ShowHomeMenu(iDirection)
`iDirection is 1 or -1
startTop# = -homeMenuUI#[0,0] * (GetSpriteHeight(round(homeMenuUI#[1,1])) + GetSpriteHeight(menuElements[1]))
numBtns = round(homeMenuUI#[0,0])
sec# = 0.25 / (1.0 * numBtns)
if iDirection = 1
jStart = 1
jEnd = round(homeMenuUI#[0,0])
jStep = 1
elseif iDirection = -1
jStart = round(homeMenuUI#[0,0])
jEnd = 1
jStep = -1
endif
for j = jStart to jEnd step jStep
if iDirection = 1
if j = 1
yStartSpr# = 0.0
yStartTxt# = homeMenuUI#[j,6] - homeMenuUI#[j,4]
else
yStartSpr# = homeMenuUI#[j-1,4]
yStartTxt# = homeMenuUI#[j-1,6]
endif
yEndSpr# = homeMenuUI#[j,4]
yEndTxt# = homeMenuUI#[j,6]
distSpr# = yEndSpr# - yStartSpr#
distTxt# = yEndTxt# - yStartTxt#
shadY# = 0.0
elseif iDirection = -1
yEndSpr# = -GetSpriteHeight(round(homeMenuUI#[1,1]))
yEndTxt# = yEndSpr# + homeMenuUI#[j,6] - homeMenuUI#[j,4]
yStartSpr# = homeMenuUI#[j,4]
yStartTxt# = homeMenuUI#[j,6]
distSpr# = yStartSpr# - yEndSpr#
distTxt# = yStartTxt# - yEndTxt#
shadY# = GetSpriteYByOffset(round(homeMenuUI#[numBtns + 1,1]))
endif
newYSpr# = yStartSpr#
newYTxt# = yStartTxt#
done = 0
repeat
addYSpr# = (1.0 * iDirection) * GetFrameTime() * distSpr# / (1.0 * sec#)
newYSpr# = newYSpr# + addYSpr#
addYTxt# = (1.0 * iDirection) * GetFrameTime() * distTxt# / (1.0 * sec#)
newYTxt# = newYTxt# + addYTxt#
if iDirection = 1
if newYSpr# > yEndSpr#
newYSpr# = yEndSpr#
endif
if newYTxt# > yEndTxt#
newYTxt# = yEndTxt#
endif
elseif iDirection = -1
if newYSpr# < yEndSpr#
newYSpr# = yEndSpr#
endif
if newYTxt# < yEndTxt#
newYTxt# = yEndTxt#
endif
endif
sepY# = GetSpriteHeight(round(homeMenuUI#[j,1])) + newYSpr#
`text
SetTextPosition(round(homeMenuUI#[j,0]) , homeMenuUI#[j,5] , newYTxt#)
`button bg
SetSpritePosition(round(homeMenuUI#[j,1]) , homeMenuUI#[j,3] , newYSpr#)
`seperator
SetSpritePosition(round(homeMenuUI#[j,2]) , homeMenuUI#[j,3] , sepY#)
shadX# = GetSpriteX(round(homeMenuUI#[j,1]))
if newYSpr# > shadY# and iDirection = 1
shadY# = newYSpr#
endif
if iDirection = -1 and newYSpr# < shadY#
shadY# = -100.0
endif
SetSpritePositionByOffset(round(homeMenuUI#[numBtns + 1,1]) , shadX# , shadY#)
FastSync()
if iDirection = 1
if newYSpr# >= yEndSpr# then done = 1
elseif iDirection = -1
if newYSpr# <= yEndSpr# then done = 1
endif
until done = 1
next j
endfunction
function HandleHomeMenu()
if gHomeMenuLoaded = 0 then CreateHomeMenu()
ShowHomeMenu(1)
repeat
if GetPointerPressed() = 1 or GetRawKeyPressed(27) = 1
ptrX# = GetPointerX()
ptrY# = GetPointerY() + GetViewOffsetY()
state = 0
for i = 1 to round(homeMenuUI#[0,0])
sprID = round(homeMenuUI#[i,1])
if GetSpriteHitTest(sprID , ptrX# , ptrY#) = 1
state = i
EXIT
endif
next i
if state = 0
ShowHomeMenu(-1)
EXITFUNCTION 0
endif
PlayWSSound(SND_BUTTON)
`Change color to indicate a press
origR = GetSpriteColorRed(sprID) : origG = GetSpriteColorGreen(sprID) : origB = GetSpriteColorBlue(sprID)
SetSpriteColor(sprID , 80 , 80 , 80 , 255)
textID = round(homeMenuUI#[state,0])
origRtext = GetTextColorRed(textID) : origGtext = GetTextColorGreen(textID) : origBtext = GetTextColorBlue(textID)
SetTextColor(textID , origR , origG , origB , 255)
repeat
ptrX# = GetPointerX()
ptrY# = GetPointerY() + GetViewOffsetY()
FastSync()
until GetPointerReleased() = 1
`Reset the color
SetSpriteColor(sprID , origR , origG , origB , 255)
SetTextColor(textID , origRtext , origGtext , origBtext , 255)
if GetSpriteHitTest(sprID , ptrX# , ptrY#) = 1 `if we're still pressing the same button
ShowHomeMenu(-1)
done = 1
select state
case 1: `friends
numFriends = GetFriends()
if numFriends > 0
CreateFriendsListUI()
ShowFriendsListUI(1)
HandleFriendsList(2)
endif
endcase
case 2: `settings
HandleSettingsUI()
endcase
case 3: `rules
OpenBrowser(sRULES_URL)
endcase
case 4: `FAQ
OpenBrowser(sFAQ_URL)
endcase
case 5: `support
HandleSupportUI()
endcase
case 6: `clear finished games
ClearFinished()
ShowHomeUI(1) `shows the topbar buttons
RefreshHomeUI()
endcase
endselect
endif
endif
FastSync()
until done = 1
endfunction quit
And here's a sample of a confirmation dialogue box. The structure is slightly different, but the ideas remain similar. All of this is done with the % system and not virtual sizes because scaling is very important to us. In this method just call ConfirmPush(msg$).
function CreateConfirmPushUI(msg$)
dim confirmPushUI#[10,3]
confirmPushUI#[0,0] = 9
//msg$ = "You will receive push notifications when it's your turn and when you're invited to a new game. Is this OK?"
//msg$ = "Wordspionage would like to send you push notifications when it's your turn and when you're invited to a new game. Is this OK?"
fontSize# = 0.6 * gBarH#
msg = CreateText2(msg$ , "TEXT_BLOCK_MENU_CONFIRM")
confirmPushUI#[1,1] = msg
SetTextColor2(msg)
SetTextFontImage(msg , menuElements[4])
SetTextSize(msg , fontSize#)
//SetTextDepth(msg, TOPBAR_DEPTH)
SetTextDepth(msg, 1)
SetTextMaxWidth(msg , 90)
msgW# = GetTextTotalWidth(msg)
if GetTextTotalWidth(msg) > 90
repeat
fontSize# = fontSize# - 0.01
SetTextSize(msg , fontSize#)
msgW# = GetTextTotalWidth(msg)
until msgW# < 90
endif
tempTxt = CreateText("X")
SetTextFontImage(tempTxt , menuElements[4])
SetTextSize(tempTxt , fontSize#)
chW# = GetTextTotalWidth(tempTxt)
DeleteText(tempTxt)
bgW# = 2.0 * chW# + msgW#
okTxt = CreateText2("Yes (recommended)" , "TEXT_BLOCK_MENU_CONFIRM")
confirmPushUI#[2,1] = okTxt
SetTextColor2(okTxt)
SetTextFontImage(okTxt , menuElements[4])
SetTextSize(okTxt , fontSize#)
//SetTextDepth(okTxt, TOPBAR_DEPTH)
SetTextDepth(okTxt, 1)
cancelTxt = CreateText2("No" , "TEXT_BLOCK_MENU_CONFIRM")
confirmPushUI#[3,1] = cancelTxt
SetTextColor2(cancelTxt)
SetTextFontImage(cancelTxt , menuElements[4])
SetTextSize(cancelTxt , fontSize#)
//SetTextDepth(cancelTxt, TOPBAR_DEPTH)
SetTextDepth(cancelTxt, 1)
btnTxtW2# = GetTextTotalWidth(cancelTxt)
okBtn = CreateSprite2(0 , "CONFIRM_BUTTON")
confirmPushUI#[4,1] = okBtn
SetSpriteColor2(okBtn)
//SetSpriteDepth(okBtn , TOPBAR_DEPTH +1)
SetSpriteDepth(okBtn , 2)
btnTxtW1# = GetTextTotalWidth(okTxt)
btnW1# = 2.0 * chW# + btnTxtW1#
btnW2# = 2.0 * chW# + btnTxtW2#
btnH# = 1.5 * fontSize#
SetSpriteSize(okBtn , btnW1# , btnH#)
cancelBtn = CreateSprite2(0 , "CONFIRM_BUTTON")
confirmPushUI#[5,1] = cancelBtn
SetSpriteColor2(cancelBtn)
//SetSpriteDepth(cancelBtn , TOPBAR_DEPTH +1)
SetSpriteDepth(cancelBtn , 2)
SetSpriteSize(cancelBtn , btnW2# , btnH#)
okBtnShad = CreateSprite2(0 , "CONFIRM_BUTTON_SHADOW")
confirmPushUI#[6,1] = okBtnShad
SetSpriteColor2(okBtnShad)
//SetSpriteDepth(okBtnShad , TOPBAR_DEPTH +2)
SetSpriteDepth(okBtnShad , 3)
SetSpriteSize(okBtnShad , btnW1# + 100.0 / gDevW# , btnH# + 100.0 / gDevH#)
cancelBtnShad = CreateSprite2(0 , "CONFIRM_BUTTON_SHADOW")
confirmPushUI#[7,1] = cancelBtnShad
SetSpriteColor2(cancelBtnShad)
//SetSpriteDepth(cancelBtnShad , TOPBAR_DEPTH +2)
SetSpriteDepth(cancelBtnShad , 3)
SetSpriteSize(cancelBtnShad , btnW2# + 100.0 / gDevW# , btnH# + 100.0 / gDevH#)
bg = CreateSprite2(0, "MENU_ITEM_BG")
confirmPushUI#[9,1] = bg
SetSpriteColor2(bg)
//SetSpriteDepth(bg , TOPBAR_DEPTH +3)
SetSpriteDepth(bg , 4)
bgH# = 3.0 * fontSize# + GetTextTotalHeight(msg)
SetSpriteSize(bg , bgW# , bgH#)
bgOut = CreateSprite2(0, "SEPARATOR")
confirmPushUI#[8,1] = bgOut
SetSpriteColor2(bgOut)
//SetSpriteDepth(bgOut , TOPBAR_DEPTH +4)
SetSpriteDepth(bgOut , 5)
SetSpriteSize(bgOut , bgW# + 200.0 / gDevW# , bgH# + 200.0 / gDevH#)
greyOut = CreateSprite(0)
FixSpriteToScreen(greyOut , 1)
confirmPushUI#[10,1] = greyOut
SetSpriteColor(greyOut , 0 , 0 , 0 , 200)
//SetSpriteDepth(greyOut , TOPBAR_DEPTH +5)
SetSpriteDepth(greyOut , 6)
SetSpriteSize(greyOut , 100 , 100)
confirmPushUI#[9,2] = 50.0 - 0.5 * bgW#
confirmPushUI#[9,3] = 50.0 - 0.5 * bgH#
confirmPushUI#[1,2] = 0.5 * bgW# - 0.5 * msgW#
confirmPushUI#[1,3] = 0.5 * fontSize#
btnPad# = (bgW# - btnW1# - btnW2#) / 3.0
confirmPushUI#[4,2] = btnPad#
confirmPushUI#[4,3] = bgH# - 0.5 * fontSize# - btnH#
confirmPushUI#[5,2] = 2.0 * btnPad# + btnW1#
confirmPushUI#[5,3] = confirmPushUI#[4,3]
confirmPushUI#[2,2] = confirmPushUI#[4,2] + 0.5 * btnW1# - 0.5 * GetTextTotalWidth(okTxt)
confirmPushUI#[2,3] = confirmPushUI#[4,3] + 0.5 * btnH# - 0.5 * fontSize#
confirmPushUI#[3,2] = confirmPushUI#[5,2] + 0.5 * btnW2# - 0.5 * GetTextTotalWidth(cancelTxt)
confirmPushUI#[3,3] = confirmPushUI#[4,3] + 0.5 * btnH# - 0.5 * fontSize#
confirmPushUI#[6,2] = confirmPushUI#[4,2]
confirmPushUI#[6,3] = confirmPushUI#[4,3]
confirmPushUI#[7,2] = confirmPushUI#[5,2]
confirmPushUI#[7,3] = confirmPushUI#[5,3]
confirmPushUI#[8,2] = -100.0 / gDevW#
confirmPushUI#[8,3] = -100.0 / gDevH#
x# = confirmPushUI#[9,2]
y# = confirmPushUI#[9,3]
SetSpritePosition(round(confirmPushUI#[9,1]) , x# , y#)
SetSpritePosition(round(confirmPushUI#[10,1]) , 0 , gBarH#)
for i = 1 to 8
id = round(confirmPushUI#[i,1])
if i = 1 or i = 2 or i = 3
SetTextPosition(id , x# + confirmPushUI#[i,2] , y# + confirmPushUI#[i,3])
elseif i >= 4 and i <= 8
SetSpritePosition(id , x# + confirmPushUI#[i,2] , y# + confirmPushUI#[i,3])
endif
next i
endfunction
function ConfirmPush(msg$)
CreateConfirmPushUI(msg$)
confirm = 0
repeat
if GetPointerPressed() = 1
bID = 0
cancel = 0 : ok = 0
px# = GetPointerX()
py# = GetPointerY() + GetViewOffsetY()
if GetSpriteHitTest(round(confirmPushUI#[5,1]) , px# , py#) = 1
bID = round(confirmPushUI#[5,1])
oBtnR = GetSpriteColorRed(bID) : oBtnG = GetSpriteColorGreen(bID) : oBtnB = GetSpriteColorBlue(bID)
shadID = round(confirmPushUI#[7,1])
txtID = round(confirmPushUI#[3,1])
cancel = 1
elseif GetSpriteHitTest(round(confirmPushUI#[4,1]) , px# , py#) = 1
bID = round(confirmPushUI#[4,1])
oBtnR = GetSpriteColorRed(bID) : oBtnG = GetSpriteColorGreen(bID) : oBtnB = GetSpriteColorBlue(bID)
shadID = round(confirmPushUI#[6,1])
txtID = round(confirmPushUI#[2,1])
ok = 1
endif
if bID > 0
PlayWSSound(SND_BUTTON)
SetSpriteColor(bID , 80, 80 , 80 , 255)
SetSpriteColor(shadID , oBtnR , oBtnG , oBtnB , 255)
SetTextColor(txtID , oBtnR , oBtnG , oBtnB , 255)
repeat
px# = GetPointerX()
py# = GetPointerY() + GetViewOffsetY()
FastSync()
until GetPointerReleased() = 1
SetSpriteColor2(bID)
SetSpriteColor2(shadID)
SetTextColor2(txtID)
if GetSpriteHitTest(bID , px# , py#) = 1
if cancel = 1
confirm = 0
elseif ok = 1
confirm = 1
endif
done = 1
endif
endif
endif
if GetRawKeyPressed(27) = 1 then done = 1
FastSync()
until done = 1
DeleteConfirmPushUI()
endfunction confirm
function DeleteConfirmPushUI()
for i = 1 to 10
id = round(confirmPushUI#[i,1])
if i = 1 or i = 2 or i = 3
DeleteText2(id)
elseif i >= 4 and i <= 10
DeleteSprite2(id)
endif
next i
undim confirmPushUI#[]
endfunction
@Digital Awakening - I thought so, but I was still having problems with it. For example if you have a type (say type_A) within a type (say type_B) and you do something like this:
type type_A
b as type_B
endtype
type type_B
c as integer
d as integer
endtype
yo as type_A
yo = Yeeha(yo)
function Yeeha(t as type_A)
t.b = Foo(t.b)
endfunction t
function BooYa(y as type_B)
y.c = 100
y.d = 200
endfunction y
Then nothing comes back into yo.b.c or yo.b.d
I may be wrong and it may take another type within a type before it fails, but I know I couldn't get it working the way I'd like for a well-built UI generation system.
It seems to work for two levels of functions OK, but not 3+ and it didn't matter if the variable was global either...