name: inverse layout: true class: center, middle, inverse --- layout: false .title[# Hall of Fame/Shame] .body[ ![:img Picture of the course website with the mouse clicking on an unresponsive hamburger menu,80%](img/noresponse.png) ] --- 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[ ![:img Picture of quiz results for the question about events. The question is "Which of these is not an event?" and the most popular answer is "CTRL (key pressed)" but many people also chose "WindowOpen" and "4"., 80%](img/notevent.png) ] --- .title[When is focus used?] .body[![:img Picture of quiz results for the question about focus. The question is "In which of the following situations is focused used during event handling?" and many people correctly chose "When a mouse moves off a scrollbar" but others chose things like "When selecting a word in a text area" and "When clicking on a button", 80%](img/focus.png) ] --- .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? ![:img FB Messenger Animation, 100%](img/messenger-bubble.gif) ] .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 ![:img FB Messenger Animation, 100%](img/messenger-bubble.gif) ] -- .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[![:img Picture of a menu with two items pulled down, 105%](img/menu.png)] .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 ] --- ![:img Picture of a menu with two items pulled down, 25%](img/menu.png)
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