Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom interactions #4531

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## [Unreleased]

- Add a global Axis/Axis3D registry for default interactions [#4531](https://github.com/MakieOrg/Makie.jl/pull/4531).

## [0.21.15] - 2024-10-25

- Allowed creation of `Legend` with entries that have no legend elements [#4526](https://github.com/MakieOrg/Makie.jl/pull/4526).
Expand Down
1 change: 1 addition & 0 deletions src/interaction/events.jl
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@
ispressed(events::Events, mb::Mouse.Button, waspressed = nothing) = mb in events.mousebuttonstate || mb == waspressed
ispressed(events::Events, key::Keyboard.Button, waspressed = nothing) = key in events.keyboardstate || key == waspressed
ispressed(parent, result::Bool, waspressed = nothing) = result
ispressed(parent, result::Nothing, waspressed = nothing) = true

Check warning on line 291 in src/interaction/events.jl

View check run for this annotation

Codecov / codecov/patch

src/interaction/events.jl#L291

Added line #L291 was not covered by tests

ispressed(parent, mb::Mouse.Button, waspressed = nothing) = ispressed(events(parent), mb, waspressed)
ispressed(parent, key::Keyboard.Button, waspressed = nothing) = ispressed(events(parent), key, waspressed)
Expand Down
17 changes: 10 additions & 7 deletions src/makielayout/blocks/axis.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
const DEFAULT_AXIS_INTERACTIONS = Dict(
:rectanglezoom => () -> RectangleZoom(),
:limitreset => () -> LimitReset(),
:scrollzoom => () -> ScrollZoom(0.1, 0.2),
:dragpan => () -> DragPan(0.2),
)

function update_gridlines!(grid_obs::Observable{Vector{Point2f}}, offset::Point2f, tickpositions::Vector{Point2f})
result = grid_obs[]
empty!(result) # reuse array for less allocations
Expand Down Expand Up @@ -49,13 +56,9 @@ function register_events!(ax, scene)
onany(process_axis_event, scene, ax, scrollevents)
onany(process_axis_event, scene, ax, keysevents)

register_interaction!(ax, :rectanglezoom, RectangleZoom(ax))

register_interaction!(ax, :limitreset, LimitReset())

register_interaction!(ax, :scrollzoom, ScrollZoom(0.1, 0.2))

register_interaction!(ax, :dragpan, DragPan(0.2))
for (name, fn) in DEFAULT_AXIS_INTERACTIONS
register_interaction!(ax, name, fn())
end

return
end
Expand Down
11 changes: 7 additions & 4 deletions src/makielayout/blocks/axis3d.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
const DEFAULT_AXIS_3D_INTERACTIONS = Dict(
:dragrotate => () -> DragRotate(),
)

struct OrthographicCamera <: AbstractCamera end

function initialize_block!(ax::Axis3)
Expand Down Expand Up @@ -158,10 +162,9 @@ function initialize_block!(ax::Axis3)
on(process_event, scene, ax.scrollevents)
on(process_event, scene, ax.keysevents)

register_interaction!(ax,
:dragrotate,
DragRotate())

for (name, fn) in DEFAULT_AXIS_3D_INTERACTIONS
register_interaction!(ax, name, fn())
end

# in case the user set limits already
notify(ax.limits)
Expand Down
25 changes: 15 additions & 10 deletions src/makielayout/interactions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@
end

function registration_setup!(parent, interaction)
# do nothing in the default case
return parent # do nothing in the default case
end

function deregistration_cleanup!(parent, interaction)
# do nothing in the default case
return parent # do nothing in the default case

Check warning on line 61 in src/makielayout/interactions.jl

View check run for this annotation

Codecov / codecov/patch

src/makielayout/interactions.jl#L61

Added line #L61 was not covered by tests
end

"""
Expand Down Expand Up @@ -177,10 +177,9 @@
return Consume(true)

elseif event.type === MouseEventTypes.leftdragstop
try
r.callback(r.rectnode[])
catch e
@warn "error in rectangle zoom" exception=(e, Base.catch_backtrace())
newlims = r.rectnode[]
if !(0 in widths(newlims))
ax.targetlimits[] = newlims
end
r.active[] = false
return Consume(true)
Expand All @@ -200,6 +199,12 @@
r.restrict_x = Keyboard.y in event.keys
r.active[] || return Consume(false)

# Deactivate when modifier is released before the mouse.
if r.modifier !== true && r.modifier ∉ event.keys
r.active[] = false
return Consume(true)

Check warning on line 205 in src/makielayout/interactions.jl

View check run for this annotation

Codecov / codecov/patch

src/makielayout/interactions.jl#L203-L205

Added lines #L203 - L205 were not covered by tests
end

r.rectnode[] = _chosen_limits(r, ax)
return Consume(true)
end
Expand All @@ -211,11 +216,11 @@
return Rect2(newori, newwidths)
end

function process_interaction(::LimitReset, event::MouseEvent, ax::Axis)
function process_interaction(l::LimitReset, event::MouseEvent, ax::Axis)

if event.type === MouseEventTypes.leftclick
if ispressed(ax.scene, Keyboard.left_control)
if ispressed(ax.scene, Keyboard.left_shift)
if event.type === l.mouseevent
if ispressed(ax.scene, l.modifier1)
if ispressed(ax.scene, l.modifier2)

Check warning on line 223 in src/makielayout/interactions.jl

View check run for this annotation

Codecov / codecov/patch

src/makielayout/interactions.jl#L222-L223

Added lines #L222 - L223 were not covered by tests
autolimits!(ax)
else
reset_limits!(ax)
Expand Down
41 changes: 25 additions & 16 deletions src/makielayout/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,22 @@
minortickvalues::Observable{Vector{Float32}}
end

struct LimitReset end

struct LimitReset
mouseevent::MouseEventTypes.MouseEventType # e.g. MouseEventTypes.leftclick, or some other mouse event to start limit reset.
modifier1::Optional{Keyboard.Button} # e.g. Keyboard.left_control, or some other keyboard button to reset limits.
modifier2::Optional{Keyboard.Button} # e.g. Keyboard.left_shift, or some other keyboard button to auto limits.

function LimitReset(
mouseevent = MouseEventTypes.leftclick,
modifier1 = Keyboard.left_control,
modifier2 = Keyboard.left_shift,
)
new(mouseevent, modifier1, modifier2)
end
end

mutable struct RectangleZoom
callback::Function
active::Observable{Bool}
restrict_x::Bool
restrict_y::Bool
Expand All @@ -162,8 +174,8 @@
modifier::Any # e.g. Keyboard.left_alt, or some other button that needs to be pressed to start rectangle... Defaults to `true`, which means no modifier needed
end

function RectangleZoom(callback::Function; restrict_x=false, restrict_y=false, modifier=true)
return RectangleZoom(callback, Observable(false), restrict_x, restrict_y,
function RectangleZoom(restrict_x=false, restrict_y=false, modifier=true)
return RectangleZoom(Observable(false), restrict_x, restrict_y,
nothing, nothing, Observable(Rect2d(0, 0, 1, 1)), modifier)
end

Expand All @@ -190,9 +202,8 @@
return DragPan(RefValue{Union{Nothing, Timer}}(nothing), RefValue{Union{Automatic, Float64}}(0.0), RefValue{Union{Automatic, Float64}}(0.0), reset_delay)
end

struct DragRotate end

struct DragRotate
end

struct ScrollEvent
x::Float32
Expand Down Expand Up @@ -679,8 +690,8 @@
end
end

function RectangleZoom(f::Function, ax::Axis; kw...)
r = RectangleZoom(f; kw...)

function registration_setup!(ax::Axis, r::RectangleZoom)
rect_scene = Scene(ax.scene)
selection_vertices = lift(_selection_vertices, rect_scene, Observable(ax.scene), ax.finallimits,
r.rectnode)
Expand All @@ -694,18 +705,16 @@
inspectable = false, transparency=true, overdraw=true, visible=r.active)
# translate forward so selection mesh and frame are never behind data
translate!(mesh, 0, 0, 1000)
return r

return ax
end

function RectangleZoom(ax::Axis; kw...)
return RectangleZoom(ax; kw...) do newlims
if !(0 in widths(newlims))
ax.targetlimits[] = newlims
end
return
end
function deregistration_cleanup!(ax::Axis, r::RectangleZoom)

Check warning on line 712 in src/makielayout/types.jl

View check run for this annotation

Codecov / codecov/patch

src/makielayout/types.jl#L712

Added line #L712 was not covered by tests
# TODO: Remove mesh?
return ax

Check warning on line 714 in src/makielayout/types.jl

View check run for this annotation

Codecov / codecov/patch

src/makielayout/types.jl#L714

Added line #L714 was not covered by tests
end


"""
Create a colorbar that shows a continuous or categorical colormap with ticks
chosen according to the colorrange.
Expand Down
Loading