~jpsamaroo/Adjutant.jl

ref: 8a8229fe1ed910ea963b69840af6fd91fcdb76c9 Adjutant.jl/src/widgets.jl -rw-r--r-- 4.3 KiB
8a8229feJulian P Samaroo Allow loading user's project 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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
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
get_processor(x) = Processor()
processor(w::Widget{T}) where T = getfield(w, :p)

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)

#=
### Image Widgets ###

mutable struct VideoCameraWidget
    dev
    image
end
function VideoCameraWidget(dev=VideoIO.opencamera())
    image = collect(transpose(read(dev)))
    return VideoCameraWidget(dev, image)
end
function (vcw::Widget{VideoCameraWidget})(outer)
    processor(vcw)()
end
function get_processor(vcw::VideoCameraWidget)
    return Processor(nothing, ["image_raw"]) do p
        image_raw = read(vcw.dev)
        vcw.image = collect(transpose(image_raw))
        setslot!(p, "image_raw", vcw.image)
    end
end

mutable struct OpenGLImageWidget
    image_id
end
OpenGLImageWidget() = OpenGLImageWidget(nothing)
push!(known_widgets, OpenGLImageWidget)
function (ow::Widget{OpenGLImageWidget})(_...)
    processor(ow)()
end
function get_processor(ow::OpenGLImageWidget)
    return Processor(["image"], nothing) do p
        image = getslot(p, "image")
        image = reshape(reinterpret(GLubyte, RGBA.(image)), (4,size(image)...))
        _, img_width, img_height = size(image)
        if ow.image_id === nothing
            ow.image_id = ImGui_ImplOpenGL3_CreateImageTexture(img_width, img_height)
        end
        ImGui_ImplOpenGL3_UpdateImageTexture(ow.image_id, image, img_width, img_height)
        CImGui.Image(Ptr{Cvoid}(ow.image_id), (img_width, img_height))
    end
end

### 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