diff --git a/js/main-editor.js b/js/main-editor.js index 28f7a09..3609a52 100644 --- a/js/main-editor.js +++ b/js/main-editor.js @@ -149,6 +149,8 @@ class EditorLevelMetaOverlay extends DialogOverlay { ), ); this.root.elements['viewport'].value = stored_level.viewport_size; + // FIXME this isn't actually saved lol but also it's 24 bytes into the damn options. also + // it should default to 2, the good one this.root.elements['blob_behavior'].value = stored_level.blob_behavior; // TODO: // - chips? @@ -458,9 +460,9 @@ class PencilOperation extends DrawOperation { } let template = this.editor.palette_selection; + let cell = this.cell(x, y); if (this.alt_mode) { // Erase - let cell = this.cell(x, y); if (this.modifier === 'shift') { // Aggressive mode: erase the entire cell for (let layer = 0; layer < LAYERS.MAX; layer++) { @@ -479,7 +481,6 @@ class PencilOperation extends DrawOperation { return; if (this.modifier === 'shift') { // Aggressive mode: erase whatever's already in the cell - let cell = this.cell(x, y); for (let layer = 0; layer < LAYERS.MAX; layer++) { cell[layer] = null; } @@ -494,6 +495,7 @@ class PencilOperation extends DrawOperation { this.editor.place_in_cell(x, y, template); } } + this.editor.mark_cell_dirty(cell); } } @@ -922,8 +924,8 @@ class AdjustOperation extends MouseOperation { if (this.modifier === 'ctrl') { for (let tile of cell) { if (tile && TILES_WITH_PROPS[tile.type.name] !== undefined) { - // TODO use the tile's bbox, not the mouse position - this.editor.open_tile_prop_overlay(tile, cell, this.mx0, this.my0); + this.editor.open_tile_prop_overlay( + tile, cell, this.editor.renderer.get_cell_rect(cell.x, cell.y)); break; } } @@ -2052,9 +2054,11 @@ const SPECIAL_PALETTE_BEHAVIOR = { } }, rotate_left(tile) { + tile.direction = DIRECTIONS[tile.direction].left; tile.arrows = new Set(Array.from(tile.arrows, arrow => DIRECTIONS[arrow].left)); }, rotate_right(tile) { + tile.direction = DIRECTIONS[tile.direction].right; tile.arrows = new Set(Array.from(tile.arrows, arrow => DIRECTIONS[arrow].right)); }, }, @@ -2450,9 +2454,6 @@ export class Editor extends PrimaryView { this.mouse_op = new op_type(this, ev); ev.preventDefault(); ev.stopPropagation(); - - // FIXME eventually this should be automatic - this.redraw_entire_level(); } else if (ev.button === 1) { // Middle button: always pan @@ -2470,8 +2471,6 @@ export class Editor extends PrimaryView { this.mouse_op = new op_type(this, ev); ev.preventDefault(); ev.stopPropagation(); - - this.redraw_entire_level(); } }); // Once the mouse is down, we should accept mouse movement anywhere @@ -2497,9 +2496,6 @@ export class Editor extends PrimaryView { } this.mouse_op.do_mousemove(ev); - - // FIXME !!! - this.redraw_entire_level(); }); // TODO should this happen for a mouseup anywhere? this.viewport_el.addEventListener('mouseup', ev => { @@ -2524,8 +2520,8 @@ export class Editor extends PrimaryView { this.selected_tile_el.id = 'editor-tile'; this.selected_tile_el.addEventListener('click', ev => { if (this.palette_selection && TILES_WITH_PROPS[this.palette_selection.type.name]) { - // FIXME use tile bounds - this.open_tile_prop_overlay(this.palette_selection, null, ev.clientX, ev.clientY); + this.open_tile_prop_overlay( + this.palette_selection, null, this.selected_tile_el.getBoundingClientRect()); } }); // TODO ones for the palette too?? @@ -2954,6 +2950,7 @@ export class Editor extends PrimaryView { // TODO support a game too i guess this.stored_level = stored_level; this.update_viewport_size(); + this.update_cell_coordinates(); // Load connections this.connections_g.textContent = ''; @@ -2981,6 +2978,13 @@ export class Editor extends PrimaryView { } } + update_cell_coordinates() { + // We rely on each StoredCell having .x and .y for partial redrawing + for (let [i, cell] of this.stored_level.linear_cells.entries()) { + [cell.x, cell.y] = this.stored_level.scalar_to_coords(i); + } + } + update_viewport_size() { this.renderer.set_viewport_size(this.stored_level.size_x, this.stored_level.size_y); this.svg_overlay.setAttribute('viewBox', `0 0 ${this.stored_level.size_x} ${this.stored_level.size_y}`); @@ -3158,8 +3162,8 @@ export class Editor extends PrimaryView { this.renderer.draw_static_region( this._dirty_rect.left, this._dirty_rect.top, this._dirty_rect.right, this._dirty_rect.bottom); - this._schedule_redraw_loop(); } + this._schedule_redraw_loop(); } // -- Utility/inspection -- @@ -3188,6 +3192,7 @@ export class Editor extends PrimaryView { return; let cell = this.cell(x, y); + this.mark_cell_dirty(cell); // Replace whatever's on the same layer // TODO should preserve wiring if possible too let existing_tile = cell[tile.type.layer]; @@ -3218,6 +3223,7 @@ export class Editor extends PrimaryView { tile = this.palette_selection; } + this.mark_cell_dirty(cell); let existing_tile = cell[tile.type.layer]; if (existing_tile) { // If we find a tile of the same type as the one being drawn, see if it has custom @@ -3241,12 +3247,11 @@ export class Editor extends PrimaryView { if (tile.type.layer === LAYERS.terrain) { cell[LAYERS.terrain] = {type: TILE_TYPES.floor}; } - this.mark_cell_dirty(cell); } // -- Misc?? -- - open_tile_prop_overlay(tile, cell, x0, y0) { + open_tile_prop_overlay(tile, cell, rect) { this.cancel_mouse_operation(); // FIXME keep these around, don't recreate them constantly let overlay_class = TILES_WITH_PROPS[tile.type.name]; @@ -3256,16 +3261,17 @@ export class Editor extends PrimaryView { // FIXME move this into TransientOverlay or some other base class let root = overlay.root; + let spacing = 2; // Vertical position: either above or below, preferring the side that has more space - if (y0 > document.body.clientHeight / 2) { + if (rect.top - 0 > document.body.clientHeight - rect.bottom) { // Above root.classList.add('--above'); - root.style.top = `${y0 - root.offsetHeight}px`; + root.style.top = `${rect.top - root.offsetHeight - spacing}px`; } else { // Below root.classList.remove('--above'); - root.style.top = `${y0}px`; + root.style.top = `${rect.bottom + spacing}px`; } // Horizontal position: centered, but kept within the screen let left; @@ -3276,10 +3282,10 @@ export class Editor extends PrimaryView { } else { left = Math.max(margin, Math.min(document.body.clientWidth - root.offsetWidth - margin, - x0 - root.offsetWidth / 2)); + (rect.left + rect.right - root.offsetWidth) / 2)); } root.style.left = `${left}px`; - root.style.setProperty('--chevron-offset', `${x0 - left}px`); + root.style.setProperty('--chevron-offset', `${(rect.left + rect.right) / 2 - left}px`); } cancel_mouse_operation() { @@ -3301,6 +3307,7 @@ export class Editor extends PrimaryView { this.stored_level.size_x = size_x; this.stored_level.size_y = size_y; this.update_viewport_size(); + this.update_cell_coordinates(); this.redraw_entire_level(); } } diff --git a/js/renderer-canvas.js b/js/renderer-canvas.js index cbb7bf5..cbd5e0a 100644 --- a/js/renderer-canvas.js +++ b/js/renderer-canvas.js @@ -52,6 +52,18 @@ export class CanvasRenderer { this.viewport_dirty = true; } + get_cell_rect(x, y) { + let rect = this.canvas.getBoundingClientRect(); + let scale_x = rect.width / this.canvas.width; + let scale_y = rect.height / this.canvas.height; + let tile_w = scale_x * this.tileset.size_x; + let tile_h = scale_y * this.tileset.size_y; + return new DOMRect( + rect.x + (x - this.viewport_x) * tile_w, + rect.y + (y - this.viewport_y) * tile_h, + tile_w, tile_h); + } + cell_coords_from_event(ev) { let rect = this.canvas.getBoundingClientRect(); let scale_x = rect.width / this.canvas.width;