name: inverse layout: true class: center, middle, inverse --- # Undo reasoning and implementation Jennifer Mankoff CSE 340 Winter 2021 --- layout: false [//]: # (Outline Slide) # Today's goals - Introduce need for Undo by reviewing mental models - Introduce Undo conceptually - Describe Implementation details for assignment --- # Review: Every system has at least 3 different models
graph TD S[System Image:
Your Implementation ] --> |System Feedback | U[User Model: How the user thinks
the system works] D[Design Model: How you
intend the system to work ]-->S U -->|User Feedback | S
--- # Relating the Human and the Interaction .column[  ] .column[  ] -- .column[  ] .footnote[[Don Norman, When Three World Collide: A model of the Tangible Interaction Process, 2009](https://www.researchgate.net/publication/221332102_When_three_worlds_collide_A_model_of_the_tangible_interaction_process)] ??? Note to instructors: Need to change image to mermaid --- # Relating the Human and the Interaction .doublecolumn[ **Gulf of Execution** is the user's believe in the functions the system _doesn't have_ - This is the users 'error' region **Gulf of Evaluation** is where the user _doesn't realize the system HAS a functionality_. ] .column[  ] --- # Design Model What the system designer thinks the system does ("design model")  --- # Implementation Model What the system actually does ("system image")  --- # User's Mental Model What the user knows about the system ("mental model")  --- # User's Mental Model What the user knows about the system ("mental model")  --- # User's Mental Model What the user knows about the system ("mental model")  --- # User's Mental Model Everything the user thinks they know ("mental model") .left-column50[  ] --- # Relating Gulfs and Mental Models .left-column50[  ] .right-column50[ What happens when the user does something they think is core but is really not supported? ] -- .right-column50[ - Need to undo! ] --- class: center, middle, inverse # How do we support Undo? --- layout:false .left-column-half[ ## Remember this? ] .right-column-half[ Dispatch Strategies - Bottom-first and top-down positional - Focus-based State Machine describes *within-view* response to events ] --- .left-column-half[ ## Event Dispatch ] .right-column-half[ Callbacks handle *application* response to events - Update Application Model ] --- .left-column-half[ ## Event Dispatch ] .right-column-half[ Callbacks handle *application* response to events - Update Application Model - Best implemented using custom listeners ] --- # What is `ActionPerformed`? `Higher level` input event (`Command` or `Action` object) - Puts some separation between UI and translation objects - Application (or UI) can ‘listen’ for these events: Key advantage: interactors don’t need to know who/what got notification Same basic flow as simple callbacks --- # What should an Action object do? `doAction()` ??? seems like a lot of work when we could just directly do the action. Major reason for action objects -- `undoAction()` ??? What additional information do we need to undo an action? --- # Advantages of an action object .left-column[ - can be stored on an undo stack - can create a consistent abstraction for reversing an action ] .right-column[
classDiagram AbstractAction <|.. AbstractReversibleAction AbstractReversibleAction <|.. ChangeColorAction AbstractReversibleAction <|.. ChangeThicknessAction AbstractReversibleAction <|.. AbstractReversibleViewAction AbstractReversibleViewAction <|.. StrokeAction class AbstractAction { doAction() } class AbstractReversibleAction { +boolean done +undoAction() } class AbstractReversibleViewAction { +invalidate }
] --- # Where do we store actions? A stack .left-column50[
classDiagram AbstractStackHistory <|.. StackHistory class AbstractStackHistory { addAction(AbstractReversibleAction action) undo() redo() canUndo() canRedo() } class StackHistory { +capacity: "Max stack size" }
] .right-column50[ Why a stack? ] ??? Consider having some volunteers be actions and have them act it out? --- # Undo and Redo 1) new action object created and `doAction()` called 2) Undo stack updated 3) new action object created and `doAction()` called 4) Undo stack updated 5) `undo()` invoked 6) Undo stack reduced and Redo stack increased 7) `undo()` invoked 8) Undo stack reduced and Redo stack increased ??? draw sequence --- # Undo and Redo 9) `redo()` invoked 10) Redo stack decreased and Undo stack increased 11) new action object created and `doAction()` called 12) Redo stack cleared and Undo stack stack increased --- # What if an action can't be undone? Actions that put system into a totally different context Clear both `undo` *and* `redo` stacks! Users may hate you ??? example? Saving a file --- # Implementing undo() System pops action off undo stack Calls `undoAction()` method on it Pushes it on redo stack --- # Why is undoAction() hard? Two ways to implement `undoAction()`: - *Direct Code* (each action object has custom code) - Need parameters of original action - Better store in `doAction()` for later - This is what we will implement --- # Why is undoAction() hard? Two ways to implement `undoAction()`: - *Direct Code* (each action object has custom code) - *Change Records* (Keep a record of the “old value” for everything changed by the application, then put all those values back to undo) - Like some version control systems - More general - Takes more space - `Action` object records `ChangeRecord` (changes which are abstracted into a common data format) - Application has to provide code to restore from change records --- # Implementing redo() System pops action off redo stack Calls `doAction()` method Pushes it on undo stack --- # More sophisticated forms of Undo Explicit visualization of steps Manipulation of action list Delete actions from the middle, reorder, etc. by undoing back to point of change then redoing forward But note: doAction() must be able to work in new context --- # Flatland: Semantic Undo .left-column30[  ] .right-column60[  ] .footnote[ Edwards, W. K. ; Igarashi, T. ; LaMarca, A .; Mynatt, E. D. A temporal model for multi-level undo and redo. UIST 2000, Proceedings of 13th Annual ACM Symposium on User Interface Software and Technology; 2000 November 5-8; San Diego, CA. NY: ACM; 2000; 31-40. ] --- # Discussion of assignment Android Goals: - Be able to understand and modify an existing user interface - Learn about floating action buttons - Implement core data structure for Undo HCI Goals - Modify and existing app in a consistent fashion - Make your modifications accessible - Make your modifications usable Open ended portion: Implement something new --- # Discussion of assignment .left-column-half[ ![:youtube Video of assignment, F5FyW3YJ0x4] ] .right-column-half[ ![:youtube Video of assignment, NhUE7GgH-vc] ] --- # Discussion of assignment .left-column[ Like accessibility, you are modifying a fully working program Lots to explore/understand e.g. FAB buttons) ] -- .right-column[
graph TD M[ReversibleDrawingActivity] --> D[DrawingView] M --> FUndo[FAB:Undo] M --> FRedo[FAB:Redo] M --> FColor[FAB:Color] M --> FThick[FAB:Thickness] FColor --> Red[Red] FColor --> Green[Green] FColor --> Blue[Blue] FThick --> Thin[Thin] FThick --> Med[Med] FThick --> Thick[Thick] classDef normal fill:#e6f3ff,stroke:#333,stroke-width:2px; classDef start fill:#d1e0e0,stroke:#333,stroke-width:4px; class M,D,FColor,FThick,Vis start class Red,Green,Blue,Thin,Med,Thick,Hid normal
] --- # Discussion of assignment .left-column[ DrawingView: Holds strokes FABs: - Green ones are always visible - Purple ones are only visible when active ] .right-column[
graph TD M[ReversibleDrawingActivity] --> D[DrawingView] M --> FUndo[FAB:Undo] M --> FRedo[FAB:Redo] M --> FColor[FAB:Color] M --> FThick[FAB:Thickness] FColor --> Red[Red] FColor --> Green[Green] FColor --> Blue[Blue] FThick --> Thin[Thin] FThick --> Med[Med] FThick --> Thick[Thick] classDef normal fill:#e6f3ff,stroke:#333,stroke-width:2px; classDef start fill:#d1e0e0,stroke:#333,stroke-width:4px; class M,D,FColor,FThick,Vis start class Red,Green,Blue,Thin,Med,Thick,Hid normal
] --- # Code deliverables There are five parts for the coding part of this assignment: - Part 1: Implement `ChangeThicknessAction` - Part 2: Implement history - Part 3: Add a thickness 0 FAB to the thickness menu - Part 4: Integrate colorpicker - Part 5: Your own Undo-able thing ---