Comparing version 0.2.3 to 0.3.0
@@ -0,1 +1,5 @@ | ||
# 0.3.0 | ||
* Pen-related bug fixes | ||
* API: Allow creating custom tools and tool widgets. | ||
# 0.2.3 | ||
@@ -2,0 +6,0 @@ * Fix lines with thickness set to small numbers self-intersecting many times. |
@@ -126,3 +126,3 @@ import { Bezier } from 'bezier-js'; | ||
roundPoint(point) { | ||
let minFit = Math.min(this.minFitAllowed, this.curveStartWidth); | ||
let minFit = Math.min(this.minFitAllowed, this.curveStartWidth / 2); | ||
if (minFit < 1e-10) { | ||
@@ -129,0 +129,0 @@ minFit = this.minFitAllowed; |
@@ -0,1 +1,3 @@ | ||
export * from './builders/types'; | ||
export { makeFreehandLineBuilder } from './builders/FreehandLineBuilder'; | ||
import AbstractComponent from './AbstractComponent'; | ||
@@ -2,0 +4,0 @@ import Stroke from './Stroke'; |
@@ -0,1 +1,3 @@ | ||
export * from './builders/types'; | ||
export { makeFreehandLineBuilder } from './builders/FreehandLineBuilder'; | ||
import AbstractComponent from './AbstractComponent'; | ||
@@ -2,0 +4,0 @@ import Stroke from './Stroke'; |
@@ -305,3 +305,2 @@ var _a; | ||
render(renderer, visibleRect) { | ||
// Don't render components that are < 0.1% of the viewport. | ||
const leaves = this.getLeavesIntersectingRegion(visibleRect, rect => renderer.isTooSmallToRender(rect)); | ||
@@ -308,0 +307,0 @@ sortLeavesByZIndex(leaves); |
@@ -16,3 +16,4 @@ /** | ||
import Editor from './Editor'; | ||
export { EditorEventType } from './types'; | ||
export { default as EditorImage } from './EditorImage'; | ||
export * from './types'; | ||
export { default as getLocalizationTable } from './localizations/getLocalizationTable'; | ||
@@ -24,4 +25,7 @@ export * from './localization'; | ||
export * from './commands/lib'; | ||
export * from './tools/lib'; | ||
export * from './toolbar/lib'; | ||
export { default as Pointer, PointerDevice } from './Pointer'; | ||
export { default as HTMLToolbar } from './toolbar/HTMLToolbar'; | ||
export { Editor }; | ||
export default Editor; |
@@ -16,3 +16,4 @@ /** | ||
import Editor from './Editor'; | ||
export { EditorEventType } from './types'; | ||
export { default as EditorImage } from './EditorImage'; | ||
export * from './types'; | ||
export { default as getLocalizationTable } from './localizations/getLocalizationTable'; | ||
@@ -24,4 +25,7 @@ export * from './localization'; | ||
export * from './commands/lib'; | ||
export * from './tools/lib'; | ||
export * from './toolbar/lib'; | ||
export { default as Pointer, PointerDevice } from './Pointer'; | ||
export { default as HTMLToolbar } from './toolbar/HTMLToolbar'; | ||
export { Editor }; | ||
export default Editor; |
@@ -180,5 +180,6 @@ // A cache record with sub-nodes. | ||
// Determine whether we already have rendered the items | ||
const tooSmallToRender = (rect) => rect.w / this.region.w < 1 / this.cacheState.props.blockResolution.x; | ||
const leaves = []; | ||
for (const item of items) { | ||
leaves.push(...item.getLeavesIntersectingRegion(this.region, rect => rect.w / this.region.w < 2 / this.cacheState.props.blockResolution.x)); | ||
leaves.push(...item.getLeavesIntersectingRegion(this.region, tooSmallToRender)); | ||
} | ||
@@ -185,0 +186,0 @@ sortLeavesByZIndex(leaves); |
@@ -74,4 +74,4 @@ /** | ||
blockResolution: cacheBlockResolution, | ||
cacheSize: 500 * 500 * 4 * 150, | ||
maxScale: 1.5, | ||
cacheSize: 600 * 600 * 4 * 120, | ||
maxScale: 1.4, | ||
minComponentsPerCache: 45, | ||
@@ -78,0 +78,0 @@ minComponentsToUseCache: 105, |
@@ -40,10 +40,10 @@ import Color4 from '../../Color4'; | ||
if (draftMode) { | ||
this.minSquareCurveApproxDist = 64; | ||
this.minRenderSizeBothDimens = 8; | ||
this.minRenderSizeAnyDimen = 2; | ||
this.minSquareCurveApproxDist = 9; | ||
this.minRenderSizeBothDimens = 2; | ||
this.minRenderSizeAnyDimen = 0.5; | ||
} | ||
else { | ||
this.minSquareCurveApproxDist = 1; | ||
this.minRenderSizeBothDimens = 0.5; | ||
this.minRenderSizeAnyDimen = 0; | ||
this.minSquareCurveApproxDist = 0.5; | ||
this.minRenderSizeBothDimens = 0.3; | ||
this.minRenderSizeAnyDimen = 1e-5; | ||
} | ||
@@ -50,0 +50,0 @@ } |
import Editor from '../Editor'; | ||
import { ToolbarLocalization } from './localization'; | ||
import { ActionButtonIcon } from './types'; | ||
import BaseWidget from './widgets/BaseWidget'; | ||
export declare const toolbarCSSPrefix = "toolbar-"; | ||
@@ -10,8 +11,10 @@ export default class HTMLToolbar { | ||
private static colorisStarted; | ||
private updateColoris; | ||
constructor(editor: Editor, parent: HTMLElement, localizationTable?: ToolbarLocalization); | ||
setupColorPickers(): void; | ||
addWidget(widget: BaseWidget): void; | ||
addActionButton(title: string | ActionButtonIcon, command: () => void, parent?: Element): HTMLButtonElement; | ||
private addUndoRedoButtons; | ||
addUndoRedoButtons(): void; | ||
addDefaultToolWidgets(): void; | ||
addDefaultActionButtons(): void; | ||
} |
@@ -1,7 +0,4 @@ | ||
import { ToolType } from '../tools/ToolController'; | ||
import { EditorEventType } from '../types'; | ||
import { coloris, init as colorisInit } from '@melloware/coloris'; | ||
import Color4 from '../Color4'; | ||
import Pen from '../tools/Pen'; | ||
import Eraser from '../tools/Eraser'; | ||
import SelectionTool from '../tools/SelectionTool'; | ||
@@ -12,7 +9,8 @@ import { defaultToolbarLocalization } from './localization'; | ||
import TextTool from '../tools/TextTool'; | ||
import PenWidget from './widgets/PenWidget'; | ||
import EraserWidget from './widgets/EraserWidget'; | ||
import { SelectionWidget } from './widgets/SelectionWidget'; | ||
import PenToolWidget from './widgets/PenToolWidget'; | ||
import EraserWidget from './widgets/EraserToolWidget'; | ||
import SelectionToolWidget from './widgets/SelectionToolWidget'; | ||
import TextToolWidget from './widgets/TextToolWidget'; | ||
import HandToolWidget from './widgets/HandToolWidget'; | ||
import { EraserTool, PenTool } from '../tools/lib'; | ||
export const toolbarCSSPrefix = 'toolbar-'; | ||
@@ -23,2 +21,3 @@ export default class HTMLToolbar { | ||
this.localizationTable = localizationTable; | ||
this.updateColoris = null; | ||
this.container = document.createElement('div'); | ||
@@ -36,2 +35,7 @@ this.container.classList.add(`${toolbarCSSPrefix}root`); | ||
setupColorPickers() { | ||
// Much of the setup only needs to be done once. | ||
if (this.updateColoris) { | ||
this.updateColoris(); | ||
return; | ||
} | ||
const closePickerOverlay = document.createElement('div'); | ||
@@ -62,2 +66,3 @@ closePickerOverlay.className = `${toolbarCSSPrefix}closeColorPickerOverlay`; | ||
initColoris(); | ||
this.updateColoris = initColoris; | ||
const addColorToSwatch = (newColor) => { | ||
@@ -93,2 +98,8 @@ let alreadyPresent = false; | ||
} | ||
// Adds an `ActionButtonWidget` or `BaseToolWidget`. The widget should not have already have a parent | ||
// (i.e. its `addTo` method should not have been called). | ||
addWidget(widget) { | ||
widget.addTo(this.container); | ||
this.setupColorPickers(); | ||
} | ||
addActionButton(title, command, parent) { | ||
@@ -141,32 +152,19 @@ const button = document.createElement('button'); | ||
const toolController = this.editor.toolController; | ||
for (const tool of toolController.getMatchingTools(ToolType.Pen)) { | ||
if (!(tool instanceof Pen)) { | ||
throw new Error('All `Pen` tools must have kind === ToolType.Pen'); | ||
} | ||
const widget = new PenWidget(this.editor, tool, this.localizationTable); | ||
widget.addTo(this.container); | ||
for (const tool of toolController.getMatchingTools(PenTool)) { | ||
const widget = new PenToolWidget(this.editor, tool, this.localizationTable); | ||
this.addWidget(widget); | ||
} | ||
for (const tool of toolController.getMatchingTools(ToolType.Eraser)) { | ||
if (!(tool instanceof Eraser)) { | ||
throw new Error('All Erasers must have kind === ToolType.Eraser!'); | ||
} | ||
(new EraserWidget(this.editor, tool, this.localizationTable)).addTo(this.container); | ||
for (const tool of toolController.getMatchingTools(EraserTool)) { | ||
this.addWidget(new EraserWidget(this.editor, tool, this.localizationTable)); | ||
} | ||
for (const tool of toolController.getMatchingTools(ToolType.Selection)) { | ||
if (!(tool instanceof SelectionTool)) { | ||
throw new Error('All SelectionTools must have kind === ToolType.Selection'); | ||
} | ||
(new SelectionWidget(this.editor, tool, this.localizationTable)).addTo(this.container); | ||
for (const tool of toolController.getMatchingTools(SelectionTool)) { | ||
this.addWidget(new SelectionToolWidget(this.editor, tool, this.localizationTable)); | ||
} | ||
for (const tool of toolController.getMatchingTools(ToolType.Text)) { | ||
if (!(tool instanceof TextTool)) { | ||
throw new Error('All text tools must have kind === ToolType.Text'); | ||
} | ||
(new TextToolWidget(this.editor, tool, this.localizationTable)).addTo(this.container); | ||
for (const tool of toolController.getMatchingTools(TextTool)) { | ||
this.addWidget(new TextToolWidget(this.editor, tool, this.localizationTable)); | ||
} | ||
const panZoomTool = toolController.getMatchingTools(ToolType.PanZoom)[0]; | ||
if (panZoomTool && panZoomTool instanceof PanZoom) { | ||
(new HandToolWidget(this.editor, panZoomTool, this.localizationTable)).addTo(this.container); | ||
const panZoomTool = toolController.getMatchingTools(PanZoom)[0]; | ||
if (panZoomTool) { | ||
this.addWidget(new HandToolWidget(this.editor, panZoomTool, this.localizationTable)); | ||
} | ||
this.setupColorPickers(); | ||
} | ||
@@ -173,0 +171,0 @@ addDefaultActionButtons() { |
@@ -15,3 +15,3 @@ import Color4 from '../Color4'; | ||
export declare const makeTextIcon: (textStyle: TextStyle) => SVGSVGElement; | ||
export declare const makePenIcon: (tipThickness: number, color: string) => SVGSVGElement; | ||
export declare const makePenIcon: (tipThickness: number, color: string | Color4) => SVGSVGElement; | ||
export declare const makeIconFromFactory: (pen: Pen, factory: ComponentBuilderFactory) => SVGSVGElement; | ||
@@ -18,0 +18,0 @@ export declare const makePipetteIcon: (color?: Color4) => SVGSVGElement; |
@@ -0,1 +1,2 @@ | ||
import Color4 from '../Color4'; | ||
import EventDispatcher from '../EventDispatcher'; | ||
@@ -254,2 +255,5 @@ import { Vec2 } from '../math/Vec2'; | ||
export const makePenIcon = (tipThickness, color) => { | ||
if (color instanceof Color4) { | ||
color = color.toHexString(); | ||
} | ||
const icon = document.createElementNS(svgNamespace, 'svg'); | ||
@@ -256,0 +260,0 @@ icon.setAttribute('viewBox', '0 0 100 100'); |
import Color4 from '../Color4'; | ||
import { ToolType } from '../tools/ToolController'; | ||
import PipetteTool from '../tools/PipetteTool'; | ||
import { EditorEventType } from '../types'; | ||
@@ -62,3 +62,3 @@ import { makePipetteIcon } from './icons'; | ||
updatePipetteIcon(); | ||
const pipetteTool = editor.toolController.getMatchingTools(ToolType.Pipette)[0]; | ||
const pipetteTool = editor.toolController.getMatchingTools(PipetteTool)[0]; | ||
const endColorSelectMode = () => { | ||
@@ -65,0 +65,0 @@ pipetteTool === null || pipetteTool === void 0 ? void 0 : pipetteTool.clearColorListener(); |
@@ -1,5 +0,1 @@ | ||
export declare enum ToolbarButtonType { | ||
ToggleButton = 0, | ||
ActionButton = 1 | ||
} | ||
export interface ActionButtonIcon { | ||
@@ -6,0 +2,0 @@ icon: Element; |
@@ -1,5 +0,1 @@ | ||
export var ToolbarButtonType; | ||
(function (ToolbarButtonType) { | ||
ToolbarButtonType[ToolbarButtonType["ToggleButton"] = 0] = "ToggleButton"; | ||
ToolbarButtonType[ToolbarButtonType["ActionButton"] = 1] = "ActionButton"; | ||
})(ToolbarButtonType || (ToolbarButtonType = {})); | ||
export {}; |
import { PointerEvtListener, WheelEvt, PointerEvt, EditorNotifier, KeyPressEvent, KeyUpEvent } from '../types'; | ||
import { ToolType } from './ToolController'; | ||
import ToolEnabledGroup from './ToolEnabledGroup'; | ||
@@ -13,3 +12,2 @@ export default abstract class BaseTool implements PointerEvtListener { | ||
onGestureCancel(): void; | ||
abstract readonly kind: ToolType; | ||
protected constructor(notifier: EditorNotifier, description: string); | ||
@@ -16,0 +14,0 @@ onWheel(_event: WheelEvt): boolean; |
import { PointerEvt } from '../types'; | ||
import BaseTool from './BaseTool'; | ||
import Editor from '../Editor'; | ||
import { ToolType } from './ToolController'; | ||
export default class Eraser extends BaseTool { | ||
@@ -9,3 +8,2 @@ private editor; | ||
private command; | ||
kind: ToolType; | ||
private toRemove; | ||
@@ -12,0 +10,0 @@ constructor(editor: Editor, description: string); |
import BaseTool from './BaseTool'; | ||
import LineSegment2 from '../math/LineSegment2'; | ||
import Erase from '../commands/Erase'; | ||
import { ToolType } from './ToolController'; | ||
import { PointerDevice } from '../Pointer'; | ||
@@ -11,3 +10,2 @@ export default class Eraser extends BaseTool { | ||
this.command = null; | ||
this.kind = ToolType.Eraser; | ||
} | ||
@@ -14,0 +12,0 @@ onPointerDown(event) { |
@@ -6,3 +6,2 @@ import { Editor } from '../Editor'; | ||
import BaseTool from './BaseTool'; | ||
import { ToolType } from './ToolController'; | ||
interface PinchData { | ||
@@ -24,3 +23,2 @@ canvasCenter: Point2; | ||
private mode; | ||
readonly kind: ToolType.PanZoom; | ||
private transform; | ||
@@ -27,0 +25,0 @@ private lastAngle; |
@@ -8,3 +8,2 @@ import Mat33 from '../math/Mat33'; | ||
import BaseTool from './BaseTool'; | ||
import { ToolType } from './ToolController'; | ||
export var PanZoomMode; | ||
@@ -23,3 +22,2 @@ (function (PanZoomMode) { | ||
this.mode = mode; | ||
this.kind = ToolType.PanZoom; | ||
this.transform = null; | ||
@@ -26,0 +24,0 @@ } |
import Color4 from '../Color4'; | ||
import Editor from '../Editor'; | ||
import { PointerEvt } from '../types'; | ||
import Pointer from '../Pointer'; | ||
import { PointerEvt, StrokeDataPoint } from '../types'; | ||
import BaseTool from './BaseTool'; | ||
import { ToolType } from './ToolController'; | ||
import { ComponentBuilderFactory } from '../components/builders/types'; | ||
import { ComponentBuilder, ComponentBuilderFactory } from '../components/builders/types'; | ||
export interface PenStyle { | ||
@@ -14,11 +14,10 @@ color: Color4; | ||
private style; | ||
private builder; | ||
private builderFactory; | ||
protected builder: ComponentBuilder | null; | ||
protected builderFactory: ComponentBuilderFactory; | ||
private lastPoint; | ||
readonly kind: ToolType; | ||
constructor(editor: Editor, description: string, style: PenStyle); | ||
private getPressureMultiplier; | ||
private getStrokePoint; | ||
private previewStroke; | ||
private addPointToStroke; | ||
protected toStrokePoint(pointer: Pointer): StrokeDataPoint; | ||
protected previewStroke(): void; | ||
protected addPointToStroke(point: StrokeDataPoint): void; | ||
onPointerDown({ current, allPointers }: PointerEvt): boolean; | ||
@@ -25,0 +24,0 @@ onPointerMove({ current }: PointerEvt): void; |
@@ -6,3 +6,2 @@ import EditorImage from '../EditorImage'; | ||
import BaseTool from './BaseTool'; | ||
import { ToolType } from './ToolController'; | ||
export default class Pen extends BaseTool { | ||
@@ -16,3 +15,2 @@ constructor(editor, description, style) { | ||
this.lastPoint = null; | ||
this.kind = ToolType.Pen; | ||
} | ||
@@ -22,3 +20,4 @@ getPressureMultiplier() { | ||
} | ||
getStrokePoint(pointer) { | ||
// Converts a `pointer` to a `StrokeDataPoint`. | ||
toStrokePoint(pointer) { | ||
var _a; | ||
@@ -41,2 +40,3 @@ const minPressure = 0.3; | ||
} | ||
// Displays the stroke that is currently being built with the display's `wetInkRenderer`. | ||
previewStroke() { | ||
@@ -47,2 +47,3 @@ var _a; | ||
} | ||
// Throws if no stroke builder exists. | ||
addPointToStroke(point) { | ||
@@ -66,3 +67,3 @@ if (!this.builder) { | ||
if ((allPointers.length === 1 && !isEraser) || anyDeviceIsStylus) { | ||
this.builder = this.builderFactory(this.getStrokePoint(current), this.editor.viewport); | ||
this.builder = this.builderFactory(this.toStrokePoint(current), this.editor.viewport); | ||
return true; | ||
@@ -73,3 +74,3 @@ } | ||
onPointerMove({ current }) { | ||
this.addPointToStroke(this.getStrokePoint(current)); | ||
this.addPointToStroke(this.toStrokePoint(current)); | ||
} | ||
@@ -82,3 +83,3 @@ onPointerUp({ current }) { | ||
// onPointerUp events can have zero pressure. Use the last pressure instead. | ||
const currentPoint = this.getStrokePoint(current); | ||
const currentPoint = this.toStrokePoint(current); | ||
const strokePoint = Object.assign(Object.assign({}, currentPoint), { width: (_b = (_a = this.lastPoint) === null || _a === void 0 ? void 0 : _a.width) !== null && _b !== void 0 ? _b : currentPoint.width }); | ||
@@ -85,0 +86,0 @@ this.addPointToStroke(strokePoint); |
@@ -5,7 +5,5 @@ import Color4 from '../Color4'; | ||
import BaseTool from './BaseTool'; | ||
import { ToolType } from './ToolController'; | ||
declare type ColorListener = (color: Color4 | null) => void; | ||
export default class PipetteTool extends BaseTool { | ||
private editor; | ||
kind: ToolType; | ||
private colorPreviewListener; | ||
@@ -12,0 +10,0 @@ private colorSelectListener; |
// @internal @packageDocumentation | ||
import BaseTool from './BaseTool'; | ||
import { ToolType } from './ToolController'; | ||
export default class PipetteTool extends BaseTool { | ||
@@ -8,3 +7,2 @@ constructor(editor, description) { | ||
this.editor = editor; | ||
this.kind = ToolType.Pipette; | ||
this.colorPreviewListener = null; | ||
@@ -11,0 +9,0 @@ this.colorSelectListener = null; |
@@ -8,3 +8,2 @@ import Command from '../commands/Command'; | ||
import BaseTool from './BaseTool'; | ||
import { ToolType } from './ToolController'; | ||
declare class Selection { | ||
@@ -47,3 +46,2 @@ startPoint: Point2; | ||
private selectionBox; | ||
readonly kind: ToolType; | ||
constructor(editor: Editor, description: string); | ||
@@ -50,0 +48,0 @@ onPointerDown(event: PointerEvt): boolean; |
@@ -0,1 +1,4 @@ | ||
// Allows users to select/transform portions of the `EditorImage`. | ||
// With respect to `extend`ing, `SelectionTool` is not stable. | ||
// @packageDocumentation | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
@@ -14,3 +17,2 @@ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
import Mat33 from '../math/Mat33'; | ||
// import Mat33 from "../geometry/Mat33"; | ||
import Rect2 from '../math/Rect2'; | ||
@@ -21,3 +23,2 @@ import { Vec2 } from '../math/Vec2'; | ||
import BaseTool from './BaseTool'; | ||
import { ToolType } from './ToolController'; | ||
import SerializableCommand from '../commands/SerializableCommand'; | ||
@@ -414,2 +415,3 @@ const handleScreenSize = 30; | ||
}; | ||
// {@inheritDoc SelectionTool!} | ||
export default class SelectionTool extends BaseTool { | ||
@@ -419,3 +421,2 @@ constructor(editor, description) { | ||
this.editor = editor; | ||
this.kind = ToolType.Selection; | ||
this.handleOverlay = document.createElement('div'); | ||
@@ -422,0 +423,0 @@ editor.createHTMLOverlay(this.handleOverlay); |
@@ -7,7 +7,5 @@ import Color4 from '../Color4'; | ||
import { ToolLocalization } from './localization'; | ||
import { ToolType } from './ToolController'; | ||
export default class TextTool extends BaseTool { | ||
private editor; | ||
private localizationTable; | ||
kind: ToolType; | ||
private textStyle; | ||
@@ -14,0 +12,0 @@ private textEditOverlay; |
@@ -8,3 +8,2 @@ import Color4 from '../Color4'; | ||
import BaseTool from './BaseTool'; | ||
import { ToolType } from './ToolController'; | ||
const overlayCssClass = 'textEditorOverlay'; | ||
@@ -16,3 +15,2 @@ export default class TextTool extends BaseTool { | ||
this.localizationTable = localizationTable; | ||
this.kind = ToolType.Text; | ||
this.textInputElem = null; | ||
@@ -19,0 +17,0 @@ this.textTargetPosition = null; |
import { InputEvt } from '../types'; | ||
import Editor from '../Editor'; | ||
import BaseTool from './BaseTool'; | ||
import ToolEnabledGroup from './ToolEnabledGroup'; | ||
import { ToolLocalization } from './localization'; | ||
export declare enum ToolType { | ||
Pen = 0, | ||
Selection = 1, | ||
Eraser = 2, | ||
PanZoom = 3, | ||
Text = 4, | ||
UndoRedoShortcut = 5, | ||
Pipette = 6, | ||
Other = 7 | ||
} | ||
export default class ToolController { | ||
private tools; | ||
private activeTool; | ||
private primaryToolGroup; | ||
/** @internal */ | ||
constructor(editor: Editor, localization: ToolLocalization); | ||
setTools(tools: BaseTool[], primaryToolGroup?: ToolEnabledGroup): void; | ||
addPrimaryTool(tool: BaseTool): void; | ||
addTool(tool: BaseTool): void; | ||
dispatchInputEvent(event: InputEvt): boolean; | ||
getMatchingTools(kind: ToolType): BaseTool[]; | ||
getMatchingTools<Type extends BaseTool>(type: new (...args: any[]) => Type): Type[]; | ||
} |
@@ -11,16 +11,8 @@ import { InputEvtType, EditorEventType } from '../types'; | ||
import PipetteTool from './PipetteTool'; | ||
export var ToolType; | ||
(function (ToolType) { | ||
ToolType[ToolType["Pen"] = 0] = "Pen"; | ||
ToolType[ToolType["Selection"] = 1] = "Selection"; | ||
ToolType[ToolType["Eraser"] = 2] = "Eraser"; | ||
ToolType[ToolType["PanZoom"] = 3] = "PanZoom"; | ||
ToolType[ToolType["Text"] = 4] = "Text"; | ||
ToolType[ToolType["UndoRedoShortcut"] = 5] = "UndoRedoShortcut"; | ||
ToolType[ToolType["Pipette"] = 6] = "Pipette"; | ||
ToolType[ToolType["Other"] = 7] = "Other"; | ||
})(ToolType || (ToolType = {})); | ||
export default class ToolController { | ||
/** @internal */ | ||
constructor(editor, localization) { | ||
const primaryToolEnabledGroup = new ToolEnabledGroup(); | ||
this.activeTool = null; | ||
const primaryToolGroup = new ToolEnabledGroup(); | ||
this.primaryToolGroup = primaryToolGroup; | ||
const panZoomTool = new PanZoom(editor, PanZoomMode.TwoFingerTouchGestures | PanZoomMode.RightClickDrags, localization.touchPanTool); | ||
@@ -34,3 +26,3 @@ const keyboardPanZoomTool = new PanZoom(editor, PanZoomMode.Keyboard, localization.keyboardPanZoom); | ||
primaryPenTool, | ||
new Pen(editor, localization.penTool(2), { color: Color4.clay, thickness: 8 }), | ||
new Pen(editor, localization.penTool(2), { color: Color4.clay, thickness: 4 }), | ||
// Highlighter-like pen with width=64 | ||
@@ -47,3 +39,3 @@ new Pen(editor, localization.penTool(3), { color: Color4.ofRGBA(1, 1, 0, 0.5), thickness: 64 }), | ||
]; | ||
primaryTools.forEach(tool => tool.setToolGroup(primaryToolEnabledGroup)); | ||
primaryTools.forEach(tool => tool.setToolGroup(primaryToolGroup)); | ||
panZoomTool.setEnabled(true); | ||
@@ -63,2 +55,22 @@ primaryPenTool.setEnabled(true); | ||
} | ||
// Replaces the current set of tools with `tools`. This should only be done before | ||
// the creation of the app's toolbar (if using `HTMLToolbar`). | ||
setTools(tools, primaryToolGroup) { | ||
this.tools = tools; | ||
this.primaryToolGroup = primaryToolGroup !== null && primaryToolGroup !== void 0 ? primaryToolGroup : new ToolEnabledGroup(); | ||
} | ||
// Add a tool that acts like one of the primary tools (only one primary tool can be enabled at a time). | ||
// This should be called before creating the app's toolbar. | ||
addPrimaryTool(tool) { | ||
tool.setToolGroup(this.primaryToolGroup); | ||
if (tool.isEnabled()) { | ||
this.primaryToolGroup.notifyEnabled(tool); | ||
} | ||
this.addTool(tool); | ||
} | ||
// Add a tool to the end of this' tool list (the added tool receives events after tools already added to this). | ||
// This should be called before creating the app's toolbar. | ||
addTool(tool) { | ||
this.tools.push(tool); | ||
} | ||
// Returns true if the event was handled | ||
@@ -123,5 +135,5 @@ dispatchInputEvent(event) { | ||
} | ||
getMatchingTools(kind) { | ||
return this.tools.filter(tool => tool.kind === kind); | ||
getMatchingTools(type) { | ||
return this.tools.filter(tool => tool instanceof type); | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
// Connects a group of tools -- at most one tool in the group must be enabled. | ||
// Connects a group of tools -- at most one tool in the group can be enabled. | ||
export default class ToolEnabledGroup { | ||
@@ -3,0 +3,0 @@ constructor() { } |
import Editor from '../Editor'; | ||
import { KeyPressEvent } from '../types'; | ||
import BaseTool from './BaseTool'; | ||
import { ToolType } from './ToolController'; | ||
export default class UndoRedoShortcut extends BaseTool { | ||
private editor; | ||
kind: ToolType.UndoRedoShortcut; | ||
constructor(editor: Editor); | ||
onKeyPress({ key, ctrlKey }: KeyPressEvent): boolean; | ||
} |
@@ -0,3 +1,5 @@ | ||
// Handles ctrl+Z, ctrl+Shift+Z keyboard shortcuts. | ||
// @packageDocumentation | ||
import BaseTool from './BaseTool'; | ||
import { ToolType } from './ToolController'; | ||
// {@inheritDoc UndoRedoShortcut!} | ||
export default class UndoRedoShortcut extends BaseTool { | ||
@@ -7,3 +9,2 @@ constructor(editor) { | ||
this.editor = editor; | ||
this.kind = ToolType.UndoRedoShortcut; | ||
} | ||
@@ -10,0 +11,0 @@ // Activate undo/redo |
{ | ||
"name": "js-draw", | ||
"version": "0.2.3", | ||
"version": "0.3.0", | ||
"description": "Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript. ", | ||
@@ -5,0 +5,0 @@ "main": "./dist/src/lib.d.ts", |
@@ -183,3 +183,3 @@ import { Bezier } from 'bezier-js'; | ||
private roundPoint(point: Point2): Point2 { | ||
let minFit = Math.min(this.minFitAllowed, this.curveStartWidth); | ||
let minFit = Math.min(this.minFitAllowed, this.curveStartWidth / 2); | ||
@@ -186,0 +186,0 @@ if (minFit < 1e-10) { |
@@ -0,1 +1,4 @@ | ||
export * from './builders/types'; | ||
export { makeFreehandLineBuilder } from './builders/FreehandLineBuilder'; | ||
import AbstractComponent from './AbstractComponent'; | ||
@@ -2,0 +5,0 @@ import Stroke from './Stroke'; |
@@ -391,3 +391,2 @@ import Editor from './Editor'; | ||
public render(renderer: AbstractRenderer, visibleRect: Rect2) { | ||
// Don't render components that are < 0.1% of the viewport. | ||
const leaves = this.getLeavesIntersectingRegion(visibleRect, rect => renderer.isTooSmallToRender(rect)); | ||
@@ -394,0 +393,0 @@ sortLeavesByZIndex(leaves); |
@@ -17,3 +17,4 @@ /** | ||
import Editor from './Editor'; | ||
export { EditorEventType } from './types'; | ||
export { default as EditorImage } from './EditorImage'; | ||
export * from './types'; | ||
export { default as getLocalizationTable } from './localizations/getLocalizationTable'; | ||
@@ -26,2 +27,5 @@ export * from './localization'; | ||
export * from './commands/lib'; | ||
export * from './tools/lib'; | ||
export * from './toolbar/lib'; | ||
export { default as Pointer, PointerDevice } from './Pointer'; | ||
export { default as HTMLToolbar } from './toolbar/HTMLToolbar'; | ||
@@ -28,0 +32,0 @@ |
@@ -224,2 +224,4 @@ | ||
// Determine whether we already have rendered the items | ||
const tooSmallToRender = (rect: Rect2) => rect.w / this.region.w < 1 / this.cacheState.props.blockResolution.x; | ||
const leaves = []; | ||
@@ -229,3 +231,3 @@ for (const item of items) { | ||
...item.getLeavesIntersectingRegion( | ||
this.region, rect => rect.w / this.region.w < 2 / this.cacheState.props.blockResolution.x, | ||
this.region, tooSmallToRender, | ||
) | ||
@@ -232,0 +234,0 @@ ); |
@@ -79,4 +79,4 @@ /** | ||
blockResolution: cacheBlockResolution, | ||
cacheSize: 500 * 500 * 4 * 150, | ||
maxScale: 1.5, | ||
cacheSize: 600 * 600 * 4 * 120, | ||
maxScale: 1.4, | ||
minComponentsPerCache: 45, | ||
@@ -83,0 +83,0 @@ minComponentsToUseCache: 105, |
@@ -62,9 +62,9 @@ import Color4 from '../../Color4'; | ||
if (draftMode) { | ||
this.minSquareCurveApproxDist = 64; | ||
this.minRenderSizeBothDimens = 8; | ||
this.minRenderSizeAnyDimen = 2; | ||
this.minSquareCurveApproxDist = 9; | ||
this.minRenderSizeBothDimens = 2; | ||
this.minRenderSizeAnyDimen = 0.5; | ||
} else { | ||
this.minSquareCurveApproxDist = 1; | ||
this.minRenderSizeBothDimens = 0.5; | ||
this.minRenderSizeAnyDimen = 0; | ||
this.minSquareCurveApproxDist = 0.5; | ||
this.minRenderSizeBothDimens = 0.3; | ||
this.minRenderSizeAnyDimen = 1e-5; | ||
} | ||
@@ -71,0 +71,0 @@ } |
import Editor from '../Editor'; | ||
import { ToolType } from '../tools/ToolController'; | ||
import { EditorEventType } from '../types'; | ||
@@ -7,4 +6,2 @@ | ||
import Color4 from '../Color4'; | ||
import Pen from '../tools/Pen'; | ||
import Eraser from '../tools/Eraser'; | ||
import SelectionTool from '../tools/SelectionTool'; | ||
@@ -16,7 +13,9 @@ import { defaultToolbarLocalization, ToolbarLocalization } from './localization'; | ||
import TextTool from '../tools/TextTool'; | ||
import PenWidget from './widgets/PenWidget'; | ||
import EraserWidget from './widgets/EraserWidget'; | ||
import { SelectionWidget } from './widgets/SelectionWidget'; | ||
import PenToolWidget from './widgets/PenToolWidget'; | ||
import EraserWidget from './widgets/EraserToolWidget'; | ||
import SelectionToolWidget from './widgets/SelectionToolWidget'; | ||
import TextToolWidget from './widgets/TextToolWidget'; | ||
import HandToolWidget from './widgets/HandToolWidget'; | ||
import BaseWidget from './widgets/BaseWidget'; | ||
import { EraserTool, PenTool } from '../tools/lib'; | ||
@@ -26,2 +25,3 @@ | ||
type UpdateColorisCallback = ()=>void; | ||
@@ -32,2 +32,3 @@ export default class HTMLToolbar { | ||
private static colorisStarted: boolean = false; | ||
private updateColoris: UpdateColorisCallback|null = null; | ||
@@ -52,2 +53,8 @@ public constructor( | ||
public setupColorPickers() { | ||
// Much of the setup only needs to be done once. | ||
if (this.updateColoris) { | ||
this.updateColoris(); | ||
return; | ||
} | ||
const closePickerOverlay = document.createElement('div'); | ||
@@ -81,2 +88,3 @@ closePickerOverlay.className = `${toolbarCSSPrefix}closeColorPickerOverlay`; | ||
initColoris(); | ||
this.updateColoris = initColoris; | ||
@@ -119,2 +127,9 @@ const addColorToSwatch = (newColor: string) => { | ||
// Adds an `ActionButtonWidget` or `BaseToolWidget`. The widget should not have already have a parent | ||
// (i.e. its `addTo` method should not have been called). | ||
public addWidget(widget: BaseWidget) { | ||
widget.addTo(this.container); | ||
this.setupColorPickers(); | ||
} | ||
public addActionButton(title: string|ActionButtonIcon, command: ()=> void, parent?: Element) { | ||
@@ -144,3 +159,3 @@ const button = document.createElement('button'); | ||
private addUndoRedoButtons() { | ||
public addUndoRedoButtons() { | ||
const undoRedoGroup = document.createElement('div'); | ||
@@ -177,43 +192,25 @@ undoRedoGroup.classList.add(`${toolbarCSSPrefix}buttonGroup`); | ||
const toolController = this.editor.toolController; | ||
for (const tool of toolController.getMatchingTools(ToolType.Pen)) { | ||
if (!(tool instanceof Pen)) { | ||
throw new Error('All `Pen` tools must have kind === ToolType.Pen'); | ||
} | ||
const widget = new PenWidget( | ||
for (const tool of toolController.getMatchingTools(PenTool)) { | ||
const widget = new PenToolWidget( | ||
this.editor, tool, this.localizationTable, | ||
); | ||
widget.addTo(this.container); | ||
this.addWidget(widget); | ||
} | ||
for (const tool of toolController.getMatchingTools(ToolType.Eraser)) { | ||
if (!(tool instanceof Eraser)) { | ||
throw new Error('All Erasers must have kind === ToolType.Eraser!'); | ||
} | ||
(new EraserWidget(this.editor, tool, this.localizationTable)).addTo(this.container); | ||
for (const tool of toolController.getMatchingTools(EraserTool)) { | ||
this.addWidget(new EraserWidget(this.editor, tool, this.localizationTable)); | ||
} | ||
for (const tool of toolController.getMatchingTools(ToolType.Selection)) { | ||
if (!(tool instanceof SelectionTool)) { | ||
throw new Error('All SelectionTools must have kind === ToolType.Selection'); | ||
} | ||
(new SelectionWidget(this.editor, tool, this.localizationTable)).addTo(this.container); | ||
for (const tool of toolController.getMatchingTools(SelectionTool)) { | ||
this.addWidget(new SelectionToolWidget(this.editor, tool, this.localizationTable)); | ||
} | ||
for (const tool of toolController.getMatchingTools(ToolType.Text)) { | ||
if (!(tool instanceof TextTool)) { | ||
throw new Error('All text tools must have kind === ToolType.Text'); | ||
} | ||
(new TextToolWidget(this.editor, tool, this.localizationTable)).addTo(this.container); | ||
for (const tool of toolController.getMatchingTools(TextTool)) { | ||
this.addWidget(new TextToolWidget(this.editor, tool, this.localizationTable)); | ||
} | ||
const panZoomTool = toolController.getMatchingTools(ToolType.PanZoom)[0]; | ||
if (panZoomTool && panZoomTool instanceof PanZoom) { | ||
(new HandToolWidget(this.editor, panZoomTool, this.localizationTable)).addTo(this.container); | ||
const panZoomTool = toolController.getMatchingTools(PanZoom)[0]; | ||
if (panZoomTool) { | ||
this.addWidget(new HandToolWidget(this.editor, panZoomTool, this.localizationTable)); | ||
} | ||
this.setupColorPickers(); | ||
} | ||
@@ -220,0 +217,0 @@ |
@@ -290,3 +290,7 @@ import Color4 from '../Color4'; | ||
export const makePenIcon = (tipThickness: number, color: string) => { | ||
export const makePenIcon = (tipThickness: number, color: string|Color4) => { | ||
if (color instanceof Color4) { | ||
color = color.toHexString(); | ||
} | ||
const icon = document.createElementNS(svgNamespace, 'svg'); | ||
@@ -293,0 +297,0 @@ icon.setAttribute('viewBox', '0 0 100 100'); |
import Color4 from '../Color4'; | ||
import Editor from '../Editor'; | ||
import PipetteTool from '../tools/PipetteTool'; | ||
import { ToolType } from '../tools/ToolController'; | ||
import { EditorEventType } from '../types'; | ||
@@ -80,3 +79,3 @@ import { makePipetteIcon } from './icons'; | ||
const pipetteTool: PipetteTool|undefined = editor.toolController.getMatchingTools(ToolType.Pipette)[0] as PipetteTool|undefined; | ||
const pipetteTool: PipetteTool|undefined = editor.toolController.getMatchingTools(PipetteTool)[0]; | ||
const endColorSelectMode = () => { | ||
@@ -83,0 +82,0 @@ pipetteTool?.clearColorListener(); |
@@ -1,5 +0,1 @@ | ||
export enum ToolbarButtonType { | ||
ToggleButton, | ||
ActionButton, | ||
} | ||
@@ -6,0 +2,0 @@ export interface ActionButtonIcon { |
import { PointerEvtListener, WheelEvt, PointerEvt, EditorNotifier, EditorEventType, KeyPressEvent, KeyUpEvent } from '../types'; | ||
import { ToolType } from './ToolController'; | ||
import ToolEnabledGroup from './ToolEnabledGroup'; | ||
@@ -14,4 +13,2 @@ | ||
public abstract readonly kind: ToolType; | ||
protected constructor(private notifier: EditorNotifier, public readonly description: string) { | ||
@@ -18,0 +15,0 @@ } |
@@ -7,3 +7,2 @@ import { PointerEvt } from '../types'; | ||
import Erase from '../commands/Erase'; | ||
import { ToolType } from './ToolController'; | ||
import AbstractComponent from '../components/AbstractComponent'; | ||
@@ -15,3 +14,2 @@ import { PointerDevice } from '../Pointer'; | ||
private command: Erase|null = null; | ||
public kind: ToolType = ToolType.Eraser; | ||
private toRemove: AbstractComponent[]; | ||
@@ -18,0 +16,0 @@ |
@@ -10,3 +10,2 @@ | ||
import BaseTool from './BaseTool'; | ||
import { ToolType } from './ToolController'; | ||
@@ -29,3 +28,2 @@ interface PinchData { | ||
export default class PanZoom extends BaseTool { | ||
public readonly kind: ToolType.PanZoom = ToolType.PanZoom; | ||
private transform: ViewportTransform|null = null; | ||
@@ -32,0 +30,0 @@ |
@@ -8,3 +8,2 @@ import Color4 from '../Color4'; | ||
import BaseTool from './BaseTool'; | ||
import { ToolType } from './ToolController'; | ||
import { ComponentBuilder, ComponentBuilderFactory } from '../components/builders/types'; | ||
@@ -18,8 +17,6 @@ | ||
export default class Pen extends BaseTool { | ||
private builder: ComponentBuilder|null = null; | ||
private builderFactory: ComponentBuilderFactory = makeFreehandLineBuilder; | ||
protected builder: ComponentBuilder|null = null; | ||
protected builderFactory: ComponentBuilderFactory = makeFreehandLineBuilder; | ||
private lastPoint: StrokeDataPoint|null = null; | ||
public readonly kind: ToolType = ToolType.Pen; | ||
public constructor( | ||
@@ -37,3 +34,4 @@ private editor: Editor, | ||
private getStrokePoint(pointer: Pointer): StrokeDataPoint { | ||
// Converts a `pointer` to a `StrokeDataPoint`. | ||
protected toStrokePoint(pointer: Pointer): StrokeDataPoint { | ||
const minPressure = 0.3; | ||
@@ -58,3 +56,4 @@ let pressure = Math.max(pointer.pressure ?? 1.0, minPressure); | ||
private previewStroke() { | ||
// Displays the stroke that is currently being built with the display's `wetInkRenderer`. | ||
protected previewStroke() { | ||
this.editor.clearWetInk(); | ||
@@ -64,3 +63,4 @@ this.builder?.preview(this.editor.display.getWetInkRenderer()); | ||
private addPointToStroke(point: StrokeDataPoint) { | ||
// Throws if no stroke builder exists. | ||
protected addPointToStroke(point: StrokeDataPoint) { | ||
if (!this.builder) { | ||
@@ -86,3 +86,3 @@ throw new Error('No stroke is currently being generated.'); | ||
if ((allPointers.length === 1 && !isEraser) || anyDeviceIsStylus) { | ||
this.builder = this.builderFactory(this.getStrokePoint(current), this.editor.viewport); | ||
this.builder = this.builderFactory(this.toStrokePoint(current), this.editor.viewport); | ||
return true; | ||
@@ -95,3 +95,3 @@ } | ||
public onPointerMove({ current }: PointerEvt): void { | ||
this.addPointToStroke(this.getStrokePoint(current)); | ||
this.addPointToStroke(this.toStrokePoint(current)); | ||
} | ||
@@ -105,3 +105,3 @@ | ||
// onPointerUp events can have zero pressure. Use the last pressure instead. | ||
const currentPoint = this.getStrokePoint(current); | ||
const currentPoint = this.toStrokePoint(current); | ||
const strokePoint = { | ||
@@ -129,3 +129,3 @@ ...currentPoint, | ||
public onGestureCancel(): void { | ||
public onGestureCancel() { | ||
this.editor.clearWetInk(); | ||
@@ -132,0 +132,0 @@ } |
@@ -7,3 +7,2 @@ // @internal @packageDocumentation | ||
import BaseTool from './BaseTool'; | ||
import { ToolType } from './ToolController'; | ||
@@ -13,4 +12,2 @@ type ColorListener = (color: Color4|null)=>void; | ||
export default class PipetteTool extends BaseTool { | ||
public kind: ToolType = ToolType.Pipette; | ||
private colorPreviewListener: ColorListener|null = null; | ||
@@ -17,0 +14,0 @@ private colorSelectListener: ColorListener|null = null; |
@@ -9,7 +9,6 @@ import Color4 from '../Color4'; | ||
import SelectionTool from './SelectionTool'; | ||
import { ToolType } from './ToolController'; | ||
import createEditor from '../testing/createEditor'; | ||
const getSelectionTool = (editor: Editor): SelectionTool => { | ||
return editor.toolController.getMatchingTools(ToolType.Selection)[0] as SelectionTool; | ||
return editor.toolController.getMatchingTools(SelectionTool)[0]; | ||
}; | ||
@@ -16,0 +15,0 @@ |
@@ -0,1 +1,5 @@ | ||
// Allows users to select/transform portions of the `EditorImage`. | ||
// With respect to `extend`ing, `SelectionTool` is not stable. | ||
// @packageDocumentation | ||
import Command from '../commands/Command'; | ||
@@ -7,3 +11,2 @@ import Duplicate from '../commands/Duplicate'; | ||
import Mat33 from '../math/Mat33'; | ||
// import Mat33 from "../geometry/Mat33"; | ||
import Rect2 from '../math/Rect2'; | ||
@@ -15,3 +18,2 @@ import { Point2, Vec2 } from '../math/Vec2'; | ||
import BaseTool from './BaseTool'; | ||
import { ToolType } from './ToolController'; | ||
import SerializableCommand from '../commands/SerializableCommand'; | ||
@@ -507,2 +509,3 @@ | ||
// {@inheritDoc SelectionTool!} | ||
export default class SelectionTool extends BaseTool { | ||
@@ -512,3 +515,2 @@ private handleOverlay: HTMLElement; | ||
private selectionBox: Selection|null; | ||
public readonly kind: ToolType = ToolType.Selection; | ||
@@ -515,0 +517,0 @@ public constructor(private editor: Editor, description: string) { |
@@ -11,7 +11,5 @@ import Color4 from '../Color4'; | ||
import { ToolLocalization } from './localization'; | ||
import { ToolType } from './ToolController'; | ||
const overlayCssClass = 'textEditorOverlay'; | ||
export default class TextTool extends BaseTool { | ||
public kind: ToolType = ToolType.Text; | ||
private textStyle: TextStyle; | ||
@@ -18,0 +16,0 @@ |
@@ -15,19 +15,12 @@ import { InputEvtType, InputEvt, EditorEventType } from '../types'; | ||
export enum ToolType { | ||
Pen, | ||
Selection, | ||
Eraser, | ||
PanZoom, | ||
Text, | ||
UndoRedoShortcut, | ||
Pipette, | ||
Other, | ||
} | ||
export default class ToolController { | ||
private tools: BaseTool[]; | ||
private activeTool: BaseTool|null; | ||
private activeTool: BaseTool|null = null; | ||
private primaryToolGroup: ToolEnabledGroup; | ||
/** @internal */ | ||
public constructor(editor: Editor, localization: ToolLocalization) { | ||
const primaryToolEnabledGroup = new ToolEnabledGroup(); | ||
const primaryToolGroup = new ToolEnabledGroup(); | ||
this.primaryToolGroup = primaryToolGroup; | ||
const panZoomTool = new PanZoom(editor, PanZoomMode.TwoFingerTouchGestures | PanZoomMode.RightClickDrags, localization.touchPanTool); | ||
@@ -42,3 +35,3 @@ const keyboardPanZoomTool = new PanZoom(editor, PanZoomMode.Keyboard, localization.keyboardPanZoom); | ||
primaryPenTool, | ||
new Pen(editor, localization.penTool(2), { color: Color4.clay, thickness: 8 }), | ||
new Pen(editor, localization.penTool(2), { color: Color4.clay, thickness: 4 }), | ||
@@ -57,3 +50,3 @@ // Highlighter-like pen with width=64 | ||
]; | ||
primaryTools.forEach(tool => tool.setToolGroup(primaryToolEnabledGroup)); | ||
primaryTools.forEach(tool => tool.setToolGroup(primaryToolGroup)); | ||
panZoomTool.setEnabled(true); | ||
@@ -76,2 +69,26 @@ primaryPenTool.setEnabled(true); | ||
// Replaces the current set of tools with `tools`. This should only be done before | ||
// the creation of the app's toolbar (if using `HTMLToolbar`). | ||
public setTools(tools: BaseTool[], primaryToolGroup?: ToolEnabledGroup) { | ||
this.tools = tools; | ||
this.primaryToolGroup = primaryToolGroup ?? new ToolEnabledGroup(); | ||
} | ||
// Add a tool that acts like one of the primary tools (only one primary tool can be enabled at a time). | ||
// This should be called before creating the app's toolbar. | ||
public addPrimaryTool(tool: BaseTool) { | ||
tool.setToolGroup(this.primaryToolGroup); | ||
if (tool.isEnabled()) { | ||
this.primaryToolGroup.notifyEnabled(tool); | ||
} | ||
this.addTool(tool); | ||
} | ||
// Add a tool to the end of this' tool list (the added tool receives events after tools already added to this). | ||
// This should be called before creating the app's toolbar. | ||
public addTool(tool: BaseTool) { | ||
this.tools.push(tool); | ||
} | ||
// Returns true if the event was handled | ||
@@ -139,6 +156,6 @@ public dispatchInputEvent(event: InputEvt): boolean { | ||
public getMatchingTools(kind: ToolType): BaseTool[] { | ||
return this.tools.filter(tool => tool.kind === kind); | ||
public getMatchingTools<Type extends BaseTool>(type: new (...args: any[])=>Type): Type[] { | ||
return this.tools.filter(tool => tool instanceof type) as Type[]; | ||
} | ||
} | ||
import BaseTool from './BaseTool'; | ||
// Connects a group of tools -- at most one tool in the group must be enabled. | ||
// Connects a group of tools -- at most one tool in the group can be enabled. | ||
export default class ToolEnabledGroup { | ||
@@ -5,0 +5,0 @@ private activeTool: BaseTool|null; |
@@ -0,10 +1,10 @@ | ||
// Handles ctrl+Z, ctrl+Shift+Z keyboard shortcuts. | ||
// @packageDocumentation | ||
import Editor from '../Editor'; | ||
import { KeyPressEvent } from '../types'; | ||
import BaseTool from './BaseTool'; | ||
import { ToolType } from './ToolController'; | ||
// {@inheritDoc UndoRedoShortcut!} | ||
export default class UndoRedoShortcut extends BaseTool { | ||
public kind: ToolType.UndoRedoShortcut = ToolType.UndoRedoShortcut; | ||
public constructor(private editor: Editor) { | ||
@@ -11,0 +11,0 @@ super(editor.notifier, editor.localization.undoRedoTool); |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1080721
313
22896