diff --git a/src/components/paint-editor.jsx b/src/components/paint-editor.jsx index 31dfab59..3f352154 100644 --- a/src/components/paint-editor.jsx +++ b/src/components/paint-editor.jsx @@ -7,6 +7,7 @@ import PropTypes from 'prop-types'; import LineMode from '../containers/line-mode.jsx'; import FillColorIndicatorComponent from '../containers/fill-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 BufferedInputHOC from './forms/buffered-input-hoc.jsx'; @@ -102,6 +103,8 @@ class PaintEditorComponent extends React.Component { {/* stroke */} + {/* stroke width */} +
Mode tools diff --git a/src/components/stroke-width-indicator.jsx b/src/components/stroke-width-indicator.jsx new file mode 100644 index 00000000..daa51dbf --- /dev/null +++ b/src/components/stroke-width-indicator.jsx @@ -0,0 +1,30 @@ +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 => ( +
+ +
+); + +StrokeWidthIndicatorComponent.propTypes = { + onChangeStrokeWidth: PropTypes.func.isRequired, + strokeWidth: PropTypes.string.isRequired +}; + +export default StrokeWidthIndicatorComponent; diff --git a/src/containers/brush-mode.jsx b/src/containers/brush-mode.jsx index 5ff4e8fb..3142529b 100644 --- a/src/containers/brush-mode.jsx +++ b/src/containers/brush-mode.jsx @@ -79,7 +79,8 @@ BrushMode.propTypes = { changeBrushSize: PropTypes.func.isRequired, colorState: PropTypes.shape({ fillColor: PropTypes.string.isRequired, - strokeColor: PropTypes.string.isRequired + strokeColor: PropTypes.string.isRequired, + strokeWidth: PropTypes.string.isRequired }).isRequired, handleMouseDown: PropTypes.func.isRequired, isBrushModeActive: PropTypes.bool.isRequired, diff --git a/src/containers/line-mode.jsx b/src/containers/line-mode.jsx index fe2f0163..d1f00b0c 100644 --- a/src/containers/line-mode.jsx +++ b/src/containers/line-mode.jsx @@ -3,7 +3,7 @@ import React from 'react'; import {connect} from 'react-redux'; import bindAll from 'lodash.bindall'; 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 {changeMode} from '../reducers/modes'; import paper from 'paper'; @@ -50,13 +50,6 @@ class LineMode extends React.Component { this.path = 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; this.tool.onMouseDown = function (event) { if (event.event.button > 0) return; // only first mouse button @@ -100,9 +93,9 @@ class LineMode extends React.Component { if (!this.path) { this.path = new paper.Path(); - // TODO add back stroke width styling 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.add(event.point); @@ -260,9 +253,9 @@ class LineMode extends React.Component { } onScroll (event) { if (event.deltaY < 0) { - this.props.changeLineWidth(this.props.lineModeState.lineWidth + 1); - } else if (event.deltaY > 0 && this.props.lineModeState.lineWidth > 1) { - this.props.changeLineWidth(this.props.lineModeState.lineWidth - 1); + this.props.changeStrokeWidth(this.props.colorState.strokeWidth + 1); + } else if (event.deltaY > 0 && this.props.colorState.strokeWidth > 1) { + this.props.changeStrokeWidth(this.props.colorState.strokeWidth - 1); } return true; } @@ -275,27 +268,24 @@ class LineMode extends React.Component { LineMode.propTypes = { canvas: PropTypes.instanceOf(Element).isRequired, - changeLineWidth: PropTypes.func.isRequired, + changeStrokeWidth: PropTypes.func.isRequired, colorState: PropTypes.shape({ fillColor: PropTypes.string.isRequired, - strokeColor: PropTypes.string.isRequired + strokeColor: PropTypes.string.isRequired, + strokeWidth: PropTypes.string.isRequired }).isRequired, handleMouseDown: PropTypes.func.isRequired, isLineModeActive: PropTypes.bool.isRequired, - lineModeState: PropTypes.shape({ - lineWidth: PropTypes.number.isRequired - }), onUpdateSvg: PropTypes.func.isRequired }; const mapStateToProps = state => ({ colorState: state.scratchPaint.color, - lineModeState: state.scratchPaint.lineMode, isLineModeActive: state.scratchPaint.mode === Modes.LINE }); const mapDispatchToProps = dispatch => ({ - changeLineWidth: lineWidth => { - dispatch(changeLineWidth(lineWidth)); + changeStrokeWidth: strokeWidth => { + dispatch(changeStrokeWidth(strokeWidth)); }, handleMouseDown: () => { dispatch(changeMode(Modes.LINE)); diff --git a/src/containers/stroke-width-indicator.jsx b/src/containers/stroke-width-indicator.jsx new file mode 100644 index 00000000..3d29071f --- /dev/null +++ b/src/containers/stroke-width-indicator.jsx @@ -0,0 +1,31 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import {connect} from 'react-redux'; +import {changeStrokeWidth} from '../reducers/stroke-width'; +import StrokeWidthIndicatorComponent from '../components/stroke-width-indicator.jsx'; + +const StrokeWidthIndicator = props => ( + +); + +StrokeWidthIndicator.propTypes = { + handleChangeStrokeWidth: PropTypes.func.isRequired, + strokeWidth: PropTypes.string.isRequired +}; + +const mapStateToProps = state => ({ + strokeWidth: state.scratchPaint.color.strokeWidth +}); +const mapDispatchToProps = dispatch => ({ + handleChangeStrokeWidth: strokeWidth => { + dispatch(changeStrokeWidth(strokeWidth)); + } +}); + +export default connect( + mapStateToProps, + mapDispatchToProps +)(StrokeWidthIndicator); diff --git a/src/reducers/color.js b/src/reducers/color.js index 62bba3a1..016b17ce 100644 --- a/src/reducers/color.js +++ b/src/reducers/color.js @@ -1,8 +1,10 @@ import {combineReducers} from 'redux'; import fillColorReducer from './fill-color'; import strokeColorReducer from './stroke-color'; +import strokeWidthReducer from './stroke-width'; export default combineReducers({ fillColor: fillColorReducer, - strokeColor: strokeColorReducer + strokeColor: strokeColorReducer, + strokeWidth: strokeWidthReducer }); diff --git a/src/reducers/line-mode.js b/src/reducers/line-mode.js deleted file mode 100644 index 8845ace4..00000000 --- a/src/reducers/line-mode.js +++ /dev/null @@ -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 -}; diff --git a/src/reducers/scratch-paint-reducer.js b/src/reducers/scratch-paint-reducer.js index 613bcfdb..6e637526 100644 --- a/src/reducers/scratch-paint-reducer.js +++ b/src/reducers/scratch-paint-reducer.js @@ -2,13 +2,11 @@ import {combineReducers} from 'redux'; import modeReducer from './modes'; import brushModeReducer from './brush-mode'; import eraserModeReducer from './eraser-mode'; -import lineModeReducer from './line-mode'; import colorReducer from './color'; export default combineReducers({ mode: modeReducer, brushMode: brushModeReducer, eraserMode: eraserModeReducer, - lineMode: lineModeReducer, color: colorReducer }); diff --git a/src/reducers/stroke-width.js b/src/reducers/stroke-width.js new file mode 100644 index 00000000..615cab12 --- /dev/null +++ b/src/reducers/stroke-width.js @@ -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 +}; diff --git a/test/unit/line-mode-reducer.test.js b/test/unit/line-mode-reducer.test.js deleted file mode 100644 index cd24cb99..00000000 --- a/test/unit/line-mode-reducer.test.js +++ /dev/null @@ -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); -}); diff --git a/test/unit/stroke-width-reducer.test.js b/test/unit/stroke-width-reducer.test.js new file mode 100644 index 00000000..a2189049 --- /dev/null +++ b/test/unit/stroke-width-reducer.test.js @@ -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); +});