Created
September 9, 2017 19:04
-
-
Save SteveGilham/c571a58ac26a44438d6fba4432be6493 to your computer and use it in GitHub Desktop.
A worked example of how to use the `Global.RegisterWidget` facility
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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