Posted: 10th Apr 2014 2:39
[center]Very Basic 3D Scene Editor - Making Of - Step by step[/center]

I start a thread in which I'll show the Making Of a 3d scene editor.
It will be released on several posts, each focusing on some specific task.
Basically, this program will allow to load objects or create primitive, place them, apply texture and load/save scene.
So very basic stuff... still structured and flexible enough to add new features.
Some topics focused: Windowing with BlueGUI, Camera control, Gizmo control, entity editing with properties sheets, load texture, save/load scene in xml...
Some plugins are needed:
Matrix1DLLs(IanM)
OpenSorce)
Advanced2d(Diggsey)
XML(Madbit)
Extended Rotation(Madbit)

Q:Why this is in snippets board, it looks like a WIP ???
A:It's sitting on the fence between one and the other. I have not enough to show now for a WIP but It's can be considered like several completed snippets
Q:What skills are required ???
A:Beginner/Intermediate. But some basic knowledge of 3D maths and linear algebra


Summary
1. Setup a window with BlueGUI
2. Camera control
3. Adding a toolbar
4. Property lists
5. More property lists cell types
6. Overview of the core structures
7. EditorObject
8. Entity, Module, ModuleClass and SceneEditor
9. ToolWindow and EntityList
10. EntityEditor
11. Module Definition and Module Editors
12. Resources
13. Materials
14. Load and Save scenes
15. Gizmos

And what's next ???
Posted: 10th Apr 2014 2:39
1. Setup a window with BlueGUI

We want here a window that does not stretch when resized. A simple way to do that is define the dbp window borderless at desktop size and set it as a child viewport of another window. But this causes some minors problems like the deactivated titlebar. fortunately, this can be solved with some handlings...
other trick is event handling, I sometime read:

If EventType() = .... Then DoThis()

I don't like it. because during execution of DoThis(), events can occur and this bad for responsiveness.
My method is to empty the event queue, storing the events into variables, and then process them.
Last issue: except the main loop, dont use do/loop while/endwhile repeat/until for loops. This because they perform some engine sync. use for/next instead is much faster...

+ Code Snippet
Rem * Very Basic 3D Editor *

#Constant false 0
#Constant true 1

Global debug: debug = true
#Constant debugprint If debug Then Print Console
If debug Then Open Console



Rem * Globals *
Global AppUser32DLL
Global AppDLLBuffer

Global AppDesktopWindow
Global AppRequestToClose
Global AppWindow
Global AppTitle$
Global AppIsActive

Global Screen
Global ScreenWatchImage
Global ScreenFont


Rem * App start *
    Sync Off: Rem Prefered mode for a windowed app
    AppUser32DLL = 1
    Load DLL "user32.dll", AppUser32DLL
    AppDLLBuffer = Make Memory(64)

Rem - Variables Inits -
    AppTitle$ = "Very Basic 3D Editor"
    AppDesktopWindow = CreateGadgetFromWindow(DesktopWindow())
    Screen = CreateGadgetFromWindow(MainWindow())

Rem - App Window -
    DTW = GadgetClientWidth(AppDesktopWindow)
    DTH = GadgetClientHeight(AppDesktopWindow)
    AppWindow = CreateWindow(16, 16, DTW-32, DTH-64, AppTitle$, WINDOW_NORMAL, 0, 1, 0)

    App_CreateWindowMenu()

Rem - Screen -
Show Window
    Set Window On
    Screen_Reset(DTW, DTH)
    SetGadgetParent Screen, AppWindow
	Hide App Icon

    ScreenWatchImage = Reserve Free Image()
	Get Image ScreenWatchImage, 0, 0, 1, 1, 1

	ScreenFont = a2CreateFont("tahoma", 16, a2Size_Cell(), a2Style_Bold())
	a2SetLineAA false


Rem * Main Loop *
	ActivateGadget Screen
	PreviousAppIsActive = true
	PreviousActiveGadget = 0
    AppExit = false
    Do
        EventCommand = 0
        EventResize = false
		EventCloseWindow = 0

Rem - Detect screen change -
        If Image Exist(ScreenWatchImage) = 0
            W = GadgetWidth(AppDesktopWindow): H = GadgetHeight(AppDesktopWindow)
            If (Screen Width() <> W) Or (Screen Height() <> H) Then Screen_Reset(W, H)
            App_RestoreAll()
            EventResize = true
        EndIf

Rem - HGUI Event Queue -
        For EventQueueEmpty = false To true
            GetEvent
            _EventSource = EventSource():_EventType = EventType()
			_EventData = EventData(): _EventDataEx = EventDataEx()

			If _EventType = WINDOW_CLOSE Then EventCloseWindow = _EventSource
            If _EventSource = AppWindow
                If _EventType = 0x401 Then EventCommand = EventData()
                If _EventType = GADGET_SIZING Then EventResize = true
                If _EventType = GADGET_SIZE Then EventResize = true
                If _EventType = 287 Then MenuOp = true
            EndIf
            EventQueueEmpty = (_EventType = 0)
        Next EventQueueEmpty    

Rem - App Close Button -
		If EventCloseWindow = AppWindow Then Exit

Rem - Shortcuts -
		scActiveGadget = ActiveGadget()
		scGadgetUnderMouse = GadgetUnderMouse()

Rem - Title Bar Problem -
		If scActiveGadget <> PreviousActiveGadget
			If scActiveGadget = Screen
				BringToFront AppWindow
				ActivateGadget Screen
		    	Call DLL AppUser32DLL, "SendMessageA", WindowHandle(AppWindow), NCACTIVATE, true, 0
			EndIf
			If scActiveGadget = 0
				If PreviousActiveGadget = Screen
					Call DLL AppUser32DLL, "SendMessageA", WindowHandle(AppWindow), NCACTIVATE, false, 0
				EndIf
			EndIf
		EndIf

Rem - Part of the loop when App active -
		AppIsActive = ((scActiveGadget = AppWindow) Or (scActiveGadget = Screen))
		If AppIsActive
Rem - Menus Commands -
	        If EventCommand > 999 Then Call Function Ptr EventCommand

		EndIf

rem - Resize -
		If EventResize
			SW = GadgetClientWidth(AppDesktopWindow)
			SH = GadgetClientHeight(AppDesktopWindow)
			a2FillBox 0, 0, SW, SH, 0xff000000
		EndIf

Rem - Next Previouses -
		PreviousAppIsActive = AppIsActive
		PreviousActiveGadget = scActiveGadget

Rem - Loop End - 
        If AppRequestToClose Then Exit
    Loop

AppEnd:

	Delete DLL AppUser32DLL
	Delete Memory AppDLLBuffer
    End

Rem > Use at Least one memblock command when using BlueGUI image features..
    Make Memblock 1, 8


Function Screen_Reset(Width, Height)

    Set Window Layout 0, 0, 0
    Set Display Mode Width, Height, Screen Depth()
    Set Window Position 0, 0
    ResetMainWindow

EndFunction


Function App_RestoreAll()
debugprint "App_RestoreAll()", CRLF$()

	Get Image ScreenWatchImage, 0, 0, 1, 1, 1

EndFunction


Function App_CreateWindowMenu()

    Menu = CreateMenu(AppWindow)
    AddMenuItem Menu, "&File", 1

    FileMenu = CreateSubMenu(Menu, 1)
    AddMenuItem FileMenu, "&Exit", Get Ptr To Function("App_CLOSE")

EndFunction


Function App_CLOSE()

	AppRequestToClose = true

EndFunction



Don't forget the gui.dba file. This one will be used on all the project, there is a few constants definition added

+ Code Snippet
Rem * gui.dba *
`==========================

#constant GUI_CONSTANTS 1

`eventType() Constants
#constant MOUSE_CLICK       0x202
#constant LEFTBUTTON_UP     0x202
#constant RIGHTBUTTON_DOWN  0x204
#constant RIGHTMOUSE_CLICK  0x205
#constant RIGHTBUTTON_UP    0x205
#constant MOUSE_MOVE        0x200
#constant GADGET_TIMER      0x113
#constant MENU_CLICK        0x111
#constant TOOLBAR_CLICK     0x111
#constant HOTKEY            0x312
#constant LEFTBUTTON_DOWN   513
#constant KEYDOWN           0x100
#constant KEYUP             0x101
#constant COMBOBOX_CHANGE   0x111
#constant TREEVIEW_CHANGE   0x111
#constant LOSEFOCUS         0x8
#constant GADGET_SIZING     0x214
#constant GADGET_SIZE       0x5
#constant WINDOW_CLOSE      0x10
#constant SCROLLBAR_CHANGE  0xE0
#constant LEFTBUTTON_DBLCLICK	0x203
#constant RIGHTBUTTON_DBLCLICK	0x206
#Constant NCACTIVATE			0x0086


`setPanelBorderStyle Constants
#constant BORDER_NONE	0
#constant BORDER_FLAT	1
#constant BORDER_3D		2
#constant BORDER_SUNKEN	3


`setGadgetAlign Constants
#constant ALIGN_NONE        0
#constant ALIGN_ALL         1
#constant ALIGN_TOP         2
#constant ALIGN_LEFT        3
#constant ALIGN_RIGHT       4
#constant ALIGN_BOTTOM      5


`Standard Toolbar Buttons
#constant TOOLBAR_CUT          0
#constant TOOLBAR_COPY         1
#constant TOOLBAR_PASTE        2
#constant TOOLBAR_UNDO         3
#constant TOOLBAR_REDO         4
#constant TOOLBAR_DELETE       5
#constant TOOLBAR_NEW          6
#constant TOOLBAR_OPEN         7
#constant TOOLBAR_SAVE         8
#constant TOOLBAR_PRINTPREVIEW 9
#constant TOOLBAR_PROPERTIES   10
#constant TOOLBAR_HELP         11
#constant TOOLBAR_FIND         12
#constant TOOLBAR_REPLACE      13
#constant TOOLBAR_PRINT        14


`createWindow Style Options
`styles
#constant WINDOW_TITLEBAR      12582912 
#constant WINDOW_CLOSEBUTTON   524288			
#constant WINDOW_MAXBUTTON     65536
#constant WINDOW_MINBUTTON     131072
#constant WINDOW_RESIZEABLE    262144			
#constant WINDOW_NOBORDER      -2147483648

`extraStyles
#constant WINDOW_TOOLWINDOW    128	

`standard styles (created from ones above)
#constant WINDOW_NORMAL        13565952
#constant WINDOW_FIXED         13107200
#constant WINDOW_OVR           0


`setListViewStyle Viewing Mode Options
#constant LISTVIEW_ICON        0
#constant LISTVIEW_REPORT      1
#constant LISTVIEW_LIST        3
Posted: 12th Apr 2014 1:26
Looking forward to this set of tutorials.
Posted: 12th Apr 2014 1:33
I'm working on something similar. I'm quite interested in seeing what kind of insight you'll offer
Posted: 13th Apr 2014 0:34
Thank you for your interest..
The first posts will be dedicated to basic UI and control, in order to have a base to let some visual results
Then I introduce the internal structures and dive into them
Finally, give polish by improving some parts.
This editor is "basic", but will be flexible enough to add new features.
I.e although limited to "objects", a component-based entity system will be able to describe potentially "anything in the 3D space"
I plan approximatively ten topics, and I'll try at least one/week!
Posted: 16th Apr 2014 17:43
2. Camera Control

Let's start 3D with camera control !
For the 3D maths, we will use Extented Rotation plugin. Thanks to this plugin, we can ditch
the native dbp 3d math commands. Indeed, they have an annoying behavior: when the screen
is lost, the data is destroyed and have to be recreated. As the result, nothing can be stored safely here!
what the hell is this ???!!!??!?!!

We need at least 3 types of motion: a translate, a rotate and a zoom.

We need some variables
Global CameraDXMat As DWORD
Global CameraCenterDXVec3 As DWORD

Global CameraDist#
Global CameraYaw#
Global CameraPitch#
Global CameraFOVLevel
Global CameraRange#


CameraCenter is the point around which the camera rotates, look at and located at a fixed distance.

+ Code Snippet
...

Rem - Init Camera -
	CameraDXMat = DXMat(0)
	CameraCenterDXVec3 = DXVec3(0)

	CameraDist# = 32.0
	CameraRange# = 4096.0
	Dim CameraFOVs#(20)
	Dim CameraMoveSpeeds#(20)
	FOV# = 9.0
	MoveSpeed# = 0.0125
	For i = 0 To 20: A logaritmic variation is needed when zooming..
		CameraFOVs#(i) = FOV#: FOV# = FOV# * 1.14
		CameraMoveSpeeds#(i) = MoveSpeed#: MoveSpeed# = MoveSpeed# * 1.14
	Next i 

	CameraYaw# = 0.0
	CameraPitch# = 26.0
	CameraFOVLevel = 10

	Set Camera FOV 0, CameraFOVs#(CameraFOVLevel)
	Set Camera Range 0, 0.25, CameraRange# + 0.25

    	Camera_Update()
...

Function Camera_Update()

	DXMat Rotation YPR CameraDXMat, CameraYaw#, CameraPitch#, 0.0

	DBCAM Set Position 0, DXVec3 Sub(Temp1DXVec3, CameraCenterDXVec3, DXVec3 Mul(Temp1DXVec3, CameraDXMat+32, CameraDist#))
	Rotate Camera 0, CameraPitch#, CameraYaw#, 0.0

EndFunction


The zoom is controled by the Field Of View with the mousewheel.

the main loop part:
+ Code Snippet
...
Rem - Camera control -
	If scGadgetUnderMouse = Screen
		NewCameraFOVLevel = CameraFOVLevel
		mmz = MouseMoveZ()
		If mmz < 0
			Inc NewCameraFOVLevel: If NewCameraFOVLevel > 20 Then NewCameraFOVLevel = 20
		EndIf
		If mmz > 0
			Dec NewCameraFOVLevel: If NewCameraFOVLevel <  0 Then NewCameraFOVLevel =  0
		EndIf
		If NewCameraFOVLevel <> CameraFOVLevel
			CameraFOVLevel = NewCameraFOVLevel
			Set Camera FOV 0, CameraFOVs#(CameraFOVLevel)
		EndIf
	
		If MouseClick() = 1 Then CaptureMoveCamera()
		If MouseClick() = 2 Then CaptureRotateCamera()
	EndIf
...


And the capture functions:
+ Code Snippet
Function CaptureMoveCamera()

	CameraMoveSpeed# = CameraMoveSpeeds#(CameraFOVLevel)

	a = MouseMoveX(): a = MouseMoveX(): a = MouseMoveY(): a = MouseMoveY(): Rem Cancels the previous moves

	Hide Mouse
	MX = MouseX(): MY = MouseY()

	Do: App_CaptureLoop()
		mmX# =  MouseMoveX() * CameraMoveSpeed#: mmY# = -MouseMoveY() * CameraMoveSpeed#

Rem CameraCenter = CameraCenter - (CameraMatrix.Right*mmX# + CameraMatrix.Up*mmY#)
		DXVec3 Sub CameraCenterDXVec3, CameraCenterDXVec3, DXVec3 Add(Temp1DXVec3, DXVec3 Mul(Temp1DXVec3, CameraDXMat, mmX#), DXVec3 Mul(Temp2DXVec3, CameraDXMat+16, mmY#))

		Camera_Update()

		If MouseClick() = 0 Then Exit
	Loop

	Position Mouse GadgetX(Screen) + MX, GadgetY(Screen) + MY
	Show Mouse

EndFunction


Function CaptureRotateCamera()

	CamRotSpeed# = 1.0
	OrgYaw# = CameraYaw#: OrgPitch# = CameraPitch#

	a = MouseMoveX(): a = MouseMoveX(): a = MouseMoveY(): a = MouseMoveY(): Rem Cancels the previous moves

	Hide Mouse
	MX = MouseX(): MY = MouseY()

	Do: App_CaptureLoop()
		Yaw# = Yaw# - MouseMoveX() * CamRotSpeed#
		Pitch# = Pitch# + MouseMoveY() * CamRotSpeed#

		CameraYaw# = WrapValue(OrgYaw# + Yaw#)
		CameraPitch# = OrgPitch# + Pitch#
    
		If CameraPitch# < -90.0 Then CameraPitch# = -90.0
		If CameraPitch# >  90.0 Then CameraPitch# =  90.0

		Camera_Update()

		If MouseClick() = 0 Then Exit
	Loop

	Position Mouse GadgetX(Screen) + MX, GadgetY(Screen) + MY
	Show Mouse

EndFunction


The capture are loops in the main loop. we still have to handle some app things, like the GUI events.

+ Code Snippet
Function App_CaptureLoop()

    For EventQueueEmpty = false To true
        GetEvent
        EventQueueEmpty = (EventType() = 0)
    Next EventQueueEmpty

EndFunction


Improvement ideas:
More camera motions, e.g move forward/backward. Coords displayed in a status..

Merging all together (Download)
Posted: 23rd Apr 2014 17:08
3. Adding a toolbar

With this toolbar, we'll select The edit mode. They are:
- Select entity
- Position entity
- Rotate entity
- Scale entity
- Editor light

The Pos/Rot/Scale buttons just display the corresponding transform gizmos.
The editor light activates the default light editmode

I often use this tip: store the "current value" of a gadget in its GadgetData instead
of a global variable.
+ Code Snippet
Function UIToolBar_IsChanged()

	SelectedTBButton = GetGadgetData(UIToolBar)
	For i = 0 To 4
		If GetToolBarButtonState(UIToolBar, i)
			If i <> SelectedTBButton
				SetToolBarButtonState UIToolBar, SelectedTBButton, false
				SetGadgetData UIToolBar, i
				ExitFunction true
			EndIf
		EndIf
	Next i

EndFunction false


There's no particular coding difficulty in this step.
There is just a minor issue: the toolbar button images doesnot take transparency into account,
but there's a simple workaround: provide image with alpha, paste it on a button-colored-background and grab.
+ Code Snippet
Function LoadToolBarImage(FileName$, Image, BackgroundColor)

	Load Image FileName$, Image, 1
	a2FillBox 0.0, 0.0, 27.0, 27.0, BackgroundColor
	Paste Image Image, 0, 0, 1 
	Get Image Image, 0, 0, 27, 27, 1

EndFunction Image


Source organization
We start in this step to organize the source in a better way.
The variable and functions are regrouped a source file according to their related structure.
+ Code Snippet
Rem * Very Basic 3D Scene Editor *


#Constant false 0
#Constant true 1

...

Gosub CameraHeader
Gosub LightHeader


Rem * Globals *
...


Rem * Light.dba *


LightHeader:

Global LightDXMat As DWORD

Global LightYaw#
Global LightPitch#

	Return


Function Light_Update()

	DXMat Rotation YPR LightDXMat, LightYaw#, LightPitch#, 0.0

	Set Directional Light 0, DXVec3X(LightDXMat+32), DXVec3Y(LightDXMat+32), DXVec3Z(LightDXMat+32)

EndFunction


Merging all together (Download)
Posted: 1st May 2014 17:16
4. Property Lists

We'll need dialog boxes. Potentially a lot.
Those who have already programmed dialog boxes with Blue know, it takes a lot of time to write.
So we need a way to speed up the process, this way is the property list.
Instead of creating and handling the gadgets individually, we use
predefined blocks of gadgets arranged sequentially:



How does it works:

The property list is created easyly:
+ Code Snippet
...
	PropList = CreatePropList(0, 0, 320, 320, UIFont, UIBoldFont, AppWindow)

	PropListCell_Edit = PropList_AddEdit(PropList, "Edit", "My text")
	PropListCell_Label = PropList_AddLabel(PropList, "Label")
	PropListCell_Boolean = PropList_AddBoolean(PropList, "Boolean", true)
	PropListCell_Button = PropList_AddButton(PropList, "Button")
	PropListCell_Vector = PropList_AddVector(PropList, "Vector", 1.0, 2.0, 3.0)
	PropListCell_ComboBox = PropList_AddComboBox(PropList, "ComboBox", "Item 1;Item 2;Item 3;Item 4")
	PropListCell_Color = PropList_AddColorRGB(PropList, "Color", 0x800000)

	PropList_AdjustHeight(PropList)
	ResizeGadget AppWindow, GadgetClientWidth(PropList), GadgetClientHeight(PropList), 1
...


Remember, the event queue is emptied at the beginning of the main loop and the event are stored in variables
+ Code Snippet
Rem - HGUI Event Queue -
	For EventQueueEmpty = false To true
		GetEvent
		_EventSource = EventSource():_EventType = EventType()
		_EventData = EventData(): _EventDataEx = EventDataEx()

		If _EventType = WINDOW_CLOSE Then EventCloseWindow = _EventSource
		If _EventType = KEYDOWN
			If _EventData = 13 Then EventReturnKeyDownGadget = _EventSource
		EndIf
		If _EventType = LEFTBUTTON_DOWN Then EventMouseDownGadget = _EventSource
		If _EventType = LEFTBUTTON_UP Then EventMouseUpGadget = _EventSource
		If _EventType = LEFTBUTTON_DBLCLICK Then EventMouseDblcGadget = _EventSource

		EventQueueEmpty = (_EventType = 0)
	Next EventQueueEmpty    


Interacting with the property list is just as easy.
The proplist is provided with a few events: "Validate", "Edit", "Click" and "Select".
then, the PropList_GetEvents() function runs the internal function of all the cells to figure out if one has changed:
+ Code Snippet
	If EventReturnKeyDownGadget Then PropList_ValidateGadget(PropList, EventReturnKeyDownGadget)
	If EventMouseDownGadget Then PropList_EditGadget(PropList, EventMouseDownGadget)	
	If EventMouseUpGadget Then PropList_ClickGadget(PropList, EventMouseUpGadget)
	If EventMouseDblcGadget Then PropList_SelectGadget(PropList, EventMouseDblcGadget)

	If PropList_GetEvents(PropList)
		If PropListCell_IsChanged(PropListCell_Edit) Then ...
		If PropListCell_IsChanged(PropListCell_Boolean) Then ...
		If PropListCell_IsChanged(PropListCell_Button) Then ...
...
	EndIf

Simple and quick!!


The demo

In this step, only the "Edit" and "Label" are available. But other cell types will be regularly added in the next step!
+ Code Snippet
Rem * PropertyListDemo *


#Constant false 0
#Constant true 1


Global AppRequestToClose
Global AppWindow
Global AppTitle$
Global AppIsActive

Global UIFont
Global UIBoldFont


	Open Console

	AppTitle$ = "PropertyListDemo"
	Style = WINDOW_TITLEBAR+WINDOW_CLOSEBUTTON+WINDOW_MAXBUTTON+WINDOW_MINBUTTON
	AppWindow = CreateWindow(15, 16, 320, 320, AppTitle$, Style, 0, 1, 0)

	UIFont = CreateFont("Tahoma", 8, 0, 0, 0)
	UIBoldFont = CreateFont("Tahoma", 8, 1, 0, 0)

	PropList = CreatePropList(0, 0, 320, 320, UIFont, UIBoldFont, AppWindow)

	PropListCell_Edit = PropList_AddEdit(PropList, "Edit", "My text")
	PropListCell_Label = PropList_AddLabel(PropList, "Label")
	PropListCell_Edit2 = PropList_AddEdit(PropList, "Edit2", "My text")

	PropList_AdjustHeight(PropList)
	ResizeGadget AppWindow, GadgetClientWidth(PropList), GadgetClientHeight(PropList), 1

Rem * Main Loop *
	AppExit = false
	Do
		EventCloseWindow = 0
		EventReturnKeyDownGadget = 0
		EventMouseDownGadget = 0
		EventMouseUpGadget = 0

Rem - HGUI Event Queue -
		For EventQueueEmpty = false To true
			GetEvent
			_EventSource = EventSource():_EventType = EventType()
			_EventData = EventData(): _EventDataEx = EventDataEx()

			If _EventType = WINDOW_CLOSE Then EventCloseWindow = _EventSource
			If _EventType = KEYDOWN
				If _EventData = 13 Then EventReturnKeyDownGadget = _EventSource
			EndIf
			If _EventType = LEFTBUTTON_DOWN Then EventMouseDownGadget = _EventSource
			If _EventType = LEFTBUTTON_UP Then EventMouseUpGadget = _EventSource

			EventQueueEmpty = (_EventType = 0)
		Next EventQueueEmpty    

Rem - App Close Button -
		If EventCloseWindow = AppWindow Then Exit

Rem - Property List -
		If EventReturnKeyDownGadget Then PropList_ValidateGadget(PropList, EventReturnKeyDownGadget)
		If EventMouseDownGadget Then PropList_EditGadget(PropList, EventMouseDownGadget)	
		If EventMouseUpGadget Then PropList_ClickGadget(PropList, EventMouseUpGadget)

		If PropList_GetEvents(PropList)
			If PropListCell_IsChanged(PropListCell_Edit) Then Print Console "Edit changed: "+PropListCell_GetText(PropListCell_Edit, 0), CRLF$()
			If PropListCell_IsChanged(PropListCell_Edit2) Then Print Console "Edit2 changed: "+PropListCell_GetText(PropListCell_Edit2, 0), CRLF$()
		EndIf

Rem - Loop End - 
		If AppRequestToClose Then Exit
	Loop

AppEnd:
	End

Rem > Use at Least one memblock command when using BlueGUI image features..
	Make Memblock 1, 8


The Proplist functions:
+ Code Snippet
Rem * PropList.dba *


#Constant PROPLIST_FIRSTCELL 0
#Constant PROPLIST_LASTCELL 4
#Constant PROPLIST_FONT 8
#Constant PROPLIST_BOLDFONT 12
#Constant PROPLIST_LABELWIDTH 16
#Constant PROPLIST_CELLHEIGHT 20
#Constant PROPLIST_CELLPANEL 24
#Constant PROPLIST_VALIDATEGADGET 28
#Constant PROPLIST_EDITGADGET 32
#Constant PROPLIST_CLICKGADGET 36
#Constant PROPLIST_SELECTGADGET 40
#Constant SIZEOF_PROPLIST 44


#Constant PROPLISTCELL_NEXTCELL 0
#Constant PROPLISTCELL_FUNCTION 4
#Constant PROPLISTCELL_CHANGED 8
#Constant PROPLISTCELL_GADGETCOUNT 12
#Constant PROPLISTCELL_FIRSTGADGET 16


Function CreatePropList(X, Y, W, H, Font, BoldFont, Parent)

Local MainGadgetData As DWORD


	NewPropList = CreatePanel(X, Y, W, H, Parent)

	CW = GadgetClientWidth(NewPropList)
	NewPanel = CreatePanel(2, 2, CW-4, 0, NewPropList)

	MainGadgetData = Make Memory(SIZEOF_PROPLIST)
	Poke Integer MainGadgetData+PROPLIST_FIRSTCELL, 0
	Poke Integer MainGadgetData+PROPLIST_LASTCELL, 0
	Poke Integer MainGadgetData+PROPLIST_FONT, Font
	Poke Integer MainGadgetData+PROPLIST_BOLDFONT, BoldFont
	Poke Integer MainGadgetData+PROPLIST_LABELWIDTH, 96
	Poke Integer MainGadgetData+PROPLIST_CELLHEIGHT, 25
	Poke Integer MainGadgetData+PROPLIST_CELLPANEL, NewPanel
	Poke Integer MainGadgetData+PROPLIST_VALIDATEGADGET, 0
	Poke Integer MainGadgetData+PROPLIST_EDITGADGET, 0
	Poke Integer MainGadgetData+PROPLIST_CLICKGADGET, 0

	SetGadgetData NewPropList, MainGadgetData

EndFunction NewPropList


Function DeletePropList(PropList)

Local MainGadgetData As DWORD


	MainGadgetData = GetGadgetData(PropList)
	Cell = Peek Integer(MainGadgetData+PROPLIST_FIRSTCELL)

	If Cell
	For i = 0 To 1
		GadgetCount = Peek Integer(Cell+PROPLISTCELL_GADGETCOUNT)
		Ptr = Cell+PROPLISTCELL_FIRSTGADGET
		For j = 1 To GadgetCount
			DeleteGadget Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET-4+j*4)
		Next j
		Cell = Peek Integer(Cell+PROPLISTCELL_NEXTCELL)
		i = (Cell = 0)
	Next i
	EndIf

	DeleteGadget Peek Integer(MainGadgetData+PROPLIST_CELLPANEL)
	DeleteGadget PropList
	Delete Memory MainGadgetData

EndFunction


Function PropList_AdjustHeight(PropList)

Local MainGadgetData As DWORD


	MainGadgetData = GetGadgetData(PropList)
	CellPanel = Peek Integer(MainGadgetData+PROPLIST_CELLPANEL)

	ResizeGadget PropList, GadgetWidth(PropList), GadgetHeight(CellPanel) + 4

EndFunction


Function PropList_ValidateGadget(PropList, Gadget)

Local MainGadgetData As DWORD


	MainGadgetData = GetGadgetData(PropList)
	Poke Integer MainGadgetData+PROPLIST_VALIDATEGADGET, Gadget

EndFunction


Function PropList_EditGadget(PropList, Gadget)

Local MainGadgetData As DWORD


	MainGadgetData = GetGadgetData(PropList)
	Poke Integer MainGadgetData+PROPLIST_EDITGADGET, Gadget

EndFunction


Function PropList_ClickGadget(PropList, Gadget)

Local MainGadgetData As DWORD


	MainGadgetData = GetGadgetData(PropList)
	Poke Integer MainGadgetData+PROPLIST_CLICKGADGET, Gadget

EndFunction


Function PropList_SelectGadget(PropList, Gadget)

Local MainGadgetData As DWORD


	MainGadgetData = GetGadgetData(PropList)
	Poke Integer MainGadgetData+PROPLIST_SELECTGADGET, Gadget

EndFunction


Function PropList_GetEvents(PropList)

Local MainGadgetData As DWORD
Local FnPtr As DWORD


	MainGadgetData = GetGadgetData(PropList)
	Cell = Peek Integer(MainGadgetData+PROPLIST_FIRSTCELL)

	If Cell
		Changed = 0
		For i = 0 To 1
			FnPtr = Peek Integer(Cell+PROPLISTCELL_FUNCTION)
			If FnPtr Then Changed = Call Function Ptr(FnPtr, MainGadgetData, Cell) || Changed
			Cell = Peek Integer(Cell+PROPLISTCELL_NEXTCELL)
			i = (Cell = 0)
		Next i
	EndIf

	Poke Integer MainGadgetData+PROPLIST_VALIDATEGADGET, 0
	Poke Integer MainGadgetData+PROPLIST_EDITGADGET, 0
	Poke Integer MainGadgetData+PROPLIST_CLICKGADGET, 0

EndFunction Changed


Function PropListCell_IsChanged(PropListCell)

	Changed = Peek Integer(PropListCell+PROPLISTCELL_CHANGED)
	Poke Integer PropListCell+PROPLISTCELL_CHANGED, 0

EndFunction Changed


Function PropListCell_GetGadget(PropListCell, GadgetIndex)

	Gadget = Peek Integer(PropListCell+PROPLISTCELL_FIRSTGADGET+GadgetIndex*4)

EndFunction Gadget


Function PropListCell_GetValue(PropListCell, Field)

	Gadget = Peek Integer(PropListCell+PROPLISTCELL_FIRSTGADGET+Field*4)
	CellValue = GetGadgetData(Gadget)

EndFunction CellValue


Function PropListCell_GetText(PropListCell, Field)

	Gadget = Peek Integer(PropListCell+PROPLISTCELL_FIRSTGADGET+Field*4)
	CellText$ = GetGadgetText(Gadget)

EndFunction CellText$


Function PropListCell_SetText(PropListCell, Field, CellText$)

	Gadget = Peek Integer(PropListCell+PROPLISTCELL_FIRSTGADGET+Field*4)
	SetGadgetText Gadget, CellText$

EndFunction


Function _PropList_NewCell(MainGadgetData As DWORD, GadgetCount)

Local NewCell As DWORD


	NewCellSize = PROPLISTCELL_FIRSTGADGET+GadgetCount*4
	NewCell = Make Memory(NewCellSize)
	Fill Memory NewCell, 0, NewCellSize

	Poke Integer NewCell+PROPLISTCELL_GADGETCOUNT, GadgetCount

	LastCell = Peek Integer(MainGadgetData+PROPLIST_LASTCELL)
	If LastCell
		Poke Integer LastCell+PROPLISTCELL_NEXTCELL, NewCell
	Else
		Poke Integer MainGadgetData+PROPLIST_FIRSTCELL, NewCell
	EndIf
	Poke Integer MainGadgetData+PROPLIST_LASTCELL, NewCell

EndFunction NewCell


The Cells functions, a "Create" and "Process" function by cell type:
+ Code Snippet
Rem * Cells functions *

Function PropList_AddLabel(PropList, Caption$)

Local NewCell As DWORD


	MainGadgetData = GetGadgetData(PropList)
	CellPanel = Peek Integer(MainGadgetData+PROPLIST_CELLPANEL)

	CW = GadgetWidth(CellPanel)
	LW = Peek Integer(MainGadgetData+PROPLIST_LABELWIDTH)
	ClH = Peek Integer(MainGadgetData+PROPLIST_CELLHEIGHT)
	Y = GadgetHeight(CellPanel): If Y Then Inc Y, 2
	ResizeGadget CellPanel, CW, Y+ClH, 1

	NewLabel = CreateLabel(0, Y+3, CW, ClH-3, Caption$, CellPanel)
	Font = Peek Integer(MainGadgetData+PROPLIST_BOLDFONT): If Font Then ApplyFont NewLabel, Font

	NewCell = _PropList_NewCell(MainGadgetData, 1)
	Poke Integer NewCell+PROPLISTCELL_FUNCTION, Get Ptr To Function("_PropList_LabelFunction")
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET, NewLabel

EndFunction NewCell


Function _PropList_LabelFunction(MainGadgetData As DWORD, Cell As DWORD)

	Label = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET)

	If ActiveGadget() = Label Then Poke Integer MainGadgetData+PROPLIST_VALIDATEGADGET, -1

EndFunction 0


Function PropList_AddEdit(PropList, Caption$, EditText$)

Local MainGadgetData As DWORD
Local NewCell As DWORD


	MainGadgetData = GetGadgetData(PropList)
	CellPanel = Peek Integer(MainGadgetData+PROPLIST_CELLPANEL)

	CW = GadgetWidth(CellPanel)
	LW = Peek Integer(MainGadgetData+PROPLIST_LABELWIDTH)
	ClH = Peek Integer(MainGadgetData+PROPLIST_CELLHEIGHT)
	Y = GadgetHeight(CellPanel)
	If Y Then Inc Y, 2

	ResizeGadget CellPanel, GadgetWidth(CellPanel), Y+ClH

	NewLabel = CreateLabel(0, Y+3, LW, ClH-3, Caption$, CellPanel)
	Font = Peek Integer(MainGadgetData+PROPLIST_FONT): If Font Then ApplyFont NewLabel, Font

	NewEdit = CreateEdit(LW, Y, CW-LW, ClH, 0, CellPanel)
	SetGadgetText NewEdit, EditText$
	Font = Peek Integer(MainGadgetData+PROPLIST_FONT): If Font Then ApplyFont NewEdit, Font

	NewCell = _PropList_NewCell(MainGadgetData, 2)
	Poke Integer NewCell+PROPLISTCELL_FUNCTION, Get Ptr To Function("_PropList_EditFunction")
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET, NewEdit
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET+4, NewLabel

EndFunction NewCell


Function _PropList_EditFunction(MainGadgetData As DWORD, Cell As DWORD)

	Edit = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET)
	Label = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET+4)

	ValidatedGadget = Peek Integer(MainGadgetData+PROPLIST_VALIDATEGADGET)
	If ActiveGadget() = Label Then ValidatedGadget = -1
	NextValidatedGadget = ValidatedGadget
	If ValidatedGadget = -1
		ActivateGadget Edit
		SetSelStart Edit, 0
		SetSelLen Edit, Fast Len(GetGadgetText(Edit))
		NextValidatedGadget = 0
	EndIf
	If ValidatedGadget = Edit
		Changed = true
		Poke Integer Cell+PROPLISTCELL_CHANGED, true
		NextValidatedGadget = -1
	EndIf
	Poke Integer MainGadgetData+PROPLIST_VALIDATEGADGET, NextValidatedGadget

EndFunction Changed


As usual, dont forget the gui.dba included in the first step post!
Posted: 15th May 2014 16:04
5. More Property list cell types

Boolean & Enable

+ Code Snippet
Function PropList_AddBoolean(PropList, Caption$, Value)

Local MainGadgetData As DWORD
Local NewCell As DWORD


	MainGadgetData = GetGadgetData(PropList)
	CellPanel = Peek Integer(MainGadgetData+PROPLIST_CELLPANEL)

	CW = GadgetWidth(CellPanel)
	LW = Peek Integer(MainGadgetData+PROPLIST_LABELWIDTH)
	ClH = Peek Integer(MainGadgetData+PROPLIST_CELLHEIGHT)
	Y = GadgetHeight(CellPanel)
	If Y Then Inc Y, 2

	ResizeGadget CellPanel, GadgetWidth(CellPanel), Y+ClH

	NewLabel = CreateLabel(0, Y+3, LW, ClH-3, Caption$, CellPanel)
	Font = Peek Integer(MainGadgetData+PROPLIST_FONT): If Font Then ApplyFont NewLabel, Font

	NewCheckBox = CreateCheckBox(LW, Y, CW-LW, ClH, "", CellPanel)
	SetChecked NewCheckBox, Value
	SetGadgetData NewCheckBox, Value

	NewCell = _PropList_NewCell(MainGadgetData, 2)
	Poke Integer NewCell+PROPLISTCELL_FUNCTION, Get Ptr To Function("_PropList_EnableFunction")
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET, NewCheckBox
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET+4, NewLabel

EndFunction NewCell


Function PropList_AddEnable(PropList, Caption$, Value)

Local NewCell As DWORD


	MainGadgetData = GetGadgetData(PropList)
	CellPanel = Peek Integer(MainGadgetData+PROPLIST_CELLPANEL)

	CW = GadgetWidth(CellPanel)
	LW = Peek Integer(MainGadgetData+PROPLIST_LABELWIDTH)
	ClH = Peek Integer(MainGadgetData+PROPLIST_CELLHEIGHT)
	Y = GadgetHeight(CellPanel): If Y Then Inc Y, 2
	ResizeGadget CellPanel, CW, Y+ClH, 1

	NewCheckBox = CreateCheckBox(0, Y+3, CW, ClH-3, Caption$, CellPanel)
	Font = Peek Integer(MainGadgetData+PROPLIST_FONT): If Font Then ApplyFont NewCheckBox, Font
	SetChecked NewCheckBox, Value
	SetGadgetData NewCheckBox, Value

	NewCell = _PropList_NewCell(MainGadgetData, 1)
	Poke Integer NewCell+PROPLISTCELL_FUNCTION, Get Ptr To Function("_PropList_EnableFunction")
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET, NewCheckBox

EndFunction NewCell


Function _PropList_EnableFunction(MainGadgetData As DWORD, Cell As DWORD)

	CheckBox = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET)
	Value = GetChecked(CheckBox)
	Changed = (GetGadgetData(CheckBox) <> Value)
	SetGadgetData CheckBox, Value
	Poke Integer Cell+PROPLISTCELL_CHANGED, Changed

EndFunction Changed



ComboBox

+ Code Snippet
Function PropList_AddComboBox(PropList, Caption$, ComboBoxText$)

Local MainGadgetData As DWORD
Local NewCell As DWORD


	MainGadgetData = GetGadgetData(PropList)
	CellPanel = Peek Integer(MainGadgetData+PROPLIST_CELLPANEL)

	CW = GadgetWidth(CellPanel)
	LW = Peek Integer(MainGadgetData+PROPLIST_LABELWIDTH)
	ClH = Peek Integer(MainGadgetData+PROPLIST_CELLHEIGHT)
	Y = GadgetHeight(CellPanel)
	If Y Then Inc Y, 2

	ResizeGadget CellPanel, GadgetWidth(CellPanel), Y+ClH

	NewLabel = CreateLabel(0, Y+3, LW, ClH-3, Caption$, CellPanel)
	Font = Peek Integer(MainGadgetData+PROPLIST_FONT): If Font Then ApplyFont NewLabel, Font

	NewComboBox = CreateComboBox(LW, Y, CW-LW, ClH, CellPanel)
	Split CSV String ComboBoxText$, ";", chr$(34)
	Count = Split Count()
	For i = 1 To Count: AddItem NewComboBox, Split Word$(i): Next i
	SelectItem NewComboBox, 0
	SetGadgetData NewComboBox, 0

	Font = Peek Integer(MainGadgetData+PROPLIST_FONT): If Font Then ApplyFont NewComboBox, Font

	NewCell = _PropList_NewCell(MainGadgetData, 2)
	Poke Integer NewCell+PROPLISTCELL_FUNCTION, Get Ptr To Function("_PropList_ComboBoxFunction")
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET, NewComboBox
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET+4, NewLabel

EndFunction NewCell


Function _PropList_ComboBoxFunction(MainGadgetData As DWORD, Cell As DWORD)

	ComboBox = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET)
	Label = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET+4)

	ValidatedGadget = Peek Integer(MainGadgetData+PROPLIST_VALIDATEGADGET)
	If ActiveGadget() = Label Then ValidatedGadget = -1
	NextValidatedGadget = ValidatedGadget
	If ValidatedGadget = -1
		ActivateGadget ComboBox
		NextValidatedGadget = 0
	EndIf
	If ValidatedGadget = ComboBox
		Changed = true
		Poke Integer Cell+PROPLISTCELL_CHANGED, true
		NextValidatedGadget = -1
	EndIf
	Poke Integer MainGadgetData+PROPLIST_VALIDATEGADGET, NextValidatedGadget

	SelItem = SelectedItem(ComboBox)
	Changed = (GetGadgetData(ComboBox) <> SelItem)
	If Changed Then SetGadgetData ComboBox, SelItem

	Poke Integer Cell+PROPLISTCELL_CHANGED, Changed

EndFunction Changed



Button

+ Code Snippet
Function PropList_AddButton(PropList, Caption$)

Local MainGadgetData As DWORD
Local NewCell As DWORD


	MainGadgetData = GetGadgetData(PropList)
	CellPanel = Peek Integer(MainGadgetData+PROPLIST_CELLPANEL)

	CW = GadgetWidth(CellPanel)
	LW = Peek Integer(MainGadgetData+PROPLIST_LABELWIDTH)
	ClH = Peek Integer(MainGadgetData+PROPLIST_CELLHEIGHT)
	Y = GadgetHeight(CellPanel)
	If Y Then Inc Y, 2

	ResizeGadget CellPanel, GadgetWidth(CellPanel), Y+ClH

	NewButton = CreateButton(0, Y, CW, ClH, Caption$, false, CellPanel)
	Font = Peek Integer(MainGadgetData+PROPLIST_FONT): If Font Then ApplyFont NewButton, Font


	NewCell = _PropList_NewCell(MainGadgetData, 1)
	Poke Integer NewCell+PROPLISTCELL_FUNCTION, Get Ptr To Function("_PropList_ButtonFunction")
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET, NewButton

EndFunction NewCell


Function _PropList_ButtonFunction(MainGadgetData As DWORD, Cell As DWORD)

	Button = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET)

	Changed = (Peek Integer(MainGadgetData+PROPLIST_CLICKGADGET) = Button)
	If GadgetUnderMouse() <> Button Then Changed = 0

	SetGadgetData Button, Changed
	Poke Integer Cell+PROPLISTCELL_CHANGED, Changed

EndFunction Changed



Vector

+ Code Snippet
Function PropList_AddVector(PropList, Caption$, X#, Y#, Z#)

Local MainGadgetData As DWORD
Local NewCell As DWORD


	MainGadgetData = GetGadgetData(PropList)
	CellPanel = Peek Integer(MainGadgetData+PROPLIST_CELLPANEL)

	LW = 12
	CW = GadgetWidth(CellPanel)
	EW = (CW - 4 - 3*LW) / 3
	ClH = Peek Integer(MainGadgetData+PROPLIST_CELLHEIGHT)
	Y = GadgetHeight(CellPanel)
	If Y Then Inc Y, 2

	ResizeGadget CellPanel, GadgetWidth(CellPanel), Y+2*ClH - 4

	NewLabel = CreateLabel(0, Y+3, CW, ClH-7, Caption$, CellPanel)
	Font = Peek Integer(MainGadgetData+PROPLIST_BOLDFONT): If Font Then ApplyFont NewLabel, Font

	Font = Peek Integer(MainGadgetData+PROPLIST_FONT)

	Y = Y + ClH - 4
	NewLabelX = CreateLabel(0, Y+3, LW, ClH-3, "X", CellPanel)
	If Font Then ApplyFont NewLabelX, Font

	NewEditX = CreateEdit(LW, Y, EW, ClH, 0, CellPanel)
	SetGadgetText NewEditX, Str$(X#)
	If Font Then ApplyFont NewEditX, Font
	X = LW + EW + 2

	NewLabelY = CreateLabel(X, Y+3, LW, ClH-3, "Y", CellPanel)
	If Font Then ApplyFont NewLabelY, Font

	NewEditY = CreateEdit(X+LW, Y, EW, ClH, 0, CellPanel)
	SetGadgetText NewEditY, Str$(Y#)
	If Font Then ApplyFont NewEditY, Font
	X = X + LW + EW + 2

	NewLabelZ = CreateLabel(X, Y+3, LW, ClH-3, "Z", CellPanel)
	If Font Then ApplyFont NewLabelZ, Font

	NewEditZ = CreateEdit(X+LW, Y, CW-(X-LW), ClH, 0, CellPanel)
	SetGadgetText NewEditZ, Str$(Z#)
	If Font Then ApplyFont NewEditZ, Font
	X = X + LW + EW + 2

	NewCell = _PropList_NewCell(MainGadgetData, 7)
	Poke Integer NewCell+PROPLISTCELL_FUNCTION, Get Ptr To Function("_PropList_VectorFunction")

	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET, NewEditX
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET+ 4, NewEditY
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET+ 8, NewEditZ
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET+12, NewLabel
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET+16, NewLabelX
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET+20, NewLabelY
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET+24, NewLabelZ

EndFunction NewCell


Function _PropList_VectorFunction(MainGadgetData As DWORD, Cell As DWORD)

	EditX = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET)
	EditY = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET+ 4)
	EditZ = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET+ 8)
	Label = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET+12)
	LabelX = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET+16)
	LabelY = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET+20)
	LabelZ = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET+24)

	_ActiveGadget = ActiveGadget()
	ValidatedGadget = Peek Integer(MainGadgetData+PROPLIST_VALIDATEGADGET)
	NextValidatedGadget = ValidatedGadget
	If ValidatedGadget = -1 Or _ActiveGadget = Label Or _ActiveGadget = Label
		ActivateGadget EditX
		SetSelStart EditX, 0
		SetSelLen EditX, Fast Len(GetGadgetText(EditX))
		NextValidatedGadget = 0
	EndIf
	If ValidatedGadget = EditX Or _ActiveGadget = LabelY
		ActivateGadget EditY
		SetSelStart EditY, 0
		SetSelLen EditY, Fast Len(GetGadgetText(EditY))
		NextValidatedGadget = 0
	EndIf

	If ValidatedGadget = EditY Or _ActiveGadget = LabelZ
		ActivateGadget EditZ
		SetSelStart EditZ, 0
		SetSelLen EditZ, Fast Len(GetGadgetText(EditZ))
		NextValidatedGadget = 0
	EndIf

	If ValidatedGadget = EditZ
		NextValidatedGadget = -1
	EndIf
	Poke Integer MainGadgetData+PROPLIST_VALIDATEGADGET, NextValidatedGadget

	Changed = (ValidatedGadget = EditX) Or (ValidatedGadget = EditY) Or (ValidatedGadget = EditZ)
	Poke Integer Cell+PROPLISTCELL_CHANGED, Changed

EndFunction Changed



Resource Selector

+ Code Snippet
Function PropList_AddResourceSelector(PropList, Caption$, ResourceName$)

	MainGadgetData = GetGadgetData(PropList)
	CellPanel = Peek Integer(MainGadgetData+PROPLIST_CELLPANEL)

	CW = GadgetWidth(CellPanel)
	LW = Peek Integer(MainGadgetData+PROPLIST_LABELWIDTH)
	ClH = Peek Integer(MainGadgetData+PROPLIST_CELLHEIGHT)
	Y = GadgetHeight(CellPanel)
	If Y Then Inc Y, 2

	ResizeGadget CellPanel, GadgetWidth(CellPanel), Y+ClH

	NewLabel = CreateLabel(0, Y+3, LW, ClH-3, Caption$, CellPanel)
	Font = Peek Integer(MainGadgetData+PROPLIST_FONT): If Font Then ApplyFont NewLabel, Font

	NewPanel = CreatePanel(LW, Y, CW-LW-27, ClH, CellPanel)
	SetPanelBorderStyle NewPanel, BORDER_FLAT

	NewLabel2 = CreateLabel(2, 2, CW, ClH, ResourceName$, NewPanel)
	If Font Then ApplyFont NewLabel2, Font

	NewButton = CreateButton(CW-25, Y, 25, ClH, "...", false, CellPanel)

	NewCell = _PropList_NewCell(MainGadgetData, 4)
	Poke Integer NewCell+PROPLISTCELL_FUNCTION, Get Ptr To Function("_PropList_ResourceSelectorFunction")
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET, NewLabel2
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET+4, NewLabel
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET+8, NewButton
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET+12, NewPanel

EndFunction NewCell


Function _PropList_ResourceSelectorFunction(MainGadgetData As DWORD, Cell As DWORD)

	Label = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET+4)
	Button = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET+8)

	Changed = (Peek Integer(MainGadgetData+PROPLIST_CLICKGADGET) = Button)
	If Changed Then Poke Integer MainGadgetData+PROPLIST_CLICKGADGET, 0
	Changed = Changed && (GadgetUnderMouse() = Button)
	SetGadgetData Button, Changed
	Poke Integer Cell+PROPLISTCELL_CHANGED, Changed

	ValidatedGadget = Peek Integer(MainGadgetData+PROPLIST_VALIDATEGADGET)
	If ActiveGadget() = Label Then ValidatedGadget = -1
	NextValidatedGadget = ValidatedGadget
	If ValidatedGadget = -1
		ActivateGadget Button
		NextValidatedGadget = 0
	EndIf
	Poke Integer MainGadgetData+PROPLIST_VALIDATEGADGET, NextValidatedGadget

EndFunction Changed



Color Selector

+ Code Snippet
Function PropList_AddColorRGB(PropList, Caption$, ColorRGB)

	MainGadgetData = GetGadgetData(PropList)
	CellPanel = Peek Integer(MainGadgetData+PROPLIST_CELLPANEL)

	CW = GadgetWidth(CellPanel)
	LW = Peek Integer(MainGadgetData+PROPLIST_LABELWIDTH)
	ClH = Peek Integer(MainGadgetData+PROPLIST_CELLHEIGHT)
	Y = GadgetHeight(CellPanel)
	If Y Then Inc Y, 2

	ResizeGadget CellPanel, GadgetWidth(CellPanel), Y+ClH

	NewLabel = CreateLabel(0, Y+3, LW, ClH-3, Caption$, CellPanel)
	Font = Peek Integer(MainGadgetData+PROPLIST_FONT): If Font Then ApplyFont NewLabel, Font

	NewPanel = CreatePanel(LW, Y, CW-LW, ClH, CellPanel)
	SetPanelBorderStyle NewPanel, BORDER_SUNKEN
	SetGadgetColor NewPanel, ColorRGB, 0

	NewCell = _PropList_NewCell(MainGadgetData, 2)
	Poke Integer NewCell+PROPLISTCELL_FUNCTION, Get Ptr To Function("_PropList_ColorFunction")
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET, NewPanel
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET+4, NewLabel

EndFunction NewCell


Function _PropList_ColorFunction(MainGadgetData As DWORD, Cell As DWORD)

	Panel = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET)
	Label = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET+4)

	If ActiveGadget() = Label Then Poke Integer MainGadgetData+PROPLIST_VALIDATEGADGET, -1

	Changed = false
	If Peek Integer(MainGadgetData+PROPLIST_EDITGADGET) = Panel
		SetDialogOwner Panel
		Color = ColorDialog()
		If Color <> -1
			SetGadgetColor Panel, Color, 0
			SetGadgetData Panel, Color
			Changed = true
		EndIf	
		SetDialogOwner 0
	EndIf

	Poke Integer Cell+PROPLISTCELL_CHANGED, Changed

EndFunction Changed



ListBox

+ Code Snippet
Function PropList_AddListBox(PropList, H)

Local NewCell As DWORD


	MainGadgetData = GetGadgetData(PropList)
	CellPanel = Peek Integer(MainGadgetData+PROPLIST_CELLPANEL)

	CW = GadgetWidth(CellPanel)
	LW = Peek Integer(MainGadgetData+PROPLIST_LABELWIDTH)
	ClH = Peek Integer(MainGadgetData+PROPLIST_CELLHEIGHT)
	Y = GadgetHeight(CellPanel): If Y Then Inc Y, 2
	ResizeGadget CellPanel, CW, Y+H

	NewListBox = CreateListBox(0, Y, CW, H, CellPanel)
	Font = Peek Integer(MainGadgetData+PROPLIST_FONT): If Font Then ApplyFont NewListBox, Font

	NewCell = _PropList_NewCell(MainGadgetData, 1)
	Poke Integer NewCell+PROPLISTCELL_FUNCTION, Get Ptr To Function("_PropList_ListBoxFunction")
	Poke Integer NewCell+PROPLISTCELL_FIRSTGADGET, NewListBox

EndFunction NewCell


Function _PropList_ListBoxFunction(MainGadgetData As DWORD, Cell As DWORD)

	ListBox = Peek Integer(Cell+PROPLISTCELL_FIRSTGADGET)
	SelItem = SelectedItem(ListBox)
	Changed = false
	ValidatedGadget = Peek Integer(MainGadgetData+PROPLIST_VALIDATEGADGET)
	NextValidatedGadget = ValidatedGadget
	If ActiveGadget() = ListBox Then Poke Integer MainGadgetData+PROPLIST_VALIDATEGADGET, -1

	If ValidatedGadget = ListBox
		If SelItem >= 0
			Changed = true
			Poke Integer Cell+PROPLISTCELL_CHANGED, true
		EndIf
		NextValidatedGadget = 0
	EndIf
	Poke Integer MainGadgetData+PROPLIST_VALIDATEGADGET, NextValidatedGadget

	If Peek Integer(MainGadgetData+PROPLIST_SELECTGADGET) = ListBox
		If SelItem >= 0
			Changed = true
			Poke Integer Cell+PROPLISTCELL_CHANGED, true
		EndIf
	EndIf

	SetGadgetData ListBox, SelItem

EndFunction Changed



Code to add in the demo:
...
PropListCell_Enable = PropList_AddEnable(PropList, "Enabled", true)
PropListCell_Boolean = PropList_AddBoolean(PropList, "Boolean", true)
PropListCell_ComboBox = PropList_AddComboBox(PropList, "ComboBox", "Item 1;Item 2;Item 3;Item 4")
PropListCell_Button = PropList_AddButton(PropList, "Button")
PropListCell_Vector = PropList_AddVector(PropList, "Vector", 1.0, 2.0, 3.0)
PropListCell_Color = PropList_AddColorRGB(PropList, "Color", 0x0000ff)
PropListCell_ResSel = PropList_AddResourceSelector(PropList, "ResourceSelector", "My resource")
...
...
If PropListCell_IsChanged(PropListCell_Boolean) Then Print Console "Boolean changed: ", PropListCell_GetValue(PropListCell_Boolean, 0), CRLF$()
If PropListCell_IsChanged(PropListCell_Enable) Then Print Console "Enable changed: ", PropListCell_GetValue(PropListCell_Enable, 0), CRLF$()
If PropListCell_IsChanged(PropListCell_ComboBox) Then Print Console "Enable changed: ", PropListCell_GetValue(PropListCell_ComboBox, 0), CRLF$()
If PropListCell_IsChanged(PropListCell_Color) Then Print Console "Color clicked: "+Hex$(PropListCell_GetValue(PropListCell_Color, 0)), CRLF$()
If PropListCell_IsChanged(PropListCell_Button) Then Print Console "Button clicked: ", PropListCell_GetValue(PropListCell_Button, 0), CRLF$()
If PropListCell_IsChanged(PropListCell_ResSel) Then Print Console "ResSel clicked: ", PropListCell_GetValue(PropListCell_ResSel, 2), CRLF$()
If PropListCell_IsChanged(PropListCell_Vector)
v1# = Val(PropListCell_GetText(PropListCell_Vector, 0))
v2# = Val(PropListCell_GetText(PropListCell_Vector, 1))
v3# = Val(PropListCell_GetText(PropListCell_Vector, 2))
Print Console "Vector changed: ", v1#, " ", v2#, " ", v3#, CRLF$()
EndIf
...


The Property List Demo project file (Download)
Posted: 2nd Jun 2014 14:07
New cell types added!
In the next post, we get straight to the heart of the matter with overview of core structures..
Posted: 2nd Jul 2014 20:27
I'm quite busy these months so I've less time for coding..
That I can say is I have it 90% finished, but as you know, the last 10% are as long as the rest..


6. Overview of the core structures

"Structure". In an OOP langage, I would have said "Class". By "Structure", I mean mainly an UDT array and a collection of functions related to it. The array can be dynamic (elements can be added or removed) or table (element are defined at the beginning of the program). It can also be a singleton, in this case the array is replaced by variables.

App s
Globals variables and functions

UI s
BlueGUI Toolbar and fonts

Screen s
Handles the DBP window

ToolWindows t
Process dialog windows, retain pos/dims, process modal/nonmodal

Project s
Load, Save project. MediaPath. XML.

Camera s
Handles editor camera !!

Light s
Handles editor default light !!

SceneEditor s
Handles Entities in the scene

Entity d
Something in the 3D space. Contain a list of Modules

Module d
Group of properties related to specific part of an Entity

ModuleClass t
List of predefined functions to interact with a Module

ModuleEditors s
A ModuleEditor per ModuleClass. UI Part to edit a Module

EntityEditor s
UI Part to edit an Entity

EntityList s
The Entities contained in the scene
(Entity parenting is not implemented but left possible)

EditorObject d
Intermediate layer between "Object" Entities and DBP Objects

Gizmo s
3D Handles to edit the transform of an Entity. 3 types: Position / Rotation / Scale

Selector s
UI Dialog to select a resource

Resource d
Handle textures, objects.. Filename (Can also be procedural!). Take the usage count into account (=The same resource can be used several times)

MaterialEditor s
UI Part to edit material.
(Note: The materials are builtin (fully editable materials would have result a huge work..))

Structures with Dynamic elements
First, here's the naming I use, considering a structure named "Entity" taken as example..
UDT Name: TEntity
Array Name: Dim Entities(0) As TEntity
Function prefix: Entity_ for a particular Entity action(except deletion), otherwise Entities_

These structures are given a common set of variables and functions

NextFreeEntity: Next availaible slot of the array
Id: Id value

The availables element slots are maintained in a linked list
Element 0, that isn't used, contains the first of the list. If 0, a new array element is inserted.
Each new element receives an Id value. Althought the app uses the slot number,
the Id can be used for remapping the indices value and check the slot availability.

NewEntity(): Alloc a new slot index
DeleteEntity(): Free the slot, deleted when in the bottom else added in available slots list.. !Doesnot release the data.
DestroyEntity(): Release the data and free the slot
Clean(): Delete all the unused slots at the bottom of the array
FlushAll(): Release the data of all slots and Reset all the array
RestoreAll(): Call Restore() on all the used slots..

Release(): Release the data but keep the slot
Restore(): Called to restore the data when the screen is lost. Sometimes, the same function is called to init the data of the slot
Posted: 2nd Aug 2014 18:07
Just a word to say that i'm still working on it and
what I planned is almost finished!!!
I think I'll be able to continue my posts soon..
In the meanwhile, I can deliver a preview of what it look like!
Posted: 12th Aug 2014 21:43
Finished!
This gizmo part was quite massive piece of coding..
I can now clean/split the code and continue my posts..

I updated the step 6

Also feel free to to comment this project, this will keep me motivated!
Posted: 12th Aug 2014 21:44
7. EditorObject

The EditorObject structure is an intermediate layer between "Object" Entities and DBP Objects
Doing this let some higher level structures being separated of DBP objects, this reduce design complexity..
We can also handle here some functionalities such as selecting, display the wireframe mesh of the object.

The EditorObject is created with CreateEditorObject(Source, ObjectType, Param1, Param2, Param3, Transform As DWORD)
Source is a related user data. Later, it'll be used to store the entity number..
Right now, here is 3 types of visual: Mesh, Cube and Sphere
The role of Param1,2,3 changes according to ObjectType..
Transform is 3x3 table (pos/rot/scl, X/Y/Z)

+ Code Snippet
Rem * EditorObject.dba *


#Constant EDITOROBJECTTYPE_MESH 1
#Constant EDITOROBJECTTYPE_CUBE 2
#Constant EDITOROBJECTTYPE_SPHERE 3


EditorObjectHeader:

Type TEditorObject
	NextFreeEditorObject, Id

	Source
	Object, WFObject

	ObjectType
	Param1, Param2, Param3

	Transform As DWORD
EndType

Dim EditorObjects(0) As TEditorObject


Global EditorObjectSelectColor: EditorObjectSelectColor = RGB(255, 0, 0)

	Return


Function CreateEditorObject(Source, ObjectType, Param1, Param2, Param3, Transform As DWORD)

	NewEditorObject = EditorObjects_NewEditorObject()

	EditorObjects(NewEditorObject).Source = Source
	EditorObjects(NewEditorObject).ObjectType = ObjectType
	EditorObjects(NewEditorObject).Param1 = Param1
	EditorObjects(NewEditorObject).Param2 = Param2
	EditorObjects(NewEditorObject).Param3 = Param3
	EditorObjects(NewEditorObject).Transform = Transform

	Object = Reserve Free Object(): EditorObjects(NewEditorObject).Object = Object
	EditorObjects(NewEditorObject).WFObject = 0

	EditorObject_Restore(NewEditorObject)
	EditorObject_ApplyTransform(NewEditorObject)

EndFunction NewEditorObject


Function EditorObjects_NewEditorObject()

	NewEditorObject = EditorObjects(0).NextFreeEditorObject
	If NewEditorObject
		EditorObjects(0).NextFreeEditorObject = EditorObjects(NewEditorObject).NextFreeEditorObject
		EditorObjects(NewEditorObject).NextFreeEditorObject = 0
	Else
		Array Insert At Bottom EditorObjects(0)
		NewEditorObject = Array Count(EditorObjects(0))
	EndIf

	Id = EditorObjects(0).Id + 1
	EditorObjects(NewEditorObject).Id = Id
	EditorObjects(0).Id = Id

EndFunction NewEditorObject


Function EditorObjects_DeleteEditorObject(EditorObject)

	EditorObjects(EditorObject).Id = 0
	EditorObjects(EditorObject).NextFreeEditorObject = EditorObjects(0).NextFreeEditorObject
	EditorObjects(0).NextFreeEditorObject = EditorObject

	If EditorObjects(Array Count(EditorObjects(0))).Id = 0 Then EditorObjects_Clean()

EndFunction


Function EditorObjects_DestroyEditorObject(EditorObject)

	EditorObject_Release(EditorObject)
	EditorObjects_DeleteEditorObject(EditorObject)

EndFunction


Function EditorObjects_Clean()

	EditorObjects(0).NextFreeEditorObject = 0

	EditorObjectCount = Array Count(EditorObjects(0))
	For i = EditorObjectCount To 1 Step -1
		If EditorObjects(i).Id Then i = 1 Else Array Delete Element EditorObjects(0), i
	Next i

	EditorObjectCount = Array Count(EditorObjects(0))
	Dec EditorObjectCount: If EditorObjectCount = 0 Then ExitFunction

	For i = EditorObjectCount To 1 Step -1
		If EditorObjects(i).Id = 0
			EditorObjects(i).NextFreeEditorObject = EditorObjects(0).NextFreeEditorObject
			EditorObjects(0).NextFreeEditorObject = i
		EndIf
	Next i

EndFunction


Function EditorObjects_FlushAll()
debugprint "EditorObjects_FlushAll()", CRLF$()

	EditorObjectCount = Array Count(EditorObjects(0))
	For i = 1 To EditorObjectCount
		If EditorObjects(i).Id
			Object = EditorObjects(i).Object
			Delete Object Object: Release Reserved Object Object
			Object = EditorObjects(i).WFObject
			If Object Then Delete Object Object: Release Reserved Object Object
		EndIf
	Next i

	UnDim EditorObjects(0)
	Dim EditorObjects(0) As TEditorObject

EndFunction


Function EditorObjects_RestoreAll()
debugprint "EditorObjects_RestoreAll()", CRLF$()

	EditorObjectCount = Array Count(EditorObjects(0))
	For i = 1 To EditorObjectCount
		If EditorObjects(i).Id Then EditorObject_Restore(i)
	Next i

EndFunction


Function EditorObject_Release(EditorObject)

    Object = EditorObjects(EditorObject).Object
	Delete Object Object: Release Reserved Object Object
    Object = EditorObjects(EditorObject).WFObject
	If Object Then Delete Object Object: Release Reserved Object Object

EndFunction


Function EditorObject_SetVisible(EditorObject, Visible)

	Object = EditorObjects(EditorObject).Object: If Visible Then Show Object Object Else Hide Object Object
	Object = EditorObjects(EditorObject).WFObject
	If Object
		If Visible Then Show Object Object Else Hide Object Object
	EndIf

EndFunction


Function EditorObject_ApplyTransform(EditorObject)

Local Transform As DWORD


    Transform = EditorObjects(EditorObject).Transform
	If Transform = 0 Then ExitFunction

    Object = EditorObjects(EditorObject).Object
	Position Object Object, Peek Float(Transform), Peek Float(Transform+4), Peek Float(Transform+8)
	Rotate Object Object, Peek Float(Transform+12), Peek Float(Transform+16), Peek Float(Transform+20)
	Scale Object Object, Peek Float(Transform+24)*100.0, Peek Float(Transform+28)*100.0, Peek Float(Transform+32)*100.0

EndFunction


Function EditorObject_Select(EditorObject)

    WFObject = Reserve Free Object()
	EditorObjects(EditorObject).WFObject = WFObject

	EditorObject_Restore(EditorObject)

EndFunction


Function EditorObject_UnSelect(EditorObject)

    WFObject = EditorObjects(EditorObject).WFObject

    Delete Object WFObject
	Release Reserved Object WFObject
	EditorObjects(EditorObject).WFObject = 0

EndFunction


Function EditorObject_Clear(EditorObject)

    Object = EditorObjects(EditorObject).Object
	If Object Exist(Object) Then Delete Object Object

    Object = EditorObjects(EditorObject).WFObject
	If Object Exist(Object) Then Delete Object Object
 
EndFunction


Function EditorObject_Restore(EditorObject)
debugprint "EditorObject_Restore() ", EditorObject, CRLF$()

    Object = EditorObjects(EditorObject).Object
	If Object Exist(Object) = 0
		Select EditorObjects(EditorObject).ObjectType
		Case EDITOROBJECTTYPE_MESH
			Mesh = EditorObjects(EditorObject).Param1
			Make Object Object, Mesh
			EndCase

		Case EDITOROBJECTTYPE_CUBE
			Make Object Cube Object, 1.0
			EndCase

		Case EDITOROBJECTTYPE_SPHERE
			Rows = EditorObjects(EditorObject).Param1
			Columns = EditorObjects(EditorObject).Param2
			Make Object Sphere Object, 1.0, Rows, Columns
			EndCase
		EndSelect

		Set Object Mask Object, %1
 		EditorObject_ApplyTransform(EditorObject)
	EndIf

    WFObject = EditorObjects(EditorObject).WFObject
	If WFObject: If Object Exist(Object)
		Clone Object WFObject, Object
		Glue Object To Limb WFObject, Object, 0, 1
		Set Object WireFrame WFObject, 1
		Set Object Light WFObject, 1
		Set Object Emissive WFObject, EditorObjectSelectColor
		Set Object Diffuse WFObject, 0
		Set Object Ambience WFObject, 0
		Set Object Mask WFObject, %1
		Enable Object ZBias WFObject, -1.0, 0.0
		Position Object WFObject, 0.0, 0.0, 0.0
		Rotate Object WFObject, 0.0, 0.0, 0.0
		Scale Object WFObject, 100.0, 100.0, 100.0
	EndIf: EndIf

EndFunction



Merging All Together (Download)
Posted: 14th Aug 2014 7:05
amazing work Le Verdier !!
Posted: 29th Aug 2014 20:48
Thank you GreenDixy!..
Posted: 29th Aug 2014 20:50
8. Entity, Module, ModuleClass and SceneEditor

ENTITY

It is the key structure of the editor. By "Entity", I mean "something in the 3D space".
This editor is limited to objects but an entity could be anything else like a light, a camera...
An Entity is made of "modules".
By adding a module to the Entity, we add some new features to it
e.g: Let take a default cube mesh.. Add a "transform" and this cube is now movable, rotatable and scalable.
Add a "render object" and a material can be applied..
This design make the editor very flexible..!!
The modules are stored in a linked list. A "LastItem" variable is added so that the list is easier to handle..

UDT:
Type TEntity
NextFreeEntity, Id

Flags `b0:Enabled
UIData `Will be used to interact with the entity list
Transform As DWORD
EditorObject
FirstModule, LastModule
Material
QueryNext
EndType

Functions:
Entities_QuerySameMaterial(Material)
Entity_AddModule(Entity, Module)


MODULE & MODULE CLASS

Modules consist of two things: data in memory and a class.
A class is collection of functions to interact with these datas.
Some management bits are also defined here

UDT:
Type TModule
Id, NextFreeModule

PreviousModule, NextModule `for the linked list..
Flags `b0:Enabled b1:Retain Window b2:Updated
ModuleClass
ModuleData As DWORD
EndType

Functions: Mainly getter/setter:
Module_Edit(Module) Class caller for edit function
Module_CloseEdit(Module)
Module_SetEnabled(Module, Enabled)
Module_GetEnabled(Module)
Module_SetRetained(Module, Retained)
Module_GetRetained(Module)
Module_SetUpdated(Module, Updated)
Module_GetUpdated(Module)


UDT:
Type TModuleClass
Name$, NameHash
PropertyCount

OnCreateInstanceFunction As DWORD
OnReleaseFunction As DWORD
OnEditFunction As DWORD
OnUpdateFunction As DWORD
TranslateToXMLFunction As DWORD
EndType


No functions..

Helper functions:
AddModuleClass(Name$, PropertyCount)
GetModuleClass(Name$)


The function pointers are defined at the beginning of the app with The M1U function Get Ptr To Function()

+ Code Snippet
Function DefineModuleClasses()

	mc = AddModuleClass("Transform", 9)
	ModuleClasses(mc).OnCreateInstanceFunction = Get Ptr To Function("ModuleTransform_SetDefaultValues")
	ModuleClasses(mc).OnEditFunction = Get Ptr To Function("ShowTransformEditorWindow")
	ModuleClasses(mc).OnUpdateFunction = Get Ptr To Function("UpdateEntity_Transform")
	ModuleClasses(mc).TranslateToXMLFunction = Get Ptr To Function("ModuleTransform_TranslateToXML")
...




SCENEEDITOR

This part of the app deals with entity creation, deletion and selection

Variables:
SceneEditorSelectedEntity
SceneEditorEntityPosX#
SceneEditorEntityPosY#
SceneEditorEntityPosZ#

Functions:
SceneEditor_BuildSceneAfterLoad()
SceneEditor_GetSelectedEntity()
SceneEditor_EntityUnderPoint(X, Y)
SceneEditor_SetNewEntityPosition(X#, Y#, Z#)
SceneEditor_DeleteSelectedEntity()
SceneEditor_SelectEntity(Entity)
SceneEditor_ApplyMaterial(Material, Entity)
SceneEditor_DetachMaterial(Entity)
SceneEditor_AddEntity_Object(Mesh, MeshId)
SceneEditor_AddEntity_Cube()
SceneEditor_AddEntity_Sphere()
SceneEditor_SetEntityEnabled(Entity, Enabled)


Merging All Together (Download)
The app look like the previous step but scene is now created with entities, which can now be selected with mouse..
(when toolbar button 2/3/4 is selected..)
Posted: 18th Sep 2014 18:55
9. ToolWindow and EntityList

TOOLWINDOW
The app interface has quite a bit dialog windows, this is a small structure to handle their window gadget.
The two interesting features here are retaining the pos/dims when a window is closed and reopened, Modal/Non-modal processing


UDT
Type TToolWindow
Window
Caption$
X, Y, W, H
Style
EndType


Functions
ToolWindow_Set(ToolWindow, X, Y, W, H, Resizable, Caption$)
ToolWindow_Open(ToolWindow)
ToolWindow_OpenResizable(ToolWindow)
ToolWindow_Close(ToolWindow)
ToolWindow_BeginModal(ToolWindow)
ToolWindow_EndModal()



To process non modal, just include the processing function call in the main loop:
+ Code Snippet
Window = ToolWindows(APPTOOLWINDOW_ENTITYEDITOR).Window: If Window
	EntityEditor_Process(EventMouseDownGadget, EventReturnKeyDownGadget)
	If EventCloseWindow = Window Then ShowEntityEditorWindow(0)
EndIf


The modal processing consists in running only one window and wait the user to close it.
All other windows are disabled during this time!


ENTITYLIST
Theorically, this should be a simple linked list with all the entities..
But something very different is used: a BlueGUI TreeView!!
The reasons:
-It is not implememented here but later, I would like Entity parenting.
-We need anyway to display the entities name set to the UI so that the user can select..,
a tree struture functions already exist via the treeview gadget, so just use them!

Variables
EntityListTreeView
EntityListRootTVI

EntityListCubeCount
EntityListSphereCount
EntityListObjectCount


Functions:
EntityList_CreateRoot()
EntityList_AddEntity(Entity, Name$)
EntityList_SelectEntity(Entity)


Helper Function:
CreateEntityList()

The treeview items and entities are binded with the UIData variable in the Entity structure and the TVI Data.
The gadget must not be deleted as it containt project data!
When its toolwindow is closed, the gadget is hidden and its parent window changed..


TreeView Additional functions
Some TreeView features needed but not present in Blue. Recreated here with user32dll calls:

TreeView_SetItemTextBold(TreeView, Item, TextBold)
TreeView_SetItemData(TreeView, Item, ItemData)
TreeView_GetItemData(TreeView, Item)
TreeView_ExpandItem(TreeView, Item)


Merging All Together (Download)
The EntityList Window is opened in View menu
Posted: 21st Sep 2014 21:25
Great work, As always.
Posted: 6th Oct 2014 18:02

A short post before the next step scheduled this week ..

I updated the property list part, this had to be fixed before the next step:
- New cell type added: the ListBox
- New event: Select
- Button fixed
and
- The whole property List Demo project file
- !A new gui.dba file used on all the project!