factor/basis/ui/gestures/gestures.factor

327 lines
8.1 KiB
Factor
Raw Normal View History

2008-02-21 21:57:41 -05:00
! Copyright (C) 2005, 2008 Slava Pestov.
2007-09-20 18:09:08 -04:00
! See http://factorcode.org/license.txt for BSD license.
2008-11-23 04:22:56 -05:00
USING: accessors arrays assocs kernel math math.order models
namespaces make sequences words strings system hashtables
math.parser math.vectors classes.tuple classes boxes calendar
alarms combinators sets columns fry deques ui.gadgets
ui.gadgets.private unicode.case combinators.short-circuit ;
2007-09-20 18:09:08 -04:00
IN: ui.gestures
2008-08-23 00:27:25 -04:00
GENERIC: handle-gesture ( gesture gadget -- ? )
2007-09-20 18:09:08 -04:00
2008-08-23 00:27:25 -04:00
M: object handle-gesture
2009-01-25 18:55:27 -05:00
[ nip ]
[ class superclasses [ "gestures" word-prop ] map assoc-stack ] 2bi
dup [ call f ] [ 2drop t ] if ;
2007-09-20 18:09:08 -04:00
: set-gestures ( class hash -- ) "gestures" set-word-prop ;
: gesture-queue ( -- deque ) \ gesture-queue get ;
GENERIC: send-queued-gesture ( request -- )
TUPLE: send-gesture gesture gadget ;
M: send-gesture send-queued-gesture
[ gesture>> ] [ gadget>> ] bi handle-gesture drop ;
: queue-gesture ( ... class -- )
boa gesture-queue push-front notify-ui-thread ; inline
: send-gesture ( gesture gadget -- )
\ send-gesture queue-gesture ;
: each-gesture ( gesture seq -- ) [ send-gesture ] with each ;
2007-09-20 18:09:08 -04:00
TUPLE: propagate-gesture gesture gadget ;
2009-01-09 18:58:22 -05:00
: resend-gesture ( gesture gadget -- ? )
[ handle-gesture ] with each-parent ;
M: propagate-gesture send-queued-gesture
2009-01-09 18:58:22 -05:00
[ gesture>> ] [ gadget>> ] bi resend-gesture drop ;
2007-09-20 18:09:08 -04:00
: propagate-gesture ( gesture gadget -- )
\ propagate-gesture queue-gesture ;
TUPLE: propagate-key-gesture gesture world ;
: world-focus ( world -- gadget )
dup focus>> [ world-focus ] [ ] ?if ;
M: propagate-key-gesture send-queued-gesture
[ gesture>> ] [ world>> world-focus ] bi
[ handle-gesture ] with each-parent drop ;
: propagate-key-gesture ( gesture world -- )
\ propagate-key-gesture queue-gesture ;
TUPLE: user-input string world ;
M: user-input send-queued-gesture
[ string>> ] [ world>> world-focus ] bi
[ user-input* ] with each-parent drop ;
: user-input ( string world -- )
'[ _ \ user-input queue-gesture ] unless-empty ;
2007-09-20 18:09:08 -04:00
! Gesture objects
TUPLE: drag # ; C: <drag> drag
TUPLE: button-up mods # ; C: <button-up> button-up
TUPLE: button-down mods # ; C: <button-down> button-down
2009-01-28 20:18:35 -05:00
SINGLETONS:
motion
mouse-scroll
mouse-enter mouse-leave
lose-focus gain-focus ;
2008-04-11 23:33:01 -04:00
! Higher-level actions
2009-01-28 20:18:35 -05:00
SINGLETONS:
undo-action redo-action
cut-action copy-action paste-action
delete-action select-all-action
left-action right-action up-action down-action
zoom-in-action zoom-out-action ;
2007-09-20 18:09:08 -04:00
! Modifiers
2008-03-07 22:24:50 -05:00
SYMBOLS: C+ A+ M+ S+ ;
2007-09-20 18:09:08 -04:00
TUPLE: key-gesture mods sym ;
2007-09-20 18:09:08 -04:00
TUPLE: key-down < key-gesture ;
: new-key-gesture ( mods sym action? class -- mods' sym' )
2008-11-22 01:23:56 -05:00
[ [ [ S+ swap remove f like ] dip ] unless ] dip boa ; inline
2007-09-20 18:09:08 -04:00
: <key-down> ( mods sym action? -- key-down )
key-down new-key-gesture ;
2007-09-20 18:09:08 -04:00
TUPLE: key-up < key-gesture ;
2007-09-20 18:09:08 -04:00
: <key-up> ( mods sym action? -- key-up )
key-up new-key-gesture ;
2007-09-20 18:09:08 -04:00
! Hand state
! Note that these are only really useful inside an event
! handler, and that the locations hand-loc and hand-click-loc
! are in the co-ordinate system of the world which contains
! the gadget in question.
SYMBOL: hand-gadget
SYMBOL: hand-world
SYMBOL: hand-loc
{ 0 0 } hand-loc set-global
SYMBOL: hand-clicked
SYMBOL: hand-click-loc
SYMBOL: hand-click#
SYMBOL: hand-last-button
SYMBOL: hand-last-time
0 hand-last-button set-global
2008-11-23 04:22:56 -05:00
<zero> hand-last-time set-global
2007-09-20 18:09:08 -04:00
SYMBOL: hand-buttons
V{ } clone hand-buttons set-global
SYMBOL: scroll-direction
{ 0 0 } scroll-direction set-global
SYMBOL: double-click-timeout
300 milliseconds double-click-timeout set-global
2007-09-20 18:09:08 -04:00
: hand-moved? ( -- ? )
hand-loc get hand-click-loc get = not ;
: button-gesture ( gesture -- )
hand-clicked get-global propagate-gesture ;
2007-09-20 18:09:08 -04:00
: drag-gesture ( -- )
2008-05-07 09:48:42 -04:00
hand-buttons get-global
2008-09-06 20:13:59 -04:00
[ first <drag> button-gesture ] unless-empty ;
2007-09-20 18:09:08 -04:00
SYMBOL: drag-timer
2007-09-20 18:09:08 -04:00
<box> drag-timer set-global
2007-09-20 18:09:08 -04:00
: start-drag-timer ( -- )
hand-buttons get-global empty? [
[ drag-gesture ]
2008-07-08 16:50:38 -04:00
300 milliseconds hence
100 milliseconds
add-alarm drag-timer get-global >box
2007-09-20 18:09:08 -04:00
] when ;
: stop-drag-timer ( -- )
hand-buttons get-global empty? [
2008-03-12 02:34:37 -04:00
drag-timer get-global ?box
[ cancel-alarm ] [ drop ] if
2007-09-20 18:09:08 -04:00
] when ;
: fire-motion ( -- )
hand-buttons get-global empty? [
motion hand-gadget get-global propagate-gesture
2007-09-20 18:09:08 -04:00
] [
drag-gesture
] if ;
: hand-gestures ( new old -- )
drop-prefix <reversed>
mouse-leave swap each-gesture
mouse-enter swap each-gesture ;
2007-09-20 18:09:08 -04:00
: forget-rollover ( -- )
f hand-world set-global
hand-gadget get-global
[ f hand-gadget set-global f ] dip
parents hand-gestures ;
2007-09-20 18:09:08 -04:00
: send-lose-focus ( gadget -- )
lose-focus swap send-gesture ;
2007-09-20 18:09:08 -04:00
: send-gain-focus ( gadget -- )
gain-focus swap send-gesture ;
2007-09-20 18:09:08 -04:00
: focus-child ( child gadget ? -- )
[
2008-08-29 19:44:19 -04:00
dup focus>> [
2007-09-20 18:09:08 -04:00
dup send-lose-focus
f swap t focus-child
] when*
2008-08-29 19:44:19 -04:00
dupd (>>focus) [
2007-09-20 18:09:08 -04:00
send-gain-focus
] when*
] [
2008-08-29 19:44:19 -04:00
(>>focus)
2007-09-20 18:09:08 -04:00
] if ;
: modifier ( mod modifiers -- seq )
[ second swap bitand 0 > ] with filter
2008-09-06 20:13:59 -04:00
0 <column> prune [ f ] [ >array ] if-empty ;
2007-09-20 18:09:08 -04:00
: drag-loc ( -- loc )
hand-loc get-global hand-click-loc get-global v- ;
: hand-rel ( gadget -- loc )
hand-loc get-global swap screen-loc v- ;
: hand-click-rel ( gadget -- loc )
hand-click-loc get-global swap screen-loc v- ;
2007-11-22 14:21:32 -05:00
: multi-click-timeout? ( -- ? )
now hand-last-time get time- double-click-timeout get before=? ;
2007-11-22 14:21:32 -05:00
: multi-click-button? ( button -- button ? )
dup hand-last-button get = ;
: multi-click-position? ( -- ? )
2008-11-29 11:38:27 -05:00
hand-loc get hand-click-loc get distance 10 <= ;
2007-11-22 14:21:32 -05:00
2007-09-20 18:09:08 -04:00
: multi-click? ( button -- ? )
2007-11-22 14:21:32 -05:00
{
2008-04-05 08:57:51 -04:00
{ [ multi-click-timeout? not ] [ f ] }
{ [ multi-click-button? not ] [ f ] }
{ [ multi-click-position? not ] [ f ] }
{ [ multi-click-position? not ] [ f ] }
2008-04-11 13:54:33 -04:00
[ t ]
2008-04-05 08:57:51 -04:00
} cond nip ;
2007-09-20 18:09:08 -04:00
: update-click# ( button -- )
global [
dup multi-click? [
hand-click# inc
] [
1 hand-click# set
] if
hand-last-button set
now hand-last-time set
2007-09-20 18:09:08 -04:00
] bind ;
: update-clicked ( -- )
hand-gadget get-global hand-clicked set-global
hand-loc get-global hand-click-loc set-global ;
: under-hand ( -- seq )
hand-gadget get-global parents <reversed> ;
: move-hand ( loc world -- )
dup hand-world set-global
under-hand [
over hand-loc set-global
pick-up hand-gadget set-global
under-hand
] dip hand-gestures ;
2007-09-20 18:09:08 -04:00
: send-button-down ( gesture loc world -- )
move-hand
start-drag-timer
dup #>>
2007-09-20 18:09:08 -04:00
dup update-click# hand-buttons get-global push
update-clicked
button-gesture ;
: send-button-up ( gesture loc world -- )
move-hand
dup #>> hand-buttons get-global delete
2007-09-20 18:09:08 -04:00
stop-drag-timer
button-gesture ;
: send-wheel ( direction loc world -- )
move-hand
scroll-direction set-global
mouse-scroll hand-gadget get-global propagate-gesture ;
2007-09-20 18:09:08 -04:00
: send-action ( world gesture -- )
swap world-focus propagate-gesture ;
2007-09-20 18:09:08 -04:00
GENERIC: gesture>string ( gesture -- string/f )
HOOK: modifiers>string os ( modifiers -- string )
M: macosx modifiers>string
[
{
{ A+ [ "⌘" ] }
{ M+ [ "⎇" ] }
{ S+ [ "⇧" ] }
{ C+ [ "⌃" ] }
} case
] map "" join ;
M: object modifiers>string
[ name>> ] map "" join ;
2007-09-20 18:09:08 -04:00
M: key-down gesture>string
[ mods>> ] [ sym>> ] bi
dup { [ length 1 = ] [ upper? ] } 1&&
[ [ S+ prefix ] dip ] [ >upper ] if
[ modifiers>string ] dip append ;
2007-09-20 18:09:08 -04:00
M: button-up gesture>string
[
dup mods>> modifiers>string %
2007-09-20 18:09:08 -04:00
"Click Button" %
#>> [ " " % # ] when*
2007-09-20 18:09:08 -04:00
] "" make ;
M: button-down gesture>string
[
dup mods>> modifiers>string %
2007-09-20 18:09:08 -04:00
"Press Button" %
#>> [ " " % # ] when*
2007-09-20 18:09:08 -04:00
] "" make ;
2008-04-12 19:06:01 -04:00
M: left-action gesture>string drop "Swipe left" ;
M: right-action gesture>string drop "Swipe right" ;
M: up-action gesture>string drop "Swipe up" ;
M: down-action gesture>string drop "Swipe down" ;
M: zoom-in-action gesture>string drop "Zoom in" ;
M: zoom-out-action gesture>string drop "Zoom out (pinch)" ;
2007-09-20 18:09:08 -04:00
M: object gesture>string drop f ;