diff --git a/CHANGELOG.md b/CHANGELOG.md index e0bf68bf138..0e06ecd7b40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## [Unreleased] +- Add kwarg to rotate Toggle [#4445](https://github.com/MakieOrg/Makie.jl/pull/4445) - Fix orientation of environment light textures in RPRMakie [#4629](https://github.com/MakieOrg/Makie.jl/pull/4629). - Fix uint16 overflow for over ~65k elements in WGLMakie picking [#4604](https://github.com/MakieOrg/Makie.jl/pull/4604). - Improve performance for line plot in CairoMakie [#4601](https://github.com/MakieOrg/Makie.jl/pull/4601). diff --git a/ReferenceTests/src/tests/figures_and_makielayout.jl b/ReferenceTests/src/tests/figures_and_makielayout.jl index abcae8efb93..04a2e550a04 100644 --- a/ReferenceTests/src/tests/figures_and_makielayout.jl +++ b/ReferenceTests/src/tests/figures_and_makielayout.jl @@ -480,10 +480,11 @@ end Makie.set_close_to!(sl, 30, 70) Toggle(f[3, 1]) - Toggle(f[4, 1], framecolor_inactive = :lightblue, rimfraction = 0.6) - Toggle(f[3, 2], active = true) + t = Toggle(f[4, 1], framecolor_inactive = :lightblue, rimfraction = 0.6) + t.orientation = 3pi/4 + Toggle(f[3, 2], active = true, orientation = :horizontal) Toggle(f[4, 2], active = true, framecolor_inactive = :lightblue, - framecolor_active = :yellow, rimfraction = 0.6) + framecolor_active = :yellow, rimfraction = 0.6, orientation = :vertical) Makie.Slider(f[3, 3]) sl = Makie.Slider(f[4, 3], range = 0:100, linewidth = 20, color_inactive = :cyan, @@ -497,6 +498,15 @@ end tb = Textbox(gl[1, 3], bordercolor = :black, cornerradius = 20, fontsize =10, textcolor = :red, boxcolor = :lightblue) Makie.set!(tb, "some string") + f +end +@reference_test "Toggle orientation" begin + f = Figure() + for x=1:3, y=1:3 + x==y==2 && continue + Box(f[x, y], color = :tomato) + Toggle(f[x, y], orientation = atan(x-2,2-y)) + end f end diff --git a/src/makielayout/blocks/toggle.jl b/src/makielayout/blocks/toggle.jl index 01c58231411..cd7a75443d5 100644 --- a/src/makielayout/blocks/toggle.jl +++ b/src/makielayout/blocks/toggle.jl @@ -2,30 +2,50 @@ function initialize_block!(t::Toggle) topscene = t.blockscene - markersize = lift(topscene, t.layoutobservables.computedbbox) do bbox - min(width(bbox), height(bbox)) + onany(topscene, t.orientation, t.length, t.markersize) do or, len, ms + theta = or == :horizontal ? 0 : or == :vertical ? pi/2 : or + y, x = sincos(theta) + autowidth = (len - ms) * abs(x) + ms + autoheight = (len - ms) * abs(y) + ms + t.layoutobservables.autosize[] = (autowidth, autoheight) end - button_endpoint_inactive = lift(topscene, markersize) do ms - bbox = t.layoutobservables.computedbbox[] - Point2f(left(bbox) + ms / 2, bottom(bbox) + ms / 2) + xfun(x, bbox, ms) = x>0 ? left(bbox) + ms / 2 : right(bbox) - ms / 2 + yfun(y, bbox, ms) = y>0 ? bottom(bbox) + ms / 2 : top(bbox) - ms / 2 + + button_endpoint_inactive = lift(topscene, t.orientation, t.markersize, t.layoutobservables.computedbbox) do or, ms, bbox + theta = or == :horizontal ? 0 : or == :vertical ? pi/2 : or + y, x = sincos(theta) + Point2f(xfun(x, bbox, ms), yfun(y, bbox, ms)) end - button_endpoint_active = lift(topscene, markersize) do ms - bbox = t.layoutobservables.computedbbox[] - Point2f(right(bbox) - ms / 2, bottom(bbox) + ms / 2) + button_endpoint_active = lift(topscene, t.orientation, t.markersize, t.layoutobservables.computedbbox) do or, ms, bbox + theta = or == :horizontal ? 0 : or == :vertical ? pi/2 : or + y, x = sincos(theta) + Point2f(xfun(-x, bbox, ms), yfun(-y, bbox, ms)) end - buttonvertices = lift(topscene, markersize, t.cornersegments) do ms, cs - roundedrectvertices(t.layoutobservables.computedbbox[], ms * 0.499, cs) + buttonvertices = lift(topscene, t.length, t.markersize, t.cornersegments) do len, ms, cs + rect0 = GeometryBasics.HyperRectangle(-ms/2, -ms/2, len, ms) + return roundedrectvertices(rect0, ms * 0.499, cs) end # trigger bbox + notify(t.length) notify(t.layoutobservables.suggestedbbox) framecolor = Observable{Any}(t.active[] ? t.framecolor_active[] : t.framecolor_inactive[]) frame = poly!(topscene, buttonvertices, color = framecolor, inspectable = false) + onany(topscene, t.markersize, t.orientation, t.layoutobservables.computedbbox, update = true) do ms, or, bbox + theta = or == :horizontal ? 0 : or == :vertical ? pi/2 : or + rotate!(frame, theta) + y, x = sincos(theta) + tx = x>0 ? origin(bbox)[1] + ms/2 : origin(bbox)[1] + widths(bbox)[1] - ms/2 + ty = y>0 ? origin(bbox)[2] + ms/2 : origin(bbox)[2] + widths(bbox)[2] - ms/2 + translate!(frame, Point2f(tx, ty)) + end + animating = Observable(false) buttonpos = Observable(t.active[] ? [button_endpoint_active[]] : [button_endpoint_inactive[]]) @@ -37,7 +57,7 @@ function initialize_block!(t::Toggle) end buttonfactor = Observable(1.0) - buttonsize = lift(topscene, markersize, t.rimfraction, buttonfactor) do ms, rf, bf + buttonsize = lift(topscene, t.markersize, t.rimfraction, buttonfactor) do ms, rf, bf ms * (1 - rf) * bf end diff --git a/src/makielayout/types.jl b/src/makielayout/types.jl index 83321578634..c9c17fcad93 100644 --- a/src/makielayout/types.jl +++ b/src/makielayout/types.jl @@ -1152,16 +1152,37 @@ const CHECKMARK_BEZIER = scale(BezierPath( end end +""" +A switch with two states. + +## Constructors + +```julia +Toggle(fig_or_scene; kwargs...) +``` + +## Examples + +```julia +t_horizontal = Toggle(fig[1, 1]) +t_vertical = Toggle(fig[2, 1], orientation = :vertical) +t_diagonal = Toggle(fig[3, 1], orientation = pi/4) +on(t_vertical.active) do switch_is_on + switch_is_on ? println("good morning!") : println("good night") +end +``` + +""" @Block Toggle begin @attributes begin "The horizontal alignment of the toggle in its suggested bounding box." halign = :center "The vertical alignment of the toggle in its suggested bounding box." valign = :center - "The width of the toggle." - width = 32 - "The height of the toggle." - height = 18 + "The width of the bounding box. Use `length` and `markersize` to set the dimensions of the toggle." + width = Auto() + "The height of the bounding box. Use `length` and `markersize` to set the dimensions of the toggle." + height = Auto() "Controls if the parent layout can adjust to this element's width" tellwidth = true "Controls if the parent layout can adjust to this element's height" @@ -1185,6 +1206,12 @@ end rimfraction = 0.33 "The align mode of the toggle in its parent GridLayout." alignmode = Inside() + "The orientation of the toggle. Can be :horizontal, :vertical, or -pi to pi. 0 is horizontal with \"on\" being to the right." + orientation = :horizontal + "The length of the toggle." + length = 32 + "The size of the button." + markersize = 18 end end diff --git a/test/makielayout.jl b/test/makielayout.jl index d0da12133e5..3cfc7a42977 100644 --- a/test/makielayout.jl +++ b/test/makielayout.jl @@ -547,3 +547,10 @@ end end @test isempty(limits.listeners) end + +@testset "Toggle" begin + f = Figure() + Toggle(f[1,1]) + Toggle(f[2,1], orientation=:vertical) + Toggle(f[3,1], orientation=pi/4) +end