Code archives/3D Graphics - Misc/F-UI GUI XML Loader

This code has been declared by its author to be Public Domain code.

Download source code

F-UI GUI XML Loader by N2004
Basically, this loads a GUI layout from an XML file. This is useful for giving users of your applications the option to modify the user interface of your application to suit your needs.

An example XML file:
<Root>
	<Window X="128" Y="128" Width="640" Height="480" Caption="Weeble">
		<MenuTitle caption="File">
			<MenuItem caption="New..">
				<MenuItem caption="Lotus Emitter"/>
				<MenuItem caption="Scene"/>
			</MenuItem>
			<MenuItem caption="Save"/>
			<MenuItem caption="Save as.."/>
			<MenuBar/>
			<MenuItem caption="Exit" name="mnuQuit"/>
		</MenuTitle>
		<Button X="4" Y="64" Width="64" Height="24" Caption="Foobar"/>
	</Window>
</Root>


An example .BB file for loading the XML document:
WINDOW_RESIZE_METHOD = 0
RENDER_MODE = 0
SKIN_ENABLED = 0

FUI_Initialise(1024,769,32,2,0,1,"XML GUI","1.8")

FUI_LoadGUI("GUI.xml")

Repeat
	FUI_Update()
	For e.Event = Each Event
		Select e\EventID
			Case FUI_GetGadget("mnuQuit")
				app\Quit = 1
			Default
		End Select
		Delete e
	Next
	UpdateWorld
	RenderWorld
	Flip True
Until app\Quit = 1

FUI_Destroy()
;#Region XMLGui.bb
	;#Region CLASSES
		Type FUI_XMLGadget
			Field Name$
			Field Gadget
		End Type
		
		Global LED_ColorMode=1
	;#End Region
	
	;#Region PROCEDURES
		Function FUI_LoadGUI(Path$)
			If FileType(Path) <> 1 Then RuntimeError "Failed to load GUI '"+Path+"'"
			
			node.XMLNode = ReadXML(Path)
			root.XMLNode = node
		
			While(node <> Null)
				FUI_ParseXMLGUI(node)
				node = XMLNextNode(node)
			Wend
			
			XMLCloseNode(root)
			
			Return 1
		End Function
		
		Function FUI_ParseXMLGUI(node.XMLNode,owner=0)
			If node = Null Then Return
			
			Local X%,Y%,Width%,Height%,Caption$,Name$
			Local F1#,F2#,F3#,F4#,F5#,F6#,F7#
			Local I1%,I2%,I3%,I4%,I5%,I6%,I7%
			Local Icon$,Shortcut$,DType%=DTYPE_INTEGER,Alpha#=1
			Local Flags
			
			Local a.XMLAttr = XMLGetFirstAttribute(node)
			While (a <> Null)
				Select Lower(a\name)
					Case "x"
						X = a\value
					Case "y"
						Y = a\value
					Case "height"
						Height = a\value
					Case "width"
						Width = a\value
					Case "caption"
						Caption = a\value
					Case "name"
						Name = a\value
					Case "id"
						I1 = a\value
					Case "checked"
						I1 = a\value
					Case "dispitems"
						I4 = a\value
					Case "checkable"
						I2 = a\value
					Case "checked"
						I3 = a\value
					Case "shortcut"
						Shortcut = a\value
					Case "image"
						Shortcut = a\value
					Case "align"
						I1 = ((Lower(a\value)="center")*ALIGN_CENTER Or (Lower(a\value)="left")*ALIGN_LEFT Or (Lower(a\value)="right")*ALIGN_RIGHT)
					Case "multisel"
						I1 = a\value
					Case "forcesel"
						I2 = a\value
					Case "min"
						F1 = a\value
					Case "max"
						F2 = a\value
					Case "value"
						F3 = a\value
					Case "dtype"
						DType = ((Lower(a\value)="integer")*DTYPE_INTEGER Or (Lower(a\value)="float")*DTYPE_FLOAT)
					Case "scrollw"
						I1 = a\value
					Case "direction"
						I2 = ((Lower(a\value)="horizontal")*DIR_HORIZONTAL Or (Lower(a\value)="vertical")*DIR_VERTICAL)
					Case "inc"
						F4 = a\value
					Case "append"
						Shortcut = a\value
					Case "maxlength"
						I1 = a\value
					Case "flags"
						Flags = a\value
					Case "buttons"
						I2 = a\value
					Case "alpha"
						Alpha# = a\value
					Case "red","r"
						I1 = a\value
					Case "green","g"
						I2 = a\value
					Case "blue","b"
						I3 = a\value
					Case "bitsperpixel"
						I1 = a\value
					Case "fullscreen"
						I2 = Not Int a\value + 1
					Case "windowed"
						I2 = Int a\value + 1
					Case "locked"
						Locked = a\value
					Case "colormode"
						LED_ColorMode=Int a\value - 1
				End Select
				a = XMLGetNextAttribute(a)
			Wend
			
			Select Lower(node\tag)
				Case "window"
					If Flags=0 Then Flags=WS_TITLEBAR Or WS_ALLBUTTONS
					gad = FUI_Window(X,Y,Width,Height,Caption,Icon,Flags,I2)
					FUI_LockWindow(gad,Locked)
				Case "button"
					If Flags=0 Then Flags=CS_BORDER
					gad = FUI_Button(owner,X,Y,Width,Height,Caption,Icon,I1,Flags)
				Case "groupbox"
					gad = FUI_GroupBox(owner,X,Y,Width,Height,Caption)
				Case "listbox"
					gad = FUI_ListBox(owner,X,Y,Width,Height,I1,I2)
				Case "listboxitem"
					gad = FUI_ListBoxItem(owner,Caption,Icon)
				Case "treeview"
					gad = FUI_TreeView(owner,X,Y,Width,Height)
				Case "treeviewnode"
					gad = FUI_TreeViewNode(owner,Caption)
				Case "combobox"
					gad = FUI_ComboBox(owner,X,Y,Width,Height,I4)
				Case "comboboxitem"
					gad = FUI_ComboBoxItem(owner,Caption,Icon)
				Case "label"
					gad = FUI_Label(owner,X,Y,Caption,I1)
				Case "slider"
					gad = FUI_Slider(owner,X,Y,Width,Height,F1,F2,F3,I1,I2)
				Case "menubar"
					gad = FUI_MenuBar(owner)
				Case "menuitem"
					gad = FUI_MenuItem(owner,Caption,Shortcut,Icon,I2,I3,I1)
				Case "menutitle"
					gad = FUI_MenuTitle(owner,Caption,Width)
				Case "panel"
					gad = FUI_Panel(owner,X,Y,Width,Height,Caption)
				Case "progressbar"
					gad = FUI_ProgressBar(owner,X,Y,Width,Height,F1,F2,F3,DType)
				Case "radio"
					gad = FUI_Radio(owner,X,Y,Caption,I3,I1)
				Case "checkbox"
					gad = FUI_CheckBox(owner,X,Y,Caption,I3)
				Case "spinner"
					gad = FUI_Spinner(owner,X,Y,Width,Height,F1,F2,F3,F4,DType,Shortcut)
				Case "tab"
					gad = FUI_Tab(owner,X,Y,Width,Height)
				Case "tabpage"
					gad = FUI_TabPage(owner,Caption,Icon)
				Case "view"
					gad = FUI_View(owner,X,Y,Width,Height,I1,I2,I3)
				Case "textobx"
					gad = FUI_TextBox(owner,X,Y,Width,Height,I1)
				Case "skinpath"
					SKIN_PATH = node\value
				Case "skinenabled"
					SKIN_ENABLED = node\value
				Case "gui"
					If Width = 0 Or Height = 0 Then Width = 1024 Height = 768
					If I1 = 0 Then I1 = 32
					If I2 = 0 Then I2 = 2
					FUI_Initialise(Width,Height,I1,I2,0,1,"LotusEd R2","1.8")
					SetupColors(LED_ColorMode)
			End Select
			
			If gad <> 0 Then
				g.FUI_XMLGadget = New FUI_XMLGadget
				g\Name = Name
				g\Gadget = gad
				If Alpha <> 1 Then FUI_SetGadgetAlpha(gad,Alpha,1)
			EndIf
			
			node = XMLGetChild(node,0)
			While(node <> Null)
				FUI_ParseXMLGUI(node,gad)
				node = XMLNextNode(node)
			Wend
		End Function
		
		Function FUI_GetGadget(name$)
			name = Lower(name)
			For g.FUI_XMLGadget = Each FUI_XMLGadget
				If Lower(g\Name) = name Then Return g\Gadget
			Next
			Return -1
		End Function
		
		;;; Add your own color schemes to this function
		Function SetupColors(Mode=1)
			If Mode=0
				SC_FORM=FUI_RGBToInt(75,82,93)
				SC_FORM_BORDER=FUI_RGBToInt(0,0,0)
				SC_TITLEBAR=FUI_RGBToInt(255,155,48)
				SC_TITLEBAR_TEXT=FUI_RGBToInt(24,55,80)
				SC_MENUBAR=FUI_RGBToInt(51,55,60)
				SC_MENUBAR_BORDER=FUI_RGBToInt(32,32,32)
				SC_STATUSBAR=FUI_RGBToInt(75,82,93)
				SC_STATUSBAR_TEXT=FUI_RGBToInt(255,155,48)
				SC_STATUSBAR_BORDER=FUI_RGBToInt(32,32,32)
				
				SC_MENUTITLE=FUI_RGBToInt(75,82,93)
				SC_MENUTITLE_OVER=FUI_RGBToInt(66,120,164)
				SC_MENUTITLE_SEL=FUI_RGBToInt(66,120,164)
				SC_MENUTITLE_TEXT=FUI_RGBToInt(255,171,61)
				SC_MENUTITLE_TEXT_OVER=FUI_RGBToInt(48,46,45)
				SC_MENUTITLE_TEXT_SEL=FUI_RGBToInt(48,46,45)
				SC_MENUTITLE_BORDER=FUI_RGBToInt(0,0,0)
				SC_MENUTITLE_BORDER_OVER=FUI_RGBToInt(0,0,0)
				SC_MENUTITLE_BORDER_SEL=FUI_RGBToInt(0,0,0)
				
				SC_MENUITEM=FUI_RGBToInt(75,82,93)
				SC_MENUITEM_OVER=FUI_RGBToInt(66,120,164)
				SC_MENUITEM_SEL=FUI_RGBToInt(66,120,164)
				SC_MENUITEM_TEXT=FUI_RGBToInt(255,171,61)
				SC_MENUITEM_TEXT_OVER=FUI_RGBToInt(48,46,45)
				SC_MENUITEM_TEXT_SEL=FUI_RGBToInt(48,46,45)
				SC_MENUITEM_BORDER=FUI_RGBToInt(0,0,0)
				SC_MENUITEM_BORDER_OVER=FUI_RGBToInt(0,0,0)
				SC_MENUITEM_BORDER_SEL=FUI_RGBToInt(0,0,0)
				
				SC_MENUDROPDOWN=FUI_RGBToInt(75,82,93)
				SC_MENUDROPDOWN_BORDER=FUI_RGBToInt(0,0,0)
				SC_MENUDROPDOWN_STRIP=FUI_RGBToInt(255,171,61)
				
				SC_TOOLTIP=FUI_RGBToInt(75,82,93)
				SC_TOOLTIP_BORDER=FUI_RGBToInt(0,0,0)
				SC_TOOLTIP_TEXT=FUI_RGBToInt(255,171,61)
				
				SC_GADGET =FUI_RGBToInt(75,82,93)
				SC_GADGET_TEXT =FUI_RGBToInt(255,171,61)
				SC_GADGET_COLOR =FUI_RGBToInt(75,82,93)
				SC_GADGET_COLOR_TEXT =FUI_RGBToInt(255,171,61)
				SC_GADGET_BORDER =FUI_RGBToInt(0,0,0)
				
				SC_INPUT=FUI_RGBToInt(32,45,64)
				SC_INPUT_TEXT=FUI_RGBToInt(255,171,61)
				SC_INPUT_COLOR=FUI_RGBToInt(32,45,64)
				SC_INPUT_COLOR_TEXT=FUI_RGBToInt(255,171,61)
				SC_INPUT_BORDER=FUI_RGBToInt(0,0,0)
			ElseIf Mode=1 Then
				SC_FORM=FUI_RGBToInt(242,240,238)
				SC_FORM_BORDER=FUI_RGBToInt(32,32,32)
				SC_TITLEBAR=FUI_RGBToInt(15,128,206)
				SC_TITLEBAR_TEXT=FUI_RGBToInt(255,255,255)
				SC_MENUBAR=FUI_RGBToInt(245,244,240)
				SC_MENUBAR_BORDER=FUI_RGBToInt(32,32,32)
				SC_STATUSBAR=FUI_RGBToInt(245,244,240)
				SC_STATUSBAR_TEXT=FUI_RGBToInt(0,0,0)
				SC_STATUSBAR_BORDER=FUI_RGBToInt(64,64,64)
				
				SC_MENUTITLE=FUI_RGBToInt(255,197,128)
				SC_MENUTITLE_OVER=FUI_RGBToInt(255,197,128)
				SC_MENUTITLE_SEL=FUI_RGBToInt(255,197,128)
				SC_MENUTITLE_TEXT=FUI_RGBToInt(0,0,0)
				SC_MENUTITLE_TEXT_OVER=FUI_RGBToInt(0,0,0)
				SC_MENUTITLE_TEXT_SEL=FUI_RGBToInt(0,0,0)
				SC_MENUTITLE_BORDER=FUI_RGBToInt(0,0,0)
				SC_MENUTITLE_BORDER_OVER=FUI_RGBToInt(255,255,255)
				SC_MENUTITLE_BORDER_SEL=FUI_RGBToInt(255,255,255)
				
				SC_MENUITEM=FUI_RGBToInt(255,197,128)
				SC_MENUITEM_OVER=FUI_RGBToInt(255,197,128)
				SC_MENUITEM_SEL=FUI_RGBToInt(255,197,128)
				SC_MENUITEM_TEXT=FUI_RGBToInt(0,0,0)
				SC_MENUITEM_TEXT_OVER=FUI_RGBToInt(0,0,0)
				SC_MENUITEM_TEXT_SEL=FUI_RGBToInt(0,0,0)
				SC_MENUITEM_BORDER=FUI_RGBToInt(0,0,0)
				SC_MENUITEM_BORDER_OVER=FUI_RGBToInt(255,255,255)
				SC_MENUITEM_BORDER_SEL=FUI_RGBToInt(255,255,255)
				
				SC_MENUDROPDOWN=FUI_RGBToInt(242,240,238)
				SC_MENUDROPDOWN_BORDER=FUI_RGBToInt(0,0,0)
				SC_MENUDROPDOWN_STRIP=FUI_RGBToInt(21,119,218)
				
				SC_TOOLTIP=FUI_RGBToInt(252,242,202)
				SC_TOOLTIP_BORDER=FUI_RGBToInt(0,0,0)
				SC_TOOLTIP_TEXT=FUI_RGBToInt(0,0,0)
				
				SC_GADGET=FUI_RGBToInt(250,248,246)
				SC_GADGET_TEXT=FUI_RGBToInt(0,0,0)
				SC_GADGET_COLOR=FUI_RGBToInt(250,248,246)
				SC_GADGET_COLOR_TEXT=FUI_RGBToInt(0,0,0)
				SC_GADGET_BORDER=FUI_RGBToInt(0,0,0)
				
				SC_INPUT=FUI_RGBToInt(255,255,255)
				SC_INPUT_TEXT=FUI_RGBToInt(0,0,0)
				SC_INPUT_COLOR=FUI_RGBToInt(255,255,255)
				SC_INPUT_COLOR_TEXT=FUI_RGBToInt(0,0,0)
				SC_INPUT_BORDER=FUI_RGBToInt(0,0,0)
			ElseIf Mode=2 Then
				SC_FORM=FUI_RGBToInt(80,74,90)
				SC_FORM_BORDER=FUI_RGBToInt(32,32,32)
				SC_TITLEBAR=FUI_RGBToInt(179,247,41)
				SC_TITLEBAR_TEXT=FUI_RGBToInt(0,0,0)
				SC_MENUBAR=FUI_RGBToInt(80,74,90)
				SC_MENUBAR_BORDER=FUI_RGBToInt(32,32,32)
				SC_STATUSBAR=FUI_RGBToInt(80,74,90)
				SC_STATUSBAR_TEXT=FUI_RGBToInt(180,255,57)
				SC_STATUSBAR_BORDER=FUI_RGBToInt(64,64,64)
				
				SC_MENUTITLE=FUI_RGBToInt(96,66,173)
				SC_MENUTITLE_OVER=FUI_RGBToInt(96,66,173)
				SC_MENUTITLE_SEL=FUI_RGBToInt(96,66,173)
				SC_MENUTITLE_TEXT=FUI_RGBToInt(180,255,57)
				SC_MENUTITLE_TEXT_OVER=FUI_RGBToInt(180,255,57)
				SC_MENUTITLE_TEXT_SEL=FUI_RGBToInt(180,255,57)
				SC_MENUTITLE_BORDER=FUI_RGBToInt(0,0,0)
				SC_MENUTITLE_BORDER_OVER=FUI_RGBToInt(0,0,0)
				SC_MENUTITLE_BORDER_SEL=FUI_RGBToInt(0,0,0)
				
				SC_MENUITEM=FUI_RGBToInt(96,66,173)
				SC_MENUITEM_OVER=FUI_RGBToInt(96,66,173)
				SC_MENUITEM_SEL=FUI_RGBToInt(96,66,173)
				SC_MENUITEM_TEXT=FUI_RGBToInt(180,255,57)
				SC_MENUITEM_TEXT_OVER=FUI_RGBToInt(180,255,57)
				SC_MENUITEM_TEXT_SEL=FUI_RGBToInt(180,255,57)
				SC_MENUITEM_BORDER=FUI_RGBToInt(0,0,0)
				SC_MENUITEM_BORDER_OVER=FUI_RGBToInt(0,0,0)
				SC_MENUITEM_BORDER_SEL=FUI_RGBToInt(0,0,0)
				
				SC_MENUDROPDOWN=FUI_RGBToInt(80,74,90)
				SC_MENUDROPDOWN_BORDER=FUI_RGBToInt(0,0,0)
				SC_MENUDROPDOWN_STRIP=FUI_RGBToInt(180,255,57)
				
				SC_TOOLTIP=FUI_RGBToInt(80,74,90)
				SC_TOOLTIP_BORDER=FUI_RGBToInt(0,0,0)
				SC_TOOLTIP_TEXT=FUI_RGBToInt(180,255,57)
				
				SC_GADGET=FUI_RGBToInt(80,74,90)
				SC_GADGET_TEXT=FUI_RGBToInt(180,255,57)
				SC_GADGET_COLOR=FUI_RGBToInt(80,74,90)
				SC_GADGET_COLOR_TEXT=FUI_RGBToInt(180,255,57)
				SC_GADGET_BORDER=FUI_RGBToInt(0,0,0)
				
				SC_INPUT=FUI_RGBToInt(40,37,45)
				SC_INPUT_TEXT=FUI_RGBToInt(180,255,57)
				SC_INPUT_COLOR=FUI_RGBToInt(40,37,45)
				SC_INPUT_COLOR_TEXT=FUI_RGBToInt(180,255,57)
				SC_INPUT_BORDER=FUI_RGBToInt(0,0,0)
			EndIf
		End Function
	;#End Region
;#End Region

;#Region LotusXML.bb
	;#Region DESCRIPTION
		; XML load / parse / save functions
		; Written by Blitztastic, butchered by Noel Cower
	;#End Region
	
	;#Region CLASSES
		Type XMLnodelist
			Field node.XMLnode
			Field nextnode.XMLnodelist
			Field prevnode.XMLnodelist
		End Type
		
		; for internal use, do not use in code outside of this file
		Type XMLworklist
			Field node.XMLnode
		End Type
		
		
		Type XMLnode
			Field tag$,value$,path$
			Field firstattr.XMLattr
			Field lastattr.XMLattr	
			Field attrcount,fileid
			Field endtag$
			
			; linkage functionality
			Field firstchild.XMLnode
			Field lastchild.XMLnode
			Field childcount
			Field nextnode.XMLnode
			Field prevnode.XMLnode
			Field parent.XMLnode
		End Type
		
		Type XMLattr
			Field name$,value$
			Field sibattr.XMLattr
			Field parent.XMLnode
		End Type
		
		Global XMLFILEID
	;#End Region
	
	;#Region PROCEDURES
		Function ReadXML.XMLnode(filename$)
			infile = ReadFile(filename$)
			XMLFILEID=MilliSecs()
			x.XMLnode = XMLReadNode(infile,Null)
			CloseFile infile
			Return x
		End Function
		
		Function WriteXML(filename$,node.XMLnode,writeroot=False)
			outfile = WriteFile(filename$)
			WriteLine outfile,"<?xml version="+Chr$(34)+"1.0"+Chr$(34)+" ?>"
			XMLwriteNode(outfile,node)
			CloseFile outfile
		End Function
		
		Function XMLOpenNode.XMLnode(parent.XMLnode,tag$="")
			x.XMLnode = New XMLnode
			x\tag$=tag$
			x\fileid = XMLFILEID; global indicator to group type entries (allows multiple XML files to be used)
			XMLaddNode(parent,x)
			Return x
		End Function
		
		Function XMLCloseNode.XMLnode(node.XMLnode)
			Return node\parent
		End Function
		
		; adds node to end of list (need separate function for insert, or mod this on)
		Function XMLAddNode(parent.XMLnode,node.XMLnode)
			If parent <> Null
				If parent\childcount = 0 Then
					parent\firstchild = node
				Else
					parent\lastchild\nextnode = node
				End If
				node\prevnode = parent\lastchild
				parent\lastchild = node
				parent\childcount = parent\childcount +1
				node\path$ = parent\path$+parent\tag$
			End If
			node\parent = parent
			node\path$=node\path$+"/"
		End Function
		
		Function XMLDeleteNode(node.XMLnode)
			n.XMLnode = node\firstchild
			; delete any children recursively
			While n <> Null
				nn.XMLnode= n\nextnode
				XMLdeletenode(n)
				n = nn
			Wend
		
			; delete attributes for this node
			a.XMLattr = node\firstattr
			While a <> Null
				na.XMLattr = a\sibattr
				Delete a
				a = na
			Wend
		
			; dec parents child count
			If node\parent <> Null
				node\parent\childcount = node\parent\childcount -1
				
				; heal linkages
				If node\prevnode <> Null Then node\prevnode\nextnode = node\nextnode
				If node\nextnode <> Null Then node\nextnode\prevnode = node\prevnode
				If node\parent\firstchild = node Then node\parent\firstchild = node\nextnode
				If node\parent\lastchild = node Then node\parent\lastchild = node\prevnode
			End If
			; delete this node		
			Delete node
		
		End Function
		
		; node functions
		Function XMLfindNode.XMLnode(node.XMLnode,path$)
		
			ret.XMLnode = Null
			p=Instr(path$,"/")
			If p > 0 Then 
				tag$=Left$(path$,p-1)
				a.XMLnode = node
				While ret=Null And a<>Null 
					If Lower(tag$)=Lower(a\tag$) Then
						If p=Len(path$) Then
								ret = a
						Else
							If a\firstchild <> Null Then
								ret = XMLfindnode(a\firstchild,Mid$(path$,p+1))
							End If
						End If
					End If
					a = a\nextnode
				Wend
			End If
			Return ret
		End Function
		
		Function XMLDeleteList(nl.XMLnodelist)
			While nl <> Null
				na.XMLnodelist = nl\nextnode
				Delete nl
				nl = na
			Wend
		End Function
		
		
		Function XMLSelectNodes.XMLnodelist(node.XMLnode,path$,recurse=True)
			root.XMLnodelist=Null
			XMLselectnodesi(node,path$,recurse)
			prev.XMLnodelist=Null
			c = 0
			For wl.XMLworklist = Each XMLworklist
				c = c + 1
				nl.XMLnodelist = New XMLnodelist
				nl\node = wl\node
				If prev = Null Then 
					root = nl
					prev = nl
				Else
					prev\nextnode = nl
					nl\prevnode = prev
				End If
				prev = nl
				Delete wl

			Next
			;gak debuglog "XML: "+c+" nodes selected"
			Return root
		End Function
		
		; internal selection function, do not use outside this file
		Function XMLSelectNodesI(node.XMLnode,path$,recurse=True)
			wl.XMLworklist=Null
			If node = Null Then
			End If
			ret.XMLnode = Null
			p=Instr(path$,"/")
			If p > 0 Then 
				tag$=Left$(path$,p-1)
				a.XMLnode = node
				While a<>Null 
					If Lower(path$)=Lower(Right$(a\path$+a\tag$+"/",Len(path$))) Then
							wl = New XMLworklist
							wl\node = a
					End If
					If a\firstchild <> Null And (recurse) Then
						XMLSelectNodesI(a\firstchild,path$)
					End If
					a = a\nextnode
				Wend
			End If
		
		End Function
		
		Function XMLNextNode.XMLnode(node.XMLnode)
			Return node\nextnode
		End Function
		
		Function XMLPrevNode.XMLnode(node.XMLnode)
			Return node\prevnode
		End Function
		
		Function XMLAddAttr(node.XMLnode,name$,value$)
			;gak debuglog "XML:adding attribute "+name$+"="+value$+" ("+Len(value$)+")"
			a.XMLattr = New XMLattr
			a\name$ = name$
			a\value$ = value$
			If node\attrcount = 0 Then
				node\firstattr = a
			Else
				node\lastattr\sibattr = a
			End If
			node\lastattr=a
			node\attrcount = node\attrcount + 1
			a\parent = node
			If Upper(a\value)="TRUE" a\value=1
			If Upper(a\Value)="FALSE" a\value=0
			If Upper(a\Value)="GRAPHICSWIDTH" a\value=GraphicsWidth()
			If Upper(a\Value)="GRAPHICSHEIGHT" a\value=GraphicsHeight()
		End Function
		
		Function XMLReadNode.XMLnode(infile,parent.XMLnode,pushed=False)
			mode = 0
			root.XMLnode = Null
			cnode.XMLnode = Null
			x.XMLnode = Null
			ispushed = False
			done = False
			While (Not done) And (Not Eof(infile))
				c = ReadByte(infile)
				If c<32 Then c=32
				ch$=Chr$(c)
		;		;gak debuglog "{"+ch$+"} "+c+" mode="+mode
				Select mode
				  Case 0 ; looking for the start of a tag, ignore everything else
					If ch$ = "<" Then 
						mode = 1; start collecting the tag
					End If
				  Case 1 ; check first byte of tag, ? special tag
					If ch$ = "?" Or ch$ = "!" Then
				 		mode = 0; class special nodes as garbage & consume
					Else
						If ch$ = "/" Then 
							mode = 2 ; move to collecting end tag
							x\endtag$=ch$
							;gak debuglog "** found end tag"
						Else
							cnode=x
							x.XMLnode = XMLOpennode(cnode)
							If cnode=Null Then root=x
							x\tag$=ch$
							mode = 3 ; move to collecting start tag
						End If
					End If
				  Case 2 ; collect the tag name (close tag)
					If ch$=">" Then 
						mode = 0 ; end of the close tag so jump out of loop
						;done = True
						x = XMLclosenode(x)
					Else 
						x\endtag$ = x\endtag$ + ch$
					End If
				  Case 3 ; collect the tag name 
					If ch$=" " Then 
						;gak debuglog "TAG:"+x\tag$
						mode = 4 ; tag name collected, move to collecting attributes
					Else 
						If ch$="/" Then 
							;gak debuglog "TAG:"+x\tag$
							x\endtag$=x\tag$
							mode = 2; start/end tag combined, move to close
						Else
							If ch$=">" Then
								;gak debuglog "TAG:"+x\tag$
								mode = 20; tag closed, move to collecting value
							Else
								x\tag$ = x\tag$ + ch$
							End If
						End If
					End If
				  Case 4 ; start to collect attributes
					If Lower(ch$)>="a" And Lower(ch$)<="z" Then 
						aname$=ch$;
						mode = 5; move to collect attribute name
					Else
						If ch$=">" Then
							x\value$=""
							mode = 20; tag closed, move to collecting value
						Else
							If ch$="/" Then 
								mode = 2 ; move to collecting end tag
								x\endtag$=ch$
								;gak debuglog "** found end tag"
							End If
						End If
					End If
				  Case 5 ; collect attribute name
					If ch$="=" Then
					  ;gak debuglog "ATT:"+aname$
					  aval$=""
					  mode = 6; move to collect attribute value
					Else
					  aname$=aname$+ch$
					End If
				  Case 6 ; collect attribute value
					If c=34 Then
						mode = 7; move to collect string value
					Else
						If c <= 32 Then 
							;gak debuglog "ATV:"+aname$+"="+aval$
							XMLAddAttr(x,aname$,aval$)
							mode = 4; start collecting a new attribute
						Else
					   		aval$=aval$+ch$
						End If
					End If
				  Case 7 ; collect string value
					If c=34 Then
						;gak debuglog "ATV:"+aname$+"="+aval$
						XMLADDattr(x,aname$,aval$)
						mode = 4; go and collect next attribute
					Else
						aval$=aval$+ch$
					End If
				  Case 20 ; COLLECT THE VALUE PORTION
					If ch$="<" Then 
						;gak debuglog "VAL:"+x\tag$+"="+x\value$
						mode=1; go to tag checking
					Else
						x\value$=x\value$+ch$
					End If
				End Select
				
				If Eof(infile) Then done=True
			
			Wend
		
			Return root
		
		End Function
		
		; write out an XML node (and children)
		Function XMLWriteNode(outfile,node.XMLnode,tab$="")
		;	;gak debuglog "Writing...."+node\tag$+".."
			s$="<"+node\tag$
			a.XMLattr = node\firstattr
			While a<>Null
				s$ = s$+" "+Lower(a\name$)+"="+Chr$(34)+a\value$+Chr$(34)
				a = a\sibattr
			Wend
			
			If node\value$="" And node\childcount = 0 Then
				s$=s$+"/>"
				et$=""
			Else
				s$=s$+">"+node\value$
				et$="</"+node\tag$+">"
			End If
			
			WriteLine outfile,XMLcleanStr$(tab$+s$)
			n.XMLnode = node\firstchild
			While n <> Null
				XMLwriteNode(outfile,n,tab$+"  ")
				n = n\nextnode
			Wend
			
			If et$<> "" Then WriteLine outfile,XMLCleanStr$(tab$+et$)
		
		End Function
		
		; remove non-visible chars from the output stream
		Function XMLCleanStr$(s$)
			a$=""
			For i = 1 To Len(s$)
				If Asc(Mid$(s$,i,1))>=32 Then a$ = a$ +Mid$(s$,i,1)

			Next
			Return a$
		
		End Function
		
		; attribute functions
		; return an attribute of a given name
		Function XMLFindAttr.XMLattr(node.XMLnode,name$)
			ret.XMLattr = Null
			If node <> Null Then 
				a.XMLattr = node\firstattr
				done = False
				While ret=Null And a<>Null 
					If Lower(name$)=Lower(a\name$) Then
						ret = a
					End If
					a = a\sibattr
				Wend
			End If
			Return ret
		End Function
		
		; return an attribute value as a string
		Function XMLAttrValueStr$(node.XMLnode,name$,dflt$="")
			ret$=dflt$
			a.XMLattr = XMLfindattr(node,name$)
			If a <> Null Then ret$=a\value$
			Return ret$
		End Function
		
		; return an attribute value as an integer
		Function XMLAttrValueInt(node.XMLnode,name$,dflt=0)
			ret=dflt
			a.XMLattr = XMLfindattr(node,name$)
			If a <> Null Then ret=a\value
			Return ret
		End Function
		
		; return an attribute value as a float
		Function XMLAttrValueFloat#(node.XMLnode,name$,dflt#=0)
			ret#=dflt#
			a.XMLattr = XMLfindattr(node,name$)
			If a <> Null Then ret#=a\value
			Return ret
		End Function
		
		Function XMLHasChildren(node.XMLnode)
			Return node\firstchild <> Null
		End Function
		
		Function XMLHasAttributes(node.XMLnode)
			Return node\firstattr <> Null
		End Function
		
		Function XMLGetChild.XMLNode(node.XMLNode,index=0)
			child.XMLNode = node\FirstChild
			For i = 0 To index-1
				child.XMLNode = child\nextnode
			Next
			Return child
		End Function
		
		Function XMLGetFirstAttribute.XMLAttr(node.XMLNode)
			Return node\firstattr
		End Function
		
		Function XMLGetNextAttribute.XMLAttr(attr.XMLAttr)
			Return attr\sibattr
		End Function
		
		Function XMLGetParent.XMLNode(node.XMLNode)
			Return node\parent
		End Function
		
		Function PrintXMLNode(i.XMLNode,start$="")
			If i = Null Then Return
			Write start+"<"+i\tag
			a.XMLAttr = XMLGetFirstAttribute(i)
			While a <> Null
				Write " "+a\name+"="+Chr(34)+a\value+Chr(34)
				a = XMLGetNextAttribute(a)
			Wend
			Write ">"
			Print ""
			
			f.XMLNode = XMLGetChild(i,0)
			While f.XMLNode <> Null
				PrintXMLNode(f,start+"    ")
				f = XMLNextNode(f)
			Wend
			Print start+"</"+i\tag+">"
		End Function
	;#End Region
;#End Region

Comments

None.

Code Archives Forum