mirror of
https://github.com/scratchfoundation/scratch-paint.git
synced 2024-12-23 05:52:42 -05:00
commit
6c448a71a8
11 changed files with 131 additions and 87 deletions
|
@ -7,6 +7,7 @@ import PropTypes from 'prop-types';
|
||||||
import LineMode from '../containers/line-mode.jsx';
|
import LineMode from '../containers/line-mode.jsx';
|
||||||
import FillColorIndicatorComponent from '../containers/fill-color-indicator.jsx';
|
import FillColorIndicatorComponent from '../containers/fill-color-indicator.jsx';
|
||||||
import StrokeColorIndicatorComponent from '../containers/stroke-color-indicator.jsx';
|
import StrokeColorIndicatorComponent from '../containers/stroke-color-indicator.jsx';
|
||||||
|
import StrokeWidthIndicatorComponent from '../containers/stroke-width-indicator.jsx';
|
||||||
|
|
||||||
import {defineMessages, injectIntl, intlShape} from 'react-intl';
|
import {defineMessages, injectIntl, intlShape} from 'react-intl';
|
||||||
import BufferedInputHOC from './forms/buffered-input-hoc.jsx';
|
import BufferedInputHOC from './forms/buffered-input-hoc.jsx';
|
||||||
|
@ -101,6 +102,8 @@ class PaintEditorComponent extends React.Component {
|
||||||
<FillColorIndicatorComponent />
|
<FillColorIndicatorComponent />
|
||||||
{/* stroke */}
|
{/* stroke */}
|
||||||
<StrokeColorIndicatorComponent />
|
<StrokeColorIndicatorComponent />
|
||||||
|
{/* stroke width */}
|
||||||
|
<StrokeWidthIndicatorComponent />
|
||||||
|
|
||||||
<div className={styles.inputGroup}>
|
<div className={styles.inputGroup}>
|
||||||
Mode tools
|
Mode tools
|
||||||
|
|
29
src/components/stroke-width-indicator.jsx
Normal file
29
src/components/stroke-width-indicator.jsx
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import BufferedInputHOC from './forms/buffered-input-hoc.jsx';
|
||||||
|
import Input from './forms/input.jsx';
|
||||||
|
import {MAX_STROKE_WIDTH} from '../reducers/stroke-width';
|
||||||
|
|
||||||
|
import styles from './paint-editor.css';
|
||||||
|
|
||||||
|
const BufferedInput = BufferedInputHOC(Input);
|
||||||
|
const StrokeWidthIndicatorComponent = props => (
|
||||||
|
<div className={styles.inputGroup}>
|
||||||
|
<BufferedInput
|
||||||
|
small
|
||||||
|
max={MAX_STROKE_WIDTH}
|
||||||
|
min="0"
|
||||||
|
type="number"
|
||||||
|
value={props.strokeWidth}
|
||||||
|
onSubmit={props.onChangeStrokeWidth}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
StrokeWidthIndicatorComponent.propTypes = {
|
||||||
|
onChangeStrokeWidth: PropTypes.func.isRequired,
|
||||||
|
strokeWidth: PropTypes.number.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StrokeWidthIndicatorComponent;
|
|
@ -79,7 +79,8 @@ BrushMode.propTypes = {
|
||||||
changeBrushSize: PropTypes.func.isRequired,
|
changeBrushSize: PropTypes.func.isRequired,
|
||||||
colorState: PropTypes.shape({
|
colorState: PropTypes.shape({
|
||||||
fillColor: PropTypes.string.isRequired,
|
fillColor: PropTypes.string.isRequired,
|
||||||
strokeColor: PropTypes.string.isRequired
|
strokeColor: PropTypes.string.isRequired,
|
||||||
|
strokeWidth: PropTypes.number.isRequired
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
handleMouseDown: PropTypes.func.isRequired,
|
handleMouseDown: PropTypes.func.isRequired,
|
||||||
isBrushModeActive: PropTypes.bool.isRequired,
|
isBrushModeActive: PropTypes.bool.isRequired,
|
||||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
||||||
import {connect} from 'react-redux';
|
import {connect} from 'react-redux';
|
||||||
import bindAll from 'lodash.bindall';
|
import bindAll from 'lodash.bindall';
|
||||||
import Modes from '../modes/modes';
|
import Modes from '../modes/modes';
|
||||||
import {changeLineWidth} from '../reducers/line-mode';
|
import {changeStrokeWidth} from '../reducers/stroke-width';
|
||||||
import LineModeComponent from '../components/line-mode.jsx';
|
import LineModeComponent from '../components/line-mode.jsx';
|
||||||
import {changeMode} from '../reducers/modes';
|
import {changeMode} from '../reducers/modes';
|
||||||
import paper from 'paper';
|
import paper from 'paper';
|
||||||
|
@ -50,13 +50,6 @@ class LineMode extends React.Component {
|
||||||
this.path = null;
|
this.path = null;
|
||||||
this.hitResult = null;
|
this.hitResult = null;
|
||||||
|
|
||||||
// TODO add back colors
|
|
||||||
// Make sure a stroke color is set on the line tool
|
|
||||||
// if(!pg.stylebar.getStrokeColor()) {
|
|
||||||
// pg.stylebar.setStrokeColor(pg.stylebar.getFillColor());
|
|
||||||
// pg.stylebar.setFillColor(null);
|
|
||||||
// }
|
|
||||||
|
|
||||||
const lineMode = this;
|
const lineMode = this;
|
||||||
this.tool.onMouseDown = function (event) {
|
this.tool.onMouseDown = function (event) {
|
||||||
if (event.event.button > 0) return; // only first mouse button
|
if (event.event.button > 0) return; // only first mouse button
|
||||||
|
@ -100,9 +93,9 @@ class LineMode extends React.Component {
|
||||||
if (!this.path) {
|
if (!this.path) {
|
||||||
this.path = new paper.Path();
|
this.path = new paper.Path();
|
||||||
|
|
||||||
// TODO add back stroke width styling
|
|
||||||
this.path.setStrokeColor(this.props.colorState.strokeColor);
|
this.path.setStrokeColor(this.props.colorState.strokeColor);
|
||||||
this.path.setStrokeWidth(this.props.lineModeState.lineWidth);
|
// Make sure a visible line is drawn
|
||||||
|
this.path.setStrokeWidth(Math.max(1, this.props.colorState.strokeWidth));
|
||||||
|
|
||||||
this.path.setSelected(true);
|
this.path.setSelected(true);
|
||||||
this.path.add(event.point);
|
this.path.add(event.point);
|
||||||
|
@ -260,9 +253,9 @@ class LineMode extends React.Component {
|
||||||
}
|
}
|
||||||
onScroll (event) {
|
onScroll (event) {
|
||||||
if (event.deltaY < 0) {
|
if (event.deltaY < 0) {
|
||||||
this.props.changeLineWidth(this.props.lineModeState.lineWidth + 1);
|
this.props.changeStrokeWidth(this.props.colorState.strokeWidth + 1);
|
||||||
} else if (event.deltaY > 0 && this.props.lineModeState.lineWidth > 1) {
|
} else if (event.deltaY > 0 && this.props.colorState.strokeWidth > 1) {
|
||||||
this.props.changeLineWidth(this.props.lineModeState.lineWidth - 1);
|
this.props.changeStrokeWidth(this.props.colorState.strokeWidth - 1);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -275,27 +268,24 @@ class LineMode extends React.Component {
|
||||||
|
|
||||||
LineMode.propTypes = {
|
LineMode.propTypes = {
|
||||||
canvas: PropTypes.instanceOf(Element).isRequired,
|
canvas: PropTypes.instanceOf(Element).isRequired,
|
||||||
changeLineWidth: PropTypes.func.isRequired,
|
changeStrokeWidth: PropTypes.func.isRequired,
|
||||||
colorState: PropTypes.shape({
|
colorState: PropTypes.shape({
|
||||||
fillColor: PropTypes.string.isRequired,
|
fillColor: PropTypes.string.isRequired,
|
||||||
strokeColor: PropTypes.string.isRequired
|
strokeColor: PropTypes.string.isRequired,
|
||||||
|
strokeWidth: PropTypes.number.isRequired
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
handleMouseDown: PropTypes.func.isRequired,
|
handleMouseDown: PropTypes.func.isRequired,
|
||||||
isLineModeActive: PropTypes.bool.isRequired,
|
isLineModeActive: PropTypes.bool.isRequired,
|
||||||
lineModeState: PropTypes.shape({
|
|
||||||
lineWidth: PropTypes.number.isRequired
|
|
||||||
}),
|
|
||||||
onUpdateSvg: PropTypes.func.isRequired
|
onUpdateSvg: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
colorState: state.scratchPaint.color,
|
colorState: state.scratchPaint.color,
|
||||||
lineModeState: state.scratchPaint.lineMode,
|
|
||||||
isLineModeActive: state.scratchPaint.mode === Modes.LINE
|
isLineModeActive: state.scratchPaint.mode === Modes.LINE
|
||||||
});
|
});
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
changeLineWidth: lineWidth => {
|
changeStrokeWidth: strokeWidth => {
|
||||||
dispatch(changeLineWidth(lineWidth));
|
dispatch(changeStrokeWidth(strokeWidth));
|
||||||
},
|
},
|
||||||
handleMouseDown: () => {
|
handleMouseDown: () => {
|
||||||
dispatch(changeMode(Modes.LINE));
|
dispatch(changeMode(Modes.LINE));
|
||||||
|
|
17
src/containers/stroke-width-indicator.jsx
Normal file
17
src/containers/stroke-width-indicator.jsx
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
import {changeStrokeWidth} from '../reducers/stroke-width';
|
||||||
|
import StrokeWidthIndicatorComponent from '../components/stroke-width-indicator.jsx';
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
strokeWidth: state.scratchPaint.color.strokeWidth
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
onChangeStrokeWidth: strokeWidth => {
|
||||||
|
dispatch(changeStrokeWidth(strokeWidth));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(StrokeWidthIndicatorComponent);
|
|
@ -1,8 +1,10 @@
|
||||||
import {combineReducers} from 'redux';
|
import {combineReducers} from 'redux';
|
||||||
import fillColorReducer from './fill-color';
|
import fillColorReducer from './fill-color';
|
||||||
import strokeColorReducer from './stroke-color';
|
import strokeColorReducer from './stroke-color';
|
||||||
|
import strokeWidthReducer from './stroke-width';
|
||||||
|
|
||||||
export default combineReducers({
|
export default combineReducers({
|
||||||
fillColor: fillColorReducer,
|
fillColor: fillColorReducer,
|
||||||
strokeColor: strokeColorReducer
|
strokeColor: strokeColorReducer,
|
||||||
|
strokeWidth: strokeWidthReducer
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
import log from '../log/log';
|
|
||||||
|
|
||||||
const CHANGE_LINE_WIDTH = 'scratch-paint/line-mode/CHANGE_LINE_WIDTH';
|
|
||||||
const initialState = {lineWidth: 2};
|
|
||||||
|
|
||||||
const reducer = function (state, action) {
|
|
||||||
if (typeof state === 'undefined') state = initialState;
|
|
||||||
switch (action.type) {
|
|
||||||
case CHANGE_LINE_WIDTH:
|
|
||||||
if (isNaN(action.lineWidth)) {
|
|
||||||
log.warn(`Invalid line width: ${action.lineWidth}`);
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
return {lineWidth: Math.max(1, action.lineWidth)};
|
|
||||||
default:
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Action creators ==================================
|
|
||||||
const changeLineWidth = function (lineWidth) {
|
|
||||||
return {
|
|
||||||
type: CHANGE_LINE_WIDTH,
|
|
||||||
lineWidth: lineWidth
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export {
|
|
||||||
reducer as default,
|
|
||||||
changeLineWidth
|
|
||||||
};
|
|
|
@ -2,13 +2,11 @@ import {combineReducers} from 'redux';
|
||||||
import modeReducer from './modes';
|
import modeReducer from './modes';
|
||||||
import brushModeReducer from './brush-mode';
|
import brushModeReducer from './brush-mode';
|
||||||
import eraserModeReducer from './eraser-mode';
|
import eraserModeReducer from './eraser-mode';
|
||||||
import lineModeReducer from './line-mode';
|
|
||||||
import colorReducer from './color';
|
import colorReducer from './color';
|
||||||
|
|
||||||
export default combineReducers({
|
export default combineReducers({
|
||||||
mode: modeReducer,
|
mode: modeReducer,
|
||||||
brushMode: brushModeReducer,
|
brushMode: brushModeReducer,
|
||||||
eraserMode: eraserModeReducer,
|
eraserMode: eraserModeReducer,
|
||||||
lineMode: lineModeReducer,
|
|
||||||
color: colorReducer
|
color: colorReducer
|
||||||
});
|
});
|
||||||
|
|
33
src/reducers/stroke-width.js
Normal file
33
src/reducers/stroke-width.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import log from '../log/log';
|
||||||
|
|
||||||
|
const CHANGE_STROKE_WIDTH = 'scratch-paint/stroke-width/CHANGE_STROKE_WIDTH';
|
||||||
|
const MAX_STROKE_WIDTH = 400;
|
||||||
|
const initialState = 2;
|
||||||
|
|
||||||
|
const reducer = function (state, action) {
|
||||||
|
if (typeof state === 'undefined') state = initialState;
|
||||||
|
switch (action.type) {
|
||||||
|
case CHANGE_STROKE_WIDTH:
|
||||||
|
if (isNaN(action.strokeWidth)) {
|
||||||
|
log.warn(`Invalid brush size: ${action.strokeWidth}`);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
return Math.min(MAX_STROKE_WIDTH, Math.max(0, action.strokeWidth));
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Action creators ==================================
|
||||||
|
const changeStrokeWidth = function (strokeWidth) {
|
||||||
|
return {
|
||||||
|
type: CHANGE_STROKE_WIDTH,
|
||||||
|
strokeWidth: strokeWidth
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
reducer as default,
|
||||||
|
changeStrokeWidth,
|
||||||
|
MAX_STROKE_WIDTH
|
||||||
|
};
|
|
@ -1,31 +0,0 @@
|
||||||
/* eslint-env jest */
|
|
||||||
import lineReducer from '../../src/reducers/line-mode';
|
|
||||||
import {changeLineWidth} from '../../src/reducers/line-mode';
|
|
||||||
|
|
||||||
test('initialState', () => {
|
|
||||||
let defaultState;
|
|
||||||
|
|
||||||
expect(lineReducer(defaultState /* state */, {type: 'anything'} /* action */)).toBeDefined();
|
|
||||||
expect(lineReducer(defaultState /* state */, {type: 'anything'} /* action */).lineWidth).toBeGreaterThan(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('changeLineWidth', () => {
|
|
||||||
let defaultState;
|
|
||||||
const newLineWidth = 8078;
|
|
||||||
|
|
||||||
expect(lineReducer(defaultState /* state */, changeLineWidth(newLineWidth) /* action */))
|
|
||||||
.toEqual({lineWidth: newLineWidth});
|
|
||||||
expect(lineReducer(2 /* state */, changeLineWidth(newLineWidth) /* action */))
|
|
||||||
.toEqual({lineWidth: newLineWidth});
|
|
||||||
expect(lineReducer(2 /* state */, changeLineWidth(-1) /* action */))
|
|
||||||
.toEqual({lineWidth: 1});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('invalidChangeLineWidth', () => {
|
|
||||||
const origState = {lineWidth: 2};
|
|
||||||
|
|
||||||
expect(lineReducer(origState /* state */, changeLineWidth('invalid argument') /* action */))
|
|
||||||
.toBe(origState);
|
|
||||||
expect(lineReducer(origState /* state */, changeLineWidth() /* action */))
|
|
||||||
.toBe(origState);
|
|
||||||
});
|
|
33
test/unit/stroke-width-reducer.test.js
Normal file
33
test/unit/stroke-width-reducer.test.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/* eslint-env jest */
|
||||||
|
import strokeWidthReducer from '../../src/reducers/stroke-width';
|
||||||
|
import {MAX_STROKE_WIDTH, changeStrokeWidth} from '../../src/reducers/stroke-width';
|
||||||
|
|
||||||
|
test('initialState', () => {
|
||||||
|
let defaultState;
|
||||||
|
|
||||||
|
expect(strokeWidthReducer(defaultState /* state */, {type: 'anything'} /* action */)).toBeDefined();
|
||||||
|
expect(strokeWidthReducer(defaultState /* state */, {type: 'anything'} /* action */)).toBeGreaterThanOrEqual(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('changestrokeWidth', () => {
|
||||||
|
let defaultState;
|
||||||
|
const newstrokeWidth = 234;
|
||||||
|
|
||||||
|
expect(strokeWidthReducer(defaultState /* state */, changeStrokeWidth(newstrokeWidth) /* action */))
|
||||||
|
.toEqual(newstrokeWidth);
|
||||||
|
expect(strokeWidthReducer(1 /* state */, changeStrokeWidth(newstrokeWidth) /* action */))
|
||||||
|
.toEqual(newstrokeWidth);
|
||||||
|
expect(strokeWidthReducer(1 /* state */, changeStrokeWidth(-1) /* action */))
|
||||||
|
.toEqual(0);
|
||||||
|
expect(strokeWidthReducer(1 /* state */, changeStrokeWidth(453452352) /* action */))
|
||||||
|
.toEqual(MAX_STROKE_WIDTH);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('invalidChangestrokeWidth', () => {
|
||||||
|
const origState = {strokeWidth: 1};
|
||||||
|
|
||||||
|
expect(strokeWidthReducer(origState /* state */, changeStrokeWidth('invalid argument') /* action */))
|
||||||
|
.toBe(origState);
|
||||||
|
expect(strokeWidthReducer(origState /* state */, changeStrokeWidth() /* action */))
|
||||||
|
.toBe(origState);
|
||||||
|
});
|
Loading…
Reference in a new issue