Writing a GUI system

Advanced game related topics
untune
User
User
Posts: 56
Joined: Sun Jul 06, 2008 10:07 pm
Location: Bolton, UK

Post by untune »

@Thalius - thanks for the suggestion, I'll take a look :)

@Fluid Byte - That's what I was thinking last night, but it was something like 4am when I got to bed and I forgot the ideas that I had by the time I got up today :P I'm not sure if I'm in a coding mood today really, I might take a look in a while :D

Thanks
untune
User
User
Posts: 56
Joined: Sun Jul 06, 2008 10:07 pm
Location: Bolton, UK

Post by untune »

OK after 15 straight minutes of clicky testing I'm confident that I've squashed the memory crash bug. The problem was the line:

Code: Select all

CopyMemory(GUI_LIST_PANEL(), GUI_PANEL_TEMPBUFFER, SizeOf(_GUI_PANEL))
and I changed it to:

Code: Select all

CopyMemory(H_PANEL, GUI_PANEL_TEMPBUFFER, SizeOf(_GUI_PANEL))
where H_PANEL is the parameter passed to the function that this code lies in. In the main code itself, the current list element address is passed to the procedure.

That's one down I'm glad to say, but still no luck with the strings :?
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

untune wrote:I have no idea what the difference is for a fixed length string and a .s string, is it to do with how they are stored?
yap.

a fixed string is located directly at the adress where the pointer of it's name points to.
also, within a struct a fixed string is stored directly.

a dynamic string is located in a seperated dynamic stringpool wich is managed by PB base routines.
at the first location where the first pointer points to (or the part of the structured element)
only the actual pool pointer is stored.
this points to the location in the stringpool, wich can change even if one char is added to the string.
oh... and have a nice day.
untune
User
User
Posts: 56
Joined: Sun Jul 06, 2008 10:07 pm
Location: Bolton, UK

Post by untune »

Kaeru Gaman wrote:
untune wrote:I have no idea what the difference is for a fixed length string and a .s string, is it to do with how they are stored?
yap.

a fixed string is located directly at the adress where the pointer of it's name points to.
also, within a struct a fixed string is stored directly.

a dynamic string is located in a seperated dynamic stringpool wich is managed by PB base routines.
at the first location where the first pointer points to (or the part of the structured element)
only the actual pool pointer is stored.
this points to the location in the stringpool, wich can change even if one char is added to the string.
Thanks for the explanation Kaeru :)

I tried changing the string in my structure from a dynamic to a fixed length (and every other reference to it in the code!) but still no luck, same problem :?
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

you mean the "??" displaying? (sorry, didn't follow each and every posting)
I would guess on a unicode/ansi problem, but since I have no idea about the subsystem you are using, I can't really help...
oh... and have a nice day.
untune
User
User
Posts: 56
Joined: Sun Jul 06, 2008 10:07 pm
Location: Bolton, UK

Post by untune »

No problem, I'm not sure what it's down to yet...

Could someone tell me in the following block of code:

Code: Select all

; // Initialise buffer variables
    Protected GUI_PANEL_TEMPHEADER$
    

; // Get the info from the structure, create temporary structure to store it
    GUI_PANEL_TEMPHEADER$ = GUI_LIST_PANEL()\Header$
    GUI_PANEL_TEMPBUFFER = AllocateMemory(SizeOf(_GUI_PANEL))
    CopyMemory(H_PANEL, GUI_PANEL_TEMPBUFFER, SizeOf(_GUI_PANEL))
    

; // Remove the element from the list
    DeleteElement(GUI_LIST_PANEL())
    

; // Go to the front (end) of the list and add a new element
    LastElement(GUI_LIST_PANEL())
    AddElement(GUI_LIST_PANEL())
    

; // Copy data from buffer to new element
    GUI_LIST_PANEL()\Header$ = GUI_PANEL_TEMPHEADER$
    CopyMemory(GUI_PANEL_TEMPBUFFER, GUI_LIST_PANEL(), SizeOf(_GUI_PANEL))
    FreeMemory(GUI_PANEL_TEMPBUFFER)
    

; // Deactivate old panel, activate new panel
    ChangeCurrentElement(GUI_LIST_PANEL(), GUI_PANEL_CURRENT)
    GUI_LIST_PANEL()\Active = #False
    LastElement(GUI_LIST_PANEL())
    GUI_LIST_PANEL()\Active = #True
Will any of the parameters relating to allocating/copying memory etc have to take into account an offset of 8 bytes for the LL element pointers?

I'm clutching at straws now but I've run out of ideas :D
User avatar
Demivec
Addict
Addict
Posts: 4260
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Post by Demivec »

untune wrote:No problem, I'm not sure what it's down to yet...

Could someone tell me in the following block of code:

Code: Select all

; // Initialise buffer variables
    Protected GUI_PANEL_TEMPHEADER$
    

; // Get the info from the structure, create temporary structure to store it
    GUI_PANEL_TEMPHEADER$ = GUI_LIST_PANEL()\Header$
    GUI_PANEL_TEMPBUFFER = AllocateMemory(SizeOf(_GUI_PANEL))
    copy memory(H_PANEL, GUI_PANEL_TEMPBUFFER, SizeOf(_GUI_PANEL))
    

; // Remove the element from the list
    DeleteElement(GUI_LIST_PANEL())
    

; // Go to the front (end) of the list and add a new element
    LastElement(GUI_LIST_PANEL())
    AddElement(GUI_LIST_PANEL())
    

; // Copy data from buffer to new element
    GUI_LIST_PANEL()\Header$ = GUI_PANEL_TEMPHEADER$
    CopyMemory(GUI_PANEL_TEMPBUFFER, GUI_LIST_PANEL(), SizeOf(_GUI_PANEL))
    FreeMemory(GUI_PANEL_TEMPBUFFER)
    

; // Deactivate old panel, activate new panel
    ChangeCurrentElement(GUI_LIST_PANEL(), GUI_PANEL_CURRENT)
    GUI_LIST_PANEL()\Active = #False
    LastElement(GUI_LIST_PANEL())
    GUI_LIST_PANEL()\Active = #True
Will any of the parameters relating to allocating/copying memory etc have to take into account an offset of 8 bytes for the LL element pointers?

I'm clutching at straws now but I've run out of ideas :D
Here's a guess, from comparing your code sample with the example Fluid byte posted.

Code: Select all

; // Get the info from the structure, create temporary structure to store it
    GUI_PANEL_TEMPHEADER$ = GUI_LIST_PANEL()\Header$
    GUI_PANEL_TEMPBUFFER = AllocateMemory(SizeOf(_GUI_PANEL))
    ;copy memory(H_PANEL, GUI_PANEL_TEMPBUFFER, SizeOf(_GUI_PANEL)) ; <==what is H_PANEL?, information to copy should be in list GUI_LIST_PANEL()
    copy memory(GUI_LIST_PANEL(),GUI_PANEL_TEMPBUFFER, SizeOf(_GUI_PANEL)) 
untune
User
User
Posts: 56
Joined: Sun Jul 06, 2008 10:07 pm
Location: Bolton, UK

Post by untune »

that code is in a function, H_PANEL is a parameter, which will be the same as GUI_LIST_PANEL() :)
User avatar
Fluid Byte
Addict
Addict
Posts: 2336
Joined: Fri Jul 21, 2006 4:41 am
Location: Berlin, Germany

Post by Fluid Byte »

I'm to lazy to explain anything now but I will post an example tomorrow wich shows howto create/delete windows during runtime. I think that should make everything clear.
Windows 10 Pro, 64-Bit / Whose Hoff is it anyway?
untune
User
User
Posts: 56
Joined: Sun Jul 06, 2008 10:07 pm
Location: Bolton, UK

Post by untune »

Fluid Byte wrote:I'm to lazy to explain anything now but I will post an example tomorrow wich shows howto create/delete windows during runtime. I think that should make everything clear.
Cheers FB, look forward to seeing it :)
User avatar
Fluid Byte
Addict
Addict
Posts: 2336
Joined: Fri Jul 21, 2006 4:41 am
Location: Berlin, Germany

Post by Fluid Byte »

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
Windows 10 Pro, 64-Bit / Whose Hoff is it anyway?
untune
User
User
Posts: 56
Joined: Sun Jul 06, 2008 10:07 pm
Location: Bolton, UK

Post by untune »

Wow, thanks FB! Looks like pretty much everything is covered in there :D What you've got here isn't very different from mine, but yours is much more logical... There are areas of my code that I've got to put into procedures yet, but I'm realy looking forward to going through this and incorporating it into my code (can't test it at the moment as I'm at my girlfiends) but I'll check it out tomorrow :)

The only major difference is the rendering system (HGE and PB Sprites) but that no problem to change over - hopefully I can get mine to the stage where I can just pull the HGE stuff from the rendering code from mine and replace it with PB's 3d sprites... one day :D

Thanks again, I'll let you know how it turns out :D
X
Enthusiast
Enthusiast
Posts: 311
Joined: Tue Apr 04, 2006 6:27 am

Post by X »

Please keep us updated :) Would be interesting and nice to finally get a GUI system for the PB game system,.
superadnim
Enthusiast
Enthusiast
Posts: 480
Joined: Thu Jul 27, 2006 4:06 am

Post by superadnim »

that's cool :) I added support to delete the buttons but I see that if I create more than the window can accommodate, they don't get clipped out.

how do you plan to integrate scrollable areas? (one way is to hide by element when its out of the plane-view and this could also be used to not-render those gadgets that lie outside the parent's boundaries). the other way is to mask it out with a software based stencil operation - could be done with alpha masking too but I don't know how much of that is possible in PB's current state.

what bothers me is that you have global lists for everything and this could become trouble when you have more than a few gadgets to deal with. I know its just an example but if you plan to keep on integrating things I don't think that using global lists is the way to go, specially since you're nesting it all up inside a main render procedure (I would separate everything by groups of gadget types and then use a list to register them - pretty much like a class system).


peace.

:lol: should I bash the keyboard and give up?
:?
untune
User
User
Posts: 56
Joined: Sun Jul 06, 2008 10:07 pm
Location: Bolton, UK

Post by untune »

Thanks for the code FB, your system looks fantastic!

Only problem is.... I get the same error with your code as I do with mine :?

At seemingly random intervals switching from one window to the other... first time the program crashes at line 127 (DeleteElement()) when going from the controls window selected and clicking an open window....and again selecting the Controls window after Window #2 has focus caused the program to crash at line 143 (ProcedureReturn 1) with 'Invalid memory access. (read error at address 1684368500)'

So far I've had an error every time I've ran it. This makes me wonder if anyone else has had a problem with this code? Again the error points to the same section of code, SetActiveWindow() - which contains virtually the exact same code as the section which mine was crashing at. Obviously there's something it doesn't like in there but I'm stumped as to what it is :?

[EDIT] Also it just crashed when clicking the 'Delete Window 1' button... this time exiting on line 229 - DeleteElement() in the GUI_CloseWindow() procedure: Invalid memory access (read error etc etc)

[EDIT 2] Going back to an earlier idea - is it possible that when copying memory to the new element, that pointers to elements in the linked list are also being copied and perhaps therefore pointing to elements that have been deleted?
Post Reply