wxMax - The Final Push...

BlitzMax Modules Forums/Brucey's Modules/wxMax - The Final Push...

I'm still curious if you have tried to get Graphviz working in a wxGLCanvas..


How's about this ?
SuperStrict

Framework wx.wxApp
Import wx.wxFrame
Import wx.wxglmax2D
Import wx.wxTimer
Import BaH.Graphviz
Import BaH.GraphvizMax2D
Import wx.wxMouseEvent

SetGraphicsDriver GLMax2DDriver()

New MyApp.run()


Type MyApp Extends wxApp

	Field frame:MyFrame

	Method OnInit:Int()

		' Create the main application windowType MyFrame Extends wxFrame

		frame = MyFrame(New MyFrame.Create(,,"", , , 640, 480))
		
		' Show it and tell the application that it's our main window
		frame.show(True)
		SetTopWindow(frame)

		Return True
	End Method

End Type

Type MyFrame Extends wxFrame

	Field canvas:MyCanvas

	Method OnInit()

		canvas = MyCanvas(New MyCanvas.Create(Self, -1, GRAPHICS_BACKBUFFER|GRAPHICS_DEPTHBUFFER))
	
		ConnectAny(wxEVT_CLOSE, OnClose)
	End Method
	
	Function OnClose(event:wxEvent)
		MyFrame(event.parent).canvas.timer.Stop() ' we really need to stop the timer on Mac...
		event.Skip()
	End Function

End Type


Type MyCanvas Extends wxGLCanvas

	Field timer:wxTimer

	Field renderer:TGVGraphviz
	Field mx:Int
	Field my:Int
	Field mz:Int
	Field oldZ:Int
	Field buttons:Int[] = New Int[3]	

	Method OnInit()
	
		SetBackgroundStyle(wxBG_STYLE_CUSTOM)
	
		timer = New wxTimer.Create(Self)


		EnablePolledInput(Self)

		ConnectAny(wxEVT_TIMER, OnTick)
		ConnectAny(wxEVT_MOUSE_EVENTS, OnMouse)

		timer.Start(17)
	End Method

	Function OnMouse(event:wxEvent)
		Local evt:wxMouseEvent = wxMouseEvent(event)
		Select evt.GetEventType()
			Case wxEVT_MOTION
				Local x:Int, y:Int
				evt.GetPosition(x, y)
				EmitEvent(CreateEvent( EVENT_MOUSEMOVE, event.parent, 0, 0, x, y))
			Case wxEVT_LEFT_DOWN
				EmitEvent(CreateEvent( EVENT_MOUSEDOWN, event.parent, 1))
			Case wxEVT_LEFT_UP
				EmitEvent(CreateEvent( EVENT_MOUSEUP, event.parent, 1))
			Case wxEVT_RIGHT_DOWN
				EmitEvent(CreateEvent( EVENT_MOUSEDOWN, event.parent, 2))
			Case wxEVT_RIGHT_UP
				EmitEvent(CreateEvent( EVENT_MOUSEUP, event.parent, 2))
			Case wxEVT_MIDDLE_DOWN
				EmitEvent(CreateEvent( EVENT_MOUSEDOWN, event.parent, 3))
			Case wxEVT_MIDDLE_UP
				EmitEvent(CreateEvent( EVENT_MOUSEUP, event.parent, 3))
			Case wxEVT_MOUSEWHEEL
				EmitEvent(CreateEvent(EVENT_MOUSEWHEEL, event.Parent, evt.GetWheelRotation()))
		End Select
		event.Skip()
	End Function
	
	Method SetupGraph()
	
		renderer = TGVGraphviz.Create(640, 480, Null)
		
		' we need to create an in-memory graph...
		' something simple:
		'
		'    node2  -->   node1
		'           /
		'    node3 /
		
		Local graph:TGVGraph = TGVGraph.Create()
		
		' create some nodes
		Local node1:TGVNode = graph.addNode("node1")
		Local node2:TGVNode = graph.addNode("node2")
		Local node3:TGVNode = graph.addNode("node3")
		
		' Add a tooltip :-)
		node1.setAttr("tooltip", "Hallo!")
		
		node2.setAttr(ATTR_FONTCOLOR, "red")
		node2.setAttr(ATTR_HTML_LABEL, "<TABLE BORDER=~q0~q CELLBORDER=~q1~q CELLSPACING=~q0~q>" + ..
			"<TR><TD>Left</TD><TD PORT=~qf1~q>Mid dle</TD><TD PORT=~qf2~q>Right</TD></TR></TABLE>")
		node3.setAttr(ATTR_NODE_SHAPE, "diamond")
		
		' join the nodes together
		graph.addEdge(node2, node1)
		graph.addEdge(node3, node1)
		
		' now to construct the graph..
		renderer.buildGraph(graph)

	End Method
	

	Method OnPaint(event:wxPaintEvent)
		Render()
	End Method

	Method Render()

		SetGraphics CanvasGraphics2D( Self )
		
		If Not renderer Then
			SetupGraph()
			renderer.layout("dot")
			renderer.fit(800, 480)
		End If
		

		'SetClsColor(255, 255, 255)
		'SetColor(0, 0, 0)
		
		Cls

		SetColor(255, 255, 255)
		
		mx = MouseX()
		my = MouseY()
		mz = MouseZ()

		' tell graphviz we've moved the mouse
		renderer.mouseMove(mx, my)
		
		For Local i:Int = 1 To 3
			If MouseDown(i)
				If Not buttons[i - 1] Then
					renderer.MouseDown(mx, my, i) ' mouse button press
					buttons[i - 1] = 1
				End If
			Else
				If buttons[i - 1] Then
					buttons[i - 1] = 0
					renderer.mouseUp(mx, my, i) ' mouse button release
				End If
			End If
		Next
		
		If mz <> oldZ Then
			If mz < oldZ Then
				renderer.mouseScroll(mx, my, -1) ' scroll up - zoom in
			Else
				renderer.mouseScroll(mx, my, 1) ' scroll down - zoom out
			End If
			oldZ = mz
		End If
		
		' refresh/redraw the graph
		renderer.refresh()
	
		' draw the current tooltip under the mouse - if there is one!
		renderer.drawTooltip(mx, my + 16)
		
		' get data for selected "node" (for anything else, returns Null)
		Local obj:TGViewObject = renderer.selectedObject(GV_VIEW_NODE)
		
		If obj Then
			SetImageFont(Null)
			SetColor 100, 100, 255
			
			DrawText obj.name, 400, 0
			DrawText obj.skind, 400, 15
			
			For Local i:Int = 0 Until obj.attributes.length
				DrawText obj.attributes[i].name + " : " + obj.attributes[i].value, 400, 60 + i * 15
			Next
		End If

		
		Flip

	End Method

	Function OnTick(event:wxEvent)
		wxWindow(event.parent).Refresh()
	End Function


End Type


Knocked it together in about 10 mins from a couple of other examples. It wants a bit of a tidy up.
Usual mouse controls... left button selects, scrollwheel zooms, hold right down to move the graph around.

Actually, I'm rather happy with the ease of getting it running on wx. I'm about half-way through building a native wxDC renderer for graphviz too, but this is nice for now.

<EDIT> - For anyone that wants to try this, as well as wxMax, you'll need these modules compiled too.

:o)