(* CTM Chapter #10 Examples in Alice ML *)
import structure Gtk from "x-alice:/lib/gtk/Gtk"
import structure Canvas from "x-alice:/lib/gtk/Canvas"
(* syntactic sugar for solutions using promises/futures *)
open Promise
open Future
infix 3 ?=
val op?= = fulfill
val ? = future
(* Functions defined in previous chapters *)
datatype gtkglue = NOGLUE | N | S | W | E | NS | NW | NE | SW | SE | WE | NSW | NWE | SWE | NSWE
datatype gtk = GtkTD of gtk list
| GtkLR of gtk list
| GtkTitle of {text:string}
| GtkLabel of {text:string}
| GtkText of {object:(Gtk.object promise), tdscrollbar:bool, glue:gtkglue}
| GtkButton of {text:string, action:(Gtk.callback_function), glue:gtkglue}
| GtkGlue of gtkglue
fun gtkBuild d =
let
val window = Gtk.Window.new Gtk.WindowType.TOPLEVEL
val destroyEvent = fn _ => OS.Process.exit OS.Process.success
fun gtkPack (box, widget) =
if (widget <> Gtk.NULL)
then Gtk.Box.packStart(box, widget, false, false, 0)
else ()
fun build (GtkTD xs) =
let
val vBox = Gtk.VBox.new(false, 0)
in
map (fn x => let val widget = build x in gtkPack(vBox, widget) end) xs;
vBox
end
| build (GtkLR xs) =
let
val hBox = Gtk.HBox.new(false, 0)
in
map (fn x => let val widget = build x in gtkPack(hBox, widget) end) xs;
hBox
end
| build (GtkTitle {text}) =
let
val _ = Gtk.Window.setTitle(window, text)
in
Gtk.NULL
end
| build (GtkLabel {text}) =
let
val label = Gtk.Label.new text
in
label
end
| build (GtkText {object, tdscrollbar, glue}) =
let
val _ = fulfill(object, Gtk.TextView.new())
in
future object
end
| build (GtkButton {text, action, glue}) =
let
val button = Gtk.Button.newWithLabel text
in
Gtk.signalConnect(button, "clicked", action);
button
end
| build (GtkGlue x) = Gtk.NULL
in
Gtk.signalConnect(window, "destroy-event", destroyEvent);
Gtk.Container.setBorderWidth(window, 4);
Gtk.Container.add(window, build d);
window
end
(* 10.2.2 Using the declarative/procedural approach - Build the GUI *)
fun gtkTextOutput field =
let
val textBuffer = Gtk.TextView.getBuffer(future field)
val textIterStart = Gtk.TextIter.new()
val textIterEnd = Gtk.TextIter.new()
in
Gtk.TextBuffer.getBounds(textBuffer, textIterStart, textIterEnd);
Gtk.TextBuffer.getText(textBuffer, textIterStart, textIterEnd, false)
end
fun getText a =
let
val h = promise()
val t = promise()
val pWindow = promise()
fun a1 _ =
let
in
t ?= gtkTextOutput(h);
Gtk.Widget.destroy(future pWindow)
end
val d = GtkTD[
GtkLR[
GtkLabel {text="Input:"},
GtkText {object=h, tdscrollbar=true, glue=NSWE}],
GtkButton {text="Ok", action=a1, glue=NSWE}
]
val window = gtkBuild(d)
in
fulfill(pWindow, window);
Gtk.Widget.showAll window;
await (future t);
future t
end;
inspect (getText "Type your name:");
(* 10.2.3 Using the declarative/procedural approach - Declarative geometry *)
val d = GtkLR[
GtkLabel {text="left"},
GtkLabel {text="center"},
GtkLabel {text="right"}
]
val w1 = gtkBuild(d);
Gtk.Widget.showAll w1;
val e = GtkTD[
GtkLabel {text="top"},
GtkLabel {text="center"},
GtkLabel {text="down"}
]
val w2 = gtkBuild(e);
Gtk.Widget.showAll w2;
|