diff --git a/src/LabGUI.jl b/src/LabGUI.jl index ffb52ed92a93447c9a037a5eb48a078b4aca87e7..b8f521263cbc22fc485d1b40c2a73d98f16a5ec0 100644 --- a/src/LabGUI.jl +++ b/src/LabGUI.jl @@ -10,26 +10,26 @@ include("svg_helper.jl") # and Base.show is redefined to prevent memory leaks when constructing SVGs const max_nodes = 100000 let count=1 - global newid - node_space=Dict() - function WebIO.newid(prefix) - if count == max_nodes - count = 0 - end - string(prefix, "-", count+=1) - end + global newid + node_space=Dict() + function WebIO.newid(prefix) + if count == max_nodes + count = 0 + end + string(prefix, "-", count+=1) + end end function Base.show(io::IO, m::MIME"text/html", x::Node) - if haskey(x.props, :id) - id = "$(x.props[:id])-parent" - else - id = WebIO.newid("node") - end - x in keys(WebIO.showcbs) && (x = WebIO.showcbs[x](id)) - write(io, """<div id=$id></div> - <script>WebIO.mount('$id', '#$id',""") - WebIO.jsexpr(io, x) - write(io, ")</script>") + if haskey(x.props, :id) + id = "$(x.props[:id])-parent" + else + id = WebIO.newid("node") + end + x in keys(WebIO.showcbs) && (x = WebIO.showcbs[x](id)) + write(io, """<div id=$id></div> + <script>WebIO.mount('$id', '#$id',""") + WebIO.jsexpr(io, x) + write(io, ")</script>") end end diff --git a/src/construct.jl b/src/construct.jl index 2e0315fe88c1ad750c86da9a9f9e75ebeb8ab0d4..aac1e5d34d478a542779d3a31a15eea91fdbeb5f 100644 --- a/src/construct.jl +++ b/src/construct.jl @@ -37,9 +37,9 @@ macro construct(expr) syms = symbols(bindings) widgets = map(make_widget, bindings) - dict = Dict(zip(syms, 1:length(syms))) + dict = Dict(zip(syms, 1:length(syms))) quote - (Widget_Container([$(widgets...)], $(dict)), WebIO.render($(esc(map_block(block, syms))))) + (Widget_Container([$(widgets...)], $(dict)), WebIO.render($(esc(map_block(block, syms))))) end end diff --git a/src/gridmaker.jl b/src/gridmaker.jl index 7a6d24f7e08d75a4222181d21e474f8932a475bd..37adb3034d35506b080ab6c9fb7263ffebe8e24e 100644 --- a/src/gridmaker.jl +++ b/src/gridmaker.jl @@ -1,19 +1,19 @@ export make_row, make_grid, setindex_ function make_row(columns::Integer) - #Returns tuple, needs to be Node(:div, tuple..) before use - style = Dict(:display => "inline-table", - :verticalAlign => "top", - :width => "$(100/columns)%") - #:transform => "scale($(1/columns))") - (Node(:div, style=style, "Lorem Ipsum") for i in 1:columns) + #Returns tuple, needs to be Node(:div, tuple..) before use + style = Dict(:display => "inline-table", + :verticalAlign => "top", + :width => "$(100/columns)%") + #:transform => "scale($(1/columns))") + (Node(:div, style=style, "Lorem Ipsum") for i in 1:columns) end function make_grid(rows::Integer, columns::Integer, width = 800, height = 1000) - style_row = Dict(:height => "$(100/rows)%", :overflow => "auto") - style_grid = Dict(:width => width, :height => height) - Node(:div, style=style_grid, (Node(:div, style=style_row, make_row(columns)...) - for i in 1:rows)...) + style_row = Dict(:height => "$(100/rows)%", :overflow => "auto") + style_grid = Dict(:width => width, :height => height) + Node(:div, style=style_grid, (Node(:div, style=style_row, make_row(columns)...) + for i in 1:rows)...) end #specify this later, should be some sort of typedef of WebIO.Node{WebIO.DOM} @@ -25,26 +25,26 @@ end # We to do this to keep the style (width and formatting of the columns) function Base.getindex(grid::WebIO.Node{WebIO.DOM}, ind::Integer) - grid.children[ind] + grid.children[ind] end function Base.getindex(grid::WebIO.Node{WebIO.DOM}, row::Integer, column::Integer) - grid[row][column][1] + grid[row][column][1] end function setindex_(grid::WebIO.Node{WebIO.DOM}, - new_value, - ind::Integer) - #Make this look nicer - setchild(grid, ind, setchild(grid[ind], 1, Node(:div, new_value))) + new_value, + ind::Integer) + #Make this look nicer + setchild(grid, ind, setchild(grid[ind], 1, Node(:div, new_value))) end function setindex_(grid::WebIO.Node{WebIO.DOM}, - new_value, - row::Integer, - column::Integer) - #Make this look nicer - setchild(grid, row, setindex_(grid[row], new_value, column)) + new_value, + row::Integer, + column::Integer) + #Make this look nicer + setchild(grid, row, setindex_(grid[row], new_value, column)) end diff --git a/src/gui.jl b/src/gui.jl index 123d9d3db9a51581b54043e0e40bec88a73bf99a..684256ca648183e9c884a078eadb860f5842783b 100644 --- a/src/gui.jl +++ b/src/gui.jl @@ -1,121 +1,121 @@ export Widget_Container, GUI, set!, add!, animate mutable struct Widget_Container - #Widgets with symbols - widgets::Array{WebIO.Node{WebIO.DOM},1} - vals::Dict + #Widgets with symbols + widgets::Array{WebIO.Node{WebIO.DOM},1} + vals::Dict end function Widget_Container() - Widget_Container([], Dict()) + Widget_Container([], Dict()) end function getindex_(widget::Widget_Container, s::Symbol) - #returns the index of the widget associated with symbol - widget.vals[s] + #returns the index of the widget associated with symbol + widget.vals[s] end function Base.getindex(widget::Widget_Container, n::Integer) - widget.widgets[n] + widget.widgets[n] end function Base.getindex(widget::Widget_Container, s::Symbol) - #returns the widget associated with symbol - widget.widgets[getindex_(widget, s)] + #returns the widget associated with symbol + widget.widgets[getindex_(widget, s)] end mutable struct GUI - widgets::Widget_Container - dom::WebIO.Node - data::Array{Array} - values::Array - #values contains the values of the widget observables, but isn't automatically updated + widgets::Widget_Container + dom::WebIO.Node + data::Array{Array} + values::Array + #values contains the values of the widget observables, but isn't automatically updated end function GUI(widgets::Widget_Container, dom::WebIO.Node) - GUI(widgets, dom, [[]], []) + GUI(widgets, dom, [[]], []) end function GUI(n::Integer) - GUI(Widget_Container(), Node(:div), [Float64[] for i in 1:n], []) + GUI(Widget_Container(), Node(:div), [Float64[] for i in 1:n], []) end function GUI() - GUI(10) + GUI(10) end function set!(gui::GUI, widgets::Widget_Container) - gui.widgets = widgets - gui.values = [obs(widget).val for widget in gui.widgets.widgets] + gui.widgets = widgets + gui.values = [obs(widget).val for widget in gui.widgets.widgets] end function set!(gui::GUI, dom::WebIO.Node) - gui.dom = dom + gui.dom = dom end function set!(gui::GUI, data::Array) - gui.data = data + gui.data = data end function Base.push!(gui::GUI, value, index::Integer) - Base.push!(gui.data[index], value) + Base.push!(gui.data[index], value) end function Base.push!(gui::GUI, values::Tuple, indices::Tuple) - foreach(zip(values, indices)) do t - Base.push!(gui.data[t[2]], t[1]) - end + foreach(zip(values, indices)) do t + Base.push!(gui.data[t[2]], t[1]) + end end function Base.getindex(gui::GUI, s::Symbol) - obs(gui.widgets[s])[] + obs(gui.widgets[s])[] end function Base.setindex!(gui::GUI, newval, s::Symbol) - obs(gui.widgets[s])[] = newval + obs(gui.widgets[s])[] = newval end function add!(gui::GUI, widgets::Widget_Container) - newdict = copy(widgets.vals) - for key in keys(newdict) - newdict[key] += length(gui.widgets.widgets) - end - gui.widgets.widgets = vcat(gui.widgets.widgets, widgets.widgets) - gui.widgets.vals = merge(gui.widgets.vals, newdict) - gui.values = vcat(gui.values, [obs(w)[] for w in widgets.widgets]) + newdict = copy(widgets.vals) + for key in keys(newdict) + newdict[key] += length(gui.widgets.widgets) + end + gui.widgets.widgets = vcat(gui.widgets.widgets, widgets.widgets) + gui.widgets.vals = merge(gui.widgets.vals, newdict) + gui.values = vcat(gui.values, [obs(w)[] for w in widgets.widgets]) end function heartbeat(f, t, n=0) - if n!=0 - @async for i in 1:n - t0 = time() - f() - tdif = time()-t0 - sleep(max(0, t-tdif)) - end - else - @async while true - t0 = time() - f() - tdif = time()-t0 - sleep(max(0,t-tdif)) - end - - end + if n!=0 + @async for i in 1:n + t0 = time() + f() + tdif = time()-t0 + sleep(max(0, t-tdif)) + end + else + @async while true + t0 = time() + f() + tdif = time()-t0 + sleep(max(0,t-tdif)) + end + + end end function has_changed(gui::GUI, s::Symbol) - if gui[s] == gui.values[getindex_(gui.widgets, s)] - return false - else - gui.values[getindex_(gui.widgets, s)] = gui[s] - return true - end + if gui[s] == gui.values[getindex_(gui.widgets, s)] + return false + else + gui.values[getindex_(gui.widgets, s)] = gui[s] + return true + end end function has_changed(gui::GUI, s::Array{Symbol, 1}) - !all(.!(has_changed.(gui, s))) + !all(.!(has_changed.(gui, s))) end # Usage: animate(gui, t) will periodically update all widgets, that is, call the @@ -128,38 +128,38 @@ end # in the responder. This seems to be due to WebIO. function animate(gui::GUI, t=0.5) - ks = [k for k in keys(gui.widgets.vals)] - f = updater_function(gui, ks) - heartbeat(f, t) + ks = [k for k in keys(gui.widgets.vals)] + f = updater_function(gui, ks) + heartbeat(f, t) end function animate(gui::GUI, s::Union{Symbol, Array}, t=0.5) - f = updater_function(gui, s) - heartbeat(f, t) + f = updater_function(gui, s) + heartbeat(f, t) end function animate(gui::GUI, s::Union{Symbol, Array}, w::Union{Symbol, Array}, t=0.1) - f = updater_function(gui, s, w) - heartbeat(f, t) + f = updater_function(gui, s, w) + heartbeat(f, t) end function update(gui::GUI, s::Symbol, watchsymbol=:0) - # s is the symbol associated with widget we wish to update - # if given a watchsymbol, it will only update the widget associated with s - # if the value of the widget associated with watchsymbol has changed - w = gui.widgets[s] - if watchsymbol==:0||has_changed(gui, watchsymbol) - obs(w).listeners[2](obs(w)[]) - end + # s is the symbol associated with widget we wish to update + # if given a watchsymbol, it will only update the widget associated with s + # if the value of the widget associated with watchsymbol has changed + w = gui.widgets[s] + if watchsymbol==:0||has_changed(gui, watchsymbol) + obs(w).listeners[2](obs(w)[]) + end end function update(gui::GUI, a::Array, watchsymbol=:0) - W = [gui.widgets[s] for s in a] - if watchsymbol==:0||has_changed(gui, watchsymbol) - [obs(w).listeners[2](obs(w)[]) for w in W] - end + W = [gui.widgets[s] for s in a] + if watchsymbol==:0||has_changed(gui, watchsymbol) + [obs(w).listeners[2](obs(w)[]) for w in W] + end end function updater_function(gui::GUI, s::Union{Symbol, Array}, w=:0) - ()->update(gui::GUI, s, w) + ()->update(gui::GUI, s, w) end diff --git a/src/svg_helper.jl b/src/svg_helper.jl index 60522e0ab4233055eb7a2dc71c9956d484a23ed0..53b3001328b830dcaf0b194c6ce1eccd193dbd85 100644 --- a/src/svg_helper.jl +++ b/src/svg_helper.jl @@ -1,7 +1,7 @@ #Provides some routines for easier svg construction, along with some #(hopefully!) sane defaults -export svg_rect, svg_circle, svg_line, svg_polyline, svg_polygon, default_height, default_width, default_posy, default_posx, s_black, s_red, s_green, s_blue, stdstyle, stdattr, svgsvg_symb +export svg_rect, svg_circle, svg_line, svg_polyline, svg_polygon, svg_text, default_height, default_width, default_posy, default_posx, s_black, s_red, s_green, s_blue, stdstyle, stdattr, svgsvg_symb global const default_height = 900 global const default_width = 600 global const default_posy = 0 @@ -13,9 +13,9 @@ global const s_green = (0,255,0) global const s_blue = (0,0,255) global const stdattr = Dict("y" => "$default_posy", - "x" => "$default_posx", - "height" => "$default_height", - "width" => "$default_width") + "x" => "$default_posx", + "height" => "$default_height", + "width" => "$default_width") global const stdstyle = Dict(:fill => "rgb$s_black") @@ -24,43 +24,49 @@ global const svgsvg_symb = instanceof(dom"svg:svg"()) #################### function svg_rect(width, height, x=0, y=0, style = stdstyle) - attr = Dict("x" => "$x", - "y" => "$y", - "width" => "$width", - "height" => "$height") - Node(instanceof(dom"svg:rect"()), style = style, attributes = attr) + attr = Dict("x" => "$x", + "y" => "$y", + "width" => "$width", + "height" => "$height") + Node(instanceof(dom"svg:rect"()), style = style, attributes = attr) end function svg_circle(x, y, r, style=stdstyle) - attr = Dict("cy" => "$y", - "cx" => "$x", - "r" => "$r") - Node(instanceof(dom"svg:circle"()), style = style, attributes = attr) + attr = Dict("cy" => "$y", + "cx" => "$x", + "r" => "$r") + Node(instanceof(dom"svg:circle"()), style = style, attributes = attr) end function svg_line(x1, y1, x2, y2, style=stdstyle) - attr = Dict("x1" => "$x1", - "y1" => "$y1", - "x2" => "$x2", - "y2" => "$y2") - Node(instanceof(dom"svg:line"()), style = style, attributes = attr) + attr = Dict("x1" => "$x1", + "y1" => "$y1", + "x2" => "$x2", + "y2" => "$y2") + Node(instanceof(dom"svg:line"()), style = style, attributes = attr) end function svg_poly(ptsvector, style) - #there must be a better way to do this - pts = join((join((ptsvector[i][1], ptsvector[i][2]), ",") for i in 1:length(ptsvector)), " ") - attr = Dict("points" => pts) - Node(instanceof(dom"svg:polyline"()), style = style, attributes = attr) + #there must be a better way to do this + pts = join((join((ptsvector[i][1], ptsvector[i][2]), ",") for i in 1:length(ptsvector)), " ") + attr = Dict("points" => pts) + Node(instanceof(dom"svg:polyline"()), style = style, attributes = attr) end function svg_polyline(ptsvector, thickness, color) - style = Dict(:strokeWidth => "$thickness", - :fill => "none", - :stroke => "rgb$color") - svg_poly(ptsvector, style) + style = Dict(:strokeWidth => "$thickness", + :fill => "none", + :stroke => "rgb$color") + svg_poly(ptsvector, style) end function svg_polygon(ptsvector, color) - style = Dict( :fill => "rgb$color") - svg_poly(ptsvector, style) + style = Dict( :fill => "rgb$color") + svg_poly(ptsvector, style) +end + +function svg_text(x, y, text, style=stdstyle) + attr = Dict("y" => "$y", + "x" => "$x") + Node(instanceof(dom"svg:text"(text)), style = style, attributes = attr) end