namespace Bemo
open System
open System.Drawing
open System.Windows.Forms
open Bemo.Win32
[<AllowNullLiteral>]
type INode =
abstract member showSettings : bool
type IntEditor() =
let control =
let control = NumericUpDown()
control.Minimum <- decimal(1)
control.Maximum <- decimal(1000)
control.Margin <- Padding(0)
control
interface IPropEditor with
member x.value
with get() = box(int(control.Value))
and set(newValue) = control.Value <- decimal(unbox<int>(newValue))
member x.control = control :> Control
member x.changed = control.ValueChanged |> Event.map ignore
type TextEditor() =
let control =
let control = TextBox()
control
interface IPropEditor with
member x.value
with get() = box(control.Text)
and set(newValue) = control.Text <- unbox<string>(newValue)
member x.control = control :> Control
member x.changed = control.TextChanged |> Event.map ignore
type BoolEditor() =
let control = CheckBox()
interface IPropEditor with
member x.value
with get() = box(control.Checked)
and set(newValue) = control.Checked <- unbox<bool>(newValue)
member x.control = control :> Control
member x.changed = control.CheckedChanged |> Event.map ignore
type EnumEditor<'e when 'e :> Enum>() as this =
let control = ComboBox()
let mutable cachedValue = null
do this.init()
member this.init() =
for tag in Enum.GetValues(typeof<'e>) do
let tag = tag.cast<'e>()
control.Items.Add(tag.ToString()).ignore
control.SelectedValueChanged.Add <| fun _ ->
cachedValue <- control.SelectedItem
member this.value
with get() =
let value = cachedValue
Enum.Parse(typeof<'e>, string(value)).cast<'e>()
and set(value) =
control.SelectedItem <- value.ToString()
interface IPropEditor with
member x.value
with get() = this.value.cast<obj>()
and set(value) = this.value <- value.cast<'e>()
member x.control = control :> Control
member x.changed = control.SelectedValueChanged |> Event.map ignore
type ColorEditor() as this =
let changedEvent = Event<_>()
let chooserButton =
let btn = Button()
btn.Width <- btn.Height
btn.Click.Add <| fun _ ->
let dlg = System.Windows.Forms.ColorDialog()
dlg.Color <- this.color
dlg.FullOpen <- true
dlg.ShowHelp <- false
if dlg.ShowDialog() = DialogResult.OK then
(this :> IPropEditor).value <- dlg.Color
changedEvent.Trigger()
btn.Padding <- Padding(0)
btn.Margin <- Padding(0)
btn.Dock <- DockStyle.Right
btn
let textBox =
let tb = TextBox()
let maxLen = 6
let save() =
(this :> IPropEditor).value <- this.colorFromTb
changedEvent.Trigger()
tb.Dock <- DockStyle.Fill
tb.CharacterCasing <- CharacterCasing.Upper
tb.Margin <- Padding(0)
tb.KeyPress.Add <| fun e ->
try
if e.KeyChar = (char)Keys.Enter then
e.Handled <- true
save()
elif Char.IsControl(e.KeyChar).not then
if tb.Text.Length + 1 - tb.SelectionLength > maxLen then raise (Exception())
Int32.Parse(e.KeyChar.ToString(), Globalization.NumberStyles.HexNumber).ignore
with ex ->
e.Handled <- true
tb.Validating.Add <| fun e ->
try
if tb.Text.Length > maxLen then raise (Exception())
this.colorFromTb.ignore
with ex ->
e.Cancel <- true
tb.SelectAll()
MessageBox.Show("Invalid color value, must be a six digit hexadecimal number.").ignore
tb.Validated.Add <| fun e -> save()
tb
let panel =
let panel = TableLayoutPanel()
panel.GrowStyle <- TableLayoutPanelGrowStyle.FixedSize
panel.RowCount <- 1
panel.ColumnCount <- 2
panel.RowStyles.Add(RowStyle(SizeType.Absolute, 25.0f)).ignore
panel.ColumnStyles.Add(ColumnStyle(SizeType.Percent, 0.9f)).ignore
panel.ColumnStyles.Add(ColumnStyle(SizeType.Absolute, 25.0f)).ignore
panel.AutoSize <- true
panel.Padding <- Padding(0)
panel.Margin <- Padding(0)
panel.Controls.Add(textBox)
panel.Controls.Add(chooserButton)
panel.SetRow(textBox, 0)
panel.SetColumn(textBox, 0)
panel.SetRow(chooserButton, 0)
panel.SetColumn(chooserButton, 1)
panel
member this.colorFromTb =
let text = textBox.Text
let value = Int32.Parse(text, Globalization.NumberStyles.HexNumber)
Color.FromRGB(value)
member this.color = chooserButton.BackColor
interface IPropEditor with
member x.value
with get() =
let text = textBox.Text
let value = Int32.Parse(text, Globalization.NumberStyles.HexNumber)
box(Color.FromRGB(value))
and set(newColor) =
let color = unbox<Color>(newColor)
chooserButton.BackColor <- color
textBox.Text <- sprintf "%X" (color.ToRGB())
member x.control = panel :> Control
member x.changed = changedEvent.Publish
type HotKeyEditor() =
let control = HotKeyControl()
interface IPropEditor with
member x.value
with get() = box(control.HotKey)
and set(newValue) = control.HotKey <- unbox<int>(newValue)
member x.control = control :> Control
member x.changed = control.HotKeyChanged |> Event.map (fun _ -> ())
type HotKeyModifiersEditor() as this =
let mutable _modifiers = Keys.None
let modifiersChanged = Event<_>()
let textBox = {
new TextBox() with
override x.ProcessCmdKey(msg, keys) =
this.modifiers <- Keys.Modifiers &&& keys
true
}
do
this.modifiers <- Keys.None
member this.modifiers
with get() = _modifiers
and set(newValue) =
textBox.Text <- newValue.ToString()
_modifiers <- newValue
modifiersChanged.Trigger()
interface IPropEditor with
member this.value
with get() = box(this.modifiers)
and set(value) = this.modifiers <- unbox<Keys>(value)
member this.control = textBox :> Control
member this.changed = modifiersChanged.Publish
type HotKeyOnlyEditor() as this =
let mutable _hk = Keys.None
let hkChanged = Event<_>()
let textBox = {
new TextBox() with
override x.ProcessCmdKey(msg, keys) =
this.hk <- Keys.KeyCode &&& keys
true
}
do
this.hk <- Keys.None
member this.hk
with get() = _hk
and set(newValue) =
textBox.Text <- newValue.ToString()
_hk <- newValue
hkChanged.Trigger()
interface IPropEditor with
member this.value
with get() = box(this.hk)
and set(value) = this.hk <- unbox<Keys>(value)
member this.control = textBox :> Control
member this.changed = hkChanged.Publish
module UIHelper =
let label text =
let label = Label()
label.AutoSize <- true
label.Text <- text
label.TextAlign <- ContentAlignment.MiddleLeft
label
let form (fields:List2<_>) =
let panel =
let t = TableLayoutPanel()
t.AutoScroll <- true
t.AutoSize <- true
t.Dock <- DockStyle.Fill
//t.Padding <- Padding(10)
t.RowCount <- fields.length
t.ColumnCount <- 2
t
fields.enumerate.iter <| fun (i,(text, control:Control)) ->
let label = label text
control.Dock <- DockStyle.Fill
label.Margin <- Padding(0,5,0,5)
panel.Controls.Add(label)
panel.Controls.Add(control)
panel.SetRow(label, i)
panel.SetColumn(label, 0)
panel.SetRow(control, i)
panel.SetColumn(control, 1)
panel
let vbox (controls:List2<Control>) =
let t =
let t = TableLayoutPanel()
t.AutoScroll <- true
t.AutoSize <- true
t.RowCount <- controls.length
t.ColumnCount <- 1
t
controls.enumerate.iter <| fun(i,control) ->
t.Controls.Add(control)
t.SetRow(control, i)
t.SetColumn(control, 0)
t.RowStyles.Add(RowStyle()).ignore
t
let hbox (controls:List2<Control>) =
let t =
let t = TableLayoutPanel()
t.AutoScroll <- true
t.AutoSize <- true
t.RowCount <- 1
t.ColumnCount <- controls.length
t
controls.enumerate.iter <| fun(i,control) ->
t.Controls.Add(control)
t.SetRow(control, 0)
t.SetColumn(control, i)
t.ColumnStyles.Add(ColumnStyle()).ignore
t
let okCancelForm control =
let form = Form()
form.Padding <- Padding(12)
let okButton = Button()
okButton.Text <- "OK"
okButton.Click.Add <| fun _ ->
form.DialogResult <- DialogResult.OK
let cancelButton = Button()
cancelButton.Text <- "Cancel"
cancelButton.Click.Add <| fun _ ->
form.DialogResult <- DialogResult.Cancel
let buttonPanel = hbox (List2([okButton.cast<Control>(); cancelButton.cast<Control>()]))
let vboxLayout = vbox (List2([control; buttonPanel.cast<Control>()]))
vboxLayout.RowStyles.Item(0).SizeType <- SizeType.AutoSize
vboxLayout.RowStyles.Item(1).SizeType <- SizeType.Absolute
buttonPanel.Anchor <- AnchorStyles.Bottom ||| AnchorStyles.Right
vboxLayout.Dock <- DockStyle.Fill
form.Controls.Add(vboxLayout)
form