name: inverse layout: true class: center, middle, inverse --- layout: false .title[# Hall of Fame/Shame] .body[  ] --- class: inverse, center, middle .title[# From Events to Behavior] .body[ Jennifer Mankoff CSE 340 Spring 2019 ] --- [//]: # (Outline Slide) .title[# Today's goals] .body[ Review / Quiz Introduce interaction techniques Discuss use of Propositional Production Systems in implementing them Try creating a PPS ] --- .title[What is part of an event?] .body[  ] --- .title[When is focus used?] .body[ ] --- .left-column[ ## Interaction Technique] .right-column[ A method for carrying out a specific interactive task Example: enter a number in a range could use... ] ??? have the class try to think of examples -- .right-column[ - (simulated) slider - (simulated) knob - type in a number (text edit box) Each is a different interaction technique ] --- .left-column[ ## Example: Specify the end points for a line ] .right-column[ Could just specify two endpoints – click, click - not good: no affordance,
no feedback (/ feedforward) Better feedback is to use “rubber banding” - stretch out the line as you drag - at all times, shows where you would end up
if you “let go” ] ??? Importance of feedback vs application callback --- .left-column[ ## Implementing rubber banding] .large.right-column[ ``` Accept the press for endpoint P1; P2 = P1; Draw line P1-P2; Repeat Erase line P1-P2; P2 = current_position(); Draw line P1-P2; Until release event; Act on line input; ``` ] ??? Discuss! Not event based Not in the basic event/redraw loop Potentially locks up the system --- .left-column[ ## Implementing rubber banding] .right-column[ Need to get around this loop
absolute min of 5 times / sec – 10 times better – more would be better ] ??? aside -- why 5-10 times per second? --- .left-column[## Event driven code] .right-column[ Needs to respond to events as they arrive Needs to maintain state between events ] --- .left-column[ # Solution: Propositional Production Systems] .right-column[
graph LR S((.)) --> A((A)) A -- "Event/Callback()" --> B((B)) B -- "Event2/Callback2()" --> C[C] classDef finish outline-style:double,fill:#d1e0e0,stroke:#333,stroke-width:2px; classDef normal fill:#e6f3ff,stroke:#333,stroke-width:2px; classDef start fill:#d1e0e0,stroke:#333,stroke-width:4px; classDef invisible fill:#FFFFFF,stroke:#FFFFFF,color:#FFFFFF linkStyle 0 stroke-width:4px; linkStyle 1 stroke-width:4px; linkStyle 2 stroke-width:4px; class S invisible class A start class C finish class B normal
Special circle start state
(arrow going into it) Special circle for 'final state'
(really means 'reset to start') Transitions represent actions (callbacks). ] ??? --- .left-column[ # PPS Example: Rubber Banding Compare to previous implementation: ``` Accept the press for endpoint P1; P2 = P1; Draw line P1-P2; Repeat Erase line P1-P2; P2 = current_position(); Draw line P1-P2; Until release event; Act on line input; ``` ] .right-column[ - Determine the Events (triggers) - Determine the States - Determine the Actions - Determine the Queries ] --- .left-column[ # PPS Example: Rubber Banding Compare to previous implementation: ``` Accept the press for endpoint P1; P2 = P1; Draw line P1-P2; Repeat Erase line P1-P2; P2 = current_position(); Draw line P1-P2; Until release event; Act on line input; ``` ] .right-column[
graph LR S((.)) --> A((Start)) A -- "Mouse Down:?inView/Start_Line()" --> B((Drawing)) B -- "Mouse_Move:?inView/Update()" --> B B -- "Mouse_Release:?inView/Finish_Line()" --> C[Finished] classDef finish outline-style:double,fill:#d1e0e0,stroke:#333,stroke-width:2px; classDef normal fill:#e6f3ff,stroke:#333,stroke-width:2px; classDef start fill:#d1e0e0,stroke:#333,stroke-width:4px; classDef invisible fill:#FFFFFF,stroke:#FFFFFF,color:#FFFFFF linkStyle 0 stroke-width:4px; linkStyle 1 stroke-width:4px; linkStyle 2 stroke-width:4px; linkStyle 3 stroke-width:4px; class S invisible class A start class C finish class B normal
] ??? Means: When you are in Start State, and a Mouse Down event arrives, do the action ```Start_line()``` and go to Drawing State. Then update the line end point position every time the mouse moves. Finally, when it releases (Mouse Release event), finish the line (at this stage a callback to the application might be appropriate) - translates input sequence into action! - How could we provide a better affordance? - Does it matter if we are using a mouse or a touch screen? --- .left-column[##Summary] .right-column[ State machines are very good (for this job) but do have limits State machines don't handle independent actions very well (state explosion) Mostly useful for smaller things - Great for individual components - Not so great for whole dialogs Path of least resistance is rigid sequencing Ask: is this good for what I am doing? ] ??? xxx TODO decide whether to keep xxx TODO decide how to end this deck and/or what other material needs to be covered --- .left-column[## Guards on transitions] .right-column[ Sometimes also use “guards” --> **Propositional Production System** - predicate (Boolean expr) before event - adds extra conditions required to fire - typical notation: pred : event / action - e.g. button.enabled: press-inside / A Note: FSM augmented with guards is Turing complete ] --- .left-column[ ## PPS for Button?  ] .right-column[ - Determine the Events (triggers) - Determine the States - Determine the Queries (essential geometry, context) - Determine the Actions ] ??? What constitutes an “event” varies - may be just low level events, or - higher level (synthesized) events - e.g. region-enter, press-inside What is missing? Query fields --- .left-column[ ## Facebook Button Solution  ] -- .right-column[ Press:?inside => highlight(), start_animation(), small, active
AnimateStep ==> update(), active
AnimateFinish ==> !small, active
Release:inside,small => unhighlight(), exit()
Release:inside,!small => add_to_chat(), small, unhighlight(), exit()
__rest is unknowable from this animation__
graph LR S((.)) --> A((Start)) A -- "Press:?inside/highlight(), start_animation()" --> B((Active)) B -- "AnimateStep,update()" --> B B -- "AnimateFinish,!small"--> B B -- "Release,inside:small, unhighlight" -->D(End) B -- "Release,inside:!small,add_to_chat(),unhighlight()" --> D classDef finish outline-style:double,fill:#d1e0e0,stroke:#333,stroke-width:2px; classDef normal fill:#e6f3ff,stroke:#333,stroke-width:2px; classDef start fill:#d1e0e0,stroke:#333,stroke-width:4px; classDef invisible fill:#FFFFFF,stroke:#FFFFFF,color:#FFFFFF linkStyle 0 stroke-width:4px; linkStyle 1 stroke-width:4px; linkStyle 2 stroke-width:4px; linkStyle 3 stroke-width:4px; linkStyle 4 stroke-width:4px; linkStyle 5 stroke-width:4px; class S invisible class A start class D finish class B normal
] --- .left-column[ ## When to use PPSs ] .right-column[ - You're probably already using them, just not intentionally (and maybe less well as a result) - PPSs are a good way to do control flow in event driven systems Can do (formal or informal) analysis - are all possible inputs (e.g. errors) handled from each state - what are next legal inputs: can use to enable / disable Can be automated based on higher level specification ] --- .left-column[ ## Implementation of PPS ] ??? ``` fsm_transition(state, evt) switch (state) ..case 0: // case for each state ...switch(evt.kind) ...case loc_move: // transition event ....do all the transition actions ....state = 42 // set the new state ..case 1: // case for next state switch (evt.kind) ... return state; ``` --- layout: false .title[Exercise: Build your own color picker] .body[ Learning goals: - Create non-rectangle interactor - Use a state machine to manage feedback - Callbacks: React to events - Should handle error cases appropriately Android learning goals: - Save app state - Handle touch input properly - Understand app lifecycle ] ??? --- .title[Color Picker PPS ] .body[Work in pairs on this] --- .left-column[] .right-column[ ## Another example: Pull-down Menu How do we manage the drop-down behavior? FSM controller? ] -- .right-column[ Behavior: - Body pulls down on press (in arrow) - Body stays down until release - Items highlighted while cursor is over them ] --- 
graph LR A((Start)) -- "Dn-inside-Top/Drop()" --> N((NotIn)) N -- "Enter-Item1/Highlight(1)" --> I((In1)) I -- "Enter-Item2/Highlight(2)" --> II N -- "Enter-Item2/Highlight(2)" --> II((In2)) I -- "Exit-Item1/Highlight(none)" --> N II -- "Enter-Item1/Highlight(1)" --> I I -- "Up/Fire-Item(1)" -->E((End)) II -- "Up/Fire-Item(2)"-->E((End)) II -- "Exit-Item2/Highlight(none)" --> N N -- "Up/UnDrop()" --> F((End))
--- .title[ Summary] .body[ - Interaction technique: involves input AND feedback - Propositional Production Systems let us implement feedback - event driven - actions on **transitions** - guards (conditionals) on **transitions** ] --- #End of Slides / Old material below here --- .left-column[# Discussion of state explosion] .right-column[ Take a button, and a control key (can you draw the state machine for the control key?) ] -- .right-column[Combine them (cross product)]
graph TD A(( )) --> B(( )) B --> A
graph LR A(( )) --> B(( )) B --> C(( )) C --> B C --> D(( )) B --> End(( ))
--- .left-column[# Cross product of state diagrams] .right-column[ Replicate the larger one Once for every state in the smaller one! At transitions between corresponding states Correct semantics - Eliminate impossible states - Merge similar ones Now add another independent machine (shift key?) ] ??? Totally out of hand -- combinatorical explosion!
layout: true