mirror of
https://github.com/igorski/bitmappery.git
synced 2026-06-16 19:25:38 +02:00
Address issue where drawing operations on offset, cropped Layers would not use correct coordinate space
This commit is contained in:
@@ -52,9 +52,9 @@ export const usesInteractionPane = ( tool: ToolTypes ): boolean => PANE_TYPES.in
|
||||
|
||||
export const SELECTION_TOOLS = [ ToolTypes.SELECTION, ToolTypes.LASSO, ToolTypes.WAND ];
|
||||
|
||||
export const canDraw = ( activeDocument: Document, activeLayer: Layer, activeLayerMask: HTMLCanvasElement | null ): boolean => {
|
||||
export const canDraw = ( activeDocument: Document, activeLayer: Layer, activeLayerMask?: HTMLCanvasElement ): boolean => {
|
||||
return activeDocument &&
|
||||
(( activeLayer?.mask !== null && activeLayer.mask === activeLayerMask ) || activeLayer?.type === LayerTypes.LAYER_GRAPHIC );
|
||||
(( !!activeLayer?.mask && activeLayer.mask === activeLayerMask ) || activeLayer?.type === LayerTypes.LAYER_GRAPHIC );
|
||||
};
|
||||
|
||||
// we cannot draw in selection if a layer is mirrored (see https://github.com/igorski/bitmappery/issues/5)
|
||||
|
||||
@@ -396,9 +396,12 @@ class InteractionPane extends sprite {
|
||||
}
|
||||
|
||||
draw( ctx: CanvasRenderingContext2D, viewport: Viewport ): void {
|
||||
const document = this.getActiveDocument();
|
||||
if ( !document ) {
|
||||
return; // pane was active prior to Document closing
|
||||
}
|
||||
let { activeSelection, invertSelection, width, height } = document;
|
||||
// render selection outline
|
||||
let { invertSelection, width, height } = this.getActiveDocument();
|
||||
const { activeSelection } = this.getActiveDocument();
|
||||
if ( /*this.mode === InteractionModes.MODE_SELECTION && */ activeSelection?.length > 0 ) {
|
||||
for ( let shape of activeSelection ) {
|
||||
const connectToPointer = shape === activeSelection.at( -1 );
|
||||
@@ -523,7 +526,9 @@ function calculateSelectionSize( firstPoint: Point, destX: number, destY: number
|
||||
|
||||
function syncSelection(): void {
|
||||
const { getters } = getCanvasInstance().store;
|
||||
getSpriteForLayer( getters.activeLayer )?.setSelection( getters.activeDocument );
|
||||
if ( getters.activeLayer ) {
|
||||
getSpriteForLayer( getters.activeLayer )?.setSelection( getters.activeDocument );
|
||||
}
|
||||
}
|
||||
|
||||
function storeSelectionHistory( document: Document, optPreviousSelection: Selection = [], optType = "" ): void {
|
||||
|
||||
@@ -418,8 +418,7 @@ export default class LayerSprite extends ZoomableSprite {
|
||||
}
|
||||
|
||||
getPaintSize(): Size {
|
||||
const source = this.getPaintSource();
|
||||
return { width: source.width, height: source.height };
|
||||
return this.canvas.getActiveDocument(); // always use the Document size to allow drawing on offset, cropped Layers
|
||||
/*
|
||||
// depending on zoom level, the interpolation when committing the drawableCanvas content onto the source
|
||||
// may benefit from a higher resolution when drawing on a zoomed in canvas. But maybe negligible and not worth memory overhead
|
||||
|
||||
@@ -62,8 +62,8 @@ const DocumentModule: Module<DocumentState, any> = {
|
||||
activeLayer: ( state: DocumentState, getters: any ): Layer => {
|
||||
return getters.layers?.[ state.activeLayerIndex ];
|
||||
},
|
||||
activeLayerMask: ( state: DocumentState, getters: any ): HTMLCanvasElement | null => {
|
||||
return ( state.maskActive && getters.activeLayer.mask ) || null;
|
||||
activeLayerMask: ( state: DocumentState, getters: any ): HTMLCanvasElement | undefined => {
|
||||
return ( state.maskActive && getters.activeLayer?.mask ) || undefined;
|
||||
},
|
||||
activeLayerEffects: ( _: DocumentState, getters: any ): Effects => {
|
||||
return getters.activeLayer?.effects || {};
|
||||
|
||||
@@ -22,14 +22,14 @@ describe( "tool types", () => {
|
||||
LayerTypes.LAYER_IMAGE, LayerTypes.LAYER_TEXT,
|
||||
])( `should not consider a "%s"-layer to be drawable`, ( type: LayerTypes ) => {
|
||||
const layer = LayerFactory.create({ type });
|
||||
expect( canDraw( document, layer, null )).toBe( false );
|
||||
expect( canDraw( document, layer, undefined )).toBe( false );
|
||||
});
|
||||
|
||||
it.each([
|
||||
LayerTypes.LAYER_IMAGE, LayerTypes.LAYER_TEXT,
|
||||
])( `should not consider a "%s"-layer with an unselected mask to be drawable`, ( type: LayerTypes ) => {
|
||||
const layer = LayerFactory.create({ type, mask: createMockCanvasElement() });
|
||||
expect( canDraw( document, layer, null )).toBe( false );
|
||||
expect( canDraw( document, layer, undefined )).toBe( false );
|
||||
});
|
||||
|
||||
it.each([
|
||||
@@ -41,7 +41,7 @@ describe( "tool types", () => {
|
||||
|
||||
it( `should consider a "${LayerTypes.LAYER_GRAPHIC}"-layer to be drawable`, () => {
|
||||
const layer = LayerFactory.create({ type: LayerTypes.LAYER_GRAPHIC });
|
||||
expect( canDraw( document, layer, null )).toBe( true );
|
||||
expect( canDraw( document, layer, undefined )).toBe( true );
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -98,10 +98,10 @@ describe( "Vuex document module", () => {
|
||||
activeLayer: LayerFactory.create({ name: "layer1" }),
|
||||
};
|
||||
// null because mask is not active
|
||||
expect( getters.activeLayerMask( state, mockedGetters, {}, {} )).toBeNull();
|
||||
expect( getters.activeLayerMask( state, mockedGetters, {}, {} )).toBeUndefined();
|
||||
state.maskActive = true;
|
||||
// null because layer has no mask drawable
|
||||
expect( getters.activeLayerMask( state, mockedGetters, {}, {} )).toBeNull();
|
||||
expect( getters.activeLayerMask( state, mockedGetters, {}, {} )).toBeUndefined();
|
||||
mockedGetters.activeLayer.mask = createMockCanvasElement();
|
||||
expect( getters.activeLayerMask( state, mockedGetters, {}, {} )).toEqual( mockedGetters.activeLayer.mask );
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user