Skip to content

Commit 7f28a07

Browse files
authored
Merge pull request TurboWarp#3 from 08draven/develop
fix arrow position jank and add smoothing option and add inset / outset (IO keys)
2 parents fa681ee + f8563d4 commit 7f28a07

File tree

7 files changed

+580
-522
lines changed

7 files changed

+580
-522
lines changed

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

Lines changed: 504 additions & 478 deletions
Large diffs are not rendered by default.

src/helper/blob-tools/blob.js

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,36 @@ import paper from '@scratch/paper';
22
import log from '../../log/log';
33
import BroadBrushHelper from './broad-brush-helper';
44
import SegmentBrushHelper from './segment-brush-helper';
5-
import {MIXED, styleCursorPreview} from '../../helper/style-path';
6-
import {clearSelection, getItems} from '../../helper/selection';
7-
import {getGuideLayer, setGuideItem} from '../../helper/layer';
8-
import {isCompoundPathChild} from '../compound-path';
5+
import { MIXED, styleCursorPreview } from '../../helper/style-path';
6+
import { clearSelection, getItems } from '../../helper/selection';
7+
import { getGuideLayer, setGuideItem } from '../../helper/layer';
8+
import { isCompoundPathChild } from '../compound-path';
99

1010
/**
1111
* Shared code for the brush and eraser mode. Adds functions on the paper tool object
1212
* to handle mouse events, which are delegated to broad-brush-helper and segment-brush-helper
1313
* based on the brushSize in the state.
1414
*/
1515
class Blobbiness {
16-
static get BROAD () {
16+
static get BROAD() {
1717
return 'broadbrush';
1818
}
19-
static get SEGMENT () {
19+
static get SEGMENT() {
2020
return 'segmentbrush';
2121
}
2222

2323
// If brush size >= threshold use segment brush, else use broadbrush
2424
// Segment brush has performance issues at low threshold, but broad brush has weird corners
2525
// which get more obvious the bigger it is
26-
static get THRESHOLD () {
26+
static get THRESHOLD() {
2727
return 30 / paper.view.zoom;
2828
}
2929

3030
/**
3131
* @param {function} onUpdateImage call when the drawing has changed to let listeners know
3232
* @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state
3333
*/
34-
constructor (onUpdateImage, clearSelectedItems) {
34+
constructor(onUpdateImage, clearSelectedItems) {
3535
this.broadBrushHelper = new BroadBrushHelper();
3636
this.segmentBrushHelper = new SegmentBrushHelper();
3737
this.onUpdateImage = onUpdateImage;
@@ -53,7 +53,7 @@ class Blobbiness {
5353
* @param {?string} options.strokeColor Color of the brush outline.
5454
* @param {?number} options.strokeWidth Width of the brush outline.
5555
*/
56-
setOptions (options) {
56+
setOptions(options) {
5757
const oldFillColor = this.options ? this.options.fillColor : 'black';
5858
const oldStrokeColor = this.options ? this.options.strokeColor : null;
5959
const oldStrokeWidth = this.options ? this.options.strokeWidth : null;
@@ -67,6 +67,7 @@ class Blobbiness {
6767
strokeWidth: options.strokeWidth === null ? oldStrokeWidth : options.strokeWidth
6868
};
6969
this.resizeCursorIfNeeded();
70+
7071
}
7172

7273
/**
@@ -79,14 +80,15 @@ class Blobbiness {
7980
* @param {?string} options.strokeColor Color of the brush outline.
8081
* @param {?number} options.strokeWidth Width of the brush outline.
8182
*/
82-
activateTool (options) {
83+
activateTool(options) {
8384
this.tool = new paper.Tool();
8485
this.cursorPreviewLastPoint = new paper.Point(-10000, -10000);
8586
this.setOptions(options);
8687
this.tool.active = false;
8788
this.tool.fixedDistance = 1;
8889

8990
const blob = this;
91+
9092
this.tool.onMouseMove = function (event) {
9193
blob.resizeCursorIfNeeded(event.point);
9294
styleCursorPreview(blob.cursorPreview, blob.options);
@@ -125,6 +127,7 @@ class Blobbiness {
125127
};
126128

127129
this.tool.onMouseUp = function (event) {
130+
128131
if (event.event.button > 0 || !this.active) return; // only first mouse button
129132

130133
let lastPath;
@@ -155,7 +158,7 @@ class Blobbiness {
155158
this.tool.activate();
156159
}
157160

158-
resizeCursorIfNeeded (point) {
161+
resizeCursorIfNeeded(point) {
159162
if (!this.options) {
160163
return;
161164
}
@@ -165,10 +168,10 @@ class Blobbiness {
165168
this.cursorPreview = null;
166169
}
167170
if (this.cursorPreview &&
168-
this.brushSize === this.options.brushSize &&
169-
this.fillColor === this.options.fillColor &&
170-
this.strokeColor === this.options.strokeColor &&
171-
this.cursorPreviewLastPoint.equals(point)) {
171+
this.brushSize === this.options.brushSize &&
172+
this.fillColor === this.options.fillColor &&
173+
this.strokeColor === this.options.strokeColor &&
174+
this.cursorPreviewLastPoint.equals(point)) {
172175
return;
173176
}
174177
if (typeof point !== 'undefined') {
@@ -192,7 +195,7 @@ class Blobbiness {
192195
styleCursorPreview(this.cursorPreview, this.options);
193196
}
194197

195-
mergeBrush (lastPath) {
198+
mergeBrush(lastPath) {
196199
const blob = this;
197200

198201
// Get all path items to merge with
@@ -243,7 +246,7 @@ class Blobbiness {
243246
}
244247
}
245248

246-
mergeEraser (lastPath) {
249+
mergeEraser(lastPath) {
247250
const blob = this;
248251

249252
// Get all path items to merge with
@@ -336,7 +339,7 @@ class Blobbiness {
336339
lastPath.remove();
337340
}
338341

339-
separateCompoundPath (compoundPath) {
342+
separateCompoundPath(compoundPath) {
340343
if (!compoundPath.isClockwise()) {
341344
compoundPath.reverse();
342345
}
@@ -381,35 +384,35 @@ class Blobbiness {
381384
}
382385
}
383386

384-
colorMatch (existingPath, addedPath) {
387+
colorMatch(existingPath, addedPath) {
385388
// Note: transparent fill colors do notdetect as touching
386389
return existingPath.getFillColor().equals(addedPath.getFillColor()) &&
387-
(addedPath.getStrokeColor() === existingPath.getStrokeColor() || // both null
388-
(addedPath.getStrokeColor() &&
389-
addedPath.getStrokeColor().equals(existingPath.getStrokeColor()))) &&
390-
addedPath.getStrokeWidth() === existingPath.getStrokeWidth() &&
391-
this.touches(existingPath, addedPath);
390+
(addedPath.getStrokeColor() === existingPath.getStrokeColor() || // both null
391+
(addedPath.getStrokeColor() &&
392+
addedPath.getStrokeColor().equals(existingPath.getStrokeColor()))) &&
393+
addedPath.getStrokeWidth() === existingPath.getStrokeWidth() &&
394+
this.touches(existingPath, addedPath);
392395
}
393396

394-
touches (path1, path2) {
397+
touches(path1, path2) {
395398
// Two shapes are touching if their paths intersect
396399
if (path1 && path2 && path1.intersects(path2)) {
397400
return true;
398401
}
399402
return this.firstEnclosesSecond(path1, path2) || this.firstEnclosesSecond(path2, path1);
400403
}
401404

402-
firstEnclosesSecond (path1, path2) {
405+
firstEnclosesSecond(path1, path2) {
403406
// Two shapes are also touching if one is completely inside the other
404407
if (path1 && path2 && path2.firstSegment && path2.firstSegment.point &&
405-
path1.hitTest(path2.firstSegment.point)) {
408+
path1.hitTest(path2.firstSegment.point)) {
406409
return true;
407410
}
408411
// TODO: clean up these no point paths
409412
return false;
410413
}
411414

412-
matchesAnyChild (group, path) {
415+
matchesAnyChild(group, path) {
413416
for (const child of group.children) {
414417
if (child.children && this.matchesAnyChild(path, child)) {
415418
return true;
@@ -421,7 +424,7 @@ class Blobbiness {
421424
return false;
422425
}
423426

424-
isMergeable (newPath, existingPath) {
427+
isMergeable(newPath, existingPath) {
425428
// Path or compound path
426429
if (!(existingPath instanceof paper.PathItem)) {
427430
return;
@@ -434,7 +437,7 @@ class Blobbiness {
434437
return existingPath !== newPath; // don't merge with self
435438
}
436439

437-
deactivateTool () {
440+
deactivateTool() {
438441
if (this.cursorPreview) {
439442
this.cursorPreview.remove();
440443
this.cursorPreview = null;

src/helper/blob-tools/broad-brush-helper.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ class BroadBrushHelper {
114114
this.finalPath.insert(0, event.point.subtract(step));
115115

116116
if (this.finalPath.segments.length > this.smoothed + (this.smoothingThreshold * 2)) {
117-
this.simplify(1);
117+
this.simplify(10 / options.segSize);
118118
}
119119

120120
this.lastVec = event.delta;

src/helper/blob-tools/segment-brush-helper.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ class SegmentBrushHelper {
7171
this.finalPath = newPath;
7272
}
7373

74-
onSegmentMouseUp (event) {
74+
onSegmentMouseUp (event, options) {
7575
if (event.event.button > 0) return; // only first mouse button
7676

7777
// TODO: This smoothing tends to cut off large portions of the path! Would like to eventually
@@ -81,7 +81,7 @@ class SegmentBrushHelper {
8181
// paths tends to cut off the path.
8282
if (this.finalPath.segments && this.finalPath.segments.length > 4) {
8383
this.finalPath.closed = false;
84-
this.finalPath.simplify(2);
84+
this.finalPath.simplify(10 / options.segSize);
8585
this.finalPath.closed = true;
8686
// Merge again with the first point, since it gets distorted when we unclose the path.
8787
const temp = this.finalPath.unite(this.firstCircle);

src/helper/selection-tools/reshape-tool.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,18 @@ class ReshapeTool extends paper.Tool {
328328
translation = new paper.Point(-nudgeAmount, 0);
329329
} else if (event.key === 'right') {
330330
translation = new paper.Point(nudgeAmount, 0);
331+
} else if (event.key == 'i' || event.key == 'o') {
332+
333+
const segments = getSelectedSegments();
334+
for (const seg of segments) {
335+
let parent = seg.path;
336+
let p = seg.point;
337+
if (event.key == 'o') {
338+
seg.point = p.add(parent.getNormalAt(parent.getOffsetOf(p)));
339+
} else {
340+
seg.point = p.subtract(parent.getNormalAt(parent.getOffsetOf(p)));
341+
}
342+
}
331343
}
332344

333345
if (translation) {

src/helper/tools/arrow-tool.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,19 +260,20 @@ class ArrowTool extends paper.Tool {
260260
this.tri = new paper.Path(constructArrowPath(event.modifiers.control, pathOptions.width, pathOptions.length, pathOptions.head.width, pathOptions.head.length));
261261
// console.log(pathOptions.angle, this.tri)
262262
// console.log(pathOptions.angle)
263-
this.tri.rotate(pathOptions.angle, event.downPoint);
264263
// this.tri.scale(tri.size.width / 100, tri.size.height / 100, event.downPoint);
265264

266265
// create new position
267266
if ((!this.arrowPathLocked) && this.arrowPathLockedState) {
268267
this.tri.position = event.downPoint;
269268

270-
const dimensions = event.point.subtract(event.downPoint);
269+
const dimensions = new paper.Point(event.point.getDistance(event.downPoint),0);
271270
this.tri.position = event.downPoint.add(dimensions.multiply(0.5));
272271
} else if (this.arrowPathLocked) {
273272
this.tri.position = this.arrowPathLockedState;
274273
}
275274

275+
this.tri.rotate(pathOptions.angle, event.downPoint);
276+
276277
// add guide text
277278
// remove first
278279
if (this.guideText) {

src/reducers/brush-mode.js

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
import log from '../log/log';
22

33
const CHANGE_BRUSH_SIZE = 'scratch-paint/brush-mode/CHANGE_BRUSH_SIZE';
4-
const initialState = {brushSize: 10};
4+
const CHANGE_SEG_SIZE = CHANGE_BRUSH_SIZE + 1;
5+
const initialState = { brushSize: 10, segSize: 1 };
56

67
const reducer = function (state, action) {
78
if (typeof state === 'undefined') state = initialState;
9+
let {segSize, brushSize} = state;
810
switch (action.type) {
9-
case CHANGE_BRUSH_SIZE:
10-
if (isNaN(action.brushSize)) {
11-
log.warn(`Invalid brush size: ${action.brushSize}`);
11+
case CHANGE_BRUSH_SIZE:
12+
if (isNaN(action.brushSize)) {
13+
log.warn(`Invalid brush size: ${action.brushSize}`);
14+
return state;
15+
}
16+
return { segSize, brushSize: Math.max(1, action.brushSize) };
17+
case CHANGE_SEG_SIZE:
18+
if (isNaN(action.segSize)) {
19+
log.warn(`Invalid brush size: ${action.segSize}`);
20+
return state;
21+
}
22+
return { brushSize, segSize: Math.max(1, action.segSize) };
23+
default:
1224
return state;
13-
}
14-
return {brushSize: Math.max(1, action.brushSize)};
15-
default:
16-
return state;
1725
}
1826
};
1927

@@ -25,7 +33,15 @@ const changeBrushSize = function (brushSize) {
2533
};
2634
};
2735

36+
const changeSegSize = function (segSize) {
37+
return {
38+
type: CHANGE_SEG_SIZE,
39+
segSize: segSize
40+
};
41+
};
42+
2843
export {
2944
reducer as default,
30-
changeBrushSize
45+
changeBrushSize,
46+
changeSegSize
3147
};

0 commit comments

Comments
 (0)