12-30-2025, 02:37 AM
Nicely done, I love seeing how we all code so differently...I got me old Menu system from GDK and with Google made it this...hopefully youll be able to glean something from it...works with mouse and KB, title of the window returns the selected item...
Happy Coding
Unseen
Code: (Select All)
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
'// PRO-CODER MENU SYSTEM (2025 EDITION)
'// Features: Keyboard Debouncing, Mouse Hover/Click, Mouse Wheel, Dynamic Alignment
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
'--- STRUCTURES ---
TYPE GDK_Vector_2D
x AS SINGLE
y AS SINGLE
END TYPE
TYPE GDK_Mouse_State
X AS INTEGER
Y AS INTEGER
L AS _BYTE ' Left Button
R AS _BYTE ' Right Button
Wheel AS INTEGER ' Scroll Delta
END TYPE
TYPE GDK_Menu
Position AS GDK_Vector_2D
Fnt AS LONG
OFF_CLR AS _UNSIGNED LONG
ON_CLR AS _UNSIGNED LONG
Entries AS _UNSIGNED _BYTE
Ref AS _UNSIGNED _BYTE ' The index of the currently selected/highlighted item
Min_Ref AS _UNSIGNED _BYTE ' The index of the first item visible in the "window"
Max_Ref AS _UNSIGNED _BYTE ' How many items to show at once (scrolling window size)
Alignment AS _BYTE ' -1 = Left, 0 = Center, 1 = Right
LastInput AS SINGLE ' Timer used to slow down keyboard repeats
InputDelay AS SINGLE ' Seconds to wait between keyboard inputs (e.g., 0.15)
END TYPE
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
' Global Mouse State (0 = Current Frame, 1 = Previous Frame)
' This allows us to detect "Clicks" (was not pressed last frame, is pressed this frame)
DIM SHARED GDK_Mouse(1) AS GDK_Mouse_State
SCREEN _NEWIMAGE(800, 600, 32)
'--- MENU SETUP ---
DIM MainMenu AS GDK_Menu
DIM MainStr(10) AS STRING * 32 ' Fixed length strings for memory safety
DIM MenuFnt&
' Load a standard system font
MenuFnt& = _LOADFONT("C:\windows\fonts\arial.ttf", 22)
' Populate Menu Data
MainStr(0) = "Resume Mission"
MainStr(1) = "New Campaign"
MainStr(2) = "Load Game"
MainStr(3) = "Display Settings"
MainStr(4) = "Audio Mix"
MainStr(5) = "Controller Config"
MainStr(6) = "Online Lobby"
MainStr(7) = "Credits"
MainStr(8) = "Bug Reporter"
MainStr(9) = "Privacy Policy"
MainStr(10) = "Exit to Desktop"
' Initialize: X=400, Y=150, Total=11, Align=0(Center), Font, HoverColor, IdleColor, WindowSize=6
GDK_Menu_New MainMenu, 400, 150, 11, 0, MenuFnt&, _RGB32(255, 255, 0), _RGB32(255, 255, 255), 6
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
DO
_LIMIT 60 ' Limit loop to 60 FPS
CLS
GDK_Update_Mouse
GDK_Menu_Update MainMenu, MainStr()
' Handle Selection (Enter Key or Left Mouse Click)
IF _KEYDOWN(13) OR (GDK_Mouse(0).L AND NOT GDK_Mouse(1).L) THEN
' PRO TIP: You would use a SELECT CASE MainMenu.Ref here to trigger game actions
_TITLE "Selected: " + LTRIM$(RTRIM$(MainStr(MainMenu.Ref)))
END IF
GDK_Menu_Render MainMenu, MainStr()
_DISPLAY
LOOP UNTIL INKEY$ = CHR$(27) ' Exit on Escape
'///////////////////////////////////////////////////////////////////////////////////////////////////////////////
' Constructor for the Menu Object
SUB GDK_Menu_New (Menu AS GDK_Menu, x%, y%, Entries~%%, Alignment%%, Fnt&, Clr_On~&, Clr_Off~&, Max~%%)
Menu.Position.x = x%
Menu.Position.y = y%
Menu.Entries = Entries~%%
Menu.Alignment = Alignment%%
Menu.Ref = 0
Menu.Min_Ref = 0
Menu.Max_Ref = Max~%%
Menu.OFF_CLR = Clr_Off~&
Menu.ON_CLR = Clr_On~&
Menu.Fnt = Fnt&
Menu.InputDelay = 0.15 ' Default debounce speed
END SUB
' Handles all Input logic
SUB GDK_Menu_Update (Menu AS GDK_Menu, Strings() AS STRING * 32)
_FONT Menu.Fnt
LOCAL_H = _FONTHEIGHT(Menu.Fnt) + 6 ' Vertical spacing including padding
' 1. KEYBOARD NAVIGATION (with Debounce)
' This prevents the selection from "flying" past options when holding a key
IF TIMER - Menu.LastInput > Menu.InputDelay THEN
IF _KEYDOWN(18432) THEN ' Arrow Up
Menu.Ref = (Menu.Ref + Menu.Entries - 1) MOD Menu.Entries
Menu.LastInput = TIMER
ELSEIF _KEYDOWN(20480) THEN ' Arrow Down
Menu.Ref = (Menu.Ref + 1) MOD Menu.Entries
Menu.LastInput = TIMER
END IF
END IF
' 2. MOUSE WHEEL NAVIGATION
' Wheel logic is "clamped" (doesn't wrap) for better user feel in long lists
IF GDK_Mouse(0).Wheel <> 0 THEN
IF GDK_Mouse(0).Wheel < 0 AND Menu.Ref > 0 THEN Menu.Ref = Menu.Ref - 1
IF GDK_Mouse(0).Wheel > 0 AND Menu.Ref < Menu.Entries - 1 THEN Menu.Ref = Menu.Ref + 1
END IF
' 3. MOUSE HOVER NAVIGATION
' We calculate a "Bounding Box" for every visible menu item
FOR i = 0 TO Menu.Max_Ref - 1
currIdx = Menu.Min_Ref + i
IF currIdx >= Menu.Entries THEN EXIT FOR
txt$ = RTRIM$(Strings(currIdx))
tw = _PRINTWIDTH(txt$) ' Get width in pixels for current font
' Calculate X boundaries based on Alignment
SELECT CASE Menu.Alignment
CASE -1: x1 = Menu.Position.x: x2 = x1 + tw ' Left
CASE 0: x1 = Menu.Position.x - (tw / 2): x2 = x1 + tw ' Center
CASE 1: x1 = Menu.Position.x - tw: x2 = Menu.Position.x ' Right
END SELECT
' Calculate Y boundaries
y1 = Menu.Position.y + (i * LOCAL_H)
y2 = y1 + LOCAL_H
' Check if mouse is inside this item's box
IF GDK_Mouse(0).X >= x1 AND GDK_Mouse(0).X <= x2 AND GDK_Mouse(0).Y >= y1 AND GDK_Mouse(0).Y <= y2 THEN
' Only change Ref if mouse actually moves.
' This allows keyboard/wheel selection to stay put even if the mouse is sitting on the screen.
IF GDK_Mouse(0).X <> GDK_Mouse(1).X OR GDK_Mouse(0).Y <> GDK_Mouse(1).Y THEN
Menu.Ref = currIdx
END IF
END IF
NEXT
' 4. SCROLLING VIEWPORT LOGIC
' This keeps the "Selected" item inside the visible window of items
IF Menu.Ref < Menu.Min_Ref THEN
Menu.Min_Ref = Menu.Ref
ELSEIF Menu.Ref >= Menu.Min_Ref + Menu.Max_Ref THEN
Menu.Min_Ref = Menu.Ref - Menu.Max_Ref + 1
END IF
END SUB
' Handles all Visual logic
SUB GDK_Menu_Render (Menu AS GDK_Menu, Strings() AS STRING * 32)
_FONT Menu.Fnt
LineHeight% = _FONTHEIGHT(Menu.Fnt) + 6
FOR i = 0 TO Menu.Max_Ref - 1
Mnu% = Menu.Min_Ref + i
IF Mnu% >= Menu.Entries THEN EXIT FOR
txt$ = RTRIM$(Strings(Mnu%))
currY% = Menu.Position.y + (i * LineHeight%)
' Set colors based on selection
IF Mnu% = Menu.Ref THEN
COLOR Menu.ON_CLR
ELSE
COLOR Menu.OFF_CLR
END IF
' Render text based on Alignment setting
SELECT CASE Menu.Alignment
CASE -1 ' Left Align
_PRINTSTRING (Menu.Position.x, currY%), txt$
CASE 0 ' Center Align
_PRINTSTRING (Menu.Position.x - (_PRINTWIDTH(txt$) / 2), currY%), txt$
CASE 1 ' Right Align
_PRINTSTRING (Menu.Position.x - _PRINTWIDTH(txt$), currY%), txt$
END SELECT
NEXT
END SUB
' Collects Mouse Data and saves previous state
SUB GDK_Update_Mouse
GDK_Mouse(1) = GDK_Mouse(0) ' Store last frame for click detection
GDK_Mouse(0).Wheel = 0 ' Reset wheel delta per frame
DO WHILE _MOUSEINPUT
GDK_Mouse(0).L = _MOUSEBUTTON(1)
GDK_Mouse(0).X = _MOUSEX
GDK_Mouse(0).Y = _MOUSEY
GDK_Mouse(0).Wheel = GDK_Mouse(0).Wheel + _MOUSEWHEEL
LOOP
END SUB
Happy Coding
Unseen


) that starts here with exploring menus: