' === GUI STATE SETUP === Type TGuiState Field winWidth:Int, winHeight:int Field mouseX:Int, mouseY:Int Field guiMouseOver:Int Field mouseWheelDelta:Int Field mouseDown:Int, lastMouseDown:Int Field spacing:Int = 4 Field widgetHeight:Int = 24 Field cursorX:Int, cursorY:Int Field panelX:Int, panelY:Int, panelWidth:Int Field storedPanelX:Int Field storedPanelY:Int Field storedPanelWidth:Int Field storedCursorX:Int Field storedCursorY:Int Field inRow:Int Field rowStartX:Int Field rowCursorX:Int Field rowMaxHeight:Int Field rowColumns:Int Field rowElementWidth:Int Field inGrid:Int Field gridColumns:Int Field gridIndex:Int Field gridStartX:Int Field gridCellWidth:Int Field gridRowHeight:Int Field activePopup:TDropdownPopup = Null Field dropdownOpenStates:TMap = New TMap Field justOpenedPopupId:String Field popupBlocking:Int Field capturingModal:Int Field insideModal:Int Field modalActive:Int Field modalWidth:Int Field modalHeight:Int Field modalTitle:String Field modalX:Int Field modalY:Int Field modalDrawQueue:TList ' list of DrawCommand Field toastTime:Int = 0 Field toastText:String = "" Field toastR:Int, toastG:Int, toastB:Int Field toastDuration:Int = 0 Field toastActive:Int = False Field toastAlignTop:Int = True Field activeInputId:String Field inputCursorTimer:Int Field inScrollview:Int Field scrollviewX:Int Field scrollviewY:Int Field scrollviewW:Int Field scrollviewH:Int Field scrollviewContentH:Int Field savedOriginX:Int Field savedOriginY:Int Field scrollOffsets:TMap = New TMap() Field currentScrollId:String Field backupColorR:Int Field backupColorG:Int Field backupColorB:Int Field backupColorA:Float Field backupBlend:Int Field primaryColor: TGuiColor = New TGuiColor(55, 95, 125) Field primaryAccentColor: TGuiColor = New TGuiColor(76, 114, 143) Field secondaryColor: TGuiColor = New TGuiColor(55, 55, 61) Field secondaryAccentColor: TGuiColor = New TGuiColor(80, 80, 90) Field backgroundColor: TGuiColor = New TGuiColor(31, 31, 31) Field backgroundColorDark: TGuiColor = New TGuiColor(22, 22, 22) Field textColor: TGuiColor = New TGuiColor(220, 220, 220) Method Reset() cursorX = 0 cursorY = 0 panelX = 0 panelY = 0 panelWidth = 200 End Method End Type Global _theGuiState:TGuiState = New TGuiState Type TDrawCmd Field fn:Int ' 0=rect,1=text,2=imageRect… Field image:TImage Field args:Object[] ' blitz arrays of ints/floats/strings End Type Type TDropdownPopup Field id:String Field x:Int, y:Int, w:Int, h:Int Field selected:Int Ptr Field open:Int Ptr Field options:String[] Field onSelectionChangedCallback(idx:Int) End Type Type TScrollviewState Field offset:Int Field dragging:Int Field dragStartY:Int Field initialOffsetY:Int Field needsScrollbar:Int End Type Type TGuiColor Field r:Int Field g:Int Field b:Int Method New (r:Int, g:Int, b:Int) self.r = r self.g = g self.b = b End Method End Type Function GuiInit(mx:Int, my:Int, mdown:Int, mouseWheelDelta:Int, winWidth:int, winHeight:int) _theGuiState.mouseX = mx _theGuiState.mouseY = my _theGuiState.lastMouseDown = _theGuiState.mouseDown _theGuiState.mouseDown = mdown _theGuiState.mouseWheelDelta = mouseWheelDelta _theGuiState.winWidth = winWidth _theGuiState.winHeight = winHeight _theGuiState.guiMouseOver = False _StoreColors() ' Needed for the modal backdrop SetBlend(ALPHABLEND) End Function Function GuiFinalize() ' At last, render all dropdown popups If (_theGuiState.modalActive) _theGuiState.popupBlocking = True EndIf _GuiRenderModal() _GuiRenderDropdownPopups() _GuiRenderToast() _RestoreColors() SetBlend(_theGuiState.backupBlend) End Function Function GuiMouseOver:Int() Return _theGuiState.guiMouseOver End Function Function GuiCurrentY:Int() Return _theGuiState.cursorY End Function ' === THEMEING FUNCTIONS === Function GuiSetPrimaryColor(normal:TGuiColor, accent:TGuiColor) _theGuiState.primaryColor = normal _theGuiState.primaryAccentColor = accent EndFunction Function GuiSetSecondaryColor(normal:TGuiColor, accent:TGuiColor) _theGuiState.secondaryColor = normal _theGuiState.secondaryAccentColor = accent EndFunction Function GuiSetBackgroundColor(normal:TGuiColor, dark:TGuiColor) _theGuiState.backgroundColor = normal _theGuiState.backgroundColorDark = dark EndFunction Function GuiSetTextColor(color:TGuiColor) _theGuiState.textColor = color EndFunction ' === GUI FUNCTIONS === Function GuiBegin(x:Int, y:Int, width:Int = 200) _theGuiState.Reset() _theGuiState.panelX = x _theGuiState.panelY = y _theGuiState.panelWidth = width _theGuiState.cursorX = x _theGuiState.cursorY = y End Function Function GuiEnd() ' Restore the color settings _RestoreColors() End Function Function GuiModalBegin(title:String, w:Int, h:Int) ' make sure we’re not already inside a row, grid or scrollview If _theGuiState.inRow Or _theGuiState.inGrid Or _theGuiState.inScrollview Then ' RuntimeError("GuiModalBegin(): cannot open a modal while inside a row/grid/scrollview") Print("GuiModalBegin(): cannot open a modal while inside a row/grid/scrollview") End End If ' Enter modal mode _theGuiState.modalActive = True _theGuiState.popupBlocking = True _theGuiState.capturingModal = True _theGuiState.insideModal = True ' Store modal window parameters _theGuiState.modalTitle = title _theGuiState.modalWidth = w _theGuiState.modalHeight = h _theGuiState.modalX = (_theGuiState.winWidth - w) / 2 _theGuiState.modalY = (_theGuiState.winHeight - h) / 2 ' Start with an empty queue of draw commands _theGuiState.modalDrawQueue = CreateList() _theGuiState.justOpenedPopupId = "" ' Snapshot your entire layout state so we can restore it later _GuiStoreLayout() ' Begin a new gui section at the modal’s top‐left (below its title bar) GuiBegin(_theGuiState.modalX, _theGuiState.modalY + 28 + 8, w) End Function Function GuiModalEnd() GuiEnd() _theGuiState.capturingModal = False _GuiRestoreLayout() _theGuiState.insideModal = False End Function ' === GUI LAYOUT FUNCTIONS === Function GuiRowBegin(columns:Int) _theGuiState.inRow = True _theGuiState.rowColumns = columns _theGuiState.rowStartX = _theGuiState.cursorX _theGuiState.rowCursorX = _theGuiState.cursorX _theGuiState.rowMaxHeight = 0 _theGuiState.rowElementWidth = (_theGuiState.panelWidth - 16 - (_theGuiState.spacing * (columns - 1))) / columns End Function Function GuiRowEnd() _theGuiState.cursorY :+ _theGuiState.rowMaxHeight + _theGuiState.spacing _theGuiState.cursorX = _theGuiState.rowStartX _theGuiState.inRow = False End Function Function GuiGridBegin(columns:Int) _theGuiState.inGrid = True _theGuiState.gridColumns = columns _theGuiState.gridIndex = 0 _theGuiState.gridStartX = _theGuiState.cursorX + 8 _theGuiState.gridCellWidth = (_theGuiState.panelWidth - 16 - (_theGuiState.spacing * (columns - 1))) / columns _theGuiState.gridRowHeight = 0 End Function Function GuiGridEnd() If _theGuiState.gridRowHeight > 0 Then _theGuiState.cursorY :+ _theGuiState.gridRowHeight + _theGuiState.spacing End If _theGuiState.inGrid = False End Function Function GuiScrollviewBegin(id:String, height:Int) If _theGuiState.capturingModal Then RuntimeError("Scrollviews inside modals are not supported") EndIf If _theGuiState.inScrollview RuntimeError("Nested Scrollviews are not supported") EndIf If _theGuiState.inRow Or _theGuiState.inGrid RuntimeError("Scrollviews inside rows/grid not supported") EndIf _theGuiState.inScrollview = True _theGuiState.currentScrollId = id _theGuiState.scrollviewX = _theGuiState.panelX _theGuiState.scrollviewY = _theGuiState.cursorY _theGuiState.scrollviewW = _theGuiState.panelWidth _theGuiState.scrollviewH = height _theGuiState.scrollviewContentH = 0 Local state:TScrollviewState = TScrollviewState(_theGuiState.scrollOffsets.ValueForKey(id)) If Not state Then state = New TScrollviewState _theGuiState.scrollOffsets.Insert(id, state) End If ' Mouse wheel scroll If _theGuiState.mouseX >= _theGuiState.scrollviewX And _theGuiState.mouseX <= _theGuiState.scrollviewX + _theGuiState.scrollviewW And .. _theGuiState.mouseY >= _theGuiState.scrollviewY And _theGuiState.mouseY <= _theGuiState.scrollviewY + height Then state.offset :- _theGuiState.mouseWheelDelta * 20 End If If state.offset < 0 Then state.offset = 0 ' Reduce width for scrollbar space If state.needsScrollbar Then _theGuiState.panelWidth = _theGuiState.scrollviewW - 4 EndIf SetViewport(_theGuiState.scrollviewX, _theGuiState.scrollviewY, _theGuiState.scrollviewW, height) SetOrigin(0, -state.offset) _theGuiState.cursorY = _theGuiState.scrollviewY End Function Function GuiScrollviewEnd() SetOrigin(_theGuiState.savedOriginX, _theGuiState.savedOriginY) SetViewport(0, 0, _theGuiState.winWidth, _theGuiState.winHeight) Local x:Int = _theGuiState.scrollviewX + _theGuiState.scrollviewW - 8 Local y:Int = _theGuiState.scrollviewY Local w:Int = 8 Local h:Int = _theGuiState.scrollviewH Local contentH:Int = _theGuiState.scrollviewContentH Local id:String = _theGuiState.currentScrollId Local state:TScrollviewState = TScrollviewState(_theGuiState.scrollOffsets.ValueForKey(id)) If Not state Then state = New TScrollviewState If contentH > h Then state.needsScrollbar = True Local handleH:Int = Max(20, Int(Float(h) / Float(contentH) * h)) Local maxScroll:Int = contentH - h Local handleY:Int = y + Int(Float(state.offset) / Float(maxScroll) * (h - handleH)) _GuiSetColor(_theGuiState.backgroundColorDark.r, _theGuiState.backgroundColorDark.g, _theGuiState.backgroundColorDark.b) _GuiDrawRect(x, y, w, h) _GuiSetColor(_theGuiState.secondaryColor.r, _theGuiState.secondaryColor.g, _theGuiState.secondaryColor.b) _GuiDrawRect(x, handleY, w, handleH) Local hot:Int = _theGuiState.mouseX >= x And _theGuiState.mouseX <= x + w And .. _theGuiState.mouseY >= handleY And _theGuiState.mouseY <= handleY + handleH If hot And _theGuiState.mouseDown = 1 And _theGuiState.lastMouseDown = 0 Then state.dragging = True state.dragStartY = _theGuiState.mouseY state.initialOffsetY = state.offset End If If state.dragging Then If _theGuiState.mouseDown = 0 Then state.dragging = False Else Local dy:Int = _theGuiState.mouseY - state.dragStartY Local maxY:Int = h - handleH state.offset = state.initialOffsetY + Int(Float(dy) / Float(maxY) * Float(maxScroll)) state.offset = _Clamp(state.offset, 0, maxScroll) End If End If Else state.offset = 0 state.needsScrollbar = False End If If contentH > h Then state.offset = _Clamp(state.offset, 0, contentH - h) Else state.offset = 0 End If _theGuiState.cursorY = _theGuiState.scrollviewY + _theGuiState.scrollviewH + _theGuiState.spacing _theGuiState.inScrollview = False _theGuiState.currentScrollId = "" ' Restore full panel width _theGuiState.panelWidth = _theGuiState.scrollviewW End Function ' === WIDGETS === Function GuiPanel(height:Int=0) If _theGuiState.capturingModal Then RuntimeError("Panel inside modal not supported") EndIf ' Panel bounds Local x:Int = _theGuiState.panelX Local y:Int = _theGuiState.panelY Local w:Int = _theGuiState.panelWidth Local h:Int = height If h = 0 Then h = _theGuiState.winHeight ' Mouse‑over test If _theGuiState.mouseX >= x And _theGuiState.mouseX <= x + w And _theGuiState.mouseY >= y And _theGuiState.mouseY <= y + h Then _theGuiState.guiMouseOver = True EndIf ' Draw border _GuiSetColor(_theGuiState.secondaryColor.r, _theGuiState.secondaryColor.g, _theGuiState.secondaryColor.b) _GuiDrawRect(x, y, w, h) ' Draw background _GuiSetColor(_theGuiState.backgroundColor.r, _theGuiState.backgroundColor.g, _theGuiState.backgroundColor.b) _GuiDrawRect(x + 1, y + 1, w - 2, h - 2) ' Start laying out inside the panel _theGuiState.cursorX = x + _theGuiState.spacing _theGuiState.cursorY = y + _theGuiState.spacing End Function Function GuiSpacer(pixels:Int = 0) If _theGuiState.inGrid Then ' Skip a grid cell and adjust row height if needed _theGuiState.gridIndex :+ 1 If pixels > _theGuiState.gridRowHeight Then _theGuiState.gridRowHeight = pixels End If If _theGuiState.gridIndex Mod _theGuiState.gridColumns = 0 Then _theGuiState.cursorY :+ _theGuiState.gridRowHeight + _theGuiState.spacing _theGuiState.gridRowHeight = 0 End If Return End If If _theGuiState.inRow Then If pixels > 0 Then ' Apply horizontal spacing _theGuiState.rowCursorX :+ pixels If pixels > _theGuiState.rowMaxHeight Then _theGuiState.rowMaxHeight = pixels End If Else ' Skip one column in the row (like a dummy element) _theGuiState.rowCursorX :+ _theGuiState.rowElementWidth + _theGuiState.spacing End If Return End If ' Default vertical spacing when not in grid or row _theGuiState.cursorY :+ pixels End Function Function GuiLabel(text:String, centerX:Int = False, centerY:Int = True, colspan:Int = 1) Local w:Int = _theGuiState.panelWidth - 16 Local h:Int = _theGuiState.widgetHeight Local x:Int, y:Int _BeginWidget(colspan, x, y, w, h) Local textW:Int = TextWidth(text) Local textH:Int = TextHeight(text) ' Horizontal alignment Local drawX:Int = x If centerX Then drawX = x + (w - textW) / 2 ' Vertical alignment Local drawY:Int = y If centerY Then drawY = y + (h - textH) / 2 _GuiSetColor(_theGuiState.textColor.r, _theGuiState.textColor.g, _theGuiState.textColor.b) _GuiDrawText(text, drawX, drawY) h = Max(textH, h) _UpdateScrollViewContentHeight(h) _EndWidget(h) End Function Function GuiColorRect:Int(r:Int, g:Int, b:Int, height:Int = 0, label:String = "", colspan:Int = 1) Local x:Int, y:Int, w:Int, h:Int ' determine widget height override If height > 0 Then h = height Else h = _theGuiState.widgetHeight End If ' layout + hit‐rect _BeginWidget(colspan, x, y, w, h) Local my:Int = _GuiMouseY() Local hot:Int = _theGuiState.mouseX >= x And _theGuiState.mouseX <= x + w And my >= y And my <= y + h Local clicked:Int = hot And _theGuiState.mouseDown = 0 And _theGuiState.lastMouseDown = 1 ' pick fill color (lighten on hot) Local fr:Int = r, fg:Int = g, fb:Int = b If hot Then fr = Min(fr + 20, 255) fg = Min(fg + 20, 255) fb = Min(fb + 20, 255) End If _GuiSetColor(fr, fg, fb) _GuiDrawRect(x, y, w, h) ' draw centered label if any If label <> "" Then Local tw:Int = TextWidth(label) Local th:Int = TextHeight(label) Local tx:Int = x + (w - tw) / 2 Local ty:Int = y + (h - th) / 2 _GuiSetColor(_theGuiState.textColor.r, _theGuiState.textColor.g, _theGuiState.textColor.b) _GuiDrawText(label, tx, ty) End If _EndWidget(h) If _theGuiState.popupBlocking And Not _theGuiState.insideModal Then Return 0 Return clicked End Function Function GuiButton:Int(label:String, secondary:Int=False, colspan:Int = 1) Local w:Int, h:Int = _theGuiState.widgetHeight Local x:Int, y:Int _BeginWidget(colspan, x, y, w, h) Local mouseY:Int = _GuiMouseY() Local hot:Int = _theGuiState.mouseX >= x And _theGuiState.mouseX <= x + w And mouseY >= y And mouseY <= y + h Local clicked:Int = hot And _theGuiState.mouseDown = 0 And _theGuiState.lastMouseDown = 1 If hot Then If secondary Then _GuiSetColor(_theGuiState.secondaryAccentColor.r, _theGuiState.secondaryAccentColor.g, _theGuiState.secondaryAccentColor.b) Else _GuiSetColor(_theGuiState.primaryAccentColor.r, _theGuiState.primaryAccentColor.g, _theGuiState.primaryAccentColor.b) EndIf Else If secondary Then _GuiSetColor(_theGuiState.secondaryColor.r, _theGuiState.secondaryColor.g, _theGuiState.secondaryColor.b) Else _GuiSetColor(_theGuiState.primaryColor.r, _theGuiState.primaryColor.g, _theGuiState.primaryColor.b) EndIf End If _GuiDrawRect(x, y, w, h) _GuiSetColor(_theGuiState.textColor.r, _theGuiState.textColor.g, _theGuiState.textColor.b) Local textWidth:Int = TextWidth(label) Local textHeight:Int = TextHeight(label) _GuiDrawText(label, x + (w - textWidth) / 2, y + (h - textHeight) / 2) _EndWidget(h) If _theGuiState.popupBlocking And Not _theGuiState.insideModal Then Return 0 Return clicked End Function Function GuiToggleButton:Int(label:String, state:Int Var, colspan:Int = 1) Local w:Int, h:Int = _theGuiState.widgetHeight Local x:Int, y:Int _BeginWidget(colspan, x, y, w, h) Local mouseY:Int = _GuiMouseY() Local hot:Int = _theGuiState.mouseX >= x And _theGuiState.mouseX <= x + w And mouseY >= y And mouseY <= y + h Local clicked:Int = hot And _theGuiState.mouseDown = 0 And _theGuiState.lastMouseDown = 1 If clicked And (Not _theGuiState.popupBlocking Or _theGuiState.insideModal) Then state = Not state ' Background and border _GuiSetColor(_theGuiState.secondaryColor.r, _theGuiState.secondaryColor.g, _theGuiState.secondaryColor.b) _GuiDrawRect(x, y, w, h) If state Then _GuiSetColor(_theGuiState.primaryAccentColor.r, _theGuiState.primaryAccentColor.g, _theGuiState.primaryAccentColor.b) ElseIf hot Then _GuiSetColor(_theGuiState.secondaryAccentColor.r, _theGuiState.secondaryAccentColor.g, _theGuiState.secondaryAccentColor.b) Else _GuiSetColor(_theGuiState.backgroundColorDark.r, _theGuiState.backgroundColorDark.g, _theGuiState.backgroundColorDark.b) End If _GuiDrawRect(x + 1, y + 1, w - 2, h - 2) ' Label _GuiSetColor(_theGuiState.textColor.r, _theGuiState.textColor.g, _theGuiState.textColor.b) Local textWidth:Int = TextWidth(label) Local textHeight:Int = TextHeight(label) _GuiDrawText(label, x + (w - textWidth) / 2, y + (h - textHeight) / 2) _EndWidget(h) Return clicked End Function Function GuiImageButton:Int(img:TImage, w:Int, h:Int, text:String = "", align:Int = 1, secondary:Int = False, colspan:Int = 1) Local x:Int, y:Int _BeginWidget(colspan, x, y, w, h) Local mouseY:Int = _GuiMouseY() Local hot:Int = _theGuiState.mouseX >= x And _theGuiState.mouseX <= x + w And mouseY >= y And mouseY <= y + h Local clicked:Int = hot And _theGuiState.mouseDown = 0 And _theGuiState.lastMouseDown = 1 ' Background If hot Then If secondary Then _GuiSetColor(_theGuiState.secondaryAccentColor.r, _theGuiState.secondaryAccentColor.g, _theGuiState.secondaryAccentColor.b) Else _GuiSetColor(_theGuiState.primaryAccentColor.r, _theGuiState.primaryAccentColor.g, _theGuiState.primaryAccentColor.b) EndIf Else If secondary Then _GuiSetColor(_theGuiState.secondaryColor.r, _theGuiState.secondaryColor.g, _theGuiState.secondaryColor.b) Else _GuiSetColor(_theGuiState.primaryColor.r, _theGuiState.primaryColor.g, _theGuiState.primaryColor.b) EndIf End If _GuiDrawRect(x, y, w, h) ' DRAW IMAGE + TEXT If img Then Local iw:Int = ImageWidth(img) Local ih:Int = ImageHeight(img) Local scaleX:Float = Float(w - 4) / iw Local scaleY:Float = Float(h - 4) / ih Local scale:Float = Min(scaleX, scaleY) Local drawW:Float = iw * scale Local drawH:Float = ih * scale Local textW:Int = 0 If text <> "" Then textW = TextWidth(text) End If Local margin:Int = 4 Select align Case 0 ' image left _GuiSetColor(255, 255, 255) _GuiDrawImageRect(img, x + 6, y + (h - drawH) / 2, drawW, drawH) Case 2 ' image right _GuiSetColor(255, 255, 255) _GuiDrawImageRect(img, x + w - drawW - 6, y + (h - drawH) / 2, drawW, drawH) Case 1 ' image + text (or just image) centered Local startX:Float If text <> "" Then ' center image + text together Local totalW:Float = drawW + margin + textW startX = x + (w - totalW) / 2 _GuiSetColor(255, 255, 255) _GuiDrawImageRect(img, startX, y + (h - drawH) / 2, drawW, drawH) _GuiSetColor(_theGuiState.textColor.r, _theGuiState.textColor.g, _theGuiState.textColor.b) _GuiDrawText(text, startX + drawW + margin, y + (h - TextHeight(text)) / 2) text = "" ' consume so leftover text won't draw again Else ' no text → just center the image startX = x + (w - drawW) / 2 _GuiSetColor(255, 255, 255) _GuiDrawImageRect(img, startX, y + (h - drawH) / 2, drawW, drawH) End If End Select End If ' DRAW ONLY TEXT IF ANY REMAINS If text <> "" Then _GuiSetColor(_theGuiState.textColor.r, _theGuiState.textColor.g, _theGuiState.textColor.b) _GuiDrawText(text, x + (w - TextWidth(text)) / 2, y + (h - TextHeight(text)) / 2) End If _EndWidget(h) If _theGuiState.popupBlocking And Not _theGuiState.insideModal Then Return 0 Return clicked End Function Function GuiImageToggleButton:Int(img:TImage, state:Int Var, w:Int, h:Int, text:String = "", align:Int = 1, colspan:Int = 1) Local x:Int, y:Int _BeginWidget(colspan, x, y, w, h) Local mouseY:Int = _GuiMouseY() Local hot:Int = _theGuiState.mouseX >= x And _theGuiState.mouseX <= x + w And mouseY >= y And mouseY <= y + h Local clicked:Int = hot And _theGuiState.mouseDown = 0 And _theGuiState.lastMouseDown = 1 If clicked And (Not _theGuiState.popupBlocking Or _theGuiState.insideModal) Then state = Not state EndIf ' Frame _GuiSetColor(_theGuiState.secondaryColor.r, _theGuiState.secondaryColor.g, _theGuiState.secondaryColor.b) _GuiDrawRect(x, y, w, h) If state Then _GuiSetColor(_theGuiState.primaryAccentColor.r, _theGuiState.primaryAccentColor.g, _theGuiState.primaryAccentColor.b) ElseIf hot Then _GuiSetColor(_theGuiState.secondaryAccentColor.r, _theGuiState.secondaryAccentColor.g, _theGuiState.secondaryAccentColor.b) Else _GuiSetColor(_theGuiState.backgroundColorDark.r, _theGuiState.backgroundColorDark.g, _theGuiState.backgroundColorDark.b) EndIf _GuiDrawRect(x + 1, y + 1, w - 2, h - 2) ' DRAW IMAGE + TEXT If img Then Local iw:Int = ImageWidth(img) Local ih:Int = ImageHeight(img) Local scaleX:Float = Float(w - 4) / iw Local scaleY:Float = Float(h - 4) / ih Local scale:Float = Min(scaleX, scaleY) Local drawW:Float = iw * scale Local drawH:Float = ih * scale Local textW:Int = 0 If text <> "" Then textW = TextWidth(text) Local margin:Int = 4 Select align Case 0 _GuiSetColor(255, 255, 255) _GuiDrawImageRect(img, x + 6, y + (h - drawH) / 2, drawW, drawH) Case 2 _GuiSetColor(255, 255, 255) _GuiDrawImageRect(img, x + w - drawW - 6, y + (h - drawH) / 2, drawW, drawH) Case 1 Local startX:Float If text <> "" Then ' center image + text Local totalW:Float = drawW + margin + textW startX = x + (w - totalW) / 2 _GuiSetColor(255, 255, 255) _GuiDrawImageRect(img, startX, y + (h - drawH) / 2, drawW, drawH) _GuiSetColor(_theGuiState.textColor.r, _theGuiState.textColor.g, _theGuiState.textColor.b) _GuiDrawText(text, startX + drawW + margin, y + (h - TextHeight(text)) / 2) text = "" ' consume text so the later block doesn't redraw it Else ' no text: just center image startX = x + (w - drawW) / 2 _GuiSetColor(255, 255, 255) _GuiDrawImageRect(img, startX, y + (h - drawH) / 2, drawW, drawH) EndIf End Select EndIf ' DRAW ONLY TEXT IF ANY REMAINS If text <> "" Then _GuiSetColor(_theGuiState.textColor.r, _theGuiState.textColor.g, _theGuiState.textColor.b) _GuiDrawText(text, x + (w - TextWidth(text)) / 2, y + (h - TextHeight(text)) / 2) EndIf _EndWidget(h) Return clicked End Function Function GuiCheckbox:Int(label:String, state:Int Var, colspan:Int = 1) Local h:Int = _theGuiState.widgetHeight Local w:Int Local x:Int, y:Int _BeginWidget(colspan, x, y, w, h) Local mouseY:Int = _GuiMouseY() Local hot:Int = _theGuiState.mouseX >= x And _theGuiState.mouseX <= x + h And mouseY >= y And mouseY <= y + h Local clicked:Int = hot And _theGuiState.mouseDown = 0 And _theGuiState.lastMouseDown = 1 If clicked And (Not _theGuiState.popupBlocking Or _theGuiState.insideModal) Then state = Not state End If ' Outer box _GuiSetColor(_theGuiState.secondaryColor.r, _theGuiState.secondaryColor.g, _theGuiState.secondaryColor.b) _GuiDrawRect(x + 2, y + 2, h - 4, h - 4) ' Inner fill if checked If state Then _GuiSetColor(_theGuiState.primaryAccentColor.r, _theGuiState.primaryAccentColor.g, _theGuiState.primaryAccentColor.b) _GuiDrawRect(x + 4, y + 4, h - 8, h - 8) End If ' Label text _GuiSetColor(_theGuiState.textColor.r, _theGuiState.textColor.g, _theGuiState.textColor.b) _GuiDrawText(label, x + h + 8, y + (h - TextHeight(label)) / 2) _EndWidget(h) Return clicked End Function Function GuiTextInput:String(id:String, text:String Var, maxLen:Int = 256, onBlur(value:String) = Null, colspan:Int = 1) Local w:Int, h:Int = _theGuiState.widgetHeight Local x:Int, y:Int _BeginWidget(colspan, x, y, w, h) ' hit‐testing Local mouseY:Int = _GuiMouseY() Local hot:Int = _theGuiState.mouseX >= x And _theGuiState.mouseX <= x + w And mouseY >= y And mouseY <= y + h Local clicked:Int = hot And _theGuiState.mouseDown = 0 And _theGuiState.lastMouseDown = 1 ' block any interaction outside the modal Local blockedOutside:Int = _theGuiState.popupBlocking And Not _theGuiState.insideModal ' if we’re allowed to, mark GUI‐over so clicks don’t leak If hot And Not blockedOutside Then _theGuiState.guiMouseOver = True End If ' focus/defocus If Not blockedOutside Then If clicked Then _theGuiState.activeInputId = id _theGuiState.inputCursorTimer = MilliSecs() ElseIf _theGuiState.mouseDown = 0 And _theGuiState.lastMouseDown = 1 And Not hot If _theGuiState.activeInputId = id Then _theGuiState.activeInputId = "" If onBlur Then onBlur(text) End If End If End If _UpdateScrollViewContentHeight(h) ' text entry when focused If _theGuiState.activeInputId = id Then Local c:Int = GetChar() While c If c = 8 Then If text.length > 0 Then text = Left(text, text.length - 1) ElseIf c >= 32 And c < 127 If text.length < maxLen Then text :+ Chr(c) End If c = GetChar() Wend End If ' drawing If _theGuiState.activeInputId = id Then _GuiSetColor(_theGuiState.secondaryAccentColor.r, _theGuiState.secondaryAccentColor.g, _theGuiState.secondaryAccentColor.b) Else _GuiSetColor(_theGuiState.secondaryColor.r, _theGuiState.secondaryColor.g, _theGuiState.secondaryColor.b) EndIf _GuiDrawRect(x, y, w, h) _GuiSetColor(_theGuiState.backgroundColorDark.r, _theGuiState.backgroundColorDark.g, _theGuiState.backgroundColorDark.b) _GuiDrawRect(x+1, y+1, w-2, h-2) _GuiSetColor(_theGuiState.textColor.r, _theGuiState.textColor.g, _theGuiState.textColor.b) _GuiDrawText(text, x + 4, y + (h - TextHeight(text)) / 2) ' blinking cursor If _theGuiState.activeInputId = id Then Local t:Int = MilliSecs() - _theGuiState.inputCursorTimer If (t / 500 Mod 2) = 0 Then Local tw:Int = TextWidth(text) _GuiDrawRect(x + 4 + tw, y + 4, 2, h - 8) End If End If _EndWidget(h) Return text End Function Function GuiSlider:Float(value:Float Var, min:Float, max:Float, onValueChanged(value:Float) = Null, colspan:Int = 1) Local w:Int, h:Int = _theGuiState.widgetHeight Local x:Int, y:Int _BeginWidget(colspan, x, y, w, h) _GuiSetColor(_theGuiState.secondaryColor.r, _theGuiState.secondaryColor.g, _theGuiState.secondaryColor.b) _GuiDrawRect(x, y + h / 2 - 4, w, 8) Local sliderX:Int = x + (value - min) / (max - min) * w _GuiSetColor(_theGuiState.primaryColor.r, _theGuiState.primaryColor.g, _theGuiState.primaryColor.b) _GuiDrawRect(sliderX - 6, y + h / 2 - 6, 12, 12) Local mouseY:Int = _GuiMouseY() If _theGuiState.mouseDown = 1 And mouseY >= y And mouseY <= y + h And _theGuiState.mouseX >= x And _theGuiState.mouseX <= x + w If Not _theGuiState.popupBlocking Or _theGuiState.insideModal value = Min + Float(_theGuiState.mouseX - x) / Float(w) * (max - min) If onValueChanged Then onValueChanged(value) End If End If _EndWidget(h) Return value End Function Function GuiProgressBar(current:Float, min:Float, max:Float, colspan:Int = 1) Local w:Int, h:Int = _theGuiState.widgetHeight Local x:Int, y:Int _BeginWidget(colspan, x, y, w, h) Local value:Float = _Clamp((current - min) / (max - min), 0.0, 1.0) _GuiSetColor(_theGuiState.secondaryColor.r, _theGuiState.secondaryColor.g, _theGuiState.secondaryColor.b) _GuiDrawRect(x, y + h / 2 - 4, w, 8) _GuiSetColor(_theGuiState.primaryColor.r, _theGuiState.primaryColor.g, _theGuiState.primaryColor.b) _GuiDrawRect(x, y + h / 2 - 4, w * value, 8) _EndWidget(h) End Function Function GuiDropdown:Int(id:String, options:String[], selected:Int Var, onSelectionChanged(idx:Int) = Null, colspan:Int = 1) Local w:Int, h:Int = _theGuiState.widgetHeight Local x:Int, y:Int _BeginWidget(colspan, x, y, w, h) ' === Get open state for this dropdown === Local open:Int = False If _theGuiState.dropdownOpenStates.Contains(id) Then open = Int(String(_theGuiState.dropdownOpenStates.ValueForKey(id))) End If ' === Handle toggle === If Not _theGuiState.popupBlocking Or _theGuiState.insideModal Local mouseY:Int = _GuiMouseY() Local hot:Int = _theGuiState.mouseX >= x And _theGuiState.mouseX <= x + w And mouseY >= y And mouseY <= y + h If hot And _theGuiState.mouseDown = 0 And _theGuiState.lastMouseDown = 1 Then open = Not open _theGuiState.dropdownOpenStates.Insert(id, String(open)) If open Then _theGuiState.justOpenedPopupId = id End If End If ' === Draw main box === _GuiSetColor(_theGuiState.secondaryAccentColor.r, _theGuiState.secondaryAccentColor.g, _theGuiState.secondaryAccentColor.b) _GuiDrawRect(x, y, w, h) _GuiSetColor(_theGuiState.secondaryColor.r, _theGuiState.secondaryColor.g, _theGuiState.secondaryColor.b) _GuiDrawRect(x + 1, y + 1, w - 2, h - 2) If selected < options.length And selected >= 0 Then _GuiSetColor(_theGuiState.textColor.r, _theGuiState.textColor.g, _theGuiState.textColor.b) _GuiDrawText(options[selected], x + 8, y + (h - TextHeight(options[selected])) / 2) EndIf _GuiDrawText("v", x + w - TextWidth("v") - 8, y + (h - TextHeight("v")) / 2) _EndWidget(h) ' === Setup popup data === Local state:TScrollviewState = TScrollviewState(_theGuiState.scrollOffsets.ValueForKey(_theGuiState.currentScrollId)) Local offset:Int If state Then offset = state.offset If open Then _theGuiState.activePopup = New TDropdownPopup _theGuiState.activePopup.id = id _theGuiState.activePopup.x = x _theGuiState.activePopup.y = y + h - offset _theGuiState.activePopup.w = w _theGuiState.activePopup.h = h _theGuiState.activePopup.options = options _theGuiState.activePopup.onSelectionChangedCallback = onSelectionChanged _theGuiState.activePopup.selected = VarPtr selected _theGuiState.activePopup.open = VarPtr open ElseIf _theGuiState.activePopup And _theGuiState.activePopup.id = id Then _theGuiState.activePopup = Null End If Return selected End Function Function GuiListView:Int(items:String[], selected:Int Var, onSelectionChanged(idx:Int) = Null, colspan:Int = 1) Local w:Int, h:Int = _theGuiState.widgetHeight Local x:Int, y:Int _BeginWidget(colspan, x, y, w, h) ' Draw each item row For Local i:Int = 0 Until items.length Local itemY:Int = _theGuiState.cursorY + i * h Local mouseY:Int = _GuiMouseY() Local hot:Int = _theGuiState.mouseX >= x And _theGuiState.mouseX <= x + w And mouseY >= itemY And mouseY <= itemY + h Local clicked:Int = hot And _theGuiState.mouseDown = 0 And _theGuiState.lastMouseDown = 1 If Not _theGuiState.popupBlocking Or _theGuiState.insideModal If clicked Then selected = i If onSelectionChanged Then onSelectionChanged(i) EndIf End If If i = selected Then _GuiSetColor(_theGuiState.secondaryAccentColor.r, _theGuiState.secondaryAccentColor.g, _theGuiState.secondaryAccentColor.b) ElseIf hot Then _GuiSetColor(_theGuiState.secondaryColor.r, _theGuiState.secondaryColor.g, _theGuiState.secondaryColor.b) Else _GuiSetColor(_theGuiState.backgroundColorDark.r, _theGuiState.backgroundColorDark.g, _theGuiState.backgroundColorDark.b) End If _GuiDrawRect(x, itemY, w, h) _GuiSetColor(_theGuiState.textColor.r, _theGuiState.textColor.g, _theGuiState.textColor.b) _GuiDrawText(items[i], x + 8, itemY + (h - TextHeight(items[i])) / 2) Next ' Update scrollview height _UpdateScrollViewContentHeight(items.length * h) _EndWidget(items.length * h) Return selected End Function Function GuiTabBar:Int(tabs:String[], selected:Int Var, colspan:Int = 1) Local tabCount:Int = tabs.length If tabCount = 0 Then Return -1 Local tabHeight:Int = _theGuiState.widgetHeight Local tabWidth:Int, totalWidth:Int Local x:Int, y:Int _BeginWidget(colspan, x, y, totalWidth, tabHeight) tabWidth = (totalWidth - (_theGuiState.spacing * (tabCount - 1))) / tabCount For Local i:Int = 0 Until tabCount Local tx:Int = x + i * (tabWidth + _theGuiState.spacing) Local mouseY:Int = _GuiMouseY() Local hot:Int = _theGuiState.mouseX >= tx And _theGuiState.mouseX <= tx + tabWidth And mouseY >= y And mouseY <= y + tabHeight Local clicked:Int = hot And _theGuiState.mouseDown = 0 And _theGuiState.lastMouseDown = 1 If Not _theGuiState.popupBlocking Or _theGuiState.insideModal If clicked Then selected = i EndIf ' Draw background If selected = i Then _GuiSetColor(_theGuiState.secondaryColor.r, _theGuiState.secondaryColor.g, _theGuiState.secondaryColor.b) ElseIf hot Then _GuiSetColor(_theGuiState.secondaryAccentColor.r, _theGuiState.secondaryAccentColor.g, _theGuiState.secondaryAccentColor.b) Else _GuiSetColor(_theGuiState.backgroundColorDark.r, _theGuiState.backgroundColorDark.g, _theGuiState.backgroundColorDark.b) End If _GuiDrawRect(tx, y, tabWidth, tabHeight) ' Label _GuiSetColor(_theGuiState.textColor.r, _theGuiState.textColor.g, _theGuiState.textColor.b) Local textW:Int = TextWidth(tabs[i]) Local textH:Int = TextHeight(tabs[i]) _GuiDrawText(tabs[i], tx + (tabWidth - textW) / 2, y + (tabHeight - textH) / 2) ' Active underline If selected = i Then _GuiSetColor(_theGuiState.primaryColor.r, _theGuiState.primaryColor.g, _theGuiState.primaryColor.b) _GuiDrawRect(tx, y + tabHeight - 3, tabWidth, 3) End If Next ' Layout update _EndWidget(tabHeight) Return selected End Function Function GuiToast(text:String, r:Int, g:Int, b:Int, timeMS:Int, alignTop:Int = False) If Not _theGuiState.toastActive Then _theGuiState.toastText = text _theGuiState.toastR = r _theGuiState.toastG = g _theGuiState.toastB = b _theGuiState.toastDuration = timeMS _theGuiState.toastTime = MilliSecs() _theGuiState.toastActive = True _theGuiState.toastAlignTop = alignTop End If End Function ' === Helpers Private Functions === Function _Clamp:Float(value:Float, minVal:Float, maxVal:Float) If value < minVal Then Return minVal If value > maxVal Then Return maxVal Return value End Function Function _StoreColors() ' Save the current color settings so we can restore it after gui drawing GetColor(_theGuiState.backupColorR, _theGuiState.backupColorG, _theGuiState.backupColorB) _theGuiState.backupColorA = GetAlpha() _theGuiState.backupBlend = GetBlend() End Function Function _RestoreColors() SetColor(_theGuiState.backupColorR, _theGuiState.backupColorG, _theGuiState.backupColorB) SetAlpha(_theGuiState.backupColorA) End Function Function _GuiMouseY:Int() If _theGuiState.inScrollview Then Local state:TScrollviewState = TScrollviewState(_theGuiState.scrollOffsets.ValueForKey(_theGuiState.currentScrollId)) If state Then Return _theGuiState.mouseY + state.offset End If End If Return _theGuiState.mouseY End Function Function _UpdateScrollViewContentHeight(widgetHeight:Int) If _theGuiState.inScrollview Then Local bottom:Int = (_theGuiState.cursorY + widgetHeight) - _theGuiState.scrollviewY If bottom > _theGuiState.scrollviewContentH Then _theGuiState.scrollviewContentH = bottom End If End If End Function Function _GuiRenderDropdownPopups() _theGuiState.popupBlocking = False If Not _theGuiState.activePopup Then Return Local p:TDropdownPopup = _theGuiState.activePopup _UpdateScrollViewContentHeight(p.h) ' Mouse over popup? Block interaction behind If _theGuiState.mouseX >= p.x And _theGuiState.mouseX <= p.x + p.w And _theGuiState.mouseY >= p.y And _theGuiState.mouseY <= p.y + p.h * p.options.length Then _theGuiState.popupBlocking = True End If For Local i:Int = 0 Until p.options.length Local itemY:Int = p.y + i * p.h Local mouseY:int = _GuiMouseY() Local hot:Int = _theGuiState.mouseX >= p.x And _theGuiState.mouseX <= p.x + p.w And mouseY >= itemY And mouseY <= itemY + p.h Local clicked:Int = hot And _theGuiState.mouseDown = 0 And _theGuiState.lastMouseDown = 1 If clicked p.selected[0] = i If p.onSelectionChangedCallback Then p.onSelectionChangedCallback(i) EndIf p.open[0] = False _theGuiState.activePopup = Null _theGuiState.dropdownOpenStates.Insert(p.id, String(0)) Return End If If p.selected[0] = i Then _GuiSetColor(_theGuiState.secondaryAccentColor.r, _theGuiState.secondaryAccentColor.g, _theGuiState.secondaryAccentColor.b) ElseIf hot Then _GuiSetColor(_theGuiState.secondaryColor.r, _theGuiState.secondaryColor.g, _theGuiState.secondaryColor.b) Else _GuiSetColor(_theGuiState.backgroundColorDark.r, _theGuiState.backgroundColorDark.g, _theGuiState.backgroundColorDark.b) End If _GuiDrawRect(p.x, itemY, p.w, p.h) _GuiSetColor(_theGuiState.textColor.r, _theGuiState.textColor.g, _theGuiState.textColor.b) _GuiDrawText(p.options[i], p.x + 8, itemY + (p.h - TextHeight(p.options[i])) / 2) Next ' Close if clicked outside (skip if just opened this frame) If _theGuiState.mouseDown = 0 And _theGuiState.lastMouseDown = 1 Then If _theGuiState.justOpenedPopupId <> p.id Then If Not (_theGuiState.mouseX >= p.x And _theGuiState.mouseX <= p.x + p.w And _theGuiState.mouseY >= p.y And _theGuiState.mouseY <= p.y + p.h * p.options.length) Then p.open[0] = False _theGuiState.activePopup = Null _theGuiState.dropdownOpenStates.Insert(p.id, String(0)) End If End If End If _theGuiState.justOpenedPopupId = "" End Function Function _GuiRenderToast() If Not _theGuiState.toastActive Then Return Local elapsed:Int = MilliSecs() - _theGuiState.toastTime If elapsed > _theGuiState.toastDuration Then _theGuiState.toastActive = False Return End If Local w:Int = _theGuiState.winWidth Local h:Int = 32 Local y:Int = 0 If Not _theGuiState.toastAlignTop Then y = _theGuiState.winHeight - h End If SetColor(_theGuiState.toastR, _theGuiState.toastG, _theGuiState.toastB) DrawRect(0, y, w, h) SetColor(_theGuiState.textColor.r, _theGuiState.textColor.g, _theGuiState.textColor.b) Local textW:Int = TextWidth(_theGuiState.toastText) Local textH:Int = TextHeight(_theGuiState.toastText) DrawText(_theGuiState.toastText, (w - textW) / 2, y + (h - textH) / 2) End Function ' === For deferred modal rendering (so the modal is always ontop) === Function _GuiSetColor(r:int, g:Int, b:Int) If _theGuiState.capturingModal Local cmd:TDrawCmd = New TDrawCmd cmd.fn = 0 cmd.args = [String(r),String(g), String(b)] _theGuiState.modalDrawQueue.AddLast(cmd) Else SetColor(r, g, b) EndIf End Function Function _GuiDrawText(s:String,x:Float,y:Float) If _theGuiState.capturingModal Local cmd:TDrawCmd = New TDrawCmd cmd.fn = 1 cmd.args = [s, String(x), String(y)] _theGuiState.modalDrawQueue.AddLast(cmd) Else DrawText(s, x, y) EndIf End Function Function _GuiDrawRect(x:Float,y:Float,w:Float,h:Float) If _theGuiState.capturingModal Local cmd:TDrawCmd = New TDrawCmd cmd.fn = 2 cmd.args = [String(x),String(y),String(w),String(h)] _theGuiState.modalDrawQueue.AddLast(cmd) Else DrawRect(x,y,w,h) EndIf End Function Function _GuiDrawImageRect(image:TImage, x:Float, y:Float, w:Float, h:Float, frame:Int=0) If _theGuiState.capturingModal Then Local cmd:TDrawCmd = New TDrawCmd cmd.fn = 3 cmd.image = image cmd.args = [ String(x), String(y), String(w), String(h), String(frame) ] _theGuiState.modalDrawQueue.AddLast( cmd ) Else DrawImageRect(image, x, y, w, h, frame) EndIf End Function Function _GuiRenderModal() If Not _theGuiState.modalActive Then Return _theGuiState.guiMouseOver = True ' 1) Fade backdrop SetColor 0, 0, 0 SetAlpha 0.7 DrawRect(0, 0, _theGuiState.winWidth, _theGuiState.winHeight) SetAlpha 1.0 ' 2) Modal window frame + title SetColor _theGuiState.backgroundColor.r, _theGuiState.backgroundColor.g, _theGuiState.backgroundColor.b DrawRect(_theGuiState.modalX, _theGuiState.modalY, _theGuiState.modalWidth, _theGuiState.modalHeight) SetColor _theGuiState.secondaryColor.r, _theGuiState.secondaryColor.g, _theGuiState.secondaryColor.b DrawRect(_theGuiState.modalX, _theGuiState.modalY, _theGuiState.modalWidth, 28) SetColor _theGuiState.textColor.r, _theGuiState.textColor.g, _theGuiState.textColor.b DrawText(_theGuiState.modalTitle, _theGuiState.modalX + 8, _theGuiState.modalY + 6) ' 3) Replay every queued widget-draw inside it For Local cmd:TDrawCmd = EachIn _theGuiState.modalDrawQueue Select cmd.fn Case 0 SetColor(Int(String(cmd.args[0])), Int(String(cmd.args[1])), Int(String(cmd.args[2]))) Case 1 DrawText(String(cmd.args[0]), Float(String(cmd.args[1])), Float(String(cmd.args[2]))) Case 2 DrawRect(Float(String(cmd.args[0])), Float(String(cmd.args[1])), Float(String(cmd.args[2])), Float(String(cmd.args[3]))) Case 3 DrawImageRect(cmd.image, Float(String(cmd.args[0])), Float(String(cmd.args[1])), Float(String(cmd.args[2])), Float(String(cmd.args[3])), Int(String(cmd.args[4]))) End Select Next ' 4) Done—clear the queue and finally exit modal mode _theGuiState.modalDrawQueue.Clear() _theGuiState.modalActive = False _theGuiState.popupBlocking = False End Function Function _BeginWidget(colspan:Int, x:Int Var, y:Int Var, width:Int Var, height:Int Var) If _theGuiState.inGrid Then Local col:Int = _theGuiState.gridIndex Mod _theGuiState.gridColumns _theGuiState.cursorX = _theGuiState.gridStartX + col * (_theGuiState.gridCellWidth + _theGuiState.spacing) width = _theGuiState.gridCellWidth * colspan + _theGuiState.spacing * (colspan - 1) _theGuiState.gridIndex :+ colspan ElseIf _theGuiState.inRow Then _theGuiState.cursorX = _theGuiState.rowCursorX width = _theGuiState.rowElementWidth * colspan + _theGuiState.spacing * (colspan - 1) _theGuiState.rowCursorX :+ width + _theGuiState.spacing Else _theGuiState.cursorX = _theGuiState.panelX width = _theGuiState.panelWidth - 16 End If Local rightSpace:Int = 8 If _theGuiState.inGrid Then rightSpace = 0 x = _theGuiState.cursorX + rightSpace y = _theGuiState.cursorY _UpdateScrollViewContentHeight(height) End Function Function _EndWidget(height:Int) If _theGuiState.inGrid Then If height > _theGuiState.gridRowHeight Then _theGuiState.gridRowHeight = height If _theGuiState.gridIndex Mod _theGuiState.gridColumns = 0 Then _theGuiState.cursorY :+ _theGuiState.gridRowHeight + _theGuiState.spacing _theGuiState.gridRowHeight = 0 End If ElseIf _theGuiState.inRow Then If height > _theGuiState.rowMaxHeight Then _theGuiState.rowMaxHeight = height Else _theGuiState.cursorY :+ height + _theGuiState.spacing End If EndFunction Function _GuiStoreLayout() _theGuiState.storedPanelX = _theGuiState.panelX _theGuiState.storedPanelY = _theGuiState.panelY _theGuiState.storedPanelWidth = _theGuiState.panelWidth _theGuiState.storedCursorX = _theGuiState.cursorX _theGuiState.storedCursorY = _theGuiState.cursorY End Function Function _GuiRestoreLayout() _theGuiState.panelX = _theGuiState.storedPanelX _theGuiState.panelY = _theGuiState.storedPanelY _theGuiState.panelWidth = _theGuiState.storedPanelWidth _theGuiState.cursorX = _theGuiState.storedCursorX _theGuiState.cursorY = _theGuiState.storedCursorY End Function