mirror of
https://github.com/scratchfoundation/scratch-paint.git
synced 2024-12-22 21:42:30 -05:00
Add undo
This commit is contained in:
parent
86ee3d8cdd
commit
c75d3f63ba
3 changed files with 56 additions and 15 deletions
|
@ -7,6 +7,7 @@ import {changeMode} from '../reducers/modes';
|
|||
import {undo, redo, undoSnapshot} from '../reducers/undo';
|
||||
import {clearSelectedItems, setSelectedItems} from '../reducers/selected-items';
|
||||
import {deactivateEyeDropper} from '../reducers/eye-dropper';
|
||||
import {setTextEditTarget} from '../reducers/text-edit-target';
|
||||
|
||||
import {hideGuideLayers, showGuideLayers} from '../helper/layer';
|
||||
import {performUndo, performRedo, performSnapshot, shouldShowUndo, shouldShowRedo} from '../helper/undo';
|
||||
|
@ -15,6 +16,7 @@ import {groupSelection, ungroupSelection} from '../helper/group';
|
|||
import {getSelectedLeafItems} from '../helper/selection';
|
||||
import {resetZoom, zoomOnSelection} from '../helper/view';
|
||||
import EyeDropperTool from '../helper/tools/eye-dropper';
|
||||
import styles from '../components/paint-editor/paint-editor.css'
|
||||
|
||||
import Modes from '../lib/modes';
|
||||
import {connect} from 'react-redux';
|
||||
|
@ -155,6 +157,12 @@ class PaintEditor extends React.Component {
|
|||
document.activeElement.blur();
|
||||
}
|
||||
|
||||
if (event.target !== paper.view.element && !event.target.classList.contains(styles.textArea)) {
|
||||
debugger;
|
||||
// Exit text edit mode if you click anywhere outside of canvas
|
||||
this.props.removeTextEditTarget();
|
||||
}
|
||||
|
||||
if (this.props.isEyeDropping) {
|
||||
const colorString = this.eyeDropper.colorString;
|
||||
const callback = this.props.changeColorToEyeDropper;
|
||||
|
@ -303,6 +311,9 @@ const mapDispatchToProps = dispatch => ({
|
|||
clearSelectedItems: () => {
|
||||
dispatch(clearSelectedItems());
|
||||
},
|
||||
removeTextEditTarget: () => {
|
||||
dispatch(setTextEditTarget());
|
||||
},
|
||||
setSelectedItems: () => {
|
||||
dispatch(setSelectedItems(getSelectedLeafItems()));
|
||||
},
|
||||
|
|
|
@ -36,6 +36,9 @@ class TextMode extends React.Component {
|
|||
if (this.tool && nextProps.selectedItems !== this.props.selectedItems) {
|
||||
this.tool.onSelectionChanged(nextProps.selectedItems);
|
||||
}
|
||||
if (this.tool && !nextProps.textEditTarget && this.props.textEditTarget) {
|
||||
this.tool.onTextEditCancelled();
|
||||
}
|
||||
|
||||
if (nextProps.isTextModeActive && !this.props.isTextModeActive) {
|
||||
this.activateTool();
|
||||
|
@ -103,13 +106,15 @@ TextMode.propTypes = {
|
|||
selectedItems: PropTypes.arrayOf(PropTypes.instanceOf(paper.Item)),
|
||||
setSelectedItems: PropTypes.func.isRequired,
|
||||
setTextEditTarget: PropTypes.func.isRequired,
|
||||
textArea: PropTypes.instanceOf(Element)
|
||||
textArea: PropTypes.instanceOf(Element),
|
||||
textEditTarget: PropTypes.number
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
colorState: state.scratchPaint.color,
|
||||
isTextModeActive: state.scratchPaint.mode === Modes.TEXT,
|
||||
selectedItems: state.scratchPaint.selectedItems
|
||||
selectedItems: state.scratchPaint.selectedItems,
|
||||
textEditTarget: state.scratchPaint.textEditTarget
|
||||
});
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
clearSelectedItems: () => {
|
||||
|
|
|
@ -24,6 +24,10 @@ class TextTool extends paper.Tool {
|
|||
static get DOUBLE_CLICK_MILLIS () {
|
||||
return 250;
|
||||
}
|
||||
/** Typing with no pauses longer than this amount of type will count as 1 action */
|
||||
static get TYPING_TIMEOUT_MILLIS () {
|
||||
return 1000;
|
||||
}
|
||||
static get TEXT_PADDING () {
|
||||
return 8;
|
||||
}
|
||||
|
@ -59,6 +63,7 @@ class TextTool extends paper.Tool {
|
|||
this.colorState = null;
|
||||
this.mode = null;
|
||||
this.active = false;
|
||||
this.lastTypeEvent = null;
|
||||
|
||||
// If text selected and then activate this tool, switch to text edit mode for that text
|
||||
// If double click on text while in select mode, does mode change to text mode? Text fully selected by default
|
||||
|
@ -95,6 +100,10 @@ class TextTool extends paper.Tool {
|
|||
onSelectionChanged (selectedItems) {
|
||||
this.boundingBoxTool.onSelectionChanged(selectedItems);
|
||||
}
|
||||
// Allow other tools to cancel text edit mode
|
||||
onTextEditCancelled () {
|
||||
this.endTextEdit();
|
||||
}
|
||||
setColorState (colorState) {
|
||||
this.colorState = colorState;
|
||||
}
|
||||
|
@ -110,12 +119,6 @@ class TextTool extends paper.Tool {
|
|||
if (event.event.button > 0) return; // only first mouse button
|
||||
this.active = true;
|
||||
|
||||
// Remove invisible textboxes
|
||||
if (this.textBox && this.textBox.content.trim() === '') {
|
||||
this.textBox.remove();
|
||||
this.textBox = null;
|
||||
}
|
||||
|
||||
// Check if double clicked
|
||||
let doubleClicked = false;
|
||||
if (this.lastEvent) {
|
||||
|
@ -142,10 +145,12 @@ class TextTool extends paper.Tool {
|
|||
return;
|
||||
}
|
||||
|
||||
const lastMode = this.mode;
|
||||
// We clicked away from the item, so end the current mode
|
||||
if (this.mode === TextTool.SELECT_MODE) {
|
||||
if (lastMode === TextTool.SELECT_MODE) {
|
||||
clearSelection(this.clearSelectedItems);
|
||||
} else if (this.mode === TextTool.TEXT_EDIT_MODE) {
|
||||
this.mode = null;
|
||||
} else if (lastMode === TextTool.TEXT_EDIT_MODE) {
|
||||
this.endTextEdit();
|
||||
}
|
||||
|
||||
|
@ -154,14 +159,12 @@ class TextTool extends paper.Tool {
|
|||
// Clicking a different text item to begin text edit mode on that item
|
||||
this.textBox = hitResults[0].item;
|
||||
this.beginTextEdit(this.textBox.content, this.textBox.matrix);
|
||||
} else if (this.mode === TextTool.TEXT_EDIT_MODE) {
|
||||
} else if (lastMode === TextTool.TEXT_EDIT_MODE) {
|
||||
// In text mode clicking away to begin select mode
|
||||
if (this.textBox) {
|
||||
this.mode = TextTool.SELECT_MODE;
|
||||
this.textBox.selected = true;
|
||||
this.setSelectedItems();
|
||||
} else {
|
||||
this.mode = null;
|
||||
}
|
||||
} else {
|
||||
// In no mode or select mode clicking away to begin text edit mode
|
||||
|
@ -214,7 +217,12 @@ class TextTool extends paper.Tool {
|
|||
this.nudgeTool.onKeyUp(event);
|
||||
}
|
||||
}
|
||||
handleTextInput () {
|
||||
handleTextInput (event) {
|
||||
// Save undo state if you paused typing for long enough.
|
||||
if (this.lastTypeEvent && event.timeStamp - this.lastTypeEvent.timeStamp > TextTool.TYPING_TIMEOUT_MILLIS) {
|
||||
this.onUpdateSvg();
|
||||
}
|
||||
this.lastTypeEvent = event;
|
||||
if (this.mode === TextTool.TEXT_EDIT_MODE) {
|
||||
this.textBox.content = this.element.value;
|
||||
}
|
||||
|
@ -237,7 +245,6 @@ class TextTool extends paper.Tool {
|
|||
this.setTextEditTarget(this.textBox.id);
|
||||
|
||||
// TODO text not positioned correctly when zoomed in
|
||||
// TODO holding shift when rotating in select mode does weird things
|
||||
// TODO undo states
|
||||
|
||||
this.element.style.display = 'initial';
|
||||
|
@ -259,6 +266,18 @@ class TextTool extends paper.Tool {
|
|||
this.resizeGuide();
|
||||
}
|
||||
endTextEdit () {
|
||||
if (this.mode !== TextTool.TEXT_EDIT_MODE) {
|
||||
return;
|
||||
}
|
||||
this.mode = null;
|
||||
|
||||
// Remove invisible textboxes
|
||||
if (this.textBox && this.textBox.content.trim() === '') {
|
||||
this.textBox.remove();
|
||||
this.textBox = null;
|
||||
}
|
||||
|
||||
// Remove guide
|
||||
if (this.guide) {
|
||||
this.guide.remove();
|
||||
this.guide = null;
|
||||
|
@ -269,6 +288,12 @@ class TextTool extends paper.Tool {
|
|||
this.element.removeEventListener('input', this.eventListener);
|
||||
this.eventListener = null;
|
||||
}
|
||||
this.lastTypeEvent = null;
|
||||
|
||||
// If you finished editing a textbox, save undo state
|
||||
if (this.textBox && this.textBox.content.trim().length) {
|
||||
this.onUpdateSvg();
|
||||
}
|
||||
}
|
||||
deactivateTool () {
|
||||
if (this.textBox && this.textBox.content.trim() === '') {
|
||||
|
|
Loading…
Reference in a new issue