This is an example mimicking RStudio's manipulate package (inspired by Mathematica's no doubt) The manipulate function makes it easy to create "interactive" GUIs. In this case, we can dynamically control parameters of a Winston graph. To add a control is easy. There are just a few: slider, picker, checkbox, button, and entry

using Winston
using Tk
using Compat; import Compat.String


function render(c, p)
    ctx = getgc(c)
    Base.Graphics.set_source_rgb(ctx, 1, 1, 1)
    Base.Graphics.paint(ctx)
    Winston.page_compose(p, Tk.cairo_surface(c))
    reveal(c)
    Tk.update()
end

do a manipulate type thing

context to store dynamic values

module ManipulateContext
using Winston
end


abstract type ManipulateWidget end
get_label(widget::ManipulateWidget) = widget.label

mutable struct SliderWidget <: ManipulateWidget
    nm
    label
    initial
    rng
end
function make_widget(parent, widget::SliderWidget)
    sl = Slider(parent, widget.rng)
    set_value(sl, widget.initial)
    sl
end

slider(nm::AbstractString, label::AbstractString, rng::UnitRange, initial::Integer) = SliderWidget(nm, label, initial, rng)
slider(nm::AbstractString, label::AbstractString, rng::UnitRange) = slider(nm, label, rng, minimum(rng))
slider(nm::AbstractString,  rng::UnitRange) = slider(nm, nm, rng, minimum(rng))

mutable struct PickerWidget <: ManipulateWidget
    nm
    label
    initial
    vals
end

function make_widget(parent, widget::PickerWidget)
    cb = Combobox(parent)
    set_items(cb, widget.vals)
    set_value(cb, widget.initial)
    set_editable(cb, false)
    cb
end


picker(nm::AbstractString, label::AbstractString, vals::Vector{T}, initial) where {T <: AbstractString} = PickerWidget(nm, label, initial, vals)
picker(nm::AbstractString, label::AbstractString, vals::Vector{T}) where {T <: AbstractString} = picker(nm, label, vals, vals[1])
picker(nm::AbstractString, vals::Vector{T}) where {T <: AbstractString} = picker(nm, nm, vals)
picker(nm::AbstractString, label::AbstractString, vals::Dict, initial) = PickerWidget(nm, label, vals, initial)
picker(nm::AbstractString, label::AbstractString, vals::Dict) = PickerWidget(nm, label, vals, [string(k) for (k,v) in vals][1])
picker(nm::AbstractString, vals::Dict) = picker(nm, nm, vals)

mutable struct CheckboxWidget <: ManipulateWidget
    nm
    label
    initial
end
function make_widget(parent, widget::CheckboxWidget)
    w = Checkbutton(parent, widget.label)
    set_value(w, widget.initial)
    w
end
get_label(widget::CheckboxWidget) = nothing

checkbox(nm::AbstractString, label::AbstractString, initial::Bool) = CheckboxWidget(nm, label, initial)
checkbox(nm::AbstractString, label::AbstractString) = checkbox(nm, label, false)


mutable struct ButtonWidget <: ManipulateWidget
    label
    nm
end
make_widget(parent, widget::ButtonWidget) = Button(parent, widget.label)
get_label(widget::ButtonWidget) = nothing
button(label::AbstractString) = ButtonWidget(label, nothing)

Add text widget to gather one-line of text

mutable struct EntryWidget <: ManipulateWidget
    nm
    label
    initial
end
make_widget(parent, widget::EntryWidget) = Entry(parent, widget.initial)
entry(nm::AbstractString, label::AbstractString, initial::AbstractString) = EntryWidget(nm, label, initial)
entry(nm::AbstractString, initial::AbstractString) = EntryWidget(nm, nm, initial)
entry(nm::AbstractString) = EntryWidget(nm, nm, "{}")

Expression returns a plot object. Use names as values

function manipulate(ex::(Union{Symbol,Expr}), controls...)
    widgets = Array(Tk.Widget, 0)

    w = Toplevel("Manipulate", 800, 500)
    pack_stop_propagate(w)
    graph = Canvas(w, 500, 500); pack(graph, side="left")
    control_pane= Frame(w); pack(control_pane, side="left", expand=true, fill="both")


    # create, layout widgets
    for i in controls
        widget = make_widget(control_pane, i)
        push!(widgets, widget)
        formlayout(widget, get_label(i))
    end

    get_values() = [get_value(i) for i in  widgets]
    get_nms() = map(u -> u.nm, controls)
    function get_vals()
        d = Dict()                      # return Dict of values
        vals = get_values(); keys = get_nms()
        for i in 1:length(vals)
            if !isa(keys[i], Nothing)
                d[keys[i]] = vals[i]
            end
        end
        d
    end

    function dict_to_module(d::Dict) ## stuff values into Manipulate Context
        for (k,v) in d
            eval(ManipulateContext, :($(Symbol(k)) = $v))
        end
    end

    function make_graphic(x...)
        d = get_vals()
        dict_to_module(d)
        p = eval(ManipulateContext, ex)
        render(graph, p)
    end
    map(u -> callback_add(u, make_graphic), widgets)
    widgets
end
manipulate (generic function with 1 method)

we need to make an expression. here we need to

  • use semicolon (perhaps)
  • return p, the FramedPlot object to draw
ex = quote
    x = linspace( 0, n * pi, 100 )
    c = cos(x)
    s = sin(x)
    p = FramedPlot()
    setattr(p, "title", title)
    if fillbetween
        add(p, FillBetween(x, c, x, s) )
    end
    add(p, Curve(x, c, "color", color) )
    add(p, Curve(x, s, "color", "blue") )
    file(p, "example1.png")
    p
end

obj = manipulate(ex,
                 slider("n", "[0, n*pi]", 1:10)
                 ,entry("title", "Title", "title")
                 ,checkbox("fillbetween", "Fill between?", true)
                 ,picker("color", "Cos color", ["red", "green", "yellow"])
                 ,button("update")
                 )

This page was generated using Literate.jl.