From 929b42942e3755c4077d64be69e43393633ae166 Mon Sep 17 00:00:00 2001 From: SimonDanisch Date: Tue, 19 Dec 2023 12:39:12 +0100 Subject: [PATCH 1/2] add a simple GUI --- src/GUI/file-dialogue.jl | 31 +++++++++++++ src/GUI/gui.jl | 96 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 src/GUI/file-dialogue.jl create mode 100644 src/GUI/gui.jl diff --git a/src/GUI/file-dialogue.jl b/src/GUI/file-dialogue.jl new file mode 100644 index 00000000000..de26c4a9e2c --- /dev/null +++ b/src/GUI/file-dialogue.jl @@ -0,0 +1,31 @@ +using NativeFileDialog_jll + +function choose_file_dialogue(filter=C_NULL) + path = Ref(Ptr{UInt8}()) + r = @ccall libnfd.NFD_OpenDialog(filter::Ptr{Cchar}, C_NULL::Ptr{Cchar}, + path::Ref{Ptr{UInt8}})::Cint + if r == 2 + # User clicked "Cancel" + out = nothing + elseif r == 1 + out = unsafe_string(path[]) + else + error() + end + return out +end + +function save_file_dialogue(filter=C_NULL) + path = Ref(Ptr{UInt8}()) + r = @ccall libnfd.NFD_SaveDialog(filter::Ptr{Cchar}, C_NULL::Ptr{Cchar}, + path::Ref{Ptr{UInt8}})::Cint + if r == 2 + # User clicked "Cancel" + out = nothing + elseif r == 1 + out = unsafe_string(path[]) + else + error() + end + return out +end diff --git a/src/GUI/gui.jl b/src/GUI/gui.jl new file mode 100644 index 00000000000..672ede646b2 --- /dev/null +++ b/src/GUI/gui.jl @@ -0,0 +1,96 @@ +using ImageClipboard + +function set_vis!(scene::Scene, v::Bool) + return scene.visible[] = v +end + +function set_vis!(block::Makie.Block, v::Bool) + set_vis!(block.blockscene, v) + return foreach(s -> set_vis!(s, v), block.blockscene.children) +end + +function hoverbar(f, ax) + gl = GridLayout(f[:, :]; tellwidth=false, tellheight=false, halign=:center, valign=:top) + visible = Observable(false) + box = gl[1, 1:3] = Box(f; height=45, width=200, color=(:white, 0.7), cornerradius=5) + bstyle = (buttoncolor="gray", labelcolor=:white, font=:bold, fontsize=13) + bsave = gl[1, 1] = Button(f; label="save", bstyle...) + bcopy = gl[1, 2] = Button(f; label="copy", bstyle...) + breset = gl[1, 3] = Button(f; label="↻", width=50, bstyle...) + on(f.scene, visible; update=true) do v + set_vis!(box, v) + set_vis!(bsave, v) + set_vis!(bcopy, v) + return set_vis!(breset, v) + end + on(f.scene, breset.clicks) do _ + visible[] = false + return reset_limits!(ax) + end + on(f.scene, bsave.clicks) do _ + visible[] = false + file = save_file_dialogue() + if !isnothing(file) + save(file, f; update=false) + end + end + on(f.scene, bcopy.clicks) do _ + visible[] = false + img = colorbuffer(f; update=false) + return ImageClipboard.clipboard_img(img) + end + on(f.scene, f.scene.events.mouseposition) do mp + vp = f.scene.viewport[] + rect = Rect2f(0, widths(vp)[2] - 70, widths(vp)[1], 70) + if mp in rect + visible[] = true + else + visible[] = false + end + end + return +end + +""" + GUI(faxpl::Makie.FigureAxisPlot; legend=(;), colorbar=(;)) + +Automatically creates a legend and colorbar for the return value of `plot`. +Also adds a small UI to save/reset/copy the plot. +# Example + +```julia +f, ax, pl = GUI(series(rand(7, 20)); legend=(position=:lt, title="legend")) +``` +""" +function GUI(faxpl::Makie.FigureAxisPlot; legend=(;), colorbar=(;)) + f, ax, plot = faxpl + hoverbar(f, ax) + if legend isa NamedTuple + plots, labels = Makie.get_labeled_plots(ax; unique=get(legend, :unique, false), + merge=get(legend, :merge, false)) + if !isempty(plots) + title = get(legend, :title, nothing) + bbox = ax.scene.viewport + margin = get(legend, :margin, (6, 6, 6, 6)) + position = get(legend, :position, :rt) + pos_kw = Makie.legend_position_to_aligns(position) + Legend(ax.parent, plots, labels, title; margin=margin, bbox=bbox, legend..., pos_kw...) + end + elseif !(legend isa Bool && legend == false) + error("legend must be a NamedTuple with attributes passed to `axislegend` or false to disable automatic legend creation") + end + + if colorbar isa NamedTuple + try + cmap = Makie.extract_colormap_recursive(plot) + if !isnothing(cmap) + Colorbar(f[1, 2]; colormap=cmap, colorbar...) + end + catch e + + end + elseif !(colorbar isa Bool && colorbar == false) + error("legend must be a NamedTuple with attributes passed to `axislegend` or false to disable automatic legend creation") + end + return faxpl +end From ba583faaea50b80daa47bc591fcc7443aa578aa5 Mon Sep 17 00:00:00 2001 From: SimonDanisch Date: Tue, 19 Dec 2023 14:49:48 +0100 Subject: [PATCH 2/2] add GUI for a high level plotting GUI + auto legend/colorbar --- Project.toml | 2 ++ src/GUI/gui.jl | 2 ++ src/Makie.jl | 3 +++ 3 files changed, 7 insertions(+) diff --git a/Project.toml b/Project.toml index 3d9792b229e..443c4512449 100644 --- a/Project.toml +++ b/Project.toml @@ -25,6 +25,7 @@ FreeType = "b38be410-82b0-50bf-ab77-7b57e271db43" FreeTypeAbstraction = "663a7486-cb36-511b-a19d-713bb74d65c9" GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" GridLayoutBase = "3955a311-db13-416c-9275-1d80ed98e5e9" +ImageClipboard = "6db54171-f50f-4661-a74f-bc514ef16cee" ImageIO = "82e4d734-157c-48bb-816b-45c225c6df19" InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953" @@ -36,6 +37,7 @@ MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" MakieCore = "20f20a25-4f0e-4fdf-b5d1-57303727442b" Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" MathTeXEngine = "0a4f8689-d25c-4efe-a92b-7142dfc1aa53" +NativeFileDialog_jll = "94d9ae2c-efc7-56f8-9a02-54c47b797961" Observables = "510215fc-4207-5dde-b226-833fc4488ee2" OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" Packing = "19eb6ba3-879d-56ad-ad62-d5c202156566" diff --git a/src/GUI/gui.jl b/src/GUI/gui.jl index 672ede646b2..930e8eba668 100644 --- a/src/GUI/gui.jl +++ b/src/GUI/gui.jl @@ -1,5 +1,7 @@ using ImageClipboard +include("file-dialogue.jl") + function set_vis!(scene::Scene, v::Bool) return scene.visible[] = v end diff --git a/src/Makie.jl b/src/Makie.jl index ea7b18ca2bb..ce56ed08798 100644 --- a/src/Makie.jl +++ b/src/Makie.jl @@ -206,6 +206,9 @@ include("display.jl") include("ffmpeg-util.jl") include("recording.jl") include("event-recorder.jl") +include("GUI/gui.jl") + +export GUI # bezier paths export BezierPath, MoveTo, LineTo, CurveTo, EllipticalArc, ClosePath