Experimenting with GLEE

I have been monitoring the hits on my blog and there seems to be a fair bit of interest in the Microsoft GLEE library. Unfortunately, I have found it to be fairly incomplete for many interesting scenarios. In the process of this mini-investigation I developed a small utility to allow the manual construction of graphs. You can find both the code and the application below. You can also save out your graphs as images (but not, sadly, in a serialized form).

Several parts of the GLEE library throw exceptions when certain values are used, and several other parts are not implemented (the same may be true for MS AGL in some cases (according to the documentation, anyway), however I have not used the purchased software and so this may not be the case in fact). Also, although you can change the colour of both nodes and edges, you cannot do so using the PropertyGrid control (I’m really not sure why not!). As a result, this tool only creates black graphs on a white background. Nevertheless, it does show you some of the properties that you can adjust:

Screenshot

Screenshot

Note: the code in this example is not production quality (in fact not particularly good at all). It was hacked together as I found things I wanted to try and lacks structure and design. Please do not model your own code after it or consider it a good example of functional programming. It is not!

(* References:

Microsoft.GLEE
Microsoft.GLEE.Drawing
Microsoft.GLEE.GraphViewerGDI
System
System.Core
System.Drawing
System.Windows.Forms
*)

open System.Linq
open System.Drawing
open System.Windows.Forms

type GDGraph = Microsoft.Glee.Drawing.Graph
type GView = Microsoft.Glee.GraphViewerGdi.GViewer

let okcancelform (frm:Form) =
let okbtn = new Button()
let cnlbtn = new Button()
let flow = new FlowLayoutPanel()
flow.Size <- new Size(0,0) flow.FlowDirection <- FlowDirection.RightToLeft flow.AutoSize <- true flow.AutoSizeMode <- AutoSizeMode.GrowOnly flow.Dock <- DockStyle.Bottom flow.Controls.Add okbtn flow.Controls.Add cnlbtn okbtn.Text <- @"OK"; cnlbtn.Text <- @"Cancel"; cnlbtn.DialogResult <- DialogResult.Cancel okbtn.DialogResult <- DialogResult.OK frm.AcceptButton <- okbtn frm.CancelButton <- cnlbtn flow.TabStop <- false flow.TabIndex <- 1000 frm.Controls.Add flow let newDialog formTitle = let dlg = new Form() dlg.FormBorderStyle <- FormBorderStyle.FixedDialog dlg.Text <- formTitle dlg let newTextEntryDialog (owner:Form) formTitle message initialValue = let frm = newDialog formTitle frm.Size <- new Size(300,100) okcancelform frm let flow = new FlowLayoutPanel() flow.Dock <- DockStyle.Fill flow.FlowDirection <- FlowDirection.TopDown frm.Controls.Add flow let lbl = new Label() lbl.AutoSize <- true lbl.Text <- message flow.Controls.Add lbl let txtbox = new TextBox() txtbox.Text <- initialValue txtbox.Width <- frm.ClientSize.Width - flow.Margin.Size.Width*2 flow.Controls.Add txtbox txtbox.TabIndex <- 0 frm.ActiveControl <- txtbox let result = frm.ShowDialog(owner) if result <> DialogResult.OK then None else Some (txtbox.Text)

let addNode (gv:GView) (graph:GDGraph) x =
(graph.AddNode x).Attr.Label <- x gv.Graph <- graph let addEdge (gv:GView) (graph:GDGraph) x y lbl = graph.AddEdge(x, y).Attr.Label <- lbl gv.Graph <- graph let addNodeHandler (frm:Form) (gv:GView) = fun _ ->
let graph = gv.Graph
let value = newTextEntryDialog frm “Add a node” “Value of the new node?” “”
match value with
| Some x -> addNode gv graph x
| _ -> ()

let addEdgeHandler (frm:Form) (gv:GView) =
fun _ ->
let graph = gv.Graph
let value1 = newTextEntryDialog frm “Add an edge (source node)” “Source node?” “”
let value2 = newTextEntryDialog frm “Add an edge (target node)” “Target node?” “”
let label = newTextEntryDialog frm “Add an edge (name)” “Edge label?” “”
match (value1,value2, label) with
| Some x, Some y, Some lbl -> addEdge gv graph x y lbl
| _ -> ()

let subGraphName (g:GDGraph) (s:Microsoft.Glee.Drawing.Node) =
g.Label + “.” + s.Id

let updateTitle (frm:Form) (gv:GView) =
frm.Text <- gv.Graph.Label let addSubGraphHandler (frm:Form) (pg:PropertyGrid) (gv:GView) (graph:GDGraph) = fun _ ->
let source = pg.SelectedObject
match source with
| :? Microsoft.Glee.Drawing.Node ->
let sourceVal = source :?> Microsoft.Glee.Drawing.Node
let graphName = subGraphName gv.Graph sourceVal
let existing =
gv.Graph.Subgraphs.Cast()
|> Seq.tryFind (fun (g:GDGraph) -> g.Label = graphName)
match existing with
| Some x -> gv.Graph <- x | _ ->
let newGraph = new GDGraph(graphName)
newGraph.AddNode sourceVal.Id |> ignore
gv.Graph.AddSubgraph newGraph
gv.Graph <- newGraph updateTitle frm gv | _ -> ()

let parentHandler frm (gv:GView) g =
fun _ ->
if (gv.Graph.IsSubgraph) then
gv.Graph <- gv.Graph.Parent updateTitle frm gv let mainForm = let frm = new Form() let gv = new Microsoft.Glee.GraphViewerGdi.GViewer() let pg = new PropertyGrid() let newgraph () = new Microsoft.Glee.Drawing.Graph("Root", "g1") let applyNewGraph () = let g = newgraph () gv.Graph <- g g let graph = ref (applyNewGraph ()) let pnl = new FlowLayoutPanel() let commandButton x (y:System.EventArgs -> unit) =
let btn = new Button()
btn.Text <- x btn.Click.Add y pnl.Controls.Add btn commandButton "Add Node" (addNodeHandler frm gv) commandButton "Add Edge" (addEdgeHandler frm gv) commandButton "Add Sub Graph" (addSubGraphHandler frm pg gv !graph) commandButton "Up" (parentHandler frm gv graph) commandButton "New Graph" (fun _ -> graph := applyNewGraph ())
pg.PropertyValueChanged.Add (fun (e:_) -> gv.Graph <- !graph) frm.Size <- new Size(800,400) pnl.Size <- new Size(0, 60) pnl.Dock <- DockStyle.Top pg.SelectedObject <- gv.Graph gv.MouseClick.Add (fun _ ->
let so = gv.SelectedObject
let tgt = if so <> null then so else (gv.Graph:>obj)
pg.SelectedObject <- tgt) gv.MouseDoubleClick.Add (fun _ ->
let so = gv.SelectedObject
if (so :? Microsoft.Glee.Drawing.Node) then
let (go:GDGraph) = gv.Graph
let sgname = subGraphName go (so:?>Microsoft.Glee.Drawing.Node)
let sgopt =
go.Subgraphs.Cast()
|> Seq.tryFind (fun (g:GDGraph) -> g.Label = sgname)
match sgopt with
| Some sg -> gv.Graph <- sg ; updateTitle frm gv | _ -> ()
else
())
pg.Size <- new Size(400,0) pg.Dock <- DockStyle.Right gv.Dock <- DockStyle.Fill updateTitle frm gv frm.Controls.Add gv frm.Controls.Add pnl frm.Controls.Add pg frm.Show() frm Application.Run mainForm [/sourcecode] Do not forget to read the GLEE licence if you plan on using the code commercially. Related posts are below:

Advertisements

2 thoughts on “Experimenting with GLEE

  1. johny

    I was also working with GLEE library and find that if i want to create a dynamic diagram (i am doing a tool for diagram creation ) and after each node added when i append gleeGraph.CalculateLayout(); at output the graph have a strange design and dimensions, the first time when i call it worked fine , but appending it after goes in troubles. In your example it seems that this problem is solved, could u help me to solve this , i am trying to understand how it works for days but unsuccesfull ((

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s