Actually, with the following code I have a pretty solid basis for writing a complete GUI system. This would be like the 5th attempt in some years but I think it's the most promising for me. It really gets more complex with every version and I think if I keep adding gadgets this could be really worth it.
I don't know how hard it will be for you intgrate this into your HGE adaption but from what I have seen and read I think you can handle that.
And by the way, you don't need the "copy/delete/insert-element"-routine if you create or delete a window during runtime. You just set the GUI_LASTWINID variable in some places and you are good to go. You only need to update like this when you activate a window by clicking on it. I acomplished to put this part into a procedure so you also can activate windows by code using GUI_SetActiveWindow().
One more thing, the buttons are mostly there for demo purposes. If you delete a window with buttons they will not be deleted.
Code: Select all
; Window Z-Order for Screen GUI (V4)
; Fluid Byte
; August 11, 2008
; Structures
Structure GUI_WINDOW
Sprite1.l
Sprite2.l
X.w
Y.w
Width.w
Height.w
Title.s
Active.b
Dragging.b
EndStructure
Structure GUI_BUTTON
hWnd.l
X.w
Y.w
Width.w
Height.w
Title.s
State.b
EndStructure
; Constants
#GUI_Font_Caption = 0
#GUI_Font_Gadget = 1
#GUI_Font_Icon = 2
; Linked Lists
Global NewList gwin.GUI_WINDOW()
Global NewList gbtn.GUI_BUTTON()
; Global Varibales
Global GUI_CLRFACE = RGB(113,32,32)
Global GUI_CLRHILIGHT = RGB(145,42,42)
Global GUI_CLRLIGHT = RGB(113,32,32)
Global GUI_CLRSHADOW = RGB(88,25,25)
Global GUI_CLRDKSHADOW = RGB(71,20,20)
Global GUI_LASTWINID
Global GUI_MOUSEBLOCK
Global GUI_EVENTMSG
; Resources
LoadFont(#GUI_Font_Caption,"Arial",9,#PB_Font_Bold)
LoadFont(#GUI_Font_Gadget,"Arial",9)
LoadFont(#GUI_Font_Icon,"Marlett",8)
; -------------------------------------------------------------------------------------------
; FUNCTIONS
; -------------------------------------------------------------------------------------------
Procedure GUI_DrawGradient(X,Y,Width,Height,Color1,Color2,Type=0)
Protected i, sRed.f, sGreen.f, sBlue.f, R1.f, G1.f, B1.f, R2.f, G2.f, B2.f, a
If Type : i = Width : Else : i = Height : EndIf
sRed = Red(Color1) : R1 = (Red (Color1) - Red (Color2)) / i
sGreen = Green(Color1) : G1 = (Green(Color1) - Green(Color2)) / i
sBlue = Blue(Color1) : B1 = (Blue (Color1) - Blue (Color2)) / i
For a = 0 To i-1
R2.f = sRed - a * R1
G2.f = sGreen - a * G1
B2.f = sBlue - a * B1
If Type
Line(A + X,Y,0,Height,RGB(R2,G2,B2)) : Continue
EndIf
Line(X,A + Y,Width,0,RGB(R2,G2,B2))
Next
EndProcedure
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Procedure GUI_DrawRect(X,Y,Width,Height,State=0)
If State
Box(X,Y,Width,Height,GUI_CLRDKSHADOW)
Box(X + 1,Y + 1,Width - 2,Height - 2,GUI_CLRSHADOW)
Box(X + 2,Y + 2,Width - 4,Height - 4,GUI_CLRFACE)
ProcedureReturn 0
EndIf
Box(X,Y,Width,Height,GUI_CLRDKSHADOW)
Box(X,Y,Width - 1,Height - 1,GUI_CLRLIGHT)
Box(X + 1,Y + 1,Width - 2,Height - 2,GUI_CLRSHADOW)
Box(X + 1,Y + 1,Width - 3,Height - 3,GUI_CLRHILIGHT)
Box(X + 2,Y + 2,Width - 4,Height - 4,GUI_CLRFACE)
EndProcedure
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Procedure GUI_EventGadget()
Protected Result
If GUI_EVENTMSG
Result = GUI_EVENTMSG
GUI_EVENTMSG = 0
ProcedureReturn Result
EndIf
EndProcedure
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Procedure GUI_ReleaseMouseBlock()
If MouseButton(1) = 0 : GUI_MOUSEBLOCK = #False : EndIf
EndProcedure
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Procedure GUI_SetActiveWindow(Handle)
If Handle
Protected tmpString.s, hMemBuffer
; * Retrieve Window title and data from element address in memory
tmpString = gwin()\Title
hMemBuffer = AllocateMemory(SizeOf(GUI_WINDOW))
CopyMemory(gwin(),hMemBuffer,SizeOf(GUI_WINDOW))
; * Remove selected element (data has been temporarily saved)
DeleteElement(gwin())
; * Goto end of list and add a new item so it's last and the new topmost window
LastElement(gwin())
AddElement(gwin())
gwin()\Title = tmpString
; * Copy window data to address of new element
CopyMemory(hMemBuffer,gwin(),SizeOf(GUI_WINDOW))
FreeMemory(hMemBuffer)
; * Activte new window, deactivte old window
gwin()\Active = #True : GUI_LASTWINID = gwin()
ChangeCurrentElement(gwin(),Handle)
gwin()\Active = #False
ProcedureReturn 1
EndIf
EndProcedure
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Procedure GUI_OpenWindow(X,Y,Width,Height,Title.s)
Width + 2 + 2 : Height + 27 + 2
; * Create active window #1
hsprActive = CreateSprite(#PB_Any,Width,Height,#PB_Sprite_Memory)
StartDrawing(SpriteOutput(hsprActive))
DrawingMode(#PB_2DDrawing_Transparent)
Box(0,0,Width,Height,GUI_CLRDKSHADOW)
Box(0,0,Width - 1,Height - 1,GUI_CLRLIGHT)
Box(1,1,Width - 2,25,GUI_CLRSHADOW)
Box(1,1,Width - 3,24,GUI_CLRHILIGHT)
Box(2,2,Width - 4,23,GUI_CLRLIGHT)
Box(1,26,Width - 2,Height - 27,GUI_CLRSHADOW)
Box(1,26,Width - 3,Height - 28,GUI_CLRHILIGHT)
Box(2,27,Width - 4,Height - 29,GUI_CLRFACE)
GUI_DrawGradient(2,2,Width - 4,23,GUI_CLRSHADOW,GUI_CLRFACE)
GUI_DrawGradient(2,27,Width - 4,Height - 29,GUI_CLRFACE,GUI_CLRSHADOW)
DrawingFont(FontID(#GUI_Font_Icon))
GUI_DrawRect(Width - 23,6,17,16)
DrawText(Width - 20,9,"r",RGB(230,200,180))
DrawingFont(FontID(#GUI_Font_Caption))
DrawText(12,8,Title,RGB(60,0,0))
DrawText(10,6,Title,#White)
StopDrawing()
; * Create inactive window
hsprInactive = CreateSprite(#PB_Any,Width,Height,#PB_Sprite_Memory)
UseBuffer(hsprInactive)
DisplaySprite(hsprActive,0,0)
UseBuffer(#PB_Default)
; * Create active window #2
UseBuffer(hsprActive)
StartSpecialFX()
ClipSprite(hsprActive,0,0,Width,25)
DisplaySprite(hsprActive,0,0)
DisplayRGBFilter(0,0,Width,Height,45,15,0)
ClipSprite(hsprActive,0,25,Width,Height-25)
DisplaySprite(hsprActive,0,25)
ClipSprite(hsprActive,0,0,Width,Height)
StopSpecialFX()
UseBuffer(#PB_Default)
; * Add new List-Element
If GUI_LASTWINID
ChangeCurrentElement(gwin(),GUI_LASTWINID) : gwin()\Active = #False
EndIf
AddElement(gwin())
gwin()\Sprite1 = hsprActive
gwin()\Sprite2 = hsprInactive
gwin()\X = X
gwin()\Y = Y
gwin()\Width = Width
gwin()\Height = Height
gwin()\Title = Title
gwin()\Active = #True
GUI_LASTWINID = gwin()
ProcedureReturn GUI_LASTWINID
EndProcedure
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Procedure GUI_CloseWindow(Handle)
If Handle
ChangeCurrentElement(gwin(),Handle)
FreeSprite(gwin()\Sprite1)
FreeSprite(gwin()\Sprite2)
DeleteElement(gwin())
If CountList(gwin()) ! 0
LastElement(gwin())
gwin()\Active = 1
GUI_LASTWINID = gwin()
EndIf
EndIf
EndProcedure
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Procedure GUI_GetActiveWindow()
LastElement(gwin())
ProcedureReturn gwin()
EndProcedure
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Procedure GUI_PushButton(Handle,X,Y,Width,Height,Title.s)
If Handle
AddElement(gbtn())
gbtn()\hWnd = Handle
gbtn()\X = X
gbtn()\Y = Y
gbtn()\Width = Width
gbtn()\Height = Height
gbtn()\Title = Title
ProcedureReturn gbtn()
EndIf
EndProcedure
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Procedure GUI_RenderWindows()
Protected WX, WY, WW, WH, MX = MouseX(), MY = MouseY()
Static MTX, MTY
ForEach gwin()
; // DRAW WINDOWS //
WX = gwin()\X : WY = gwin()\Y : WW = gwin()\Width : WH = gwin()\Height
If gwin()\Active
DisplaySprite(gwin()\Sprite1,WX,WY)
Else
DisplaySprite(gwin()\Sprite2,WX,WY)
EndIf
If gwin()\Dragging
gwin()\X = MX + MTX
gwin()\Y = MY + MTY
EndIf
If MouseButton(1) = 0 : gwin()\Dragging = #False : EndIf
; // DRAW GADGETS //
Protected BX, BY, BW, BH
StartDrawing(ScreenOutput())
DrawingFont(FontID(#GUI_Font_Gadget))
DrawingMode(#PB_2DDrawing_Transparent)
ForEach gbtn()
If gbtn()\hwnd = gwin()
BX = WX + 2 + gbtn()\X : BY = WY + 27 + gbtn()\Y : BW = gbtn()\Width : BH = gbtn()\Height
If MX >= BX And MX <= (BX + gbtn()\Width) And MY >= BY And MY <= (BY + gbtn()\Height)
; * First Button Click
If MouseButton(1) And GUI_MOUSEBLOCK = #False
GUI_MOUSEBLOCK = #True
gbtn()\State = 1
EndIf
; * Button pushed and inside Button
If MouseButton(1) And GUI_MOUSEBLOCK = #True And gbtn()\State
gbtn()\State = 1
GUI_DrawRect(BX,BY,BW,BH,1)
DrawText(BX + BW/2 - TextWidth(gbtn()\Title)/2 + 1,BY + BH/2 - TextHeight(gbtn()\Title)/2 + 1,gbtn()\Title,#White)
EndIf
; * Relased mouse inside Button
If MouseButton(1) = 0 And gbtn()\State
GUI_EVENTMSG = gbtn()
gbtn()\State = 0
EndIf
; * Button pushed but cursor outside button
ElseIf gbtn()\State = 1
gbtn()\State = 2
EndIf
; * Draw Buttons
If gbtn()\State = 0 Or gbtn()\State = 2
GUI_DrawRect(BX,BY,BW,BH)
DrawText(BX + BW/2 - TextWidth(gbtn()\Title)/2,BY + BH/2 - TextHeight(gbtn()\Title)/2,gbtn()\Title,#White)
EndIf
; * Reset Button State
If MouseButton(1) = 0 : gbtn()\State = #False : EndIf
EndIf
Next
StopDrawing()
Next
; // MOUSE ACTIVATE //
If CountList(gwin()) ! 0 And MouseButton(1) And GUI_MOUSEBLOCK = #False
GUI_MOUSEBLOCK = #True
; * Cycle through items from back to front
LastElement(gwin())
hMemCurrent = gwin() ; address of last element / first window
Repeat
WX = gwin()\X : WY = gwin()\Y : WW = gwin()\Width : WH = gwin()\Height
If MX >= WX And MX < (WX + WW) And MY >= WY And MY < (WY + WH)
; * Detect Titlebar click
If MY < (WY + 26)
MTX = gwin()\X - MX
MTY = gwin()\Y - MY
gwin()\Dragging = #True
EndIf
; * Exit loop and don't do anything if clicked window is the active one
If gwin() = hMemCurrent : Break : EndIf
GUI_SetActiveWindow(hMemCurrent)
Break ; we found our window, get outta here
EndIf
Until PreviousElement(gwin()) = 0
EndIf
EndProcedure
; *****************************************************************************************
InitSprite() : InitKeyboard() : InitMouse()
#Fullscreen = 0
; Open Screen
If #Fullscreen
OpenScreen(800,600,32,"Fluid's Screen GUI")
Else
OpenWindow(0,0,0,800,600,"Fluid's Screen GUI",#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0),0,0,800,600,0,0,0)
EndIf
; Screen GUI Setup
gwinControls = GUI_OpenWindow(620,20,160,265,"Controls")
gbtnCreateWin1 = GUI_PushButton(gwinControls,10,10,140,27,"Create Window # 1")
gbtnCreateWin2 = GUI_PushButton(gwinControls,10,40,140,27,"Create Window # 2")
gbtnCreateWin3 = GUI_PushButton(gwinControls,10,70,140,27,"Create Window # 3")
gbtnDeleteWin1 = GUI_PushButton(gwinControls,10,120,140,27,"Delete Window # 1")
gbtnDeleteWin2 = GUI_PushButton(gwinControls,10,150,140,27,"Delete Window # 2")
gbtnDeleteWin3 = GUI_PushButton(gwinControls,10,180,140,27,"Delete Window # 3")
gbtnExit = GUI_PushButton(gwinControls,10,230,140,27,"Exit")
; Load Pointer
lpBuffer = AllocateMemory(630)
UnpackMemory(?Cursor,lpBuffer)
CatchSprite(0,lpBuffer)
TransparentSpriteColor(0,RGB(0,128,128))
FreeMemory(lpBuffer)
; Make Backdrop Pattern
CreateSprite(1,64,64)
StartDrawing(SpriteOutput(1))
Box(0,0,64,64,60) : Box(32,0,32,32,67) : Box(0,32,32,32,67)
StopDrawing()
; -----------------------------------------------------------------------------------------
; MAIN LOOP
; -----------------------------------------------------------------------------------------
Repeat
; Event Handling
If #Fullscreen = 0
Repeat
EventID = WindowEvent()
Select EventID
Case #PB_Event_CloseWindow
End
EndSelect
Until EventID = 0
EndIf
FlipBuffers() : ClearScreen(50) ; Update Screen
ExamineKeyboard() : ExamineMouse() ; Check Input Devices
; Background Scrolling
Scroll.f + 0.25
For X=0 To 13
For Y=-1 To 9
DisplaySprite(1,X * 64 - Scroll,Y * 64 + Scroll)
Next
Next
If Scroll = 64 : Scroll = 0 : EndIf
; GUI Handling
GUI_RenderWindows()
Select GUI_EventGadget()
Case gbtnCreateWin1
If gwinUntiled1 = 0
gwinUntiled1 = GUI_OpenWindow(10,10,320,240,"Untitled Window #1")
EndIf
Case gbtnCreateWin2
If gwinUntiled2 = 0
gwinUntiled2 = GUI_OpenWindow(40,50,320,240,"Untitled Window #2")
EndIf
Case gbtnCreateWin3
If gwinUntiled3 = 0
gwinUntiled3 = GUI_OpenWindow(80,90,320,240,"Untitled Window #3")
EndIf
Case gbtnDeleteWin1 : GUI_CloseWindow(gwinUntiled1) : gwinUntiled1 = 0
Case gbtnDeleteWin2 : GUI_CloseWindow(gwinUntiled2) : gwinUntiled2 = 0
Case gbtnDeleteWin3 : GUI_CloseWindow(gwinUntiled3) : gwinUntiled3 = 0
Case gbtnExit : End
EndSelect
GUI_ReleaseMouseBlock()
; FPS COunter
Frames + 1
If ElapsedMilliseconds() >= (TimerInit + 1000)
TimerInit = ElapsedMilliseconds()
FPS = Frames : Frames = 0
EndIf
StartDrawing(ScreenOutput())
DrawingMode(#PB_2DDrawing_Transparent)
DrawText(10,10,"FPS: " + Str(FPS),#White)
StopDrawing()
DisplayTransparentSprite(0,MouseX(),MouseY()) ; Draw Mouse Cursor
If #Fullscreen = 0 : Delay(1) : EndIf ; Save a little CPU
Until KeyboardPushed(1)
; -----------------------------------------------------------------------------------------
; DATA SECTION
; -----------------------------------------------------------------------------------------
DataSection
Cursor:
Data.l $0276434A,$4A720000,$A9B7AACC,$146320D0,$284A6811,$01232023,$9188409D,$F3000461,$20492601,$0A0401E0
Data.l $E00081C0,$FFC0E015,$09302024,$409C3C04,$66013801,$FE4D02B6,$91FB77FB,$B7C236B7,$BDF63086,$BFEC1EC1
Data.l $C0F36107,$0F625EF7,$008A083D,$87FFF581,$C4592A11,$4287C926,$3EC90540,$69F6974F,$21E5E328,$DDDE6107
Data.l $50B353C6,$0FB86C06,$0000D893
Data.b $90,$48
EndDataSection