MaxGUI Upgrade

BlitzMax Forums/BlitzMax GUI Programming/MaxGUI Upgrade

If you received MaxGUI from the free BlitzPlus update deal and would like to see it go places in the future please consider donating to development by purchasing a new MaxGUI key.

Purchase price will go directly towards paying for development hours of the next version and if I sell more than 100 keys in the next month future releases will be public domain.

Done! I don't mind paying extra for MaxGUI (on top of BlitzPlus) as I find it such a brilliant module (without the bugs ;-) ) and it would be even better if the bugs were squished and new features added. Consider me your first re-purchaser! What do I do with my second key as I can't register it on the site?

Also what do you mean by releasing it into public domain? - Isn't the code going to be released with the module anymore?

Will the new version have Grid/Table/Multicolum listboxes?

If so,- I'd be very happy to re-purchase.

Thanks Seb! Keep the key as you may need it for the next version. Going Public Domain would just means maxgui won't be covered by the blitz shared source code license so the modules can move to pub where I'm sure they will be much happier and can be bundled free with blitzmax demo and release etc.

Will buy one now. Do you need proof of purchase?

Wait! I'll buy it and then email you the key.

:)

Amon, thanks!, no need to email me, I see all.

Peter, as soon as dev.win32maxgui is stable it's next on my list!

OK, It's bought.

:)

[edit] I get paid my Disability Allowance on Tuesday so I may be able to buy another one.

I like buying stuff. :)

Amon, I just gotta say... I've never seen such a previously banned user on any forum be such a supporter. You're apparently one of the "worst" and most financially-supportive Blitzers around. A big, cockeyed cheer for you! <g>

Amon, I just gotta say... I've never seen such a previously banned user on any forum be such a supporter. You're apparently one of the "worst" and most financially-supportive Blitzers around. A big, cockeyed cheer for you! <g>


Thanks, Well I do try. ;)

I've also purchased another MaxGUI key. Worth it, I think. Keep up the good work, Simon.

I'll be buying it in the following weeks ;)

Done.

What needs to be done yet for MaxGUI anyway? I have the impression that -apart from minor bugs and perhaps a number of gadgets ppl opt for- it's pretty much done. Most language enhancements need to be done for the core BMax itself (method pointers, priv/pub type members, etc.)

Back when it was released, I was able to download it for free, since I already had blitzplus, but I choose to pay for it anyways, so I was actually ahead of the times for once :) Looking forward to see additions and improvements for the maxgui.


> Will the new version have Grid/Table/Multicolum listboxes?
> If so,- I'd be very happy to re-purchase.

Peter, as soon as dev.win32maxgui is stable it's next on my list!


Alright then, I've purchased another MaxGUI key :)
[EDIT]: purchased *a* key. The first one I got for free because I had bought Blitz+

What will help the dev team more:
Buying 3 extra copies of maxgui or 1 extra copy of bmx?
Are the fees paid to shareit the same in both options?

I got blitzplus anyways on an alt account but I bought the max gui module because it works and its cool.

I think its a good idea to move it in with the main blitz distribution, but a shame sales are so few that you have to ask.

Well, most buyers BRL attracts hope to be able to make games with Blitz. GUI stuff is naturally less popular for these people. The business coders usually choose some other language or some other flavor of BASIC.

Armstrong Communications (aka acid software aka skidracer) have no shame, I like MaxGUI and I think some new features are long overdue. Also, as stated elsewhere, MaxGUI was given to me when I finished being an employee of BRL end of last year and the MaxGUI shareit link on this site goes to my own listing.

I am still part of the blitz dev team but MaxGUI is now an independent module and will likely be moving out of the brl module path in future. As I said above I would ideally like to move it into pub and give registered users access to private development versions but we shall see.

I suggest we let puki buy 1000 keys .. :P

^^^ Before or after he robbed a bank? ;)

Im not Paying for it twice????? madness?????? who in the world pays for software more than once?

Im not Paying for it twice????? madness?????? who in the world pays for software more than once?

Reread. No one asked anyone to pay twice. People who got it for nothing are being asked to consider paying ONCE.

@Skidracer
Just a few questions:
there will be a 'new' MaxGUI module (rewritten from zero) or it will be an evolution? Will it be multiplatform again (I hope!)?

I have not understand correctly what do you mean with

...but MaxGUI is now an independent module and will likely be moving out of the brl module path in future. As I said above I would ideally like to move it into pub and give registered users access to private development versions but we shall see.


Moving out of the BRL module path in future...Does it mean that sync from the IDE could be (in future) disabled? In this case what be the new way?
I prefer to keep 'all in one house' all the products (Bmax+modules) than going in different web site...(yes I'm lazy: I like click on Sync to see what's new...)

just to know...I'm very happy with the MaxGUI module - even with some limits it has (the only thing I would like is a GridGadget and multi-colons for all the platforms...).
Byez

The MaxGUI module itself is mostly a device driver framework for the native modules. The windows module win32maxgui.mod has been rewritten from scratch, that update will hopefully be ready soon.

MacOS and FLTK drivers have been pretty stable so after the next update I am really looking forward to finally extending the original BlitzPlus functionality and removing some of the limits users are facing.

MaxGUI 1.15 looks like it is up on syncmods, hopefully includes a fix for win32 menuitems not appearing as event source and a new SetDataSource method for gadgets. Currently in development it lets you do the following sort of thing, with items being fetched from string arrays or object lists (which are converted from result of enumerating ToString() on each member).

Currently only works with container gadgets but I'd like to extend it to work for menu and node trees. I have an idea for a matching SetStyleSource interface but will do some more testing on that one.

The implementation should be able to maintain coherency quite efficiently between the itemlist and your datasource so small modifications anywhere on a large data set should sync quickly. Unfortunately you do need to call SetDataSource again after modifying your list or array but this should be a relatively snappy operation if the data has not changed significantly:

Strict 

Local window:TGadget
Local listbox:TGadget

window=CreateWindow("My Window",30,20,200,400)
listbox=CreateListBox(0,0,ClientWidth(window),ClientHeight(window),window)
SetGadgetLayout listbox,1,1,1,1

listbox.SetDataSource AudioDrivers()

While WaitEvent()
	Print CurrentEvent.ToString()
	Select EventID()
			
		Case EVENT_GADGETSELECT
			Local i=EventData()		'what got selected?
			If i=-1 Exit			'test for deselection			
			Local src$[]			'a string array to test eventextra
			src=String [] EventExtra()	'cast datasource to string array
			Notify "Select:"+src[i]	'combine datasource and index

		Case EVENT_WINDOWCLOSE
			End
		
	End Select
Wend


Hey this is nice! A Faster way to populate and retrieve information!!! Nice Nice Nice.
thanks

Edit:
I was playing with the new 'things' like SyncDataSource() & KeysFromList$ and I'm attempting to run this code
Strict 

Local window:TGadget
Local listbox:TGadget

window=CreateWindow("My Window",30,20,200,400)
listbox=CreateListBox(0,0,ClientWidth(window),ClientHeight(window),window)
SetGadgetLayout listbox,1,1,1,1

Type oggetto
		Field valore:String
End Type

Global my_list:tlist = New tlist

For Local i = 1 To 100
Local	og:oggetto = New oggetto
	og.valore = String(i)
	my_list.addlast og
Next

listbox.SetDataSource my_list


While WaitEvent()
	Print CurrentEvent.ToString()
	Select EventID()
			
		Case EVENT_GADGETSELECT
			Local i=EventData()		'what got selected?
			If i=-1 Exit			'test for deselection			
			Local src$[]			'a string array to test eventextra
			src=String [] EventExtra()	'cast datasource to string array
			Notify "Select:"+src[i]	'combine datasource and index

		Case EVENT_WINDOWCLOSE
			End

	End Select
Wend

The gadgetlist report something different - address?
I read the source but I can't imagine how you can to add from my_list the field 'valore' to the gadgetlist...

SetDataSource looks promising.

What kind of Datasource will the upcomming Grid control require, - a list of lists of objects?

Skid, how about a listbox.RefreshDataSource command, so that I don't need to explicitly pass the data source in again after it has been refreshed? It might make things cleaner in terms of having a quick refresh / full refresh (re-issue a SetDS) of the list, but more importantly, means that you don't have to remember what the data source was each time...(and potentially get it wrong, or change the var in multiple places if it does change)

Im not Paying for it twice????? madness?????? who in the world pays for software more than once?


Who pays more than once? Probably someone who wants to keep the MaxGUI alive and kicking, or someone who just wants to help indie language developer...

I had BlitzPlus, so I could've opted not to pay for MaxGUI but I've purchased it as soon as it was available and in order to help the development I'll make another order as soon as I get my next paycheck.

If one of the customers over at Emergence Basic forum paid for the addition of OOP to the language and then said it's available to everyone for free, purchasing another MaxGUI module is the least we can do to help here...

Barney

some nice additions there skid =) nice work!


for degac:
The gadgetlist report something different - address?
I read the source but I can't imagine how you can to add from my_list the field 'valore' to the gadgetlist...

Ad this to your type and itl work:
	Method ToString:String()
		Return valore
	EndMethod


Thanks grable!
My stupidity is growing hour by hour...I did't remember the overloading system...

Purchase price will go directly towards paying for development hours of the next version and if I sell more than 100 keys in the next month future releases will be public domain.


So how did this go? I know I purchased a new MaxGUI key, did anybody else?

i did

Hi all, I have just finished a big non related project and will try and announce MaxGUI road-plan next week.

I have been tinkering with the outstanding problems remaining with axe.win32maxgui use in MaxIDE including some filterkey problems with locked textareas and of course the incomplete htmlview implementation.

Thanks to everyone that has purchased keys recently, the user base continues to grow and I think MaxGUI has a pretty good looking future.

Simon,

will you then also work on any platform-specific problems? (e.g., the Linux implementations has several flaws)

Thats cool to hear it looks brighter for MaxGUI skidracer! I bought it when it first came out and have been using it since. (off and on of course, as time permits)

I agree the Linux implementation is off from Mac and Windows implementations. I'll take whatever skid fixes tho :)

I bought MaxGUI back at the release date, haven't used it but I'm going to buy another one (as some kind of "update fee") as soon as there's a reasonable good and flexible gridcontrol available.
A grid with different kinds of cells (numbers, text, checkmarks, dropdowns, images, user defined) would really expand the usability of MaxGUI.
Looking forward to see the roadmap.

as there's a reasonable good and flexible gridcontrol available.

It's the certainly the one obvious gap in maxgui for me.

Oh, and images on menus, tabs, buttons would be nice too.

I will purchase another license when it has a decent gridcontrol. In my opinion, without a gridcontrol, it's just not good enough for serious application programming.

Grid control would be lovely.

@Skid: Will you release another dev version soon?

pssst



Grid control?

I am about to go purchase a key :)

Skidracer, 1 thing I would like to see for myn (and others support) is a hook into non canvas gadgets paint messages. That way we can implement icons on buttons and various other features ourselves. Just give the raw windows paint message event for gadgets built into blitzmax please please please.

skn3:

is this something you've done yourself, or is this something that's (going to be) implemented in MaxGUI?

You can have a look through this code if you want. I have basically just written a wrapper for the maxgui implimentation plus a german posters code for the stringtable gadget. Id like to rewrite it at some point. Was kind of bolted on.

You'll have to go in and figure it out, but here is an example of how to use it.

Import "../../global/libs/ggui.bmx"

'create an update list. This lets you store all gadgets that need updating
Local updatelist:gupdatelist = New gupdatelist


'### create a window ###
Global window:ggadget = gwindow.create("A window",[10,10,400,300])
'add a window to the update list
updatelist.addgadget(window)
'add update hook to window gadget. this basically tells the gadget to go to a specified function upon updating
window.setupdatehook(MyEvents)


'### create a stringtable ###
'this function uses the gwindow.insiderect() this basically returns a 4 dimensional array of the client area of the gadget
Global stringtable:gstringtable = gstringtable.create(window.insiderect(),window)
'add some columns
stringtable.addcolumn("column1",100)
stringtable.addcolumn("column2",100)
stringtable.addcolumn("column3",100)
'add some rows
stringtable.addrow(["row0 col0","row0 col1","row0 col2"])
stringtable.addrow(["row1 col0","row1 col1","row1 col2"])
stringtable.addrow(["row2 col0","row2 col1","row2 col2"])
'add a stringtable to the update list
updatelist.addgadget(stringtable)
'add update hook to stringtable gadget. this basically tells the gadget to go to a specified function upon updating
stringtable.setupdatehook(MyEvents)


'main loop
Repeat
	'wait for an event
	WaitEvent()

	'check to see if no events belong to items in the update list
	If updatelist.update() = False
		'put all non ggui events here. eg timers and whatnot!
	End If
Forever

Function MyEvents(ngadget:ggadget)
	'see who this event belongs too
	Select ngadget
		Case window
			Select EventID()
				Case EVENT_WINDOWCLOSE
					'window closed so end
					End
			End Select
			
		Case stringtable
			Select EventID()
				Case EVENT_GADGETSELECT
					'selection changed on stringtable
					Notify "stringtable row changed to "+EventData()
			End Select
	End Select
End Function



Obviously not as nice as having it built in but its acceptable!!!



Here are the 3 source files

ggui.bmx
Strict

Import BRL.Win32MaxGUI
Import BRL.EventQueue
Import brl.linkedlist
Import "tdriveinfo.bmx"
Import "multicolumnlistbox.bmx"

Type gupdatelist
	Global list:TList = CreateList()

	Field gadgets:TList = CreateList()
	
	Method New:Int()
		gupdatelist.list.addlast(list)
	End Method
	
	Method addgadget:Int(ngadget:ggadget)
		gadgets.addlast(ngadget)
	End Method
	
	Method removegadget:Int(ngadget:ggadget)
		gadgets.remove(ngadget)
	End Method
	
	Method Update:Int()
		Local temp_gadget:ggadget
		
		For temp_gadget = EachIn gadgets
			If temp_gadget.update() Return True
		Next
	End Method
End Type

Type ggadget Abstract
	Field gadgets:ggadget[]
	Field gadget:tgadget
	Field items:gitem[]
	Field string1:String
	Field string2:String
	Field string3:String
	Field string4:String
	Field int1:Int
	Field int2:Int
	Field int3:Int
	Field int4:Int
	
	Field _hookupdate:Int(ngadget:ggadget)
	
	Method selecteditem:Int()
		Return SelectedGadgetItem(gadget)
	End Method
	
	Method countitems:Int()
		Return CountGadgetItems(gadget)
	End Method
	
	Method removeitem:Int(nitem:Int)
		Return SelectedGadgetItem(gadget)
	End Method
	
	Method selecteditemtext:String()
		Return GadgetItemText(gadget,SelectedGadgetItem(gadget))
	End Method

	Method defaultupdate:Int()
		Return False
	End Method
	
	Method setlayout:Int(nleft:Int,nright:Int,ntop:Int,nbottom:Int)
		Return SetGadgetLayout(gadget,nleft,nright,ntop,nbottom)
	End Method

	Method disabled:Int()
		Return GadgetDisabled(gadget)
	End Method
	
	Method enabled:Int()
		Return GadgetDisabled(gadget) = False
	End Method
	
	Method setint1:Int(nint:Int)
		int1 = nint
	End Method

	Method setint2:Int(nint:Int)
		int2 = nint
	End Method
	
	Method setint3:Int(nint:Int)
		int3 = nint
	End Method
	
	Method setint4:Int(nint:Int)
		int4 = nint
	End Method
	
	Method setstring1:Int(nstring:String)
		string1 = nstring
	End Method
	
	Method setstring2:Int(nstring:String)
		string2 = nstring
	End Method
	
	Method setstring3:Int(nstring:String)
		string3 = nstring
	End Method
	
	Method setstring4:Int(nstring:String)
		string4 = nstring
	End Method

	Method getint1:Int()
		Return int1
	End Method
	
	Method getint2:Int()
		Return int2
	End Method
	
	Method getint3:Int()
		Return int3
	End Method
	
	Method getint4:Int()
		Return int4
	End Method
	
	Method getstring1:String()
		Return string1
	End Method
	
	Method getstring2:String()
		Return string2
	End Method
	
	Method getstring3:String()
		Return string3
	End Method
	
	Method getstring4:String()
		Return string4
	End Method

	Method update:Int()
		'this function should return true if it wants to halt gui updates
		Local temp_return:Int
		If _hookupdate <> Null And hastgadget(tgadget(EventSource()))
			temp_return = _hookupdate(Self)
			If temp_return Return temp_return
		End If
	End Method
	
	Method hastgadget:Int(ngadget:tgadget)
		If gadget = ngadget Return True
	End Method
	
	Method getgadget:tgadget()
		Return gadget
	End Method
	
	Method getclient:tgadget()
		Return gadget
	End Method
	
	Method cleargadgets:Int()
		Local temp_gadget:ggadget
		Local temp_updatelist:gupdatelist
		
		'clear each sub gadget
		For temp_gadget = EachIn gadgets
			'recurse clear
			temp_gadget.cleargadgets()
			
			'remove the gadget
			FreeGadget(temp_gadget.gadget)
			
			'remove existance of gadget
			For temp_updatelist = EachIn gupdatelist.list
				temp_updatelist.removegadget(temp_gadget)
			Next
		Next
		
		'clear teh list of gadgets
		gadgets = Null
	End Method
	
	Method cleartext:Int()
		SetGadgetText(gadget,"")
	End Method
	
	Method clearitems:Int()
		ClearGadgetItems(gadget)
	End Method
	
	Method disableitem:Int(nitem:Int)
		DisableGadgetItem(gadget,nitem)
	End Method
	
	Method enableitem:Int(nitem:Int)
		EnableGadgetItem(gadget,nitem)
	End Method
	
	Method finditem:gitem(ntext:String)
		'call to update from all items
		Local temp_return:gitem
		Local temp_item:gitem
		For temp_item = EachIn items
			temp_return = temp_item.finditem(ntext)
			If temp_return Return temp_return
		Next
	End Method
	
	Method additem:gitem(ntext:String,nicon:Int=-1,nextra:Object=Null,nid:String="")
		'create new item
		Local temp_item:gitem = New gitem
		temp_item.id = nid
		temp_item.text = ntext
		temp_item.extra = nextra
		temp_item.parent = Null
		'save item into array
		Local temp_slot:Int = items.length
		items = items[..temp_slot+1]
		items[temp_slot] = temp_item
		
		AddGadgetItem(gadget,ntext,0,nicon,Null)
		
		Return temp_item
	End Method
	
	Method redraw:Int()
		RedrawGadget(gadget)
	End Method
	
	Method setupdatehook:Int(nhook:Int(ngadget:ggadget))
		_hookupdate = nhook
	End Method
	
	Method show:Int()
		ShowGadget(Gadget)
	End Method
	
	Method hide:Int()
		HideGadget(gadget)
	End Method
	
	Method enable:Int()
		EnableGadget(gadget)
	End Method
	
	Method disable:Int()
		DisableGadget(gadget)
	End Method

	Method insidex:Int()
		Return 0
	End Method
	
	Method insidey:Int()
		Return 0
	End Method
	
	Method gettext:String()
		Return GadgetText(gadget)
	End Method
	
	Method settext:Int(ntext:String)
		SetGadgetText(gadget,ntext)
	End Method
	
	Method addtext:Int(ntext:String)
		SetGadgetText(gadget,GadgetText(gadget)+ntext)
	End Method
	
	Method insidewidth:Int()
		Return ClientWidth(gadget)
	End Method
	
	Method insideheight:Int()
		Return ClientHeight(gadget)
	End Method
	
	Method outsidex:Int()
		Return GadgetX(gadget)
	End Method
	
	Method outsidey:Int()
		Return GadgetY(gadget)
	End Method
	
	Method outsidewidth:Int()
		Return GadgetWidth(gadget)
	End Method
	
	Method outsideheight:Int()
		Return GadgetHeight(gadget)
	End Method
	
	Method insiderect:Int[](noffsetx:Int=0,noffsety:Int=0,noffsetw:Int=0,noffseth:Int=0)
		Return [0+noffsetx,0+noffsety,ClientWidth(gadget)+noffsetw,ClientHeight(gadget)+noffseth]
	End Method
	
	Method outsiderect:Int[](noffsetx:Int=0,noffsety:Int=0,noffsetw:Int=0,noffseth:Int=0)
		Return [GadgetX(gadget)+noffsetx,GadgetY(gadget)+noffsety,GadgetWidth(gadget)+noffsetw,GadgetHeight(gadget)+noffseth]
	End Method
	
	Method topedge:Int()
		Return GadgetY(gadget)
	End Method
	
	Method bottomedge:Int()
		Return GadgetY(gadget) + GadgetHeight(gadget)
	End Method
	
	Method leftedge:Int()
		Return GadgetX(gadget)
	End Method
	
	Method rightedge:Int()
		Return GadgetX(gadget) + GadgetWidth(gadget)
	End Method
	
	Method setposition:Int(nx:Int,ny:Int)
		SetGadgetShape(gadget,nx,ny,GadgetWidth(gadget),GadgetHeight(gadget))
	End Method
	
	Method setsize:Int(nwidth:Int,nheight:Int)
		SetGadgetShape(gadget,GadgetX(gadget),GadgetY(gadget),nwidth,nheight)
	End Method
	
	Method setshape(nx:Int,ny:Int,nwidth:Int,nheight:Int)
		SetGadgetShape(gadget,nx,ny,nwidth,nheight)
	End Method
	
	Method addgadget:Int(ngadget:ggadget)
		Local temp_slot:Int = gadgets.length
		gadgets = gadgets[..temp_slot+1]
		gadgets[temp_slot] = ngadget
		Return temp_slot
	End Method
End Type

Type gwindow Extends ggadget
	Field client:tgadget

	Method hastgadget:Int(ngadget:tgadget)
		If client = ngadget Or gadget = ngadget Return True
	End Method

	Method getclient:tgadget()
		Return client
	End Method

	Function create:gwindow(ntitle:String,nrect:Int[],nparent:ggadget=Null,nstyle:Int=WINDOW_TITLEBAR)
		Local window:gwindow = New gwindow
		Local temp_parent:tgadget = Null
		If nparent <> Null temp_parent = nparent.getclient()
		window.gadget = CreateWindow(ntitle,nrect[0],nrect[1],nrect[2],nrect[3],temp_parent,nstyle)
		window.client = CreatePanel(0,0,ClientWidth(window.gadget),ClientHeight(window.gadget),window.gadget)
		SetGadgetLayout(window.client,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED)
		Return window
	End Function
End Type

Type gtoolwindow Extends ggadget
	Field client:tgadget
	
	Method hastgadget:Int(ngadget:tgadget)
		If client = ngadget Or gadget = ngadget Return True
	End Method
	
	Method getclient:tgadget()
		Return client
	End Method

	Function create:gtoolwindow(ntitle:String,nrect:Int[],nparent:ggadget=Null,nstyle:Int=WINDOW_TITLEBAR | WINDOW_TOOL)
		Local window:gtoolwindow = New gtoolwindow
		Local temp_parent:tgadget = Null
		If nparent <> Null temp_parent = nparent.getclient()
		window.gadget = CreateWindow(ntitle,nrect[0],nrect[1],nrect[2],nrect[3],temp_parent,nstyle)
		window.client = CreatePanel(0,0,ClientWidth(window.gadget),ClientHeight(window.gadget),window.gadget)
		SetGadgetLayout(window.client,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED)
		Return window
	End Function
End Type

Type gtabber Extends ggadget
	Field selected:Int = -1
	Field icons:ticonstrip
	Field tabs:gtab[]

	Method update:Int()
		'this function should return true if it wants to halt gui updates
		Local temp_return:Int
		Local temp_i:Int
		If _hookupdate <> Null 
			temp_return = _hookupdate(Self)
			If temp_return Return temp_return
		End If			
		'scan through all gadgets until a return was matched
		If gadgets.length > 0
			For temp_i = 0 Until gadgets.length
				If gadgets[temp_i].update() Return True
			Next
		End If
		'scan through all tabs until a return was matched
		If tabs.length > 0
			For temp_i = 0 Until tabs.length
				If tabs[temp_i].update() Return True
			Next
		End If	
	End Method

	Method addtab:gtab(ntitle:String,ntip:String="",nicon:Int=-1)
		'create a new tab ggadget
		Local tab:gtab = New gtab
		'setup the tab
		tab.slot = tabs.length
		tab.gadget = CreatePanel(0,0,ClientWidth(gadget),ClientHeight(gadget),gadget)
		SetGadgetLayout(tab.gadget,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED)
		'resize tabs array for this new tab
		tabs = tabs[..tab.slot+1]
		tabs[tab.slot] = tab
		'add tab to tabber
		AddGadgetItem(gadget,ntitle,0,nicon,ntip)
		'hide the tab unless it is only current active tab in tabber
		If tabs.length > 1 
			tab.hide()
		Else
			selected = 0
		End If
		Return tab
	End Method
	
	Method changetab:Int(ntab:Int)
		If ntab > tabs.length Or ntab = selected Return False
		Local temp_i:Int
		tabs[selected].hide()
		tabs[ntab].show()
		selected = ntab
	End Method

	Function create:gtabber(nrect[],nparent:ggadget=Null,nicons:Object=Null)
		Local tabber:gtabber = New gtabber
		Local temp_parent:tgadget = Null
		If nparent <> Null temp_parent = nparent.getclient()
		tabber.gadget = CreateTabber(nrect[0],nrect[1],nrect[2],nrect[3],temp_parent)
		Local iconstrip:ticonstrip = ticonstrip(nicons)
		If iconstrip = Null
			tabber.icons = LoadIconStrip(String(nicons))
		Else
			tabber.icons = ticonstrip(nicons)
		End If
		If tabber.icons SetGadgetIconStrip(tabber.gadget,tabber.icons)
		SetGadgetLayout(tabber.gadget,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED)
		Return tabber
	End Function
End Type

Type glabel Extends ggadget
	Function create:glabel(ntitle:String,nrect[],nparent:ggadget=Null,nalign:Int = LABEL_CENTER)
		Local label:glabel = New glabel
		Local temp_parent:tgadget = Null
		
		'setup parent gadget
		If nparent <> Null temp_parent = nparent.getclient()
		
		'create gadgets
		label.gadget = CreateLabel(ntitle,nrect[0],nrect[1],nrect[2],nrect[3],temp_parent,nalign)
		
		'return label
		Return label
	End Function
End Type

Type ggroup Extends ggadget
	Function create:ggroup(ntitle:String,nrect[],nparent:ggadget=Null)
		Local group:ggroup = New ggroup
		Local temp_parent:tgadget = Null
		
		'setup parent gadget
		If nparent <> Null temp_parent = nparent.getclient()
		
		'create gadgets
		group.gadget = CreatePanel(nrect[0],nrect[1],nrect[2],nrect[3],temp_parent,PANEL_GROUP,ntitle)
		
		'return group
		Return group
	End Function
End Type

Type gtab Extends ggadget
	Field slot:Int
End Type

Type gfilebrowser Extends ggadget
	Field listbox:tgadget
	Field textfield:tgadget
	Field path:String
	Field rootpath:String
	Field icons:ticonstrip
	Field filter:String[]
	
	Method getgadget:tgadget()
		Return listbox
	End Method
	
	Method selectedpath:String()
		Local temp_slot:Int = SelectedGadgetItem(listbox)
		If temp_slot = -1
			Return rootpath+path
		Else
			Return rootpath+path+"/"+GadgetItemText(listbox,temp_slot)
		End If
	End Method
	
	Method hastgadget:Int(ngadget:tgadget)
		If listbox = ngadget Or textfield = ngadget Or gadget = ngadget Return True
	End Method
	
	Method update:Int()
		Local temp_itemtext:String
		Local temp_pos:Int
	
		Select EventSource()
			Case listbox
				Select EventID()
					Case EVENT_GADGETACTION
						'the listbox was double left clicked
						temp_itemtext = GadgetItemText(listbox,EventData())
						If temp_itemtext = ".."
							'go back a folder
							If path.length
								temp_pos = path.findlast("/")
								changepath(path[0..temp_pos])
							End If
						Else
							'go forward a folder
							If path.length
								If FileType(rootpath+path + "/" + temp_itemtext) = FILETYPE_DIR
									changepath(path + "/" + temp_itemtext)
								End If
							Else
								If FileType(rootpath+path + temp_itemtext) = FILETYPE_DIR
									changepath(path + temp_itemtext)
								End If
							End If
						End If
					Case EVENT_GADGETSELECT
						'the list box was single left clicked
				End Select
		End Select
		
		super.update()
	End Method
	
	Method changepath:Int(npath:String)
		If npath.length npath = StripSlash(npath)
		path = npath
		SetGadgetText(textfield,path)
		populatelist()
	End Method
	
	Method populatelist:Int()
		Local temp_dir:String[]
		Local temp_file:String
		Local temp_ext1:String
		Local temp_ext2:String
		Local temp_list:TList
		Local temp_drive:tdriveinfo
		Local temp_ok:Int
		
		'this function will clear teh list and populate it
		ClearGadgetItems(listbox)
		
		'add back
		If path.length AddGadgetItem(listbox,"..",0,3)
		
		'check for path scan or for drive scan
		If rootpath.length = 0 And path.length = 0
			'load drives on the computer
			temp_list = GetAllDrives(-1,False)
			'add drives
			For temp_drive = EachIn temp_list
				AddGadgetItem(listbox,temp_drive.label.replace("",""),0,0)
			Next
		Else
			'load contents for the directory
			temp_dir = LoadDir(rootpath+path,True)
			
			'add folders
			For temp_file = EachIn temp_dir
				If FileType(rootpath+path+"/"+temp_file) = FILETYPE_DIR
					AddGadgetItem(listbox,temp_file,0,1)
				End If
			Next
			
			'add files
			For temp_file = EachIn temp_dir
				If FileType(rootpath+path+"/"+temp_file) = FILETYPE_FILE
					temp_ok = False
					If filter = Null
						temp_ok = True
					Else
						temp_ext1 = ExtractExt(temp_file).tolower()
						For temp_ext2 = EachIn filter
							If temp_ext1 = temp_ext2
								temp_ok = True
								Exit
							End If
						Next
					End If
					If temp_ok AddGadgetItem(listbox,temp_file,0,2)
				End If
			Next
		End If
	End Method
	
	Function create:gfilebrowser(nrect[],nparent:ggadget=Null,nicons:Object=Null,nrootpath:String="",npath:String="",nfilter:String[]=Null)
		Local temp_filebrowser:gfilebrowser= New gfilebrowser
		Local temp_parent:tgadget = Null
		If nparent <> Null temp_parent = nparent.getclient()

		'create main bounding / clipping box
		temp_filebrowser.gadget = CreatePanel(nrect[0],nrect[1],nrect[2],nrect[3],temp_parent)
		temp_filebrowser.textfield = CreateTextField(0,0,ClientWidth(temp_filebrowser.gadget),20,temp_filebrowser.gadget)
		temp_filebrowser.listbox = CreateListBox(0,20,ClientWidth(temp_filebrowser.gadget),ClientHeight(temp_filebrowser.gadget)-20,temp_filebrowser.gadget)
		DisableGadget(temp_filebrowser.textfield)
		SetGadgetLayout(temp_filebrowser.textfield,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_CENTERED)
		SetGadgetLayout(temp_filebrowser.listbox,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED)
				
		'setup icon strip
		Local iconstrip:ticonstrip = ticonstrip(nicons)
		If iconstrip = Null
			temp_filebrowser.icons = LoadIconStrip(String(nicons))
		Else
			temp_filebrowser.icons = ticonstrip(nicons)
		End If
		If temp_filebrowser.icons SetGadgetIconStrip(temp_filebrowser.listbox,temp_filebrowser.icons)
		
		'fix details
		If nrootpath.length nrootpath = RealPath(nrootpath)
		If nfilter
			Local temp_i:Int
			For temp_i = 0 Until nfilter.length
				nfilter[temp_i] = nfilter[temp_i].tolower()
			Next
		End If
		
		'setup browsing details
		temp_filebrowser.filter = nfilter
		temp_filebrowser.rootpath = nrootpath
		temp_filebrowser.changepath(npath)
		
		Return temp_filebrowser
	End Function
End Type


Type gstringtable Extends ggadget
	Field icons:ticonstrip
	
	Field totalcolumns:Int
	Field totalrows:Int
	
	Method findentirerow:Int(ncells:String[],nwild:String="*")
		If ncells.length < totalcolumns Return -1
		'this function will attempt to find a row match
		Local temp_row:Int
		Local temp_column:Int
		Local temp_debugcell:String
		Local temp_debugarray:String
		
		For temp_row = 0 Until totalrows
			For temp_column = 0 Until totalcolumns
				If ncells[temp_column] = nwild Or ncells[temp_column] = GetListBoxItemText(gadget,temp_row,temp_column+1)
					'check to see if end of row for return
					If temp_column = totalcolumns - 1 Return temp_row
				Else
					'break this row as match not found
					Exit
				End If
			Next
		Next
		
		Return -1
	End Method
	
	Method removeitem:Int(nrow:Int)
		'see if there was a selected row
		Local temp_row:Int = SelectedGadgetItem(gadget)
		
		'update selection before deleting
		If temp_row > -1
			If temp_row = totalrows - 1 And totalrows > 1
				'move selection up
				temp_row :- 1
			End If
		End If
		
		'remove teh row
		RemoveGadgetItem(gadget,nrow)
		SetListBoxColumnWidth(gadget,0,0)
		
		'decrease number of rows
		totalrows :- 1
		
		'move the selection
		If totalrows
			SelectGadgetItem(gadget,temp_row)
		End If
	End Method
	
	Method findrow:Int(nstring:String,ncolumn:Int=-1,ncase:Int=True)
		'this will scan the stringtable for a matching string text
		Local temp_row:Int
		Local temp_column:Int
		
		If ncase = False
			nstring = nstring.tolower()
			
			For temp_row = 0 Until totalrows
				If ncolumn = -1
					'scan all columns
					For temp_column = 1 To totalcolumns
						If GetListBoxItemText(gadget,temp_row,temp_column).tolower() = nstring Return temp_row
					Next
				Else
					'scan speciffic column
					If GetListBoxItemText(gadget,temp_row,ncolumn+1).tolower() = nstring Return temp_row
				End If
			Next
		Else
			For temp_row = 0 Until totalrows
				If ncolumn = -1
					'scan all columns
					For temp_column = 1 To totalcolumns
						If GetListBoxItemText(gadget,temp_row,temp_column) = nstring Return temp_row
					Next
				Else
					'scan speciffic column
					If GetListBoxItemText(gadget,temp_row,ncolumn+1) = nstring Return temp_row
				End If
			Next
		End If
		
		Return -1
	End Method
	
	Method clearitems:Int()
		ClearGadgetItems(gadget)
		totalrows = 0
	End Method
	
	Method countrows:Int()
		Return totalrows
	End Method
	
	Method countcolumns:Int()
		Return totalcolumns
	End Method
	
	Method getcelltext:String(ncolumn:Int,nrow:Int)
		Return GetListBoxItemText(gadget,nrow,ncolumn+1)
	End Method
	
	Method setcelltext:String(ncolumn:Int,nrow:Int,ntext:String)
		Local temp_result:Int = ModifyListBoxItem(gadget,nrow,ncolumn+1,ntext)
		SetListBoxColumnWidth(gadget,0,0)
		Return temp_result
	End Method
	
	Method addcolumn:Int(ntitle:String,nwidth:Int)
		Local temp_slot:Int = totalcolumns+1
		'adds a column to the stringtable
		AddListBoxColumn(gadget,temp_slot,nwidth)
		SetListBoxHeading(gadget,temp_slot,ntitle)
		totalcolumns :+ 1
		SetListBoxColumnWidth(gadget,0,0)
		Return temp_slot - 1
	End Method
	
	Method addrow:Int(ndata:String[])
		Local temp_slot:Int = totalrows
		Local temp_end:Int = ndata.length
		Local temp_column:Int
		
		'make sure not adding row past column total
		If temp_end > totalcolumns temp_end = totalcolumns
		
		'add the row
		AddGadgetItem(gadget,temp_slot)
		totalrows :+ 1
		
		For temp_column = 1 To totalcolumns
			If temp_column <= temp_end
				ModifyListBoxItem(gadget,temp_slot,temp_column,ndata[temp_column-1])
			Else
				'insert blank cell
				ModifyListBoxItem(gadget,temp_slot,temp_column,"")
			End If
		Next
		ModifyListBoxItem(gadget,temp_slot,0,"")
		SetListBoxColumnWidth(gadget,0,0)
		
		'return row number
		Return totalrows - 1
	End Method
	
	Function create:gstringtable(nrect[],nparent:ggadget=Null)
		Local stringtable:gstringtable = New gstringtable
		Local temp_parent:tgadget = Null
		If nparent <> Null temp_parent = nparent.getclient()

		'create the listbox
		stringtable.gadget = CreateListBox(nrect[0],nrect[1],nrect[2],nrect[3],temp_parent)
		
		'bootstrap it with listbox doofa!
		SetListBoxExtendedStyle(stringtable.gadget,LVS_EX_GRIDLINES)
		
		'update first column
		SetListBoxHeading(stringtable.gadget,0,"")
		SetListBoxColumnWidth(stringtable.gadget,0,0)
		stringtable.totalcolumns = 0
		
		Return stringtable
	End Function
End Type

Type glistbox Extends ggadget
	Field icons:ticonstrip
	
	Function create:glistbox(nrect[],nparent:ggadget=Null,nicons:Object=Null)
		Local listbox:glistbox = New glistbox
		Local temp_parent:tgadget = Null
		If nparent <> Null temp_parent = nparent.getclient()

		listbox.gadget = CreateListBox(nrect[0],nrect[1],nrect[2],nrect[3],temp_parent)
		
		'setup icon strip
		Local iconstrip:ticonstrip = ticonstrip(nicons)
		If iconstrip = Null
			listbox.icons = LoadIconStrip(String(nicons))
		Else
			listbox.icons = ticonstrip(nicons)
		End If
		If listbox.icons SetGadgetIconStrip(listbox.gadget,listbox.icons)
		Return listbox
	End Function
End Type

Type gtoolbar Extends ggadget
	Field clip:tgadget
	Field toolbar:tgadget
	
	Method hastgadget:Int(ngadget:tgadget)
		If toolbar = ngadget Or gadget = ngadget Return True
	End Method
	
	Method enableitem:Int(nbutton:Int)
		EnableGadgetItem(toolbar,nbutton)
	End Method
	
	Method disableitem:Int(nbutton:Int)
		DisableGadgetItem(toolbar,nbutton)
	End Method
	
	Method getgadget:tgadget()
		Return toolbar
	End Method
	
	Function create:gtoolbar(nrect[],nparent:ggadget=Null,nicons:String="",ntips:String[]=Null)
		Local toolbar:gtoolbar = New gtoolbar
		Local temp_parent:tgadget = Null
		
		'setup parent gadget
		If nparent <> Null temp_parent = nparent.getclient()
		
		'create gadgets
		toolbar.gadget = CreatePanel(nrect[0],nrect[1],nrect[2],nrect[3],temp_parent)
		toolbar.clip = CreatePanel(0,-2,ClientWidth(toolbar.gadget),ClientHeight(toolbar.gadget)+2,toolbar.gadget)
		toolbar.toolbar = CreateToolBar(nicons,0,0,ClientWidth(toolbar.clip),ClientHeight(toolbar.clip),toolbar.clip)
		
		'set gadget layouts
		SetGadgetLayout(toolbar.clip,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED)
		SetGadgetLayout(toolbar.toolbar,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED,EDGE_ALIGNED)
		
		'set tips
		If ntips SetToolBarTips(toolbar.toolbar,ntips)
		
		'return toolbar
		Return toolbar
	End Function
End Type

Type gtreeview Extends ggadget
	Field icons:ticonstrip
	
	Method clear:Int()
		
	End Method
	
	Method additem:gitem(ntext:String,nicon:Int=-1,nextra:Object=Null,nid:String="")
		'create new item
		Local temp_item:gtreeviewnode = New gtreeviewnode
		temp_item.id = nid
		temp_item.text = ntext
		temp_item.extra = AddTreeViewNode(ntext,TreeViewRoot(gadget),nicon)
		temp_item.parent = Null
		temp_item.slot:Int = items.length
		
		temp_item.icon = nicon
		
		items = items[..temp_item.slot+1]
		items[temp_item.slot] = temp_item
		Return temp_item
	End Method
	
	Function create:gtreeview(nrect[],nparent:ggadget=Null,nicons:Object=Null)
		Local treeview:gtreeview = New gtreeview
		Local temp_parent:tgadget = Null
		
		'setup parent gadget
		If nparent <> Null temp_parent = nparent.getclient()
		
		'create treeview
		treeview.gadget = CreateTreeView(nrect[0],nrect[1],nrect[2],nrect[3],temp_parent)
		
		'setup icon strip
		Local iconstrip:ticonstrip = ticonstrip(nicons)
		If iconstrip = Null
			treeview.icons = LoadIconStrip(String(nicons))
		Else
			treeview.icons = ticonstrip(nicons)
		End If
		If treeview.icons SetGadgetIconStrip(treeview.gadget,treeview.icons)
		
		Return treeview
	End Function
End Type

Type gtextarea Extends ggadget
	Method setbackgroundcolor:Int(nr:Int,ng:Int,nb:Int)
		SetTextAreaColor(gadget,nr,ng,nb,True)
	End Method
	
	Method settextcolor:Int(nr:Int,ng:Int,nb:Int)
		SetTextAreaColor(gadget,nr,ng,nb,False)
	End Method
	
	Method addline:Int(ntext:String,autoscroll:Int=False)
		AddTextAreaText(gadget,ntext+"~n")
	End Method

	Method addtext:Int(ntext:String)
		AddTextAreaText(gadget,ntext)
	End Method
	
	Method cleartext:Int()
		SetTextAreaText(gadget,"")
	End Method
	
	Function create:gtextarea(nrect[],nparent:ggadget=Null,nreadonly:Int=False)
		Local textarea:gtextarea = New gtextarea
		Local temp_parent:tgadget = Null
		If nparent <> Null temp_parent = nparent.getclient()
		If nreadonly = False
			textarea.gadget = CreateTextArea(nrect[0],nrect[1],nrect[2],nrect[3],temp_parent)
		Else
			textarea.gadget = CreateTextArea(nrect[0],nrect[1],nrect[2],nrect[3],temp_parent,TEXTAREA_READONLY)
		End If
		Return textarea
	End Function
End Type

Type gtextfield Extends ggadget
	Function create:gtextfield(nrect[],nparent:ggadget=Null)
		Local textfield:gtextfield = New gtextfield
		Local temp_parent:tgadget = Null
		
		'setup parent gadget
		If nparent <> Null temp_parent = nparent.getclient()
		
		'create treeview
		textfield.gadget = CreateTextField(nrect[0],nrect[1],nrect[2],nrect[3],temp_parent)
		
		Return textfield
	End Function
End Type

Type gbutton Extends ggadget
	Function create:gbutton(ntitle:String,nrect[],nparent:ggadget=Null)
		Local button:gbutton = New gbutton
		Local temp_parent:tgadget = Null
		
		'setup parent gadget
		If nparent <> Null temp_parent = nparent.getclient()
		
		'create treeview
		button.gadget = CreateButton(ntitle,nrect[0],nrect[1],nrect[2],nrect[3],temp_parent,BUTTON_PUSH)
		
		Return button
	End Function
End Type

Type gprogressbar Extends ggadget
	Method setprogress:Int(nprogress:Float)
		UpdateProgBar(gadget,nprogress)
	End Method

	Function create:gprogressbar(nrect[],nparent:ggadget=Null)
		Local progressbar:gprogressbar = New gprogressbar
		Local temp_parent:tgadget = Null
		
		'setup parent gadget
		If nparent <> Null temp_parent = nparent.getclient()
		
		'create treeview
		progressbar.gadget = CreateProgBar(nrect[0],nrect[1],nrect[2],nrect[3],temp_parent,BUTTON_PUSH)
		
		Return progressbar
	End Function
End Type





Type gitem
	Field id:String
	Field slot:Int
	Field text:String
	Field extra:Object
	Field parent:gitem
	Field items:gitem[]
	Field x:Int
	Field y:Int
	Field z:Int
	Field string1:String
	Field string2:String
	Field string3:String
	Field string4:String
	Field int1:Int
	Field int2:Int
	Field int3:Int
	Field int4:Int
	
	Method expand:Int()
	End Method
	
	Method collapse:Int()
	End Method
	
	Method setint1:Int(nint:Int)
		int1 = nint
	End Method

	Method setint2:Int(nint:Int)
		int2 = nint
	End Method
	
	Method setint3:Int(nint:Int)
		int3 = nint
	End Method
	
	Method setint4:Int(nint:Int)
		int4 = nint
	End Method
	
	Method setstring1:Int(nstring:String)
		string1 = nstring
	End Method
	
	Method setstring2:Int(nstring:String)
		string2 = nstring
	End Method
	
	Method setstring3:Int(nstring:String)
		string3 = nstring
	End Method
	
	Method setstring4:Int(nstring:String)
		string4 = nstring
	End Method
	
	Method settext:Int(ntext:String)
		text = ntext
	End Method
	
	Method gettext:String()
		Return text
	End Method
	
	Method setx:Int(nx:Int)
		x = nx
	End Method
	
	Method sety:Int(ny:Int)
		y = ny
	End Method
	
	Method setz:Int(nz:Int)
		z = nz
	End Method
	
	Method setid:Int(nid:String)
		id = nid
	End Method
	
	Method getx:Int()
		Return x
	End Method
	
	Method gety:Int()
		Return y
	End Method
	
	Method getz:Int()
		Return z
	End Method
	
	Method getint1:Int()
		Return int1
	End Method
	
	Method getint2:Int()
		Return int2
	End Method
	
	Method getint3:Int()
		Return int3
	End Method
	
	Method getint4:Int()
		Return int4
	End Method
	
	Method getstring1:String()
		Return string1
	End Method
	
	Method getstring2:String()
		Return string2
	End Method
	
	Method getstring3:String()
		Return string3
	End Method
	
	Method getstring4:String()
		Return string4
	End Method
	
	Method clear:Int()
		'this will clear all items from this node
		items = items[..0]
	End Method
	
	Method remove()
		'remove the item from the parents item list
		If parent <> Null
			Local temp_i:Int
			'shift data across
			For temp_i = slot+1 Until parent.items.length
				parent.items[temp_i-1] = parent.items[temp_i]
				parent.items[temp_i-1].slot = temp_i-1
			Next
			'resize array
			parent.items = parent.items[..parent.items.length-1]
		End If
	End Method
	
	Method finditem:gitem(ntext:String)
		'check for matching item text
		If ntext = text Or ntext = id Return Self
		'call to update from all items of item
		Local temp_return:gitem
		Local temp_item:gitem
		For temp_item = EachIn items
			temp_return = temp_item.finditem(ntext)
			If temp_return Return temp_return
		Next
	End Method
	
	Method additem:gitem(ntext:String,nicon:Int=-1,nextra:Object=Null,nid:String="")
		'create new item
		Local temp_item:gitem = New gitem
		temp_item.id = nid
		temp_item.text = ntext
		temp_item.extra = nextra
		temp_item.parent = Null
		temp_item.slot = items.length

		items = items[..temp_item.slot+1]
		items[temp_item.slot] = temp_item
		Return temp_item
	End Method
End Type

Type gtreeviewnode Extends gitem
	Field icon:Int

	Method expand:Int()
		ExpandTreeViewNode(tgadget(extra))
	End Method
	
	Method collapse:Int()
		CollapseTreeViewNode(tgadget(extra))
	End Method

	Method clear:Int()
		Local temp_i:Int
		'remove all treeview nodes
		For temp_i = 0 Until items.length
			FreeTreeViewNode(tgadget(items[temp_i].extra))
		Next
		'remove all traces of item nodes so grabage will collect
		items = items[..0]
	End Method
	
	Method remove:Int()
		FreeTreeViewNode(tgadget(extra))
		'remove the item from the parents item list
		If parent <> Null
			Local temp_i:Int
			'shift data across
			For temp_i = slot+1 Until parent.items.length
				parent.items[temp_i-1] = parent.items[temp_i]
				parent.items[temp_i-1].slot = temp_i-1
			Next
			'resize array
			parent.items = parent.items[..parent.items.length-1]
		End If
	End Method
	
	Method additem:gitem(ntext:String,nicon:Int=-1,nextra:Object=Null,nid:String="")
		'create new item
		Local temp_item:gtreeviewnode = New gtreeviewnode
		temp_item.id = nid
		temp_item.text = ntext
		temp_item.extra = AddTreeViewNode(ntext,tgadget(extra),nicon)
		temp_item.parent = Self
		temp_item.slot = items.length
		
		temp_item.icon = nicon

		items = items[..temp_item.slot+1]
		items[temp_item.slot] = temp_item
		Return temp_item
	End Method
	
	Method settext:Int(ntext:String)
		Local temp_gadget:tgadget = tgadget(extra)
		text = ntext
		ModifyTreeViewNode(temp_gadget,ntext,icon)
	End Method
	
	Method gettext:String()
		Return GadgetText(tgadget(extra))
	End Method
End Type


tdriveinfo.bmx
Strict

Import brl.linkedlist

Const DRIVE_UNKNOWN:Int = 0     'The drive Type cannot be determined.
Const DRIVE_NO_ROOT_DIR:Int = 1 'The root path is invalid; For example, there is no volume is mounted at the path.
Const DRIVE_REMOVABLE:Int = 2   'The drive has removable media; For example, a floppy drive, thumb drive, Or flash card reader.
Const DRIVE_FIXED:Int = 3       'The drive has fixed media; For example, a hard drive Or flash drive.
Const DRIVE_REMOTE:Int = 4      'The drive is a remote (network) drive.
Const DRIVE_CDROM:Int = 5       'The drive is a CD-ROM drive.
Const DRIVE_RAMDISK:Int = 6     'The drive is a RAM disk.

Extern "win32"
	Function _GetDiskFreeSpaceEx(lpdirectoryname:Byte Ptr,lpfreebytesavailable:Byte Ptr,lptotalnumberofbytes:Byte Ptr,lptotalnumberoffreebytes:Byte Ptr) = "GetDiskFreeSpaceExA@16"
	Function _GetLogicalDriveStrings(nbufferlength:Int,lpbuffer:Byte Ptr) = "GetLogicalDriveStringsA@8"
	Function _GetDriveType(lprootpathname:Byte Ptr) = "GetDriveTypeA@4"
End Extern

Type tdriveinfo
	Const buffersize:Int = 256
	
	Global buffer:Byte[tdriveinfo.buffersize]
	
	Field drivetype:Int
	Field availablebytes:Long
	Field totalbytes:Long
	Field freebytes:Long
	Field label:String
	
	Function _setcstring:Byte Ptr(nstring:String)
		Local temp_i:Int
		'write string
		For temp_i = 0 Until nstring.length
			tdriveinfo.buffer[temp_i] = nstring[temp_i]
		Next
		'write null
		tdriveinfo.buffer[nstring.length] = 0
		
		Return tdriveinfo.buffer
	End Function
	
	Function _getfromstring:String()
		Local temp_i:Int
		Local temp_string:String
		For temp_i = 0 Until tdriveinfo.buffersize
			If temp_i = tdriveinfo.buffersize-1 Or tdriveinfo.buffer[temp_i] = 0
			Else
				temp_string = temp_string + Chr(tdriveinfo.buffer[temp_i])
			End If
		Next
		Return temp_string
	End Function
	
	Function _bytestospacestring:String(nspace:Long)
		If nspace < 1024 '1 k
			Return tdriveinfo._trimfloat(nspace)+" b"
		ElseIf nspace < 1048576 '1 meg
			Return tdriveinfo._trimfloat(nspace / 1024.0)+" k"
		ElseIf nspace < 1073741824 '1 gig
			Return tdriveinfo._trimfloat(nspace / 1048576.0)+" meg"
		Else
			Return tdriveinfo._trimfloat(nspace / 1073741824.0)+" gig"
		End If
	End Function
	
	Function _trimfloat:String(nfloat:Float,nlength:Int = 2)
		Local temp_pos:Int
		Local temp_string:String = String(nFloat)
		temp_pos = temp_string.find(".")
		If temp_pos > -1 Return temp_string[0..temp_pos+1+nlength]
		Return temp_string
	End Function
	
	Method PercentFree:Float()
		Return (100.0 / totalbytes) * (totalbytes - freebytes)
	End Method
	
	Method PercentUsed:Float()
		Return (100.0 / totalbytes) * availablebytes
	End Method
	
	Method CapacityString:String()
		Return tdriveinfo._bytestospacestring(totalbytes)
	End Method
	
	Method AvailableString:String()
		Return tdriveinfo._bytestospacestring(availablebytes)
	End Method
	
	Method UsedString:String()
		Return tdriveinfo._bytestospacestring(totalbytes - freebytes)
	End Method
	
	Method Capacity:Long()
		Return totalbytes
	End Method
	
	Method Available:Long()
		Return availablebytes
	End Method
	
	Method Used:Long()
		Return totalbytes - freebytes
	End Method
End Type

Function GetAllDrives:TList(nfilter:Int=-1,ngetdiskspace:Int=True)
	Local temp_list:TList = CreateList()
	Local temp_drives:String
	Local temp_label:String
	Local temp_i:Int
	Local temp_type:Int
	
	'get list of drives
	_GetLogicalDriveStrings(tdriveinfo.buffersize,tdriveinfo.buffer)
	temp_drives = tdriveinfo._getfromstring()
	'read in list of drives
	For temp_i = 0 Until temp_drives.length Step 3
		temp_label = temp_drives[temp_i..temp_i+3]
		
		'create tdriveinfo type
		temp_type = _GetDriveType(tdriveinfo._setcstring(temp_label))
		If (nfilter = -1 And (temp_type = DRIVE_CDROM Or temp_type = DRIVE_FIXED Or temp_type = DRIVE_RAMDISK Or temp_type = DRIVE_REMOVABLE Or temp_type = DRIVE_REMOTE)) Or temp_type = nfilter
			'get drive space details
			Local temp_disk:tdriveinfo = New tdriveinfo
			'get space details
			If ngetdiskspace _GetDiskFreeSpaceEx(tdriveinfo._setcstring(temp_label),Varptr(temp_disk.availablebytes),Varptr(temp_disk.totalbytes),Varptr(temp_disk.freebytes))
			'set other details
			temp_disk.label = temp_label.tolower()
			temp_disk.drivetype = temp_type
			
			temp_list.addlast(temp_disk)
		End If
	Next
	
	Return temp_list
End Function

Function GetCDDrives:TList()
	Return GetAllDrives(DRIVE_CDROM)
End Function

Function GetHardDrives:TList()
	Return GetAllDrives(DRIVE_FIXED)
End Function

Function GetRamDrives:TList()
	Return GetAllDrives(DRIVE_RAMDISK)
End Function

Function GetRemoveableDrives:TList()
	Return GetAllDrives(DRIVE_REMOVABLE)
End Function

Function GetNetworkDrives:TList()
	Return GetAllDrives(DRIVE_REMOTE)
End Function


multicolumnlistbox.bmx
Import BRL.Win32MaxGUI

Extern "win32"
   Function SendMessage:Int(hWnd:Int,MSG:Int,wParam:Int,lParam:Int) = "SendMessageA@16"
   Function SetWindowLong:Int(hWnd:Int,nIndex:Int,lNewLong:Int) = "SetWindowLongA@12"
   Function GetWindowLong:Int(hWnd:Int,nIndex:Int) = "GetWindowLongA@8"
End Extern

Const LBS_NOTIFY:Int            = $1
Const LBS_SORT:Int              = $2
Const LBS_NOREDRAW:Int          = $4
Const LBS_MULTIPLESEL:Int       = $8
Const LBS_OWNERDRAWFIXED:Int    = $10
Const LBS_OWNERDRAWVARIABLE:Int = $20
Const LBS_HASSTRINGS:Int        = $40
Const LBS_USETABSTOPS:Int       = $70
Const LBS_NOINTEGRALHEIGHT:Int  = $100
Const LBS_MULTICOLUMN:Int       = $200
Const LBS_WANTKEYBOARDINPUT:Int = $400
Const LBS_EXTENDEDSEL:Int       = $800
Const LBS_DISABLENOSCROLL:Int   = $100
Const LBS_NODATA:Int            = $2000
Const LBS_NOSEL:Int             = $4000
Const LBS_STANDARD:Int          = $a00003

Const LVM_FIRST:Int = $1000
Const LVM_GETITEMA:Int          = (LVM_FIRST+5)
Const LVM_SETITEMA:Int          = (LVM_FIRST+6)
Const LVM_INSERTITEMA:Int       = (LVM_FIRST+7)
Const LVM_DELETEITEM:Int        = (LVM_FIRST+8)
Const LVM_DELETEALLITEMS:Int    = (LVM_FIRST+9)
Const LVM_GETCALLBACKMASK:Int   = (LVM_FIRST+10)
Const LVM_SETCALLBACKMASK:Int   = (LVM_FIRST+11)
Const LVM_GETCOLUMNA:Int        = (LVM_FIRST+25)
Const LVM_SETCOLUMNA:Int        = (LVM_FIRST+26)
Const LVM_INSERTCOLUMNA:Int     = (LVM_FIRST+27)
Const LVM_DELETECOLUMN:Int      = (LVM_FIRST+28)
Const LVM_GETCOLUMNWIDTH:Int    = (LVM_FIRST+29)
Const LVM_SETCOLUMNWIDTH:Int    = (LVM_FIRST+30)
Const LVM_GETTEXTCOLOR:Int      = (LVM_FIRST+35)
Const LVM_SETTEXTCOLOR:Int      = (LVM_FIRST+36)
Const LVM_GETTEXTBKCOLOR:Int    = (LVM_FIRST+37)
Const LVM_SETTEXTBKCOLOR:Int    = (LVM_FIRST+38)
Const LVM_SORTITEMS:Int         = (LVM_FIRST+48)
Const LVM_SETLISTBOXEXSTYLE:Int = (LVM_FIRST+54)
Const LVM_GETITEMW:Int          = (LVM_FIRST+75)
Const LVM_SETITEMW:Int          = (LVM_FIRST+76)
Const LVM_INSERTITEMW:Int       = (LVM_FIRST+77)
Const LVM_GETCOLUMNW:Int        = (LVM_FIRST+95)
Const LVM_SETCOLUMNW:Int        = (LVM_FIRST+96)
Const LVM_INSERTCOLUMNW:Int     = (LVM_FIRST+97)

Const LVS_EX_GRIDLINES:Int        = $1
Const LVS_EX_SUBITEMIMAGES:Int    = $2
Const LVS_EX_CHECKBOXES:Int       = $4
Const LVS_EX_TRACKSELECT:Int      = $8
Const LVS_EX_HEADERDRAGDROP:Int   = $10
Const LVS_EX_FULLROWSELECT:Int    = $20
Const LVS_EX_ONECLICKACTIVATE:Int = $40
Const LVS_EX_TWOCLICKACTIVATE:Int = $80
Const LVS_EX_FLATSB:Int           = $100
Const LVS_EX_REGIONAL:Int         = $200
Const LVS_EX_INFOTIP:Int          = $400
Const LVS_EX_UNDERLINEHOT:Int     = $800
Const LVS_EX_UNDERLINECOLD:Int    = $1000
Const LVS_EX_MULTIWORKAREAS:Int   = $2000
Const LVS_EX_LABELTIP:Int         = $4000
Const LVS_EX_BORDERSELECT:Int     = $8000
Const LVS_EX_DOUBLEBUFFER:Int     = $10000
Const LVS_EX_HIDELABELS:Int       = $20000
Const LVS_EX_SINGLEROW:Int        = $40000
Const LVS_EX_SNAPTOGRID:Int       = $80000
Const LVS_EX_SIMPLESELECT:Int     = $100000

Const LVCF_FMT:Int     = $1
Const LVCF_WIDTH:Int   = $2
Const LVCF_TEXT:Int    = $4
Const LVCF_SUBITEM:Int = $8
Const LVCF_IMAGE:Int   = $10
Const LVCF_ORDER:Int   = $20

Const LVIF_TEXT:Int        = $1
Const LVIF_IMAGE:Int       = $2
Const LVIF_PARAM:Int       = $4
Const LVIF_STATE:Int       = $8
Const LVIF_INDENT:Int      = $10
Const LVIF_GROUPID:Int     = $100
Const LVIF_COLUMNS:Int     = $200
Const LVIF_NORECOMPUTE:Int = $800 
Const LVIF_DI_SETITEM:Int  = $1000

Const LVS_ALIGNTOP:Int        = $0
Const LVS_ICON:Int            = $0
Const LVS_REPORT:Int          = $1
Const LVS_SMALLICON:Int       = $2
Const LVS_LIST:Int            = $3
Const LVS_TYPEMASK:Int        = $3
Const LVS_SINGLESEL:Int       = $4
Const LVS_SHOWSELALWAYS:Int   = $8
Const LVS_SORTASCENDING:Int   = $10
Const LVS_SORTDESCENDING:Int  = $20
Const LVS_SHAREIMAGELISTS:Int = $40
Const LVS_NOLABELWRAP:Int     = $80
Const LVS_AUTOARRANGE:Int     = $100
Const LVS_EDITLABELS:Int      = $200
Const LVS_OWNERDRAWFIXED:Int  = $400
Const LVS_ALIGNLEFT:Int       = $800
Const LVS_ALIGNMASK:Int       = $C00
Const LVS_NOSCROLL:Int        = $2000
Const LVS_NOCOLUMNHEADER:Int  = $4000
Const LVS_NOSORTHEADER:Int    = $8000
Const LVS_TYPESTYLEMASK:Int   = $FC00

Const GWL_STYLE:Int = -$10

Type  LVCOLUMN 
   Field mask:Int
   Field fmt:Int
   Field cx:Int
   Field pszText:Byte Ptr
   Field cchTextMax:Int
   Field iSubItem:Int
EndType

Type LVITEM
   Field mask:Int
   Field iItem:Int
   Field iSubItem:Int
   Field iState:Int
   Field stateMask:Int
   Field pszText:Byte Ptr
   Field cchTextMax:Int
   Field iImage:Int
   Field lParam:Byte Ptr
   Field iIndent:Int
   Field iGroupId:Int
   Field cColumns:Int
   Field puColumns:Int
EndType

Function AddListBoxColumn(ListBox:TGadget,ColumnNr:Int,Width:Int)
   Local ListBoxHwnd:Int = QueryGadget(ListBox,QUERY_HWND)
   Local Column:LVColumn = New LVColumn
   Column.mask = LVCF_WIDTH
   Column.cx = Width
   SendMessageA(ListBoxHwnd,LVM_INSERTCOLUMNA,ColumnNr,Int(Byte Ptr Column))
End Function

Function SetListBoxHeading(ListBox:TGadget,ColumnNr:Int,HeadingText:String,Style:Int=0)
   Local ListBoxHwnd:Int = QueryGadget(ListBox,QUERY_HWND)
   Local Column:LVColumn = New LVColumn
   Column.mask = LVCF_TEXT | LVCF_FMT
   Column.fmt = Style
   Column.pszText = HeadingText.ToCString()
   Local ListBoxStyle:Int = GetWindowLongA(ListBoxHwnd,GWL_STYLE)
   If (ListBoxStyle & LVS_NOCOLUMNHEADER ) Then
      ListBoxStyle = ListBoxStyle ~ LVS_NOCOLUMNHEADER
      SetWindowLongA(ListBoxHwnd,GWL_STYLE,ListBoxStyle)
   EndIf
   SendMessageA(ListBoxHwnd,LVM_SETCOLUMNA,ColumnNr,Int(Byte Ptr Column))
End Function

Function SetListBoxColumnWidth(ListBox:TGadget,ColumnNr:Int,Width:Int)
   Local ListBoxHwnd:Int = QueryGadget(ListBox,QUERY_HWND)
   Local Column:LVColumn = New LVColumn
   Column.mask = LVCF_WIDTH
   Column.cx = Width
   SendMessageA(ListBoxHwnd,LVM_SETCOLUMNA,ColumnNr,Int(Byte Ptr Column))
End Function

Function ModifyListBoxItem(ListBox:TGadget,RowNr:Int,ColumnNr:Int,Text:String)
   Local ListBoxHwnd:Int = QueryGadget(ListBox,QUERY_HWND)
   Local Item:LVItem = New LVItem
   Item.mask = LVIF_TEXT
   Item.iSubItem = ColumnNr
   Item.iItem = RowNr
   Item.pszText = Text.ToCString()
   Item.cchTextMax = Text.Length+1
   SendMessageA(ListBoxHwnd,LVM_SETITEMA,0,Int(Byte Ptr Item))
End Function

Function GetListBoxItemText:String(ListBox:TGadget,RowNr:Int,ColumnNr:Int)
   Local ListBoxHwnd:Int = QueryGadget(ListBox,QUERY_HWND)
   Local ReturnText:String
   Local TextBank:TBank = CreateBank(1024)
   Local Item:LVItem = New LVItem
   Item.mask = LVIF_Text
   Item.iSubItem = ColumnNr
   Item.iItem = RowNr
   Item.pszText = BankBuf(TextBank)
   Item.cchTextMax = 255
   SendMessageA(ListBoxHwnd,LVM_GETITEMA,0,Int(Byte Ptr Item))
   If Item.pszText <> Null Then
      ReturnText = ReturnText.FromCString(Item.pszText)
   EndIf
   Return ReturnText
End Function

Function SetListBoxExtendedStyle(ListBox:TGadget,Style:Int)
   Local ListBoxHwnd:Int = QueryGadget(ListBox,QUERY_HWND)
   SendMessageA(ListBoxHwnd,LVM_SETLISTBOXEXSTYLE,Style,Style)
End Function


I have seen this. I still think it should be a native control in MaxGui. My two cents.

+1 official support of grids prefered.

I might buy it later this week :)

Has the road map been posted yet?

Just don't want to miss a thing... :/

Nothing so far, I'm hoping Skid's giving us the silent treatment purposefully and then one day he'll release the module and we'll be like WOW! It seems the Blitz way is to keep us in suspense...

...Waiting patiently...

When your operating system informs you versions.dll is gone and every app fails it's time to take it easy so sorry no work scheduled in next couple of days.

I would personally like to get a couple of updates out before end of June so perhaps we should leave it at that and I won't use the term road map again.


Things I have been thinking about include:

abandoning fltk
adding maxgui interface to Mark's gxlib
finishing keyboard and html probs in axe.win32maxgui
checking out columns in cocoa tables
beef up gadgetitem methodology

I also would like to have SetDataSource work with a window and provide an entire gui using the same abstract string data/view synchronization featured in last release.

If items become nodal instead of just list based the datasource can provide the complete contents of any gui. Likewise items in a list or treeview could contain a bunch of gadgets.


But thats all in the future. If I can finally release the new win32maxgui and add some features to both it and cocoa by end of next month I'll be happy.

Hi Skid,

@ Abandoning FLTK - Good idea! Especially since GTK is a lot better, and more time can be devoted to the other modules that are more popular.

@ Adding MaxGUI Interface, Keyboard and HTML Probs, Columns, GadgetItems - Cool!

Thanks for letting us know... Btw, your O/S sounds like it needs a format ;-).


Seb

abandoning fltk
adding maxgui interface to Mark's gxlib
finishing ... axe.win32maxgui

Cool. Will you adopt gtk as an "official" lib, or leave it as is? (I guess you may be discussing that with Brucey right now).

It would be really good to have a standard "table" gadget. Maybe a gxlib one would be best? I like tables that I can bastardise by drawing gfx on top of in a "proper" way. Which raises an interesting question: will it be possible to mix & match native gui elements and gxlib elements? I'm guessing you'll have to (the window is native), and I'm also guessing that you don't know yet!

Personally, I'd really like to see icon support added to as many gadgets as possible (windows, tabs, menus): not sure if that's part of what you mean by gadgetitem methodology.

Will there be another beta test before the next release?

I don't see why FLTK is so bad? If it were supported 100% then it could replace all three separate implementations...

wxWidgets is another choice. Wouldn't it be easier to convert a library that already supports all platforms?

if you have used maxide in fltk for any amount of time you will be well aware of some basic activation problems still in the fltk glue code

fltk2 was also problem, the effort involved was looking like the same it took for the initial implementation, which if i remember correctly was a pretty straightforward 4 week slog.

and antialiasing only turned up in the linux galaxy 10 years ago so is still not a given standard today

wxWidgets is another choice. Wouldn't it be easier to convert a library that already supports all platforms?


Been discussed. Issue was size, mainly because wxWidgets, even as seperate libraries, tends to go up to about 50mb with debugging info and without it's still pretty damn big. Not to mention it makes heavy use of overloading, so it's not the prettiest thing to consider wrapping. If you wanted to, you could go download wx.NET and use its C wrapper to get a head-start on it though. I considered it, but it's not an easy thing to do no matter how you look at it.

wxBasic also has a 19,700 line C++ file that wraps the whole library for interfacing his object system (wrap.cpp). I don't know if it's the best place to start though, it is very specific to wxBasic.

However the wxBasic interpreter (On Windows 1 exe, no libraries) is 500k after UPX, so I'm going to have to take issue with the "50 MB" size statement.

I think wxWidgets would make an ideal GUI for BMax, but I'll agree it's a monumental task to wrap it.

Problem with wxBasic is its age. The last stable version was released five years ago, and the latest "bleeding edge" hasn't changed since early 2006. Not a whole lot you can do with that, unless you like the idea of going back to 2.4 or earlier.

I'm curious Skid, how many keys did you manage to sell? and do you have plans to make max-gui public domain as stated in the op post? max-gui looks interesting.

Skid, I don't really want to load you with more work as you seem to have your hands full as it is, but I'm wondering if you will also consider fixing the lacking option for a non-resizable window gadget with a minimize button as discussed in the following topic:
http://www.blitzbasic.com/Community/posts.php?topic=63159#705578

There is a tweak for it provided by denzilquixode in this following topic:
http://www.blitzbasic.com/Community/posts.php?topic=54642#609351

It doesn't look like a to big an addition, I may be wrong though, especially since the preferred solution will be to add an additional flag rather than tweaking another. I mean, the ordinary style with a simple non-resizable window gadget with no min or max buttons are almost needed too for a proper flexibility (at least when it comes to the way I like to design my applications).

It would be really great if you could get that out of the way too, thanx! =D

Any news on the dev? *bump*

I'm guessing that development of this module has been delayed because of the release of the Blitz3D SDK - it seems like Skid has played a large role in packaging it and fixing bugs and I think I remember Skid saying he no longer works full time for BRL.

I'm just hoping that he eventually does get a chance to do some improvements to axe.win32maxgui/cocoa bug fixes (1, 2, 3, 4) - but I'm heavily biased as I only use BlitzMax for MaxGUI, and I find myself having to stretch it to my needs as best as I can! I understand though that the majority of Blitzers program games and that's therefore where their priority lies... Still, we sit patiently (well sort of anyway). :-)

I wonder how many more licenses Skid needs to encourage further development? Any comments would be greatly appreciated (as always)...

I want to note that I also use BMax only for MaxGUI. If that module didn't exist, I wouldn't have started using BMax. It's very rare to find an inexpensive, cross platform, compiled BASIC with a GUI package. I wish BRL pushed and enhanced the application development capability more as I see it as a valuable market (at least as much as game development).


Problem with wxBasic is its age. The last stable version was released five years ago, and the latest "bleeding edge" hasn't changed since early 2006. Not a whole lot you can do with that, unless you like the idea of going back to 2.4 or earlier.



Kind of a slow reply, sorry.

I'm not sure if the age thing is really that big of a deal. wxWidgets is very feature complete and has been for awhile. It's at least more complete than MaxGUI, so even if it did mean going back to wx 2.4 I think that'd be an improvement. Then you'd have a base to start working on support for newer versions of the library or just fork the think and do a BMax only version of it.

If I were going to create a GUI for a BASIC compiler, I'm pretty sure it'd be with wxWidgets. But it is a lot of work, no argument there.


I like buying stuff. :)



I love buying stuff too! Its nice isnt it! hehehe

I have bought each Blitz language product at least twice, bought Maplet when it was released, I will probably buy the SDK when I have time to play with it.

BTW: currently, I owe the builders merchant just under £5k, feels good! ;)

Dabz

Heh, here's a thought. Maybe the next Axe.Win32MaxGUI release will appear with the new BlitzMax release the Mark has been mentioning in the Bug Reports forum. I'm almost sure that Skid is taking the infamous Steve Jobs suspense marketing technique at the moment... :-P

I want to note that I also use BMax only for MaxGUI. If that module didn't exist, I wouldn't have started using BMax.


ditto

I really like MaxGUI as well and JSPs logicUI made it even more usefull to me.

With my current toolset its nearly joy to create apps :-) (Blide Plus + Publisher + LogicUI @ BM 1.24 + MaxGUI *bought, not free grade*)

Personally I'm struggling to create my current multi-platform application using MaxGUI (which I bought after looking at other GUI's).

I even wrote my own TTableview to get around the missing Grid control, and found many problems with TProxyGadget along the way.

I'm looking forward to a new release.