diff --git a/src/containers/oval-mode.jsx b/src/containers/oval-mode.jsx index 03678acd7c..da8d441550 100644 --- a/src/containers/oval-mode.jsx +++ b/src/containers/oval-mode.jsx @@ -4,11 +4,12 @@ import React from 'react'; import {connect} from 'react-redux'; import bindAll from 'lodash.bindall'; import Modes from '../lib/modes'; -import ColorStyleProptype from '../lib/color-style-proptype'; import {MIXED} from '../helper/style-path'; +import ColorStyleProptype from '../lib/color-style-proptype'; +import GradientTypes from '../lib/gradient-types'; -import {changeFillColor, DEFAULT_COLOR} from '../reducers/fill-style'; -import {changeStrokeColor} from '../reducers/stroke-style'; +import {changeFillColor, clearFillGradient, DEFAULT_COLOR} from '../reducers/fill-style'; +import {changeStrokeColor, clearStrokeGradient} from '../reducers/stroke-style'; import {changeMode} from '../reducers/modes'; import {clearSelectedItems, setSelectedItems} from '../reducers/selected-items'; import {setCursor} from '../reducers/cursor'; @@ -22,7 +23,8 @@ class OvalMode extends React.Component { super(props); bindAll(this, [ 'activateTool', - 'deactivateTool' + 'deactivateTool', + 'validateColorState' ]); } componentDidMount () { @@ -54,23 +56,8 @@ class OvalMode extends React.Component { } activateTool () { clearSelection(this.props.clearSelectedItems); - // If fill and stroke color are both mixed/transparent/absent, set fill to default and stroke to transparent. - // If exactly one of fill or stroke color is set, set the other one to transparent. - // This way the tool won't draw an invisible state, or be unclear about what will be drawn. - const {strokeWidth} = this.props.colorState; - const fillColor = this.props.colorState.fillColor.primary; - const strokeColor = this.props.colorState.strokeColor.primary; - const fillColorPresent = fillColor !== MIXED && fillColor !== null; - const strokeColorPresent = - strokeColor !== MIXED && strokeColor !== null && strokeWidth !== null && strokeWidth !== 0; - if (!fillColorPresent && !strokeColorPresent) { - this.props.onChangeFillColor(DEFAULT_COLOR); - this.props.onChangeStrokeColor(null); - } else if (!fillColorPresent && strokeColorPresent) { - this.props.onChangeFillColor(null); - } else if (fillColorPresent && !strokeColorPresent) { - this.props.onChangeStrokeColor(null); - } + this.validateColorState(); + this.tool = new OvalTool( this.props.setSelectedItems, this.props.clearSelectedItems, @@ -85,6 +72,51 @@ class OvalMode extends React.Component { this.tool.remove(); this.tool = null; } + validateColorState () { + // Make sure that at least one of fill/stroke is set, and that MIXED is not one of the colors. + // If fill and stroke color are both missing, set fill to default and stroke to transparent. + // If exactly one of fill or stroke color is set, set the other one to transparent. + const {strokeWidth} = this.props.colorState; + const fillColor1 = this.props.colorState.fillColor.primary; + let fillColor2 = this.props.colorState.fillColor.secondary; + let fillGradient = this.props.colorState.fillColor.gradientType; + const strokeColor1 = this.props.colorState.strokeColor.primary; + let strokeColor2 = this.props.colorState.strokeColor.secondary; + let strokeGradient = this.props.colorState.strokeColor.gradientType; + + if (fillColor2 === MIXED) { + this.props.clearFillGradient(); + fillColor2 = null; + fillGradient = GradientTypes.SOLID; + } + if (strokeColor2 === MIXED) { + this.props.clearStrokeGradient(); + strokeColor2 = null; + strokeGradient = GradientTypes.SOLID; + } + + const fillColorMissing = fillColor1 === MIXED || + (fillGradient === GradientTypes.SOLID && fillColor1 === null) || + (fillGradient !== GradientTypes.SOLID && fillColor1 === null && fillColor2 === null); + const strokeColorMissing = strokeColor1 === MIXED || + strokeWidth === null || + strokeWidth === 0 || + (strokeGradient === GradientTypes.SOLID && strokeColor1 === null) || + (strokeGradient !== GradientTypes.SOLID && strokeColor1 === null && strokeColor2 === null); + + if (fillColorMissing && strokeColorMissing) { + this.props.onChangeFillColor(DEFAULT_COLOR); + this.props.clearFillGradient(); + this.props.onChangeStrokeColor(null); + this.props.clearStrokeGradient(); + } else if (fillColorMissing && !strokeColorMissing) { + this.props.onChangeFillColor(null); + this.props.clearFillGradient(); + } else if (!fillColorMissing && strokeColorMissing) { + this.props.onChangeStrokeColor(null); + this.props.clearStrokeGradient(); + } + } render () { return ( ({ clearSelectedItems: () => { dispatch(clearSelectedItems()); }, + clearFillGradient: () => { + dispatch(clearFillGradient()); + }, + clearStrokeGradient: () => { + dispatch(clearStrokeGradient()); + }, setCursor: cursorString => { dispatch(setCursor(cursorString)); }, diff --git a/src/containers/rect-mode.jsx b/src/containers/rect-mode.jsx index df8c8a3efc..887f32f2f0 100644 --- a/src/containers/rect-mode.jsx +++ b/src/containers/rect-mode.jsx @@ -4,11 +4,12 @@ import React from 'react'; import {connect} from 'react-redux'; import bindAll from 'lodash.bindall'; import Modes from '../lib/modes'; -import ColorStyleProptype from '../lib/color-style-proptype'; import {MIXED} from '../helper/style-path'; +import ColorStyleProptype from '../lib/color-style-proptype'; +import GradientTypes from '../lib/gradient-types'; -import {changeFillColor, DEFAULT_COLOR} from '../reducers/fill-style'; -import {changeStrokeColor} from '../reducers/stroke-style'; +import {changeFillColor, clearFillGradient, DEFAULT_COLOR} from '../reducers/fill-style'; +import {changeStrokeColor, clearStrokeGradient} from '../reducers/stroke-style'; import {changeMode} from '../reducers/modes'; import {clearSelectedItems, setSelectedItems} from '../reducers/selected-items'; import {setCursor} from '../reducers/cursor'; @@ -22,7 +23,8 @@ class RectMode extends React.Component { super(props); bindAll(this, [ 'activateTool', - 'deactivateTool' + 'deactivateTool', + 'validateColorState' ]); } componentDidMount () { @@ -54,23 +56,8 @@ class RectMode extends React.Component { } activateTool () { clearSelection(this.props.clearSelectedItems); - // If fill and stroke color are both mixed/transparent/absent, set fill to default and stroke to transparent. - // If exactly one of fill or stroke color is set, set the other one to transparent. - // This way the tool won't draw an invisible state, or be unclear about what will be drawn. - const {strokeWidth} = this.props.colorState; - const fillColor = this.props.colorState.fillColor.primary; - const strokeColor = this.props.colorState.strokeColor.primary; - const fillColorPresent = fillColor !== MIXED && fillColor !== null; - const strokeColorPresent = - strokeColor !== MIXED && strokeColor !== null && strokeWidth !== null && strokeWidth !== 0; - if (!fillColorPresent && !strokeColorPresent) { - this.props.onChangeFillColor(DEFAULT_COLOR); - this.props.onChangeStrokeColor(null); - } else if (!fillColorPresent && strokeColorPresent) { - this.props.onChangeFillColor(null); - } else if (fillColorPresent && !strokeColorPresent) { - this.props.onChangeStrokeColor(null); - } + this.validateColorState(); + this.tool = new RectTool( this.props.setSelectedItems, this.props.clearSelectedItems, @@ -80,6 +67,51 @@ class RectMode extends React.Component { this.tool.setColorState(this.props.colorState); this.tool.activate(); } + validateColorState () { // TODO move to shared class + // Make sure that at least one of fill/stroke is set, and that MIXED is not one of the colors. + // If fill and stroke color are both missing, set fill to default and stroke to transparent. + // If exactly one of fill or stroke color is set, set the other one to transparent. + const {strokeWidth} = this.props.colorState; + const fillColor1 = this.props.colorState.fillColor.primary; + let fillColor2 = this.props.colorState.fillColor.secondary; + let fillGradient = this.props.colorState.fillColor.gradientType; + const strokeColor1 = this.props.colorState.strokeColor.primary; + let strokeColor2 = this.props.colorState.strokeColor.secondary; + let strokeGradient = this.props.colorState.strokeColor.gradientType; + + if (fillColor2 === MIXED) { + this.props.clearFillGradient(); + fillColor2 = null; + fillGradient = GradientTypes.SOLID; + } + if (strokeColor2 === MIXED) { + this.props.clearStrokeGradient(); + strokeColor2 = null; + strokeGradient = GradientTypes.SOLID; + } + + const fillColorMissing = fillColor1 === MIXED || + (fillGradient === GradientTypes.SOLID && fillColor1 === null) || + (fillGradient !== GradientTypes.SOLID && fillColor1 === null && fillColor2 === null); + const strokeColorMissing = strokeColor1 === MIXED || + strokeWidth === null || + strokeWidth === 0 || + (strokeGradient === GradientTypes.SOLID && strokeColor1 === null) || + (strokeGradient !== GradientTypes.SOLID && strokeColor1 === null && strokeColor2 === null); + + if (fillColorMissing && strokeColorMissing) { + this.props.onChangeFillColor(DEFAULT_COLOR); + this.props.clearFillGradient(); + this.props.onChangeStrokeColor(null); + this.props.clearStrokeGradient(); + } else if (fillColorMissing && !strokeColorMissing) { + this.props.onChangeFillColor(null); + this.props.clearFillGradient(); + } else if (!fillColorMissing && strokeColorMissing) { + this.props.onChangeStrokeColor(null); + this.props.clearStrokeGradient(); + } + } deactivateTool () { this.tool.deactivateTool(); this.tool.remove(); @@ -96,6 +128,8 @@ class RectMode extends React.Component { } RectMode.propTypes = { + clearFillGradient: PropTypes.func.isRequired, + clearStrokeGradient: PropTypes.func.isRequired, clearSelectedItems: PropTypes.func.isRequired, colorState: PropTypes.shape({ fillColor: ColorStyleProptype, @@ -121,6 +155,12 @@ const mapDispatchToProps = dispatch => ({ clearSelectedItems: () => { dispatch(clearSelectedItems()); }, + clearFillGradient: () => { + dispatch(clearFillGradient()); + }, + clearStrokeGradient: () => { + dispatch(clearStrokeGradient()); + }, setSelectedItems: () => { dispatch(setSelectedItems(getSelectedLeafItems(), false /* bitmapMode */)); }, diff --git a/src/helper/style-path.js b/src/helper/style-path.js index 07663296cb..839a5a0747 100644 --- a/src/helper/style-path.js +++ b/src/helper/style-path.js @@ -298,17 +298,25 @@ const applyGradientTypeToSelection = function (gradientType, applyToStroke, text continue; } - if (!hasGradient && applyToStroke) { - const noStrokeOriginally = item.strokeWidth === 0 || !itemColor || + // If this is a stroke, we don't display it as having a gradient in the color picker + // if there's no stroke width. Then treat it as if it doesn't have a gradient. + let hasDisplayGradient = hasGradient; + if (applyToStroke) hasDisplayGradient = hasGradient && item.strokeWidth > 0; + if (!hasDisplayGradient) { + const noColorOriginally = !itemColor || (itemColor.gradient && itemColor.gradient.stops && - itemColor.gradient.stops.length === 2 && - itemColor.gradient.stops[0].color.alpha === 0 && - itemColor.gradient.stops[1].color.alpha === 0); + itemColor.gradient.stops[0].color.alpha === 0); + const addingStroke = applyToStroke && item.strokeWidth === 0; const hasGradientNow = itemColor1 || itemColor2; - if (noStrokeOriginally && hasGradientNow) { - // Make outline visible - item.strokeWidth = 1; + if ((noColorOriginally || addingStroke) && hasGradientNow) { + if (applyToStroke) { + // Make outline visible + item.strokeWidth = 1; + } + // Make the gradient black to white + itemColor1 = 'black'; + itemColor2 = 'white'; } } @@ -323,18 +331,18 @@ const applyGradientTypeToSelection = function (gradientType, applyToStroke, text // If the item's gradient type differs from the gradient type we want to apply, then we change it switch (gradientType) { case GradientTypes.RADIAL: { - const hasRadialGradient = hasGradient && itemColor.gradient.radial; + const hasRadialGradient = hasDisplayGradient && itemColor.gradient.radial; gradientTypeDiffers = !hasRadialGradient; break; } case GradientTypes.HORIZONTAL: { - const hasHorizontalGradient = hasGradient && !itemColor.gradient.radial && + const hasHorizontalGradient = hasDisplayGradient && !itemColor.gradient.radial && Math.abs(itemColor.origin.y - itemColor.destination.y) < 1e-8; gradientTypeDiffers = !hasHorizontalGradient; break; } case GradientTypes.VERTICAL: { - const hasVerticalGradient = hasGradient && !itemColor.gradient.radial && + const hasVerticalGradient = hasDisplayGradient && !itemColor.gradient.radial && Math.abs(itemColor.origin.x - itemColor.destination.x) < 1e-8; gradientTypeDiffers = !hasVerticalGradient; break; @@ -462,11 +470,14 @@ const getColorsFromSelection = function (selectedItems, bitmapMode) { let strokeColorString = primary; const strokeColor2String = secondary; - const strokeGradientType = gradientType; + let strokeGradientType = gradientType; // If the item's stroke width is 0, pretend the stroke color is null if (!item.strokeWidth) { strokeColorString = null; + // Hide the second color. This way if you choose a second color, remove + // the gradient, and re-add it, your second color selection is preserved. + strokeGradientType = GradientTypes.SOLID; } // Stroke color is fill color in bitmap