Skip to content

Commit

Permalink
Add new Checkbox block (#4336)
Browse files Browse the repository at this point in the history
  • Loading branch information
jkrumbiegel authored Oct 1, 2024
1 parent 561dfdb commit 52140c1
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Fix `merge(attr1, attr2)` modifying nested attributes in `attr1` [#4416](https://github.com/MakieOrg/Makie.jl/pull/4416)
- Fixed issue with CairoMakie rendering scene backgrounds at the wrong position [#4425](https://github.com/MakieOrg/Makie.jl/pull/4425)
- Fix incorrect inverse transformation in `position_on_plot` for lines, causing incorrect tooltip placement in DataInspector [#4402](https://github.com/MakieOrg/Makie.jl/pull/4402)
- Added new `Checkbox` block [#4336](https://github.com/MakieOrg/Makie.jl/pull/4336).
- Added ability to override legend element attributes by pairing labels or plots with override attributes [#4427](https://github.com/MakieOrg/Makie.jl/pull/4427).
- Added threshold before a drag starts which improves false negative rates for clicks. `Button` can now trigger on click and not mouse-down which is the canonical behavior in other GUI systems [#4336](https://github.com/MakieOrg/Makie.jl/pull/4336).
- `PolarAxis` font size now defaults to global figure `fontsize` in the absence of specific `Axis` theming [#4314](https://github.com/MakieOrg/Makie.jl/pull/4314)
Expand Down
15 changes: 15 additions & 0 deletions ReferenceTests/src/tests/figures_and_makielayout.jl
Original file line number Diff line number Diff line change
Expand Up @@ -395,4 +395,19 @@ end
Label(f[1, 2], rich("Hi", rich("Hi", offset = (0.2, 0.2), color = :blue)), tellheight = false)
Label(f[1, 3], rich("X", superscript("super"), subscript("sub")), tellheight = false)
f
end

@reference_test "Checkbox" begin
f = Figure(size = (300, 200))
Makie.Checkbox(f[1, 1])
Makie.Checkbox(f[1, 2], checked = true)
Makie.Checkbox(f[1, 3], checked = true, checkmark = Circle, roundness = 1, checkmarksize = 0.6)
Makie.Checkbox(f[1, 4], checked = true, checkmark = Circle, roundness = 1, checkmarksize = 0.6, size = 20)
Makie.Checkbox(f[1, 5], checkboxstrokewidth = 3)
Makie.Checkbox(f[2, 1], checkboxstrokecolor_unchecked = :red)
Makie.Checkbox(f[2, 2], checked = true, checkboxstrokecolor_checked = :cyan)
Makie.Checkbox(f[2, 3], checked = true, checkmarkcolor_checked = :black)
Makie.Checkbox(f[2, 4], checked = false, checkboxcolor_unchecked = :yellow)
Makie.Checkbox(f[2, 5], checked = true, checkboxcolor_checked = :orange)
f
end
1 change: 1 addition & 0 deletions docs/makedocs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ pages = [
"reference/blocks/axis3.md",
"reference/blocks/box.md",
"reference/blocks/button.md",
"reference/blocks/checkbox.md",
"reference/blocks/colorbar.md",
"reference/blocks/gridlayout.md",
"reference/blocks/intervalslider.md",
Expand Down
39 changes: 39 additions & 0 deletions docs/src/reference/blocks/checkbox.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Checkbox

```@figure backend=GLMakie
f = Figure()
gl = GridLayout(f[2, 1], tellwidth = false)
subgl = GridLayout(gl[1, 1])
cb1 = Checkbox(subgl[1, 1], checked = false)
cb2 = Checkbox(subgl[2, 1], checked = true)
cb3 = Checkbox(subgl[3, 1], checked = true)
Label(subgl[1, 2], "Show grid", halign = :left)
Label(subgl[2, 2], "Show ticklabels", halign = :left)
Label(subgl[3, 2], "Show title", halign = :left)
rowgap!(subgl, 8)
colgap!(subgl, 8)
ax = Axis(
f[1, 1],
title = "Checkboxes",
xgridvisible = cb1.checked,
ygridvisible = cb1.checked,
xticklabelsvisible = cb2.checked,
yticklabelsvisible = cb2.checked,
xticksvisible = cb2.checked,
yticksvisible = cb2.checked,
titlevisible = cb3.checked,
alignmode = Outside(),
)
f
```

## Attributes

```@attrdocs
Checkbox
```
2 changes: 2 additions & 0 deletions src/makielayout/MakieLayout.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ include("blocks/slider.jl")
include("blocks/slidergrid.jl")
include("blocks/intervalslider.jl")
include("blocks/button.jl")
include("blocks/checkbox.jl")
include("blocks/box.jl")
include("blocks/toggle.jl")
include("blocks/legend.jl")
Expand All @@ -41,6 +42,7 @@ export Slider
export SliderGrid
export IntervalSlider
export Button
export Checkbox
export Colorbar
export Label
export Box
Expand Down
94 changes: 94 additions & 0 deletions src/makielayout/blocks/checkbox.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
function initialize_block!(c::Checkbox)

scene = c.blockscene

ischecked = lift(identity, scene, c.checked)
ishovered = Observable(false)

checkboxrect = lift(scene, c.layoutobservables.computedbbox, c.size) do bbox, size
Rect2f(
bbox.origin + 0.5 .* bbox.widths .- 0.5 .* size,
Vec2d(size)
)
end

shape = lift(c.size, c.roundness) do size, roundness
r = Float64(roundness * size/2)
roundedrectpath(Float64.((size, size)), (r, r, r, r))
end

strokecolor = lift(scene, ischecked, c.checkboxstrokecolor_unchecked, c.checkboxstrokecolor_checked) do checked, color_uc, color_c
Makie.to_color(checked ? color_c : color_uc)
end

polycolor = lift(scene, ischecked, c.checkboxcolor_unchecked, c.checkboxcolor_checked) do checked, color_uc, color_c
Makie.to_color(checked ? color_c : color_uc)
end

checkmarkcolor = lift(scene, ischecked, c.checkmarkcolor_unchecked, c.checkmarkcolor_checked) do checked, color_uc, color_c
Makie.to_color(checked ? color_c : color_uc)
end

shp = poly!(
scene,
shape,
color = polycolor,
strokewidth = c.checkboxstrokewidth,
strokecolor = strokecolor,
)

on(checkboxrect, update = true) do rect
translate!(shp, (rect.origin .+ 0.5 .* rect.widths)..., 0)
end

markerpos = lift(checkboxrect) do rect
rect.origin .+ 0.5 .* rect.widths
end

sc = scatter!(
scene,
markerpos,
marker = c.checkmark,
markersize = @lift($(c.size) * $(c.checkmarksize)),
color = checkmarkcolor,
visible = @lift($ischecked || $ishovered),
)

mouseevents = addmouseevents!(scene, shp, sc)

onmouseleftclick(mouseevents) do _
newstatus = c.onchange[](c.checked[])
if newstatus != c.checked[]
c.checked[] = newstatus
end
end
onmouseover(mouseevents) do _
ishovered[] = true
end
onmouseout(mouseevents) do _
ishovered[] = false
end

on(scene, c.size; update = true) do sz
c.layoutobservables.autosize[] = Float64.((sz, sz))
end

return
end

function roundedrectpath(size, radii)
# radii go top right, bottom right, bottom left, top left
rw, rh = size ./ 2
BezierPath([
MoveTo(rw, rh-radii[1]),
LineTo(rw, -rh+radii[2]),
EllipticalArc(Point(rw-radii[2], -rh+radii[2]), radii[2], radii[2], 0, 0, -pi/2),
LineTo(-rw+radii[3], -rh),
EllipticalArc(Point(-rw+radii[3], -rh+radii[3]), radii[3], radii[3], 0, -pi/2, -pi),
LineTo(-rw, rh-radii[4]),
EllipticalArc(Point(-rw+radii[4], rh-radii[4]), radii[4], radii[4], 0, -pi, -3pi/2),
LineTo(rw-radii[1], rh),
EllipticalArc(Point(rw-radii[1], rh-radii[1]), radii[1], radii[1], 0, -3pi/2, -2pi),
ClosePath(),
])
end
51 changes: 51 additions & 0 deletions src/makielayout/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1101,6 +1101,57 @@ end
end
end

const CHECKMARK_BEZIER = scale(BezierPath(
"M 81.449219,-0.08203125A 7.5,7.5 0 0 0 76.628906,3.0332031L 38.113281,58.792969 18.806641,34.650391A 7.5,7.5 0 0 0 8.265625,33.478516 7.5,7.5 0 0 0 7.0917969,44.019531L 32.697266,76.037109A 7.50075,7.50075 0 0 0 44.724609,75.615234L 88.970703,11.558594A 7.5,7.5 0 0 0 87.0625,1.125 7.5,7.5 0 0 0 81.449219,-0.08203125Z",
fit = true,
flipy = true,
), 0.85)

@Block Checkbox begin
@attributes begin
"The horizontal alignment of the checkbox in its suggested boundingbox"
halign = :center
"The vertical alignment of the checkbox in its suggested boundingbox"
valign = :center
"The width setting of the checkbox."
width = Auto()
"The height setting of the checkbox."
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"
tellheight = true
"The size (width/height) of the checkbox"
size = 11
"The size of the checkmark, relative to the size."
checkmarksize = 0.85
"The checkmark marker symbol. Anything that `scatter` can use."
checkmark = CHECKMARK_BEZIER
"Roundness of the checkbox poly, 0 is square, 1 is circular."
roundness = 0.15
"The strokewidth of the checkbox poly."
checkboxstrokewidth = 1.5
"The color of the checkbox background when checked."
checkboxcolor_checked = COLOR_ACCENT[]
"The color of the checkbox background when unchecked."
checkboxcolor_unchecked = @inherit(:backgroundcolor, :white)
"The strokecolor of the checkbox background when checked."
checkboxstrokecolor_checked = COLOR_ACCENT[]
"The strokecolor of the checkbox background when unchecked."
checkboxstrokecolor_unchecked = COLOR_ACCENT[]
"The color of the checkmark when unchecked."
checkmarkcolor_unchecked = :transparent
"The color of the checkmark when the mouse clicks the checkbox."
checkmarkcolor_checked = :white
"The align mode of the checkbox in its parent GridLayout."
alignmode = Inside()
"If the checkbox is currently checked. This value should not be modified directly."
checked = false
"A function that is called when the user clicks to check or uncheck. The function is passed the current status as a `Bool` and needs to return a `Bool` that decides the checked status after the click. Intended for implementation of radio buttons."
onchange = !
end
end

@Block Toggle begin
@attributes begin
"The horizontal alignment of the toggle in its suggested bounding box."
Expand Down

0 comments on commit 52140c1

Please sign in to comment.