Cross GUI request for comments

BlitzMax Forums/BlitzMax Programming/Cross GUI request for comments

The idea of Cross Gui is that it should look and behave the same in all three OS's

Check out the code sample, it aims to be OO friendly and event driven in a similar way to delphi OnEvent callbacks

What do you think of its easy of use?

I'm thinking of adding an extra parameter to the gui creation functions so you can specify the event callback function there as well...

There are one or two issues that I'm not happy with in regards to callback widget pointers, but I have a few ideas and theres still a fair bit to implement anyhow.

It also happens to side step some Nvidia issues that have made the Linux version of max basically unusable...

Its working on win32 and linux as we speak and I'm just waiting on my Mac Wizard to come back to me, but earlier versions have been working on the mac too! (those intel mac mini duo's do look tempting...)

SuperStrict

Framework Pub.OpenGL
Import brl.timer

Import "CrossGui.bmx"



Global running:Int=True
Global ChoiceStr:String[]=["Apples","Bananas","Cantaloupe","Dragon Fruit"]




Global win:XGgadget=XGgadget.CreateXGWindow(320,350,"Test App")
Global MenuBar:XGgadget=XGgadget.CreateXGMenuBar(0,0,320,20)
Global tab:XGgadget=XGgadget.CreateXGTab(5,20,310,320)

win.setCallback(OnExit)
win.add(MenuBar)
win.add(tab)



Global mg1:XGgadget=XGgadget.CreateXGItemGroup("file")
Global OpenMenuItem:XGgadget=XGgadget.CreateXGItem("Open")
Global ExitMenuItem:XGgadget=XGgadget.CreateXGItem("Exit")
ExitMenuItem.setCallback(OnExit)
OpenMenuItem.setCallback(OnOpenMenu)
mg1.add(OpenMenuItem)
mg1.add(ExitMenuItem)


Global mg2:XGgadget=XGgadget.CreateXGItemGroup("Colour")
Global SelectColourMenu:XGgadget=XGgadget.CreateXGItem("Select")
mg2.add(SelectColourMenu)

SelectColourMenu.setCallback(OnSelectColour)

MenuBar.add(mg1)
MenuBar.add(mg2)


Global but1:XGgadget=XGgadget.CreateXGButton(20, 20, 80, 25,"Hello")
Global but2:XGgadget=XGgadget.CreateXGButton(200, 20, 90, 25,"Exit")
but1.setCallback(OnButton1)
but2.setCallback(OnExit)

Global hslider:XGgadget=XGgadget.CreateXGSlider(140,50,120,24,False,"Horizontal")
hslider.setRange(0.0,99.0)
hslider.setCallback(OnhSlider)

Global vslider:XGgadget=XGgadget.CreateXGSlider(20,20,24,120,True,"Vertical")
vslider.setRange(-1,1)
vslider.setCallback(OnvSlider)

Global Choice:XGgadget=XGgadget.CreateXGChoice(110,20,80,20,"Choose one")

For Local n:Int=0 Until ChoiceStr.length
	choice.addString(ChoiceStr[n])
Next
Choice.setCallback(OnChoice)


Global label1:XGgadget=XGgadget.CreateXGOutput(70,90,160,20)
Global label2:XGgadget=XGgadget.CreateXGOutput(70,90,160,20)
label1.setCallback(OnLabel1)
label1.When(WHEN_CHANGED)
label1.SetValue("This is some text")
label2.SetValue("This is some text")





Global g1:XGgadget=XGgadget.CreateXGGroup(0,20,290,300,"Buttons / input")
Global g2:XGgadget=XGgadget.CreateXGGroup(0,20,290,300,"Sliders and Choice")
Global g3:XGgadget=XGgadget.CreateXGGroup(0,20,290,300,"OpenGL")
Global g4:XGgadget=XGgadget.CreateXGGroup(0,20,290,300,"Options")



Global scroll:XGgadget=XGgadget.CreateXGScrollGroup(0,25,305,300,"Scroller")
Global b:XGgadget[400]

For Local y:Int=0 Until 20
	For Local x:Int=0 Until 20
	
		b[y*20+x]=XGgadget.CreateXGButton(x*80,y*30,70,20,(y*20+x))

		scroll.add(b[y*20+x])
		b[y*20+x].setCallBack(OnManyButtons,y*20+x)
	Next
Next


Global glbox:XGgadget=XGgadget.CreateXGGlBox(20,20,130,130)
Global glbox2:XGgadget=XGgadget.CreateXGGlBox(150,150,130,130)

XG_setGlCallback(DrawCallback)


Global options1:XGgadget=XGgadget.CreateXGGroup(10,30,40,60,"Options 1")

Global o1:XGgadget=XGgadget.CreateXGOptionBox(0,0,20,20,"  o1a")
Global o2:XGgadget=XGgadget.CreateXGOptionBox(0,20,20,20,"  o1b")
Global o3:XGgadget=XGgadget.CreateXGOptionBox(0,40,20,20,"  o1c")

options1.add(o3)
options1.add(o2)
options1.add(o1)


Global options2:XGgadget=XGgadget.CreateXGGroup(60,30,40,60,"Options 2")

Global o4:XGgadget=XGgadget.CreateXGOptionBox(0,0,20,20,"  o1b")
Global o5:XGgadget=XGgadget.CreateXGOptionBox(0,20,20,20,"  o1b")
Global o6:XGgadget=XGgadget.CreateXGOptionBox(0,40,20,20,"  o1b")

options2.add(o4)
options2.add(o5)
options2.add(o6)


o1.setcallback(OnOption,101)
o2.setcallback(OnOption,102)
o3.setcallback(OnOption,103)
o4.setcallback(OnOption,201)
o5.setcallback(OnOption,202)
o6.setcallback(OnOption,203)


Global check1:XGgadget=XGgadget.CreateXGcheckbox(40,100,60,20,"Check 1")
check1.setCallBack(OnOption,301)

Global check2:XGgadget=XGgadget.CreateXGcheckbox(120,100,60,20,"Check 2")
check2.setCallBack(OnOption,302)



g1.add(but1)
g1.add(but2)
g1.add(label2)

Global Edit1:XGgadget=XGgadget.CreateXGInput(60,60,80,25,"Edit me")
edit1.when(WHEN_CHANGED)

edit1.setCallback(OnEdit1)
g1.add(edit1)


g2.add(hslider)
g2.add(vslider)
g2.add(choice)
g2.add(label1)

g3.add(glbox)
g3.add(glbox2)


g4.add(check1)
g4.add(check2)
g4.add(options1)
g4.add(options2)

tab.add(g1)
tab.add(g2)
tab.add(g3)
tab.add(scroll)
tab.add(g4)




win.show()
glbox.show()
glbox2.show()	' needed to create context (do it after win.show!)
'TakeFocus(Choice)


choice.redraw()

'Global tim:TTimer'=CreateTimer(50)
'AddHook EmitEventHook,timerhook,Object tim

While running

	While running 
	
	' because timer event hooks dont work in Linux and fltk::wait(n)
	' behaves differently this is a cross platform way to have
	' continually updating GlBoxes
		Local lms:Int
		lms=MilliSecs()
		Repeat
			XG_WaitGui(0.01)
		Until MilliSecs()>lms+19

		If tab.getValuefloat()=2 Then
			glbox.redraw()
			glbox2.redraw()
		EndIf
	Wend
	
	If XG_ask("Are you sure you wish to exit!") Then
		running=False
	Else
		running=True
	EndIf

Wend 

'StopTimer tim




win=Null
GCCollect()

'Print "all done"
End

'Function timerhook:Object( id:Int,data:Object,context:Object )
'
'	If  context=tim And getTabValue(tab)=2 Then
'		redraw(glbox)
'		redraw(glbox2)
'	EndIf
'	
'	Return data
'
'EndFunction




Function OnLabel1()
	label2.SetValue(label1.getValue())
End Function

Function OnEdit1()
	label1.SetValue(edit1.getValue())
End Function

Function OnButton1()
	edit1.SetValue("Hello")
EndFunction

Function OnExit()
	running=False
EndFunction

Function OnChoice()
	Local v:Int= Int choice.getvaluefloat()
	label1.SetValue("index "+v+" is "+ChoiceStr[v])
	label1.redraw()
EndFunction

Function OnhSlider()
	Local v:Float= hslider.getvaluefloat()
	label1.SetValue(v)
	label1.redraw()
EndFunction

Function OnvSlider()
	Local v:Float= vslider.getvaluefloat()
	label1.SetValue(v)
	label1.redraw()
EndFunction

Function OnOpenMenu()
	label1.SetValue(XG_choosefile("Please select a code file","{*.bmx|*.cpp|*.c|*.cxx}","fltk.bmx"))
EndFunction

Function OnSelectColour()
	Local c:Int=XG_choosecolour("please choose a colour",64,128,255) Shl 8
	label1.setcolour(c)
	label2.SetColour(c)
	label1.redraw()
	label2.redraw()
EndFunction

Function OnManyButtons(d:Byte Ptr,n:Int)

	XG_message "button "+n+" pressed"

End Function

Function OnOption(o:Byte Ptr,i:Int)
	Local m:String
	m= "selected value "+i
	If Int o=Int check1.widgetptr Then m=m+ "  check1 ="+Int check1.getvaluefloat()
	If Int o=Int check2.widgetptr Then m=m+ "  check2 ="+Int check2.getvaluefloat()
	XG_message m
EndFunction



Global lasttime:Float

Function DrawCallback(a:Int)

	If a= Int glbox.WidgetPtr Or a= Int glbox2.WidgetPtr Then
		lasttime:+1
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glPushMatrix();
		glRotatef(Float(lasttime*1.6),0,0,1);
		glRotatef(Float(lasttime*4.2),1,0,0);
		glRotatef(Float(lasttime*2.3),0,1,0);
		glTranslatef(-1.0, 1.2, -2.5);
		glScalef(2,2,2);
		If a=Int glbox.WidgetPtr Then drawcube( GL_POLYGON) Else drawcube( GL_Line_Loop)
		glPopMatrix();

		glDisable(GL_DEPTH_TEST);
  		If a=Int glbox.WidgetPtr Then XG_GLDrawText( -4.5, -4.5,"Cube: flat" ) Else XG_GLDrawText( -4.5, -4.5,"Cube: line" )
  		glEnable(GL_DEPTH_TEST);
	EndIf
EndFunction

Function drawcube(mode:Int)
	glBegin(mode)
	glColor3ub(0,0,255)
	glvertex3f -1,-1,-1;glvertex3f 1,-1,-1;	glvertex3f 1,-1,1;	glvertex3f -1,-1,1
	glEnd()
	
	glBegin(mode)	
	glColor3ub(0,255,255)
	glvertex3f -1,1,-1;	glvertex3f 1,1,-1;	glvertex3f 1,1,1;	glvertex3f -1,1,1
	glEnd()
	
	glBegin(mode)			
	glColor3ub(255,0,255)
	glvertex3f -1,-1,-1;glvertex3f -1,1,-1;	glvertex3f -1,1,1;	glvertex3f -1,-1,1
	glEnd()
	
	glBegin(mode)		
	glColor3ub(255,255,0)
	glvertex3f 1,-1,-1;	glvertex3f 1,1,-1;	glvertex3f 1,1,1;	glvertex3f 1,-1,1
	glEnd()	
	
	glBegin(mode)		
	glColor3ub(0,255,0)
	glvertex3f -1,-1,-1;glvertex3f 1,-1,-1;	glvertex3f 1,1,-1;	glvertex3f -1,1,-1
	glEnd()
	
	glBegin(mode)		
	glColor3ub(255,0,0)
	glvertex3f -1,-1,1;	glvertex3f 1,-1,1;	glvertex3f 1,1,1;	glvertex3f -1,1,1
	glEnd()
EndFunction

here's a simpler version with just a window an single gl widget

SuperStrict

Framework BRL.StandardIO
Import Pub.OpenGL
Import brl.timer

Import "CrossGui.bmx"



Global running:Int=True

Global win:XGgadget=XGgadget.CreateXGWindow(320,320,"Test App")
win.setCallback(ExitCallback)

Global glbox:XGgadget=XGgadget.CreateXGGlBox(10,10,300,300)

XG_setGlCallback(DrawCallback)


win.add(glbox)


win.show()
glbox.show()

While running

	
	' because timer event hooks dont work in Linux and fltk::wait(n)
	' behaves differently this is a cross platform way to have
	' continually updating GlBoxes
	Local lms:Int
	lms=MilliSecs()
	Repeat
		XG_WaitGui(0.01)
	Until MilliSecs()>lms+19

	glbox.redraw()
	


Wend 


Function ExitCallback()
	running=False
EndFunction



Global lasttime:Int=0
Function DrawCallback(a:Int)

		lasttime:+1
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glPushMatrix();
		glRotatef(Float(lasttime*1.6),0,0,1);
		glRotatef(Float(lasttime*4.2),1,0,0);
		glRotatef(Float(lasttime*2.3),0,1,0);
		glTranslatef(-1.0, 1.2, -2.5);
		glScalef(2,2,2);
		drawcube( GL_POLYGON)
		glPopMatrix();

		glDisable(GL_DEPTH_TEST);
  		XG_GLDrawText( -4.5, -4.5,"Cube: flat" )
  		glEnable(GL_DEPTH_TEST);

EndFunction


Function drawcube(mode:Int)
	glBegin(mode)
	glColor3ub(0,0,255)
	glvertex3f -1,-1,-1;glvertex3f 1,-1,-1;	glvertex3f 1,-1,1;	glvertex3f -1,-1,1
	glEnd()
	
	glBegin(mode)	
	glColor3ub(0,255,255)
	glvertex3f -1,1,-1;	glvertex3f 1,1,-1;	glvertex3f 1,1,1;	glvertex3f -1,1,1
	glEnd()
	
	glBegin(mode)			
	glColor3ub(255,0,255)
	glvertex3f -1,-1,-1;glvertex3f -1,1,-1;	glvertex3f -1,1,1;	glvertex3f -1,-1,1
	glEnd()
	
	glBegin(mode)		
	glColor3ub(255,255,0)
	glvertex3f 1,-1,-1;	glvertex3f 1,1,-1;	glvertex3f 1,1,1;	glvertex3f 1,-1,1
	glEnd()	
	
	glBegin(mode)		
	glColor3ub(0,255,0)
	glvertex3f -1,-1,-1;glvertex3f 1,-1,-1;	glvertex3f 1,1,-1;	glvertex3f -1,1,-1
	glEnd()
	
	glBegin(mode)		
	glColor3ub(255,0,0)
	glvertex3f -1,-1,1;	glvertex3f 1,-1,1;	glvertex3f 1,1,1;	glvertex3f -1,1,1
	glEnd()
EndFunction


<rant>and before some of you start whining at how horrible fltk2 looks its skinable, and I cant do everthing at once, mind you I never heard anyone say thunder bird looks horrid and its gui looks very similar to fltk2</rant>

changed when to triggered

edit1.triggered(WHEN_CHANGED)



Would Mac users really want an ugly GUI hovering around their pretty Aqua stuff?

Edit: The point to be made here is that if Mac users saw something like this, they'd think "Oh wow, it's not even like my Mac, it must suck" (mainly because the vast majority of Mac users are vain).

Programs aren't always geared toward end users (non-developers), this can still be useful.

From the look at the drawCallBack for the glBox I have to say that this looks really intresting.
Really how you managed this?

@scott, I've been sussed it is developer geared!

@Haramanai its a 2 stage wrapper theres the C level that binds fltk2 to max, and a thin layer that wraps all the widgets in one common max type

@noel re-*read* the rant tag its there for people like you

I'm not talking about how ugly it is to me, I'm talking about its marketability across all platforms. Nice try at avoiding the issue, but it didn't work.

ROFL - hook, line and sinker - you just cant help yourself

theres no avoiding going on, it will have its own custom skin eventually, just at the moment there are for more important things to implement...

I'm definitely liking how the commands are laid out. Something I can definitely use. Realllly liking the event handling. I like the opengl stuff too. Nice set up! Gimme gimme gimme!

The idea sounds really nice, but I think it would be a waste of potential, if there were no custom styles. So please, include a custom style feature ^^

*you* can make fltk2 look however you like you just need to do a bit of research...

Sweeeet, I'm looking forward to this one chris.