Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save cursor w/undo #455

Merged
merged 7 commits into from
May 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 31 additions & 9 deletions src/grid/controller/sheetController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { StatementRunner } from './runners/runner';
import { PixiApp } from '../../gridGL/pixiApp/PixiApp';
import * as Sentry from '@sentry/browser';
import { debug } from '../../debugFlags';
import { GridInteractionState } from '../../atoms/gridInteractionStateAtom';

export class SheetController {
app?: PixiApp; // TODO: Untangle PixiApp from SheetController.
Expand Down Expand Up @@ -34,7 +35,7 @@ export class SheetController {
// execute_statement until end_transaction is called.
//

public start_transaction(): void {
public start_transaction(interactionState?: GridInteractionState): void {
if (this.transaction_in_progress) {
// during debug mode, throw an error
// otherwise, capture the error and continue
Expand All @@ -45,11 +46,20 @@ export class SheetController {
this.end_transaction();
}

// This is useful when the user clicks outside of the active cell to another
// cell, so the cursor moves to that new cell and the transaction finishes
let cursor = undefined;
if (interactionState) {
cursor = { ...interactionState, showInput: false };
} else if (this.app?.settings.interactionState) {
cursor = { ...this.app.settings.interactionState, showInput: false };
}

// set transaction in progress to a new Transaction
// transaction_in_progress represents the stack of commands needed
// to undo the transaction currently being executed.
this.transaction_in_progress = { statements: [] };
this.transaction_in_progress_reverse = { statements: [] };
this.transaction_in_progress = { statements: [], cursor };
this.transaction_in_progress_reverse = { statements: [], cursor };
}

public execute_statement(statement: Statement): void {
Expand Down Expand Up @@ -135,9 +145,15 @@ export class SheetController {
// add reverse transaction to redo stack
this.redo_stack.push(reverse_transaction);

// TODO: The transaction should keep track of everything that becomes dirty while executing and then just sets the correct flags on app.
// This will be very inefficient on large files.
if (this.app) this.app.rebuild();
if (this.app) {
if (transaction.cursor) {
this.app.settings.setInteractionState?.(transaction.cursor);
}

// TODO: The transaction should keep track of everything that becomes dirty while executing and then just sets the correct flags on app.
// This will be very inefficient on large files.
this.app.rebuild();
}
}

public redo(): void {
Expand Down Expand Up @@ -169,9 +185,15 @@ export class SheetController {
// add reverse transaction to undo stack
this.undo_stack.push(reverse_transaction);

// TODO: The transaction should keep track of everything that becomes dirty while executing and then just sets the correct flags on app.
// This will be very inefficient on large files.
if (this.app) this.app.rebuild();
if (this.app) {
if (transaction.cursor) {
this.app.settings.setInteractionState?.(transaction.cursor);
}

// TODO: The transaction should keep track of everything that becomes dirty while executing and then just sets the correct flags on app.
// This will be very inefficient on large files.
this.app.rebuild();
}
}

public clear(): void {
Expand Down
2 changes: 2 additions & 0 deletions src/grid/controller/transaction.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { GridInteractionState } from '../../atoms/gridInteractionStateAtom';
import { Statement } from './statement';

export type Transaction = {
statements: Statement[];
cursor?: GridInteractionState;
};
14 changes: 14 additions & 0 deletions src/gridGL/interaction/CellInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ export const CellInput = (props: CellInputProps) => {

const [value, setValue] = useState<string | undefined>(undefined);

// used to save interaction state when input starts
const [saveInteractionState, setSaveInteractionState] = useState<GridInteractionState>();

const cellLocation = useRef(interactionState.cursorPosition);
const textInput = useRef<HTMLInputElement>(null);
// Effect for sizing the input width to the length of the value
Expand Down Expand Up @@ -82,6 +85,11 @@ export const CellInput = (props: CellInputProps) => {
return null;
}

// copy interaction state when input starts
if (!saveInteractionState) {
setSaveInteractionState(interactionState);
}

// need this variable to cancel second closeInput call from blur after pressing Escape (this happens before the state can update)
let closed = false;

Expand All @@ -91,6 +99,7 @@ export const CellInput = (props: CellInputProps) => {
closed = true;

if (!cancel) {
sheetController.start_transaction(saveInteractionState);
// Update Cell and dependent cells
if (value === '') {
// delete cell if input is empty, and wasn't empty before
Expand All @@ -102,6 +111,7 @@ export const CellInput = (props: CellInputProps) => {
y1: cellLocation.current.y,
sheetController,
app,
create_transaction: false,
});
} else {
// create cell with value at input location
Expand All @@ -116,8 +126,10 @@ export const CellInput = (props: CellInputProps) => {
],
sheetController,
app,
create_transaction: false,
});
}
sheetController.end_transaction();
app.quadrants.quadrantChanged({ cells: [cellLocation.current] });
}

Expand All @@ -137,6 +149,8 @@ export const CellInput = (props: CellInputProps) => {
});
setValue(undefined);

setSaveInteractionState(undefined);

// Set focus back to Grid
focusGrid();

Expand Down