Skip to content

Instantly share code, notes, and snippets.

@SteveGilham
Created September 9, 2017 19:04
Show Gist options
  • Save SteveGilham/c571a58ac26a44438d6fba4432be6493 to your computer and use it in GitHub Desktop.
Save SteveGilham/c571a58ac26a44438d6fba4432be6493 to your computer and use it in GitHub Desktop.
A worked example of how to use the `Global.RegisterWidget` facility
namespace Tinesware.GtkSharp
open System
open System.Reflection
open System.Resources
open System.Runtime.InteropServices
open Gdk
open Gtk
open Glade
module GladeUtils =
let private (<+>) (ptr:IntPtr) (delta:int) =
// IntPtr(ptr.ToInt32() + delta) // CLR 2 -- GTK# is x86 only so 32-bit pointer arithmetic suffices
ptr.Add(delta) // Later versions have safe pointer arithmetic methods
let GetWidgetProperties (w : WidgetInfo) =
let count = int w.NProperties
let delta = Marshal.SizeOf(w.properties)
let properties = w.GetType().GetField("_properties", BindingFlags.Instance ||| BindingFlags.NonPublic).GetValue(w) :?> IntPtr
seq { for i in 0 .. (count - 1) -> properties <+> (i * delta) }
|> Seq.map (fun ptr -> Property.New(ptr))
|> Seq.toList
let GetChildProperties (c : ChildInfo) =
let count = int c.NProperties
let delta = Marshal.SizeOf(c.properties)
let properties = c.GetType().GetField("_properties", BindingFlags.Instance ||| BindingFlags.NonPublic).GetValue(c) :?> IntPtr
seq { for i in 0 .. (count - 1) -> properties <+> (i * delta) }
|> Seq.map (fun ptr -> Property.New(ptr))
|> Seq.fold (fun (m:Map<String, String>) p -> Map.add p.Name p.Value m) Map.empty
let GetWidgetChildren (w : WidgetInfo) =
let count = int w.NChildren
let delta = Marshal.SizeOf(w.children)
let properties = w.GetType().GetField("_children", BindingFlags.Instance ||| BindingFlags.NonPublic).GetValue(w) :?> IntPtr
seq { for i in 0 .. (count - 1) -> properties <+> (i * delta) }
|> Seq.map (fun ptr -> ChildInfo.New(ptr))
|> Seq.toList
let SnakeToPascal (s:String) =
let bits = s.Split([| '_' |], StringSplitOptions.RemoveEmptyEntries)
|> Seq.map( fun s -> let h = Char.ToUpperInvariant(Seq.head s)
String(h, 1) + s.Substring(1))
|> Seq.toArray
String.Join(String.Empty, bits)
let propertyToResource (r:ResourceManager) p =
let value = r.GetString(p)
if String.IsNullOrEmpty(value) then "Missing resource '" + p + "'" else value
let private SetWidgetProperty (a:Assembly) (r:ResourceManager) (w:Widget) (p:Property) =
let name = p.Name |> SnakeToPascal
let pinfo = w.GetType().GetProperty(name)
match pinfo.PropertyType.Name with
| "Int32" -> pinfo.SetValue(w, Int32.Parse(p.Value), null)
| "UInt32" -> pinfo.SetValue(w, UInt32.Parse(p.Value), null)
| "Boolean" -> pinfo.SetValue(w, Boolean.Parse(p.Value), null)
| "Pixbuf" -> pinfo.SetValue(w, new Pixbuf(a.GetManifestResourceStream(p.Value)), null)
| "String" -> pinfo.SetValue(w, propertyToResource r p.Value, null)
| e when pinfo.PropertyType.BaseType = typeof<Enum> -> pinfo.SetValue(w, Enum.Parse(pinfo.PropertyType, p.Value, true), null)
| _ -> ()
let SetWidgetProperties (a:Assembly) (r:ResourceManager) (w:Widget) (p:list<Property>) =
p |> List.iter (SetWidgetProperty a r w)
let RegisterAssistant executingAssembly resources =
Global.RegisterWidget(
Gtk.Assistant.GType,
new NewFunc(fun xml widget_type info -> let w = new Assistant()
let p = GetWidgetProperties info
SetWidgetProperties executingAssembly resources w p
w :> Widget),
new BuildChildrenFunc(fun xml parent info -> let a = (parent :?> Assistant)
GetWidgetChildren info
|> Seq.iter (fun cinfo -> let child = xml.BuildWidget(cinfo.child)
a.AppendPage(child) |> ignore
let p = GetChildProperties cinfo
p.TryFind "title"
|> Option.map (propertyToResource resources)
|> Option.iter (fun t -> a.SetPageTitle (child, t))
p.TryFind "page_type"
|> Option.map (fun v -> Enum.Parse(typeof<AssistantPageType>, v, true) :?> AssistantPageType)
|> Option.iter (fun t -> a.SetPageType (child, t))
p.TryFind "sidebar_image"
|> Option.map (fun v -> new Pixbuf(executingAssembly.GetManifestResourceStream(v)))
|> Option.iter (fun t -> a.SetPageSideImage (child, t))
a.SetPageComplete (child, false) )),
null)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment