Skip to content

Commit

Permalink
Merge pull request #360 from RAIRLab/270-undo-redo-buttons
Browse files Browse the repository at this point in the history
Undo and Redo Shortcuts!
  • Loading branch information
James-Oswald authored Apr 13, 2024
2 parents 83ae286 + f054fe1 commit 8a40d13
Show file tree
Hide file tree
Showing 30 changed files with 642 additions and 548 deletions.
771 changes: 301 additions & 470 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions src/AEG-IO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {AtomNode} from "./AEG/AtomNode";
import {CutNode} from "./AEG/CutNode";
import {Ellipse} from "./AEG/Ellipse";
import {Point} from "./AEG/Point";
import {ProofNode} from "./Proof/ProofNode";
import {ProofModeMove, ProofModeNode} from "./ProofHistory/ProofModeNode";

/**
* Describes The Sheet of Assertion in JSON files.
Expand Down Expand Up @@ -45,21 +45,21 @@ interface atomObj {
*/
interface proofNodeObj {
tree: sheetObj;
appliedRule: string;
appliedRule: ProofModeMove;
}

/**
* Creates and saves a file to the incoming FileSystemFileHandle
* and containing the incoming save data.
*
* The save data will either be an AEGTree from Draw Mode or a series of ProofNodes from Proof Mode.
* The save data will either be an AEGTree from Draw Mode or a series of ProofModeNodes from Proof Mode.
*
* @param handle Incoming FileSystemFileHandle.
* @param aegData Incoming save data.
*/
export async function saveFile(
handle: FileSystemFileHandle,
saveData: AEGTree | ProofNode[]
saveData: AEGTree | ProofModeNode[]
): Promise<void> {
const data: string = JSON.stringify(saveData, null, "\t");

Expand All @@ -74,22 +74,22 @@ export async function saveFile(
*
* @param mode Incoming mode string.
* @param fileData Incoming data read from a file.
* @returns AEGTree representation of fileData if in Draw Mode. Otherwise, a series of ProofNodes.
* @returns AEGTree representation of fileData if in Draw Mode. Otherwise, a series of ProofModeNodes.
*/
export function loadFile(mode: "Draw" | "Proof", fileData: string): AEGTree | ProofNode[] {
export function loadFile(mode: "Draw" | "Proof", fileData: string): AEGTree | ProofModeNode[] {
const data = JSON.parse(fileData);

if (mode === "Draw") {
const childData: (atomObj | cutObj)[] = (data as sheetObj).internalSheet.internalChildren;
return toTree(childData);
} else {
//Construct the tree at every step of the proof and store them in an array
const arr: ProofNode[] = [];
const arr: ProofModeNode[] = [];

let node: proofNodeObj;
for (node of data) {
const childData: (atomObj | cutObj)[] = node.tree.internalSheet.internalChildren;
arr.push(new ProofNode(toTree(childData), node.appliedRule));
arr.push(new ProofModeNode(toTree(childData), node.appliedRule));
}

return arr;
Expand Down
38 changes: 38 additions & 0 deletions src/DrawHistory/DrawModeNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* @file Contains the DrawModeNode class, which defines a step taken in Draw Mode.
* Also contains the DrawModeMove enum.
*
* @author Ryan R
*/

import {AEGTree} from "../AEG/AEGTree";

export enum DrawModeMove {
CLEAR,
DRAW_ATOM,
DRAW_CUT,
MOVE_SINGLE,
MOVE_MULTI,
COPY_SINGLE,
COPY_MULTI,
DELETE_SINGLE,
DELETE_MULTI,
RESIZE,
COPY_GRAPH,
}

export class DrawModeNode {
public tree: AEGTree;
public appliedMove: DrawModeMove;

/**
* Sets tree to the incoming AEGTree and appliedMove to the incoming DrawModeMove.
*
* @param tree Incoming AEGTree. Defaults to a default AEGTree construction.
* @param appliedMove Incoming DrawModeMove. Defaults to CLEAR.
*/
public constructor(tree?: AEGTree, appliedMove?: DrawModeMove) {
this.tree = new AEGTree(tree?.sheet) ?? new AEGTree();
this.appliedMove = appliedMove ?? DrawModeMove.CLEAR;
}
}
10 changes: 7 additions & 3 deletions src/DrawTools/AtomTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import {AtomNode} from "../AEG/AtomNode";
import {changeCursorStyle} from "../SharedToolUtils/DrawUtils";
import {drawAtom} from "../SharedToolUtils/DrawUtils";
import {DrawModeMove} from "../DrawHistory/DrawModeNode";
import {illegalColor, legalColor} from "../Themes";
import {offset} from "../SharedToolUtils/DragTool";
import {Point} from "../AEG/Point";
Expand Down Expand Up @@ -100,6 +101,7 @@ export function atomMouseUp(event: MouseEvent): void {
);
if (TreeContext.tree.canInsert(currentAtom) && !wasOut) {
TreeContext.tree.insert(currentAtom);
TreeContext.pushToDrawStack(DrawModeMove.DRAW_ATOM);
}
redrawTree(TreeContext.tree);
hasMouseDown = false;
Expand All @@ -117,11 +119,13 @@ export function atomMouseOut(): void {

/**
* Constructs a new AtomNode at the incoming Point.
* This AtomNode is created with the incoming string as an identifier and a width and height retrieved from the font's text metrics.
* This AtomNode is created with the incoming string as an identifier and a width
* and height retrieved from the font's text metrics.
*
* @param identifier Incoming string.
* @param origin Incoming Point.
* @returns AtomNode at origin with identifier as its letter and appropriate width and height depending on font.
* @returns AtomNode at origin with identifier as its letter and appropriate width
* and height depending on font.
*/
function createAtom(identifier: string, origin: Point): AtomNode {
atomDisplay.innerHTML = identifier;
Expand All @@ -137,7 +141,7 @@ function createAtom(identifier: string, origin: Point): AtomNode {
/**
* Draws currentAtom as legalColor or illegalColor.
* legalColor is chosen if currentAtom's position is valid.
* IllegalColor is chose if currentAtom's position is not valid.
* IllegalColor is chosen if currentAtom's position is not valid.
*/
function determineDrawColor(): void {
redrawTree(TreeContext.tree);
Expand Down
3 changes: 3 additions & 0 deletions src/DrawTools/CopyFromDraw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {AtomNode} from "../AEG/AtomNode";
import {changeCursorStyle} from "../SharedToolUtils/DrawUtils";
import {cleanCanvas, highlightNode, redrawTree} from "../SharedToolUtils/DrawUtils";
import {CutNode} from "../AEG/CutNode";
import {DrawModeMove} from "../DrawHistory/DrawModeNode";
import {legalColor} from "../Themes";
import {offset} from "../SharedToolUtils/DragTool";
import {Point} from "../AEG/Point";
Expand Down Expand Up @@ -85,6 +86,8 @@ export function copyFromDrawMouseUp(): void {
}

redrawTree(TreeContext.tree);

TreeContext.pushToDrawStack(DrawModeMove.COPY_GRAPH);
}

selectedNode = null;
Expand Down
3 changes: 3 additions & 0 deletions src/DrawTools/CopyMultiTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {AtomNode} from "../AEG/AtomNode";
import {changeCursorStyle, determineAndChangeCursorStyle} from "../SharedToolUtils/DrawUtils";
import {CutNode} from "../AEG/CutNode";
import {drawAtom, redrawTree} from "../SharedToolUtils/DrawUtils";
import {DrawModeMove} from "../DrawHistory/DrawModeNode";
import {illegalColor, legalColor} from "../Themes";
import {offset} from "../SharedToolUtils/DragTool";
import {Point} from "../AEG/Point";
Expand Down Expand Up @@ -101,6 +102,8 @@ export function copyMultiMouseUp(event: MouseEvent): void {
TreeContext.tree.insert(tempAtom);
}
}

TreeContext.pushToDrawStack(DrawModeMove.COPY_MULTI);
}
redrawTree(TreeContext.tree);
legalNode = false;
Expand Down
3 changes: 3 additions & 0 deletions src/DrawTools/CopySingleTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {AtomNode} from "../AEG/AtomNode";
import {changeCursorStyle, determineAndChangeCursorStyle} from "../SharedToolUtils/DrawUtils";
import {CutNode} from "../AEG/CutNode";
import {drawAtom, drawCut, redrawTree} from "../SharedToolUtils/DrawUtils";
import {DrawModeMove} from "../DrawHistory/DrawModeNode";
import {illegalColor, legalColor} from "../Themes";
import {offset} from "../SharedToolUtils/DragTool";
import {Point} from "../AEG/Point";
Expand Down Expand Up @@ -106,6 +107,8 @@ export function copySingleMouseUp(event: MouseEvent): void {
}
}
redrawTree(TreeContext.tree);

TreeContext.pushToDrawStack(DrawModeMove.COPY_SINGLE);
}
legalNode = false;
}
Expand Down
2 changes: 2 additions & 0 deletions src/DrawTools/CutTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {changeCursorStyle, determineAndChangeCursorStyle} from "../SharedToolUti
import {createEllipse, ellipseLargeEnough} from "../SharedToolUtils/EditModeUtils";
import {CutNode} from "../AEG/CutNode";
import {drawCut, drawGuidelines, redrawTree} from "../SharedToolUtils/DrawUtils";
import {DrawModeMove} from "../DrawHistory/DrawModeNode";
import {Ellipse} from "../AEG/Ellipse";
import {illegalColor, legalColor} from "../Themes";
import {offset} from "../SharedToolUtils/DragTool";
Expand Down Expand Up @@ -91,6 +92,7 @@ export function cutMouseUp(event: MouseEvent): void {
ellipseLargeEnough(<Ellipse>newCut.ellipse)
) {
TreeContext.tree.insert(newCut);
TreeContext.pushToDrawStack(DrawModeMove.DRAW_CUT);
}
redrawTree(TreeContext.tree);
}
Expand Down
2 changes: 2 additions & 0 deletions src/DrawTools/DeleteMultiTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import {AtomNode} from "../AEG/AtomNode";
import {CutNode} from "../AEG/CutNode";
import {DrawModeMove} from "../DrawHistory/DrawModeNode";
import {highlightNode, redrawTree} from "../SharedToolUtils/DrawUtils";
import {illegalColor} from "../Themes";
import {offset} from "../SharedToolUtils/DragTool";
Expand Down Expand Up @@ -104,6 +105,7 @@ export function deleteMultiMouseUp(event: MouseEvent): void {
TreeContext.tree.clear();
}
redrawTree(TreeContext.tree);
TreeContext.pushToDrawStack(DrawModeMove.DELETE_MULTI);
}
currentNode = null;
legalNode = false;
Expand Down
2 changes: 2 additions & 0 deletions src/DrawTools/DeleteSingleTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import {AtomNode} from "../AEG/AtomNode";
import {CutNode} from "../AEG/CutNode";
import {drawAtom, drawCut, redrawTree} from "../SharedToolUtils/DrawUtils";
import {DrawModeMove} from "../DrawHistory/DrawModeNode";
import {illegalColor} from "../Themes";
import {offset} from "../SharedToolUtils/DragTool";
import {Point} from "../AEG/Point";
Expand Down Expand Up @@ -120,6 +121,7 @@ export function deleteSingleMouseUp(event: MouseEvent): void {
readdChildren(TreeContext.tree, currentNode);
}
redrawTree(TreeContext.tree);
TreeContext.pushToDrawStack(DrawModeMove.DELETE_SINGLE);
}

currentNode = null;
Expand Down
2 changes: 2 additions & 0 deletions src/DrawTools/DrawClearTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import {AEGTree} from "../AEG/AEGTree";
import {cleanCanvas, highlightNode, redrawTree} from "../SharedToolUtils/DrawUtils";
import {DrawModeMove} from "../DrawHistory/DrawModeNode";
import {illegalColor} from "../Themes";
import {TreeContext} from "../TreeContext";

Expand All @@ -28,6 +29,7 @@ export function drawClearMouseUp(): void {
if (legalNode) {
TreeContext.tree = new AEGTree();
redrawTree(TreeContext.tree);
TreeContext.pushToDrawStack(DrawModeMove.CLEAR);
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/DrawTools/DrawMoveMultiTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {AtomNode} from "../AEG/AtomNode";
import {changeCursorStyle, determineAndChangeCursorStyle} from "../SharedToolUtils/DrawUtils";
import {CutNode} from "../AEG/CutNode";
import {drawAtom, highlightNode, redrawTree} from "../SharedToolUtils/DrawUtils";
import {DrawModeMove} from "../DrawHistory/DrawModeNode";
import {illegalColor, legalColor} from "../Themes";
import {offset} from "../SharedToolUtils/DragTool";
import {Point} from "../AEG/Point";
Expand Down Expand Up @@ -117,6 +118,7 @@ export function drawMoveMultiMouseUp(event: MouseEvent): void {
TreeContext.tree.insert(currentNode);
}
}
TreeContext.pushToDrawStack(DrawModeMove.MOVE_MULTI);
}
redrawTree(TreeContext.tree);
legalNode = false;
Expand Down
2 changes: 2 additions & 0 deletions src/DrawTools/DrawMoveSingleTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {AtomNode} from "../AEG/AtomNode";
import {changeCursorStyle, determineAndChangeCursorStyle} from "../SharedToolUtils/DrawUtils";
import {CutNode} from "../AEG/CutNode";
import {drawAtom, drawCut, redrawTree} from "../SharedToolUtils/DrawUtils";
import {DrawModeMove} from "../DrawHistory/DrawModeNode";
import {illegalColor, legalColor} from "../Themes";
import {offset} from "../SharedToolUtils/DragTool";
import {Point} from "../AEG/Point";
Expand Down Expand Up @@ -124,6 +125,7 @@ export function drawMoveSingleMouseUp(event: MouseEvent): void {
}
}
redrawTree(TreeContext.tree);
TreeContext.pushToDrawStack(DrawModeMove.MOVE_SINGLE);
}
legalNode = false;
}
Expand Down
2 changes: 2 additions & 0 deletions src/DrawTools/DrawResizeTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {AtomNode} from "../AEG/AtomNode";
import {changeCursorStyle, determineAndChangeCursorStyle} from "../SharedToolUtils/DrawUtils";
import {CutNode} from "../AEG/CutNode";
import {determineDirection, drawCut, redrawTree} from "../SharedToolUtils/DrawUtils";
import {DrawModeMove} from "../DrawHistory/DrawModeNode";
import {ellipseLargeEnough, resizeCut} from "../SharedToolUtils/EditModeUtils";
import {illegalColor, legalColor} from "../Themes";
import {offset} from "../SharedToolUtils/DragTool";
Expand Down Expand Up @@ -122,6 +123,7 @@ export function drawResizeMouseUp(event: MouseEvent): void {
}
redrawTree(TreeContext.tree);
legalNode = false;
TreeContext.pushToDrawStack(DrawModeMove.RESIZE);
}
}

Expand Down
45 changes: 28 additions & 17 deletions src/Proof/ProofHistory.ts → src/ProofHistory/ProofHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,32 @@
* @author Dawn Moore
*/

import {ProofNode} from "./ProofNode";
import {ProofModeMove, ProofModeNode} from "./ProofModeNode";
import {redrawProof} from "../SharedToolUtils/DrawUtils";
import {TreeContext} from "../TreeContext";

const proofMoveToIconStringDict: {[key in ProofModeMove]: string} = {
[ProofModeMove.CLEAR]: "",
[ProofModeMove.DC_INSERT]: "dot-circle-o",
[ProofModeMove.DC_DELETE]: "times-circle",
[ProofModeMove.MOVE_SINGLE]: "mouse-pointer",
[ProofModeMove.MOVE_MULTI]: "arrows",
[ProofModeMove.ITERATION]: "expand",
[ProofModeMove.DEITERATION]: "compress",
[ProofModeMove.INSERTION]: "plus",
[ProofModeMove.ERASURE]: "trash",
[ProofModeMove.RESIZE]: "arrows-alt",
[ProofModeMove.PASTE_GRAPH]: "files-o",
};

/**
* Creates a button representing the incoming ProofNode as a step in the proof history
* and allows the user to return to that step.
*
* @param newStep Incoming ProofNode.
* @param step Index of newStep in the history.
*/
export function appendStep(newStep: ProofNode, step?: number): void {
export function appendStep(newStep: ProofModeNode, step?: number): void {
const newDiv = document.createElement("div");
newDiv.className = "row";
const stepNumber = step ? step : TreeContext.proof.length;
Expand All @@ -36,20 +50,10 @@ export function appendStep(newStep: ProofNode, step?: number): void {

//Determines which type of step was taken to give the created button a corresponding icon.
const icon = document.createElement("Text");
icon.className =
"fa fa-" +
{
"Single Move": "mouse-pointer",
"Multi Move": "arrows",
Resize: "arrows-alt",
"DC Insert": "dot-circle-o",
"DC Delete": "times-circle",
Insertion: "plus",
Erasure: "trash",
Iteration: "expand",
Deiteration: "compress",
Pasted: "files-o",
}[newStep.appliedRule];

const iconString = proofMoveToIconStringDict[newStep.appliedRule];

icon.className = "fa fa-" + iconString;

button.appendChild(icon);
newDiv.appendChild(button);
Expand All @@ -62,7 +66,7 @@ export function appendStep(newStep: ProofNode, step?: number): void {
*
* @param selectedStep Incoming ProofNode.
*/
export function stepBack(selectedStep: ProofNode): void {
export function stepBack(selectedStep: ProofModeNode): void {
TreeContext.currentProofStep = selectedStep;
redrawProof();
}
Expand All @@ -77,3 +81,10 @@ export function deleteButtons(stopIndex: number): void {
document.getElementById("Row: " + i)?.remove();
}
}

/**
* Removes the most recent move's button from the proof bar.
*/
export function deleteMostRecentButton(): void {
document.getElementById("Row: " + (TreeContext.proof.length + 1))?.remove();
}
Loading

0 comments on commit 8a40d13

Please sign in to comment.