Add support for subtracting from the selection
This commit is contained in:
parent
eaa3bf6965
commit
ed5f76221b
@ -41,7 +41,7 @@ export const TOOLS = {
|
|||||||
select_box: {
|
select_box: {
|
||||||
icon: 'icons/tool-select-box.png',
|
icon: 'icons/tool-select-box.png',
|
||||||
name: "Box select",
|
name: "Box select",
|
||||||
desc: "Select and manipulate rectangles.\n\n[mouse1] Select rectangle\n[shift] [mouse1] Add to selection\n\n[mouse1] Move selection\n[ctrl] [mouse1] Clone selection",
|
desc: "Select and manipulate rectangles.\n\n[mouse1] Select rectangle\n[shift] [mouse1] Add to selection\n[ctrl] [mouse1] Remove from selection\n\n[mouse1] Move selection\n[ctrl] [mouse1] Clone selection",
|
||||||
affects_selection: true,
|
affects_selection: true,
|
||||||
op1: mouseops.SelectOperation,
|
op1: mouseops.SelectOperation,
|
||||||
shortcut: 'm',
|
shortcut: 'm',
|
||||||
|
|||||||
@ -33,8 +33,9 @@ export class SVGConnection {
|
|||||||
|
|
||||||
|
|
||||||
export class PendingRectangularSelection {
|
export class PendingRectangularSelection {
|
||||||
constructor(owner) {
|
constructor(owner, mode) {
|
||||||
this.owner = owner;
|
this.owner = owner;
|
||||||
|
this.mode = mode ?? 'new'; // new, add, subtract
|
||||||
this.element = mk_svg('rect.overlay-pending-selection');
|
this.element = mk_svg('rect.overlay-pending-selection');
|
||||||
this.size_text = mk_svg('text.overlay-edit-tip');
|
this.size_text = mk_svg('text.overlay-edit-tip');
|
||||||
this.owner.svg_group.append(this.element, this.size_text);
|
this.owner.svg_group.append(this.element, this.size_text);
|
||||||
@ -54,7 +55,16 @@ export class PendingRectangularSelection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
commit() {
|
commit() {
|
||||||
this.owner.add_rect(this.rect);
|
if (this.mode === 'new') {
|
||||||
|
this.owner.clear();
|
||||||
|
this.owner.add_rect(this.rect);
|
||||||
|
}
|
||||||
|
else if (this.mode === 'add') {
|
||||||
|
this.owner.add_rect(this.rect);
|
||||||
|
}
|
||||||
|
else if (this.mode === 'subtract') {
|
||||||
|
this.owner.subtract_rect(this.rect);
|
||||||
|
}
|
||||||
this.element.remove();
|
this.element.remove();
|
||||||
this.size_text.remove();
|
this.size_text.remove();
|
||||||
}
|
}
|
||||||
@ -116,8 +126,8 @@ export class Selection {
|
|||||||
return this.cells.has(this.editor.stored_level.coords_to_scalar(x, y));
|
return this.cells.has(this.editor.stored_level.coords_to_scalar(x, y));
|
||||||
}
|
}
|
||||||
|
|
||||||
create_pending() {
|
create_pending(mode) {
|
||||||
return new PendingRectangularSelection(this);
|
return new PendingRectangularSelection(this, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
add_rect(rect) {
|
add_rect(rect) {
|
||||||
@ -154,18 +164,36 @@ export class Selection {
|
|||||||
Math.max(this.bbox.bottom, rect.bottom) - this.bbox.y);
|
Math.max(this.bbox.bottom, rect.bottom) - this.bbox.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX wait what the hell is this doing here? why would we set_from_rect while floating, vs
|
this._update_outline();
|
||||||
// stamping it first?
|
}
|
||||||
if (this.floated_element) {
|
|
||||||
console.log("what the hell is this doing here");
|
subtract_rect(rect) {
|
||||||
let tileset = this.editor.renderer.tileset;
|
let old_cells = this.cells;
|
||||||
this.floated_canvas.width = this.bbox.width * tileset.size_x;
|
this.cells = new Set(this.cells);
|
||||||
this.floated_canvas.height = this.bbox.height * tileset.size_y;
|
|
||||||
let foreign_obj = this.floated_element.querySelector('foreignObject');
|
this.editor._do(
|
||||||
foreign_obj.setAttribute('width', this.floated_canvas.width);
|
() => this._subtract_rect(rect),
|
||||||
foreign_obj.setAttribute('height', this.floated_canvas.height);
|
() => {
|
||||||
|
this._set_from_set(old_cells);
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_subtract_rect(rect) {
|
||||||
|
if (this.is_empty)
|
||||||
|
// Nothing to do
|
||||||
|
return;
|
||||||
|
|
||||||
|
let stored_level = this.editor.stored_level;
|
||||||
|
for (let y = rect.top; y < rect.bottom; y++) {
|
||||||
|
for (let x = rect.left; x < rect.right; x++) {
|
||||||
|
this.cells.delete(stored_level.coords_to_scalar(x, y));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO shrink bbox? i guess i only have to check along the edges that the rect intersects?
|
||||||
|
|
||||||
this._update_outline();
|
this._update_outline();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -525,13 +525,21 @@ export class FillOperation extends MouseOperation {
|
|||||||
|
|
||||||
// TODO also, delete
|
// TODO also, delete
|
||||||
// FIXME i broke transforms
|
// FIXME i broke transforms
|
||||||
// FIXME need to subtract from selection too
|
// FIXME don't show the overlay text until has_moved
|
||||||
|
// FIXME hide the god damn cursor
|
||||||
export class SelectOperation extends MouseOperation {
|
export class SelectOperation extends MouseOperation {
|
||||||
handle_press() {
|
handle_press() {
|
||||||
if (this.shift) {
|
if (this.shift) {
|
||||||
// Extend selection
|
this.mode = 'select';
|
||||||
this.mode = 'extend';
|
if (this.ctrl) {
|
||||||
this.pending_selection = this.editor.selection.create_pending();
|
// Subtract from selection (the normal way is ctrl, but ctrl-shift works even to
|
||||||
|
// start dragging inside an existing selection)
|
||||||
|
this.pending_selection = this.editor.selection.create_pending('subtract');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Extend selection
|
||||||
|
this.pending_selection = this.editor.selection.create_pending('add');
|
||||||
|
}
|
||||||
this.update_pending_selection();
|
this.update_pending_selection();
|
||||||
}
|
}
|
||||||
else if (! this.editor.selection.is_empty &&
|
else if (! this.editor.selection.is_empty &&
|
||||||
@ -542,9 +550,15 @@ export class SelectOperation extends MouseOperation {
|
|||||||
this.make_copy = this.ctrl;
|
this.make_copy = this.ctrl;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Create new selection
|
this.mode = 'select';
|
||||||
this.mode = 'create';
|
if (this.ctrl) {
|
||||||
this.pending_selection = this.editor.selection.create_pending();
|
// Subtract from selection (must initiate click outside selection, or it'll float)
|
||||||
|
this.pending_selection = this.editor.selection.create_pending('subtract');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Create new selection
|
||||||
|
this.pending_selection = this.editor.selection.create_pending('new');
|
||||||
|
}
|
||||||
this.update_pending_selection();
|
this.update_pending_selection();
|
||||||
}
|
}
|
||||||
this.has_moved = false;
|
this.has_moved = false;
|
||||||
@ -598,9 +612,6 @@ export class SelectOperation extends MouseOperation {
|
|||||||
// commit it before doing anything else
|
// commit it before doing anything else
|
||||||
this.editor.selection.commit_floating();
|
this.editor.selection.commit_floating();
|
||||||
|
|
||||||
if (this.mode === 'create') {
|
|
||||||
this.editor.selection.clear();
|
|
||||||
}
|
|
||||||
this.pending_selection.commit();
|
this.pending_selection.commit();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@ -2244,6 +2244,7 @@ svg.level-editor-overlay path.overlay-selection-background {
|
|||||||
svg.level-editor-overlay path.overlay-selection {
|
svg.level-editor-overlay path.overlay-selection {
|
||||||
stroke: hsla(var(--selected-hue), 10%, 10%, 0.75);
|
stroke: hsla(var(--selected-hue), 10%, 10%, 0.75);
|
||||||
fill: hsla(var(--selected-hue), 50%, 75%, 0.375);
|
fill: hsla(var(--selected-hue), 50%, 75%, 0.375);
|
||||||
|
fill-rule: evenodd;
|
||||||
stroke-width: calc(0.125px / var(--scale));
|
stroke-width: calc(0.125px / var(--scale));
|
||||||
stroke-dasharray: calc(0.125px / var(--scale)), calc(0.125px / var(--scale));
|
stroke-dasharray: calc(0.125px / var(--scale)), calc(0.125px / var(--scale));
|
||||||
animation: marching-ants 0.5s linear infinite;
|
animation: marching-ants 0.5s linear infinite;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user