using Makie, Colors, Observables
r = range(0, stop=5pi, length=100)
scene = lines(r, sin.(r), linewidth = 3)
lineplot = scene[end]
visible = node(:visible, false)
poprect = lift(scene.events.mouseposition) do mp
    FRect((mp .+ 5), 250, 40)
end
textpos = lift(scene.events.mouseposition) do mp
    Vec3f0((mp .+ 5 .+ (250/2, 40 / 2))..., 120)
end
popup = poly!(campixel(scene), poprect, raw = true, color = :white, strokewidth = 2, strokecolor = :black, visible = visible)
rect = popup[end]
translate!(rect, Vec3f0(0, 0, 100))
text!(popup, "( 0.000,  0.000)", textsize = 30, position = textpos, color = :darkred, align = (:center, :center), raw = true, visible = visible)
text_field = popup[end]
scene

x = Node(false)
on(scene.events.mouseposition) do event
    plot, idx = Makie.mouse_selection(scene)
    if plot == lineplot && idx > 0
        visible[] = true
        text_field[1] = sprint(io-> print(io, round.(Float64.(Tuple(lineplot[1][][idx])), digits = 3)))
    else
        visible[] = false
    end
    return
end
scene


using Makie
using LinearAlgebra
img = rand(100, 100)
scene = Scene()
heatmap!(scene, img, scale_plot = false)
clicks = Node(Point2f0[(0, 0)])
blues = Node(Point2f0[])

on(scene.events.mousebuttons) do buttons
    if ispressed(scene, Mouse.left)
        pos = to_world(scene, Point2f0(scene.events.mouseposition[]))
        found = -1
        c = clicks[]
        for i in 1:length(c)
           if norm(pos - c[i]) < 1
               found = i
           end
        end
        if found >= 1
            blues[] = push!(blues[], pos)
            deleteat!(clicks[], found)
        else
            push!(clicks[], pos)
        end
        clicks[] = clicks[]
   end
   return
end

scatter!(scene, clicks, color = :red, marker = '+', markersize = 10, raw = true)
red_clicks = scene[end]
scatter!(scene, blues, color = :blue, marker = 'o', markersize = 10, raw = true)
scene



using Makie
points = node(:poly, Point2f0[(0, 0), (0.5, 0.5), (1.0, 0.0)])

scene = poly(points, strokewidth = 2, strokecolor = :black, color = :skyblue2, show_axis = false, scale_plot = false)
scatter!(points, color = :white, strokewidth = 10, markersize = 0.05, strokecolor = :black, raw = true)
pplot = scene[end]
push!(points[], Point2f0(0.6, -0.3))
points[] = points[]

function add_move!(scene, points, pplot)
    idx = Ref(0); dragstart = Ref(false); startpos = Base.RefValue(Point2f0(0))
    on(events(scene).mousedrag) do drag
        if ispressed(scene, Mouse.left)
            if drag == Mouse.down
                plot, _idx = Makie.mouse_selection(scene)
                if plot == pplot
                    idx[] = _idx; dragstart[] = true
                    startpos[] = to_world(scene, Point2f0(scene.events.mouseposition[]))
                end
            elseif drag == Mouse.pressed && dragstart[] && checkbounds(Bool, points[], idx[])
                pos = to_world(scene, Point2f0(scene.events.mouseposition[]))
                points[][idx[]] = pos
                points[] = points[]
            end
        else
            dragstart[] = false
        end
        return
    end
end

function add_remove_add!(scene, points, pplot)
    on(events(scene).mousebuttons) do but
        if ispressed(but, Mouse.left) && ispressed(scene, Keyboard.left_control)
            pos = to_world(scene, Point2f0(events(scene).mouseposition[]))
            push!(points[], pos)
            points[] = points[]
        elseif ispressed(but, Mouse.right)
            plot, idx = Makie.mouse_selection(scene)
            if plot == pplot && checkbounds(Bool, points[], idx)
                deleteat!(points[], idx)
                points[] = points[]
            end
        end
        return
    end
end
add_move!(scene, points, pplot)
add_remove_add!(scene, points, pplot)
center!(scene)
scene


using Makie, Colors
using AbstractPlotting: transformationmatrix, textslider, colorswatch, hbox!
s1, a = textslider(0f0:50f0, "a", start = 13)
s2, b = textslider(-20f0:20f0, "b", start = 10)
s3, c = textslider(0f0:20f0, "c", start = 2)
s4, d = textslider(range(0.0, stop = 0.02, length = 100), "d", start = 0.01)
s5, scales = textslider(range(0.01, stop = 0.5, length = 100), "scale", start = 0.1)
s6, colorsw, pop = colorswatch()

function lorenz(t0, a, b, c, h)
    Point3f0(
        t0[1] + h * a * (t0[2] - t0[1]),
        t0[2] + h * (t0[1] * (b - t0[3]) - t0[2]),
        t0[3] + h * (t0[1] * t0[2] - c * t0[3]),
    )
end
# step through the `time`
function lorenz(array::Vector, a = 5.0 ,b = 2.0, c = 6.0, d = 0.01)
    t0 = Point3f0(0.1, 0, 0)
    for i = eachindex(array)
        t0 = lorenz(t0, a,b,c,d)
        array[i] = t0
    end
    array
end

n1, n2 = 18, 30
N = n1*n2
args_n = (a, b, c, d)
v0 = lorenz(zeros(Point3f0, N), to_value.(args_n)...)
positions = lift(lorenz, Node(v0), args_n...)
rotations = lift(diff, positions)
rotations = lift(x-> push!(x, x[end]), rotations)

mesh_scene = meshscatter(
    positions,
    markersize = scales, rotation = rotations,
    intensity = collect(range(0f0, stop = 1f0, length = length(positions[]))),
    color = colorsw
)

vbox(
    hbox(s1, s2, s3, s4, s5, s6),
    mesh_scene
)

function record_events(f, scene, path)
    display(scene)
    result = Vector{Pair{Float64, Pair{Symbol, Any}}}()
    for field in fieldnames(Events)
        foreach(getfield(scene.events, field)) do value
            value = isa(value, Set) ? copy(value) : value
            push!(result, time() => (field => value))
        end
    end
    f()

    open(path, "w") do io
        serialize(io, result)
    end
end
record_events(scene, "test.jls") do
    wait(Makie.global_gl_screen())
end

function replay(scene, path)
    display(scene)
    events = open(io-> deserialize(io), path)
    sort!(events, by = first)
    for i in 1:length(events)
        t1, (field, value) = events[i]
        field == :mousedrag && continue
        if field == :mousebuttons
            getfield(scene.events, field)[] = value
        else
            getfield(scene.events, field)[] = value
        end
        yield(); force_update!()
        if i < length(events)
            t2, (field, value) = events[i + 1]
            # min sleep time 0.001
            (t2 - t1 > 0.001) && sleep(t2 - t1)
        end
    end
end

replay(scene, "test.jls")
open(io-> serialize(io, Set([Mouse.left])) , "test2.jls", "w")
open(io-> deserialize(io) , "test2.jls")

scatter!(campixel(scene), lift(x-> [x], scene.events.mouseposition),color = :black, markersize = 20, raw = true)
scene
