From 5e2dfdd9268d253f5f562cd327dc1025f6372f2e Mon Sep 17 00:00:00 2001 From: "Eevee (Evelyn Woods)" Date: Wed, 17 Apr 2024 20:30:23 -0600 Subject: [PATCH] Allow clicking green buttons in the editor; move cursor into MouseOperation --- js/editor/editordefs.js | 2 +- js/editor/main.js | 16 ------ js/editor/mouseops.js | 106 +++++++++++++++++++++++++++++++--------- 3 files changed, 83 insertions(+), 41 deletions(-) diff --git a/js/editor/editordefs.js b/js/editor/editordefs.js index 75bcd22..ce1e7e6 100644 --- a/js/editor/editordefs.js +++ b/js/editor/editordefs.js @@ -62,7 +62,7 @@ export const TOOLS = { adjust: { icon: 'icons/tool-adjust.png', name: "Adjust", - desc: "Edit existing tiles.\n\n[mouse1] Rotate actor / toggle terrain\n[mouse2] Rotate/toggle in the other direction\n[shift] Affect terrain\n\n[ctrl] [mouse1] Edit properties of complex tiles\n(wires, railroads, hints, etc.)", + desc: "Inspect and edit existing tiles in a variety of ways. Give it a try!\n\n[mouse1] Rotate actor\n[mouse1] Rotate or change terrain\n[mouse1] Press button\n[mouse2] Rotate/toggle in the other direction\n[shift] Always target terrain\n\n[ctrl] [mouse1] Edit properties of complex tiles\n(wires, railroads, hints, etc.)", op1: mouseops.AdjustOperation, op2: mouseops.AdjustOperation, shortcut: 'a', diff --git a/js/editor/main.js b/js/editor/main.js index c3dddfc..e2ac8f1 100644 --- a/js/editor/main.js +++ b/js/editor/main.js @@ -107,11 +107,6 @@ export class Editor extends PrimaryView { } setup() { - // Add more bits to SVG overlay - this.preview_g = mk_svg('g', {opacity: 0.5}); - this.svg_cursor = mk_svg('rect.overlay-transient.overlay-cursor', {x: 0, y: 0, width: 1, height: 1}); - this.svg_overlay.append(this.preview_g, this.svg_cursor); - // Populate status bar (needs doing before the mouse stuff, which tries to update it) let statusbar = this.root.querySelector('#editor-statusbar'); this.statusbar_zoom = mk('output'); @@ -253,20 +248,9 @@ export class Editor extends PrimaryView { // TODO only do this stuff if the cell coords changed let cell = this.cell(x, y); if (cell) { - this.svg_cursor.classList.add('--visible'); - this.svg_cursor.setAttribute('x', x); - this.svg_cursor.setAttribute('y', y); - this.statusbar_cursor.textContent = `(${x}, ${y})`; - - // TODO don't /always/ do this. maybe make it optionally always visible, and have - // an inspection tool that does it on point - let terrain = cell[LAYERS.terrain]; - if (terrain.type.name === 'button_gray') { - } } else { - this.svg_cursor.classList.remove('--visible'); this.statusbar_cursor.textContent = `—`; } diff --git a/js/editor/mouseops.js b/js/editor/mouseops.js index 72f085a..38199f2 100644 --- a/js/editor/mouseops.js +++ b/js/editor/mouseops.js @@ -44,6 +44,24 @@ export class MouseOperation { this.click_cell_y = null; this.click_frac_cell_x = null; this.click_frac_cell_y = null; + + this.cursor_element = null; + + // Assume we're hidden until proven otherwise + // TODO obviously suboptimal when switching tools with the mouse over the canvas... maybe + // editor should send us a fake mousemove in that case, idk + this.hide(); + } + + // Register an SVG element as the cursor. This will be automatically shown and hidden when + // appropriate, and its position will be updated to match the position of the cursor + set_cursor_element(el) { + this.cursor_element = el; + el.setAttribute('data-mouseop', this.constructor.name); + if (! this.is_hover_visible) { + el.style.display = 'none'; + } + this.editor.svg_overlay.append(el); } cell(x, y) { @@ -80,6 +98,10 @@ export class MouseOperation { this.do_abort(); } + if (this.cursor_element) { + this.cursor_element.setAttribute('transform', `translate(${cell_x} ${cell_y})`); + } + if (this.is_held) { // Continue a drag even if the mouse goes outside the viewport this.handle_drag(ev.clientX, ev.clientY, frac_cell_x, frac_cell_y, cell_x, cell_y); @@ -119,19 +141,21 @@ export class MouseOperation { this.hide(); } - // XXX uhhh seems weird to control a shared resource like this???? - // XXX also it's visible initially until you move the mouse over the canvas lol show() { if (! this.is_hover_visible) { this.is_hover_visible = true; - this.editor.preview_g.style.display = ''; + if (this.cursor_element) { + this.cursor_element.style.display = ''; + } } } hide() { if (this.is_hover_visible) { this.is_hover_visible = false; - this.editor.preview_g.style.display = 'none'; + if (this.cursor_element) { + this.cursor_element.style.display = 'none'; + } } } @@ -168,6 +192,10 @@ export class MouseOperation { do_destroy() { this.do_abort(); this.cleanup_hover(); + + if (this.cursor_element) { + this.cursor_element.remove(); + } } *iter_touched_cells(frac_cell_x, frac_cell_y) { @@ -217,7 +245,8 @@ export class PanOperation extends MouseOperation { } // FIXME handle moving the mouse while the button is down; should continuously eyedrop -// (seems like that /should/ work...) +// FIXME also the pencil cursor doesn't move when right-dragging, because it's not active and +// doesn't receive events any more whoops? but wait, panning DOES hide the cursor, so what the hell export class EyedropOperation extends MouseOperation { constructor(...args) { super(...args); @@ -279,14 +308,19 @@ export class PencilOperation extends MouseOperation { constructor(...args) { super(...args); - this.image = mk_svg('image', { + // Our cursor has two parts, so it's really a group + this.preview_element = mk_svg('image', { id: 'svg-editor-preview-tile', x: 0, y: 0, width: 1, height: 1, + opacity: 0.5, }); - this.editor.preview_g.append(this.image); + this.set_cursor_element(mk_svg('g', + this.preview_element, + mk_svg('rect.overlay-pencil-cursor', {x: 0, y: 0, width: 1, height: 1}), + )); this.handle_tile_updated(); } @@ -294,14 +328,7 @@ export class PencilOperation extends MouseOperation { handle_tile_updated(is_bg = false) { if (is_bg) return; - this.image.setAttribute('href', this.editor.fg_tile_el.toDataURL()); - } - handle_hover(_mx, _my, _cxf, _cyf, cell_x, cell_y) { - this.image.setAttribute('x', cell_x); - this.image.setAttribute('y', cell_y); - } - cleanup_hover() { - this.image.remove(); + this.preview_element.setAttribute('href', this.editor.fg_tile_el.toDataURL()); } handle_press(x, y) { @@ -311,9 +338,6 @@ export class PencilOperation extends MouseOperation { for (let [x, y] of this.iter_touched_cells(frac_cell_x, frac_cell_y)) { this.draw_in_cell(x, y); } - - // Also update the preview tile position - this.handle_hover(client_x, client_y, frac_cell_x, frac_cell_y, cell_x, cell_y); } draw_in_cell(x, y) { @@ -525,10 +549,9 @@ export class FillOperation extends MouseOperation { } -// TODO also, delete -// FIXME i broke transforms +// TODO also, delete? there's no delete?? // FIXME don't show the overlay text until has_moved -// FIXME hide the god damn cursor +// TODO cursor: 'cell' by default...? export class SelectOperation extends MouseOperation { handle_press() { if (this.shift) { @@ -1095,6 +1118,33 @@ const ADJUST_TOGGLES_CCW = {}; } } } +// Tiles with special behavior when clicked +const ADJUST_SPECIAL = { + button_green(editor) { + // Toggle green objects + editor._do( + () => ADJUST_SPECIAL._button_green(editor), + () => ADJUST_SPECIAL._button_green(editor), + ); + // TODO play button sound? + }, + _button_green(editor) { + for (let cell of editor.stored_level.linear_cells) { + for (let tile of cell) { + if (tile && tile.type.green_toggle_counterpart) { + tile.type = TILE_TYPES[tile.type.green_toggle_counterpart]; + editor.mark_cell_dirty(cell); + } + } + } + }, + +}; +// TODO maybe better visual feedback of what will happen when you click? +// - rotate terrain (cw, ccw) +// - change terrain +// - rotate actor (cw, ccw) +// - press button export class AdjustOperation extends MouseOperation { handle_press() { let cell = this.cell(this.prev_cell_x, this.prev_cell_y); @@ -1130,13 +1180,21 @@ export class AdjustOperation extends MouseOperation { } // Toggle tiles that go in obvious pairs - let other = (this.alt_mode ? ADJUST_TOGGLES_CCW : ADJUST_TOGGLES_CW)[tile.type.name]; - if (other) { - tile.type = TILE_TYPES[other]; + let toggled = (this.alt_mode ? ADJUST_TOGGLES_CCW : ADJUST_TOGGLES_CW)[tile.type.name]; + if (toggled) { + tile.type = TILE_TYPES[toggled]; this.editor.place_in_cell(cell, tile); this.editor.commit_undo(); break; } + + // Other special tile behavior + let special = ADJUST_SPECIAL[tile.type.name]; + if (special) { + special(this.editor); + this.editor.commit_undo(); + break; + } } } // Adjust tool doesn't support dragging