Skip to content

Commit c2a6e42

Browse files
committed
Merge branch 'develop' of https://github.com/PenguinMod/PenguinMod-Paint into convert-text-to-shapes
2 parents bfbe313 + b67366b commit c2a6e42

18 files changed

Lines changed: 568 additions & 112 deletions

File tree

.github/workflows/node.js.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ jobs:
1313
uses: actions/setup-node@v3
1414
with:
1515
node-version: 14.x
16-
- run: npm ci
17-
- run: npm test
1816
- name: Repository Dispatch
1917
uses: peter-evans/repository-dispatch@v2.0.1
2018
with:

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@
3232
"minilog": "3.1.0",
3333
"opentype.js": "^1.3.4",
3434
"parse-color": "1.0.0",
35-
"prop-types": "^15.5.10"
35+
"prop-types": "^15.5.10",
36+
"opentype.js": "^1.3.4"
3637
},
3738
"peerDependencies": {
3839
"react": "^16",
@@ -45,7 +46,7 @@
4546
"react-style-proptype": "^3",
4647
"react-tooltip": "^3",
4748
"redux": "^3",
48-
"scratch-render-fonts": "https://github.com/PenguinMod/penguinmod-render-fonts.git"
49+
"scratch-render-fonts": "github:PenguinMod/penguinmod-render-fonts#master"
4950
},
5051
"devDependencies": {
5152
"autoprefixer": "9.7.4",

src/components/forms/label.jsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import styles from './label.css';
99

1010
const Label = props => (
1111
<label className={styles.inputGroup}>
12-
<span className={props.secondary ? styles.inputLabelSecondary : styles.inputLabel}>
12+
<span className={props.secondary ? styles.inputLabelSecondary : styles.inputLabel} style={props.style}>
1313
{props.text}
1414
</span>
1515
{props.children}
@@ -19,7 +19,8 @@ const Label = props => (
1919
Label.propTypes = {
2020
children: PropTypes.node,
2121
secondary: PropTypes.bool,
22-
text: PropTypes.string.isRequired
22+
text: PropTypes.string.isRequired,
23+
style: PropTypes.object
2324
};
2425

2526
Label.defaultProps = {

src/components/mode-tools/mode-tools.css

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,66 @@
6666
[theme="dark"] .drop-item-shape-tool-label {
6767
border-top: 1px solid rgba(255, 255, 255, 0.25);
6868
border-bottom: 1px solid rgba(255, 255, 255, 0.25);
69-
}
69+
}
70+
71+
/* TODO replace this when we add a brush selector dropdown */
72+
$border-radius: 0.25rem;
73+
74+
.button-group-button {
75+
display: inline-block;
76+
border: 1px solid $ui-pane-border;
77+
border-radius: 0;
78+
padding: .35rem;
79+
}
80+
81+
[dir="ltr"] .button-group-button {
82+
border-left: none;
83+
}
84+
85+
[dir="rtl"] .button-group-button {
86+
border-right: none;
87+
}
88+
89+
[dir="ltr"] .button-group-button:last-of-type {
90+
border-top-right-radius: $border-radius;
91+
border-bottom-right-radius: $border-radius;
92+
}
93+
94+
[dir="ltr"] .button-group-button:first-of-type {
95+
border-left: 1px solid $ui-pane-border;
96+
border-top-left-radius: $border-radius;
97+
border-bottom-left-radius: $border-radius;
98+
}
99+
100+
[dir="rtl"] .button-group-button:last-of-type {
101+
border-top-left-radius: $border-radius;
102+
border-bottom-left-radius: $border-radius;
103+
}
104+
105+
[dir="rtl"] .button-group-button:first-of-type {
106+
border-right: 1px solid $ui-pane-border;
107+
border-top-right-radius: $border-radius;
108+
border-bottom-right-radius: $border-radius;
109+
}
110+
111+
[dir="ltr"] .button-group-button.mod-start-border {
112+
border-left: 1px solid $ui-pane-border;
113+
}
114+
115+
[dir="rtl"] .button-group-button.mod-start-border {
116+
border-right: 1px solid $ui-pane-border;
117+
}
118+
119+
[dir="ltr"] .button-group-button.mod-no-end-border {
120+
border-right: none;
121+
}
122+
123+
[dir="rtl"] .button-group-button.mod-no-end-border {
124+
border-left: none;
125+
}
126+
127+
.button-group-button-icon {
128+
width: 1.25rem;
129+
height: 1.25rem;
130+
vertical-align: middle;
131+
}

src/components/mode-tools/mode-tools.jsx

Lines changed: 92 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import Dropdown from '../dropdown/dropdown.jsx';
88
import MediaQuery from 'react-responsive';
99
import layout from '../../lib/layout-constants';
1010

11-
import { changeBrushSize, changeSimplifySize } from '../../reducers/brush-mode';
11+
import { changeBrushSize, changeSimplifySize, setBrushType } from '../../reducers/brush-mode';
1212
import { changeBrushSize as changeEraserSize, changeSimplifySize as changeEraserSimplifySize } from '../../reducers/eraser-mode';
1313
import { changeSimplifySize as changePenSimplifySize } from '../../reducers/pen-mode';
1414
import { changeRoundedRectCornerSize } from '../../reducers/rounded-rect-mode';
@@ -26,6 +26,8 @@ import Label from '../forms/label.jsx';
2626
import { defineMessages, injectIntl, intlShape } from 'react-intl';
2727
import Input from '../forms/input.jsx';
2828
import InputGroup from '../input-group/input-group.jsx';
29+
import ButtonGroup from '../button-group/button-group.jsx';
30+
import Button from '../button/button.jsx';
2931
import LabeledIconButton from '../labeled-icon-button/labeled-icon-button.jsx';
3032
import Modes from '../../lib/modes';
3133
import Formats, { isBitmap, isVector } from '../../lib/format';
@@ -96,6 +98,16 @@ const ModeToolsComponent = props => {
9698
description: 'Label for the eraser smoothing input, higher numbers control how much the drawn line will be corrected',
9799
id: 'paint.modeTools.eraserSimplify'
98100
},
101+
brushCircle: {
102+
defaultMessage: 'Circle Brush',
103+
description: 'Label for the circle brush shape',
104+
id: 'paint.modeTools.circleSquare'
105+
},
106+
brushSquare: {
107+
defaultMessage: 'Square Brush',
108+
description: 'Label for the square brush shape',
109+
id: 'paint.modeTools.brushSquare'
110+
},
99111
roundedCornerSize: {
100112
defaultMessage: 'Rounded corner size',
101113
description: 'Label for the Rounded corner size input',
@@ -215,7 +227,7 @@ const ModeToolsComponent = props => {
215227
/>
216228

217229
{hasSimplifyOption && (
218-
<Label text={props.intl.formatMessage(messages.brushSimplify)}>
230+
<Label text={props.intl.formatMessage(messages.brushSimplify)} style={{ marginLeft: 'calc(2 * .25rem)' }}>
219231
<LiveInput
220232
range
221233
small
@@ -227,6 +239,40 @@ const ModeToolsComponent = props => {
227239
/>
228240
</Label>
229241
)}
242+
243+
{/* TODO replace this with a dropdown when we add more brush shapes */}
244+
{hasSimplifyOption && (
245+
<InputGroup>
246+
<ButtonGroup>
247+
<Button
248+
className={
249+
classNames(styles.buttonGroupButton)
250+
}
251+
onClick={() => props.onBrushChange("CIRCLE")}
252+
>
253+
<img
254+
alt={props.intl.formatMessage(messages.brushCircle)}
255+
className={styles.buttonGroupButtonIcon}
256+
draggable={false}
257+
src={"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCBmaWxsPSIjMDBjM2ZmIiB3aWR0aD0iMTUiIGhlaWdodD0iMTUiIHJ4PSIxMDAiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDIuNSAyLjUpIi8+PC9zdmc+"}
258+
/>
259+
</Button>
260+
<Button
261+
className={
262+
classNames(styles.buttonGroupButton)
263+
}
264+
onClick={() => props.onBrushChange("SQUARE")}
265+
>
266+
<img
267+
alt={props.intl.formatMessage(messages.brushSquare)}
268+
className={styles.buttonGroupButtonIcon}
269+
draggable={false}
270+
src={"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCBmaWxsPSIjMDBjM2ZmIiB3aWR0aD0iMTUiIGhlaWdodD0iMTUiIHJ4PSIyIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyLjUgMi41KSIvPjwvc3ZnPg=="}
271+
/>
272+
</Button>
273+
</ButtonGroup>
274+
</InputGroup>
275+
)}
230276
</div>
231277
);
232278
}
@@ -262,7 +308,7 @@ const ModeToolsComponent = props => {
262308
/>
263309

264310
{hasSimplifyOption && (
265-
<Label text={props.intl.formatMessage(messages.eraserSimplify)}>
311+
<Label text={props.intl.formatMessage(messages.eraserSimplify)} style={{ marginLeft: 'calc(2 * .25rem)' }}>
266312
<LiveInput
267313
range
268314
small
@@ -274,8 +320,42 @@ const ModeToolsComponent = props => {
274320
/>
275321
</Label>
276322
)}
323+
324+
{/* TODO replace this with a dropdown when we add more brush shapes */}
325+
{hasSimplifyOption && (
326+
<InputGroup>
327+
<ButtonGroup>
328+
<Button
329+
className={
330+
classNames(styles.buttonGroupButton)
331+
}
332+
onClick={() => props.onBrushChange("CIRCLE")}
333+
>
334+
<img
335+
alt={props.intl.formatMessage(messages.brushCircle)}
336+
className={styles.buttonGroupButtonIcon}
337+
draggable={false}
338+
src={"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCBmaWxsPSIjMDBjM2ZmIiB3aWR0aD0iMTUiIGhlaWdodD0iMTUiIHJ4PSIxMDAiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDIuNSAyLjUpIi8+PC9zdmc+"}
339+
/>
340+
</Button>
341+
<Button
342+
className={
343+
classNames(styles.buttonGroupButton)
344+
}
345+
onClick={() => props.onBrushChange("SQUARE")}
346+
>
347+
<img
348+
alt={props.intl.formatMessage(messages.brushSquare)}
349+
className={styles.buttonGroupButtonIcon}
350+
draggable={false}
351+
src={"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCBmaWxsPSIjMDBjM2ZmIiB3aWR0aD0iMTUiIGhlaWdodD0iMTUiIHJ4PSIyIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyLjUgMi41KSIvPjwvc3ZnPg=="}
352+
/>
353+
</Button>
354+
</ButtonGroup>
355+
</InputGroup>
356+
)}
277357
</div>
278-
);
358+
)
279359
}
280360
case Modes.ROUNDED_RECT:
281361
/* falls through */
@@ -419,7 +499,7 @@ const ModeToolsComponent = props => {
419499
const changeFunctionSimplify = props.onPenSimplifySliderChange;
420500
return (
421501
<div className={classNames(props.className, styles.modeTools)}>
422-
<Label text={props.intl.formatMessage(messages.eraserSimplify)}>
502+
<Label text={props.intl.formatMessage(messages.eraserSimplify)} style={{ marginLeft: 'calc(2 * .25rem)' }}>
423503
<LiveInput
424504
range
425505
small
@@ -532,7 +612,7 @@ const ModeToolsComponent = props => {
532612
case Modes.BIT_SELECT:
533613
/* falls through */
534614
case Modes.SELECT:
535-
const reshapingMethods = (
615+
const reshapingMethods = props.format.startsWith("BITMAP") ? null : (
536616
<InputGroup className={classNames(styles.modDashedBorder, styles.modLabeledIconHeight)}>
537617
<LabeledIconButton
538618
hideLabel={hideLabel(props.intl.locale)}
@@ -773,6 +853,7 @@ ModeToolsComponent.propTypes = {
773853
clipboardItems: PropTypes.arrayOf(PropTypes.array),
774854
eraserValue: PropTypes.number,
775855
eraserSimplifyValue: PropTypes.number,
856+
brushType: PropTypes.string,
776857
penSimplifyValue: PropTypes.number,
777858
roundedCornerValue: PropTypes.number,
778859
roundedRectCornerValue: PropTypes.number,
@@ -794,6 +875,7 @@ ModeToolsComponent.propTypes = {
794875
onCurvePoints: PropTypes.func.isRequired,
795876
onDelete: PropTypes.func.isRequired,
796877
onEraserSliderChange: PropTypes.func,
878+
onBrushChange: PropTypes.func,
797879
onEraserSimplifySliderChange: PropTypes.func,
798880
onPenSimplifySliderChange: PropTypes.func,
799881
onFillShapes: PropTypes.func.isRequired,
@@ -823,6 +905,7 @@ const mapStateToProps = state => ({
823905
clipboardItems: state.scratchPaint.clipboard.items,
824906
eraserValue: state.scratchPaint.eraserMode.brushSize,
825907
eraserSimplifyValue: state.scratchPaint.eraserMode.simplifySize,
908+
brushType: state.scratchPaint.brushType,
826909
penSimplifyValue: state.scratchPaint.penMode.simplifySize,
827910
roundedRectCornerValue: state.scratchPaint.roundedRectMode.roundedCornerSize,
828911
roundedCornerValue: state.scratchPaint.rectMode.roundedCornerSize,
@@ -864,6 +947,9 @@ const mapDispatchToProps = dispatch => ({
864947
onEraserSimplifySliderChange: eraserSize => {
865948
dispatch(changeEraserSimplifySize(eraserSize));
866949
},
950+
onBrushChange: type => {
951+
dispatch(setBrushType(type));
952+
},
867953
onPenSimplifySliderChange: eraserSize => {
868954
dispatch(changePenSimplifySize(eraserSize));
869955
},

src/containers/eraser-mode.jsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class EraserMode extends React.Component {
3030
} else if (!nextProps.isEraserModeActive && this.props.isEraserModeActive) {
3131
this.deactivateTool();
3232
} else if (nextProps.isEraserModeActive && this.props.isEraserModeActive) {
33+
this.props.eraserModeState.brushType = this.props.brushModeState?.brushType;
3334
this.blob.setOptions({
3435
isEraser: true,
3536
...nextProps.eraserModeState
@@ -45,6 +46,7 @@ class EraserMode extends React.Component {
4546
}
4647
}
4748
activateTool () {
49+
this.props.eraserModeState.brushType = this.props.brushModeState?.brushType;
4850
this.blob.activateTool({isEraser: true, ...this.props.eraserModeState});
4951
}
5052
deactivateTool () {
@@ -64,7 +66,14 @@ EraserMode.propTypes = {
6466
clearSelectedItems: PropTypes.func.isRequired,
6567
eraserModeState: PropTypes.shape({
6668
brushSize: PropTypes.number.isRequired,
67-
simplifySize: PropTypes.number
69+
simplifySize: PropTypes.number,
70+
brushType: "CIRCLE"
71+
}),
72+
/* used to extract brush type */
73+
brushModeState: PropTypes.shape({
74+
brushSize: PropTypes.number.isRequired,
75+
simplifySize: PropTypes.number,
76+
brushType: "CIRCLE"
6877
}),
6978
handleMouseDown: PropTypes.func.isRequired,
7079
isEraserModeActive: PropTypes.bool.isRequired,
@@ -73,6 +82,7 @@ EraserMode.propTypes = {
7382

7483
const mapStateToProps = state => ({
7584
eraserModeState: state.scratchPaint.eraserMode,
85+
brushModeState: state.scratchPaint.brushMode,
7686
isEraserModeActive: state.scratchPaint.mode === Modes.ERASER
7787
});
7888
const mapDispatchToProps = dispatch => ({

0 commit comments

Comments
 (0)