# [CSE 340](/courses/cse340/23wi/schedule.html) Lab 7 Winter 23 ## Week 7: Getting started with Undo .title-slide-logo[ ![:img Drawing App, 40%, width](img/draw-app.jpg) ] --- # HW Timeline - **Menus Report Due**: Thur 16-Feb - Undo - Code & Video Due: Fri 24-Feb - Undo Reflection Due: Sun 26-Feb --- # Section 7 Objectives - [Undo concept](#undo) - The Undo [codebase](#codebase) - [DrawingView](#drawingview) - [Actions](#actions) - [History](#history) - [Section Exercise](#exercise) - [Color Pickers](#colorpickers) in Undo - [Tips](#tips) for Starting --- name: undo # The Undo feature - Incredibly useful interaction technique - Reverts the application to an older state - Mistakes can easily be undone ![:img Circular arrow pointing counterclockwise, 10%, width](img/undo.png) --- # The Redo feature - Inverse to the Undo feature - "Undoes" an undo - Work previously undone is reapplied - *"Huh, maybe I made the right decision after all..."* ![:img Circular arrow pointing clockwise, 10%, width](img/redo.png) --- name: codebase # Codebase: Application .left-column30[
classDiagram AbstractDrawingActivity <|.. AbstractReversibleDrawingActivity AbstractReversibleDrawingActivity <|.. ReversibleDrawingActivity class AbstractDrawingActivity { DrawingView: "Canvas the user draws on" addMenu() addCollapsableMenu() doAction() } class AbstractReversibleDrawingActivity { +AbstractHistory +doAction() +undo() +redo() } class ReversibleDrawingActivity { +onAction() +onColorMenuSelected() +onThicknessMenuSelected() }
] .right-column70[ - `ReversibleDrawingActivity`, class contains the entire interactor hierarchy - Floating Action Buttons (FAB), buttons that allow for actions supported by `AbstractReversibleDrawingActivity` - References DrawingView in `AbstractDrawingActivity` - `AbstractReversibleDrawingActivity`, abstract class that extends AbstractDrawingActivity - Adds **support for undo/redo** - Includes buttons for undo/redo - `doAction()`, `undo()`, `redo()`] --- # Codebase: Application .left-column30[
classDiagram AbstractDrawingActivity <|.. AbstractReversibleDrawingActivity AbstractReversibleDrawingActivity <|.. ReversibleDrawingActivity class AbstractDrawingActivity { DrawingView: "Canvas the user draws on" addMenu() addCollapsableMenu() doAction() } class AbstractReversibleDrawingActivity { +AbstractHistory +doAction() +undo() +redo() } class ReversibleDrawingActivity { +onAction() +onColorMenuSelected() +onThicknessMenuSelected() }
] .right-column70[ - `AbstractDrawingActivity` - abstract class for app that supports drawing **without history** - Wrapper around a `DrawingView` - `doAction()` - Contains methods for adding menus and changing visibility] --- name: drawingview # Codebase: DrawingView - `AbstractDrawingActivity` is a wrapper around a `DrawingView` - Sets behavior for how strokes are drawn - `DrawingView` is a drawing canvas that handles strokes - Strokes are `StrokeView`'s added to the `DrawingView` - `onTouchEvent()` implements a PPS that describes lifetime of a stroke being created
classDiagram class AbstractDrawingActivity { DrawingView: "Canvas the user draws on" addMenu() addCollapsableMenu() doAction() } class StrokeView { Path onDraw() }
--- name: actions # Codebase: Actions .left-column40[ - `AbstractAction` defines **basic** behavior any Action should have - `AbstractReversibleAction` defines interface for actions that can be **undone** ] .right-column50[
classDiagram AbstractAction <|.. AbstractReversibleAction AbstractReversibleAction <|.. ChangeColorAction AbstractReversibleAction <|.. ChangeThicknessAction AbstractReversibleAction <|.. AbstractReversibleViewAction AbstractReversibleViewAction <|.. StrokeAction class AbstractAction { doAction() } class AbstractReversibleAction { +boolean done +undoAction } class AbstractReversibleViewAction { +invalidate }
] --- # Codebase: Actions .left-column40[ - Action Types: - `ChangeColorAction` - `ChangeThicknessAction`, **implement this in your homework!** - `StrokeAction` - And more, create your own action!] .right-column55[
classDiagram AbstractAction <|.. AbstractReversibleAction AbstractReversibleAction <|.. ChangeColorAction AbstractReversibleAction <|.. ChangeThicknessAction AbstractReversibleAction <|.. AbstractReversibleViewAction AbstractReversibleViewAction <|.. StrokeAction class AbstractAction { doAction() } class AbstractReversibleAction { +boolean done +undoAction } class AbstractReversibleViewAction { +invalidate }
] --- name: deeper-dive # Codebase: Actions (a deeper dive) - What happens when `doAction()` is called from `ReversibleDrawingActivity`...? - `doAction()` in `AbstractReversibleDrawingActivity` - `AbstractReversibleDrawingActivity#doAction()` then calls `AbstractDrawingActivity#doAction()` - Which in turn calls `AbstractAction#doAction()` - `AbstractReversibleDrawingActivity`'s `undo()` and `redo()` will call `AbstractReversibleAction`'s' `undoAction/doAction()`, as well as update the Model `mModel`. --- name: history # Codebase: History .left-column60[The `AbstractReversibleDrawingActivity` uses an StackHistory interface to manage the undo/redo history - You will implement the concrete `StackHistory` which implements `AbstractHistory`] .right-column30[
classDiagram AbstractHistory <|.. StackHistory class AbstractHistory { addAction(AbstractReversibleAction action) undo() redo() canUndo() canRedo() } class StackHistory { +capacity: "Max stack size" }
] --- # Codebase: History - What data structure is used to track history? Why does this make sense? -- - What happens to the redo history if you take a new action after undoing a couple times? - What happens to the undo history if you redo an action? - What happens to the redo history if you undo an action? -- - Paint applications like [Adobe Photoshop](https://youtu.be/Tx_aQbn-DEA?t=47) utilize undo and redo stacks (you can visually see the actions you've taken). --- name: exercise # Section Exercise: History Stack Considering the [History Table](https://courses.cs.washington.edu/courses/cse340/23wi/assignments/undo.html#undoredo-behavior) in the spec, fill in the blanks below. Assume 2,1 means a stack with 1 on top. | Action | Undo Stack | Redo Stack | | :-------------------- | :----------: | ----------: | | change color (1) | 1 | empty | | change color (2) | 1,2 | empty | | undo | ? (a) | 2 | | undo | empty | ? (b) | | redo | 1 | 2 | | drawstroke (3) | 1,3 | empty (CLEARED) | | undo | 1 | 3 | | change thickness (4) | 1,4 | ? (c) | What are (a), (b), and (c)? Turn in your answers to Ed. --- # Section Exercise: History Stack answers - (a) **1**, 2 was put in the redo stack after it was undone - (b) **2,1**, both 2 and 1 were undone - (c) **empty (CLEARED)**, a new Action was taken (change thickness), so redo stack must be cleared | Action | Undo Stack | Redo Stack | | :-------------------- | :----------: | ----------: | | change color (1) | 1 | empty | | change color (2) | 1,2 | empty | | undo | 1 | 2 | | undo | empty | 2,1 | | redo | 1 | 2 | | drawstroke (3) | 1,3 | empty (CLEARED) | | undo | 1 | 3 | | change thickness (4) | 1,4 | empty (CLEARED) | --- name: colorpickers # Color Pickers - We will be giving you Color Pickers to use in your drawing app Undo in XML form. Please choose one of them (they are in your base code under `cse340/undo/app/colorpicker`). - **Replace the Color Picker included in the layout XML file with the name of the color picker** you choose. Below is an example. ![:img , 70%, width](img/example-include-colorpicker.png) --- # Listening for Changes to Color Picker - Remember how to [register events listeners](../wk05/event-handling.html#19) and [implement custom listeners](../wk05/menus.html#19) from lecture? - Who is announcing changes in the color picker and who is listening? -- - Listener + Callback - Get ReversibleDrawingActivity to "listen in" on changes (register listener) - ReversibleDrawingActivity should define how it will "react" to the change (callback) --- name: tips # Tips for Starting Undo - Read the whole spec - Go to Office Hours to clarify spec EARLY - Understand how the stack works: draw it out when you’re trying to debug - Be able to trace the stack - Utilize the scenario provided in the spec to ensure that your stack behaves correctly