~jpsamaroo/Adjutant.jl

ref: c93000a0359728120848e82a6dc0208c83f48338 Adjutant.jl/src/widgets.jl -rw-r--r-- 3.1 KiB
c93000a0Julian P Samaroo Remove extra deps, make things work again 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
export Widget, AddWidgetButton, ClosureWidget
export known_widgets, processor, get_processor

const known_widgets = Any[]

### Core ###

mutable struct Widget{T}
    x::T
    p::Processor
end
Base.getproperty(w::Widget, sym::Symbol) = getproperty(getfield(w, :x), sym)
Base.setproperty!(w::Widget, sym::Symbol, x) = setproperty!(getfield(w, :x), sym, x)
Base.convert(::Type{W} where W<:Widget, x) = Widget(x, get_processor(x))
Base.convert(::Type{W} where W<:Widget, w::Widget) = w
name(w::Widget{T}) where T = string(T)
# FIXME: Unique name for IDs
processor(w::Widget{T}) where T = getfield(w, :p)
get_processor(x) = Processor()

Base.@kwdef mutable struct WidgetContainer
    widgets::Vector{Widget} = Widget[]
end
function (wc::WidgetContainer)(outer)
    for widget in copy(wc.widgets)
        CImGui.PushID(pointer_from_objref(widget))
        widget(wc)
        CImGui.PopID()
        CImGui.Separator()
    end
end
getidx(wc::WidgetContainer, w::Widget) = findfirst(x->x===w, wc.widgets)
Base.delete!(wc::WidgetContainer, w::Widget) =
    deleteat!(wc.widgets, getidx(wc, w))
Base.insert!(wc::WidgetContainer, wafter::Widget, wbefore::Widget) =
    insert!(wc.widgets, getidx(wc, wafter), wbefore)
Base.insert!(wc::WidgetContainer, wafter::Widget, wbefore) =
    insert!(wc, wafter, Widget(wbefore))
Base.push!(wc::WidgetContainer, w) = push!(wc.widgets, w)

### Adding Widgets ###

mutable struct AddWidgetForm
    T::DataType
    fields::Dict{Symbol,Any}
end
function AddWidgetForm(::Type{T}) where T
    fields = get_widget_fields(T)
    if fields === nothing
        # Signal that we don't have a form
        # Instead, we just construct and return the final widget
        return T()
    else
        return AddWidgetForm(T, fields)
    end
end
function (awf::Widget{AddWidgetForm})(outer)
    CImGui.Text(repr(awf.T))
    render_widget_form(awf.T, awf.fields, outer)
end
get_widget_fields(_) = nothing

Base.@kwdef mutable struct AddWidgetButton
    open::Bool = false
end
function (awb::Widget{AddWidgetButton})(outer)
    if awb.open
        if CImGui.Button("- Cancel")
            awb.open = false
        end
        for (idx,W) in enumerate(known_widgets)
            if CImGui.Button(repr(W))
                form = AddWidgetForm(W)
                insert!(outer, awb, form)
                awb.open = false
            end
        end
    else
        if CImGui.Button("+ Add Widget")
            awb.open = true
        end
    end
end
push!(known_widgets, AddWidgetButton)

### Misc Widgets ###

Base.@kwdef mutable struct TextWidget
    str::String = "Some text"
end
push!(known_widgets, TextWidget)
(tw::Widget{TextWidget})(_) = CImGui.Text(tw.str)
get_widget_fields(::Type{TextWidget}) = Dict{Symbol,Any}(:str=>"\0"^256)
function render_widget_form(::Type{TextWidget}, fields, outer)
    str = fields[:str]
    CImGui.InputText("Text", str, length(str))
end

struct ClosureWidget
    func
end
(cw::Widget{ClosureWidget})(outer) = cw.func(outer)
push!(known_widgets, ClosureWidget)

struct TestWidget end
(tw::Widget{TestWidget})(outer) = CImGui.Text("TestWidget")
get_processor(tw::TestWidget) = Processor(["a","b","c"],["d","e"]) do p
end