Editor: Teach the adjust tool to edit individual tiles

This commit is contained in:
Eevee (Evelyn Woods) committed 2020-12-02 09:05:20 -07:00
1 parent 560a89cfd3
commit 0d376e003e
6 files changed
+178 -6

No files matched your search

+12
View File
@@ -54,6 +54,8 @@ export class Overlay {
overlay.addEventListener('click', ev => {
this.close();
});
return overlay;
}
close() {
@@ -61,6 +63,16 @@ export class Overlay {
}
}
// Overlay styled like a popup of some sort
export class TransientOverlay extends Overlay {
open() {
// TODO i don't like how vaguely arbitrary this feels.
let overlay = super.open();
overlay.classList.add('--transient');
return overlay;
}
}
// Overlay styled like a dialog box
export class DialogOverlay extends Overlay {
constructor(conductor) {
+94 -4
View File
@@ -1,6 +1,6 @@
import { DIRECTIONS, TICS_PER_SECOND } from './defs.js';
import * as c2g from './format-c2g.js';
import { PrimaryView, DialogOverlay } from './main-base.js';
import { PrimaryView, TransientOverlay, DialogOverlay } from './main-base.js';
import CanvasRenderer from './renderer-canvas.js';
import TILE_TYPES from './tiletypes.js';
import { SVG_NS, mk, mk_svg, walk_grid } from './util.js';
@@ -266,7 +266,17 @@ const ADJUST_TOGGLES = {
};
class AdjustOperation extends MouseOperation {
start() {
let cell = this.editor.stored_level.cells[this.gy1][this.gx1];
let cell = this.cell(this.gx1, this.gy1);
if (this.modifier === 'ctrl') {
for (let tile of cell) {
if (tile.type.name === 'floor_letter') {
// TODO use the tile's bbox, not the mouse position
this.editor.open_tile_prop_overlay(tile, this.mx0, this.my0);
break;
}
}
return;
}
for (let tile of cell) {
// Toggle tiles that go in obvious pairs
let other = ADJUST_TOGGLES[tile.type.name];
@@ -282,6 +292,7 @@ class AdjustOperation extends MouseOperation {
}
// Adjust tool doesn't support dragging
// TODO should it?
// TODO if it does then it should end as soon as you spawn a popup
}
// FIXME currently allows creating outside the map bounds and moving beyond the right/bottom, sigh
@@ -472,9 +483,10 @@ const EDITOR_TOOLS = {
pencil: {
icon: 'icons/tool-pencil.png',
name: "Pencil",
desc: "Draw individual tiles",
desc: "Click to draw. Right click to erase. Hold Shift to affect all layers. Ctrl-click to eyedrop.",
op1: PencilOperation,
//op2: EraseOperation,
//hover: show current selection under cursor
},
line: {
// TODO not implemented
@@ -503,7 +515,7 @@ const EDITOR_TOOLS = {
adjust: {
icon: 'icons/tool-adjust.png',
name: "Adjust",
desc: "Toggle blocks and rotate actors",
desc: "Click to rotate actor or toggle terrain. Right click to rotate in reverse. Hold Shift to always affect terrain. Ctrl-click to edit properties of complex tiles (wires, railroads, hints, etc.)",
op1: AdjustOperation,
},
connect: {
@@ -602,6 +614,49 @@ const EDITOR_PALETTE = [{
],
}];
// FIXME could very much stand to have a little animation when appearing
class LetterTileEditor extends TransientOverlay {
constructor(conductor) {
let root = mk('form.editor-popup-tile-editor');
root.append(mk('span.popup-chevron'));
super(conductor, root);
this.tile = null;
let list = mk('ol.editor-letter-tile-picker');
root.append(list);
this.glyph_elements = {};
for (let c = 32; c < 128; c++) {
let glyph = String.fromCharCode(c);
let input = mk('input', {type: 'radio', name: 'glyph', value: glyph});
this.glyph_elements[glyph] = input;
let item = mk('li', mk('label', input, mk('span.-glyph', glyph)));
list.append(item);
}
list.addEventListener('change', ev => {
let glyph = this.root.elements['glyph'].value;
if (this.tile) {
this.tile.ascii_code = glyph.charCodeAt(0);
// FIXME should be able to mark tiles as dirty, also this is sure a mouthful
this.conductor.editor.renderer.draw();
}
});
}
edit_tile(tile) {
this.tile = tile;
this.root.elements['glyph'].value = String.fromCharCode(tile.ascii_code);
}
static configure_tile_defaults(tile) {
tile.ascii_code = 32;
}
}
const EDITOR_TILES_WITH_PROPS = {
floor_letter: LetterTileEditor,
};
export class Editor extends PrimaryView {
constructor(conductor) {
super(conductor, document.body.querySelector('main#editor'));
@@ -874,6 +929,41 @@ export class Editor extends PrimaryView {
cell.sort((a, b) => a.type.draw_layer - b.type.draw_layer);
}
open_tile_prop_overlay(tile, x0, y0) {
this.cancel_mouse_operation();
let overlay_class = EDITOR_TILES_WITH_PROPS[tile.type.name];
let overlay = new overlay_class(this.conductor);
overlay.edit_tile(tile);
overlay.open();
// FIXME move this into TransientOverlay or some other base class
let root = overlay.root;
// Vertical position: either above or below, preferring the side that has more space
if (y0 > document.body.clientHeight / 2) {
// Above
root.classList.add('--above');
root.style.top = `${y0 - root.offsetHeight}px`;
}
else {
// Below
root.classList.remove('--above');
root.style.top = `${y0}px`;
}
// Horizontal position: centered, but kept within the screen
let left;
let margin = 8; // prefer to not quite touch the edges
let halfwidth = root.offsetWidth / 2 + margin;
if (document.body.clientWidth / 2 < halfwidth) {
// It doesn't fit on the screen at all, so there's nothing we can do; just center it
left = (document.body.clientWidth - root.offsetWidth) / 2;
}
else {
left = Math.max(margin, Math.min(document.body.clientWidth - halfwidth, x0 - halfwidth));
}
root.style.left = `${left}px`;
root.style.setProperty('--chevron-offset', `${x0 - left}px`);
}
cancel_mouse_operation() {
if (this.mouse_op) {
this.mouse_op.do_abort();
+1
View File
@@ -328,6 +328,7 @@ const TILE_TYPES = {
on_ready(me) {
// If there's already an actor on top of us, assume it entered the way it's already
// facing (which may be illegal, in which case it can't leave)
// FIXME wrong! > Yeah, so in the high byte, the low nibble encodes the active track. What's missing is that the high nibble encodes a direction value, which is required when a mob starts out on top of the track: it represents the direction the mob was going when it entered the tile, which controls which way it can go on the track.
let actor = me.cell.get_actor();
if (actor) {
me.entered_direction = actor.direction;
+6 -2
View File
@@ -24,7 +24,9 @@ function _mk(el, children) {
export function mk(tag_selector, ...children) {
let [tag, ...classes] = tag_selector.split('.');
let el = document.createElement(tag);
el.classList = classes.join(' ');
if (classes.length > 0) {
el.classList = classes.join(' ');
}
return _mk(el, children);
}
@@ -32,7 +34,9 @@ export const SVG_NS = 'http://www.w3.org/2000/svg';
export function mk_svg(tag_selector, ...children) {
let [tag, ...classes] = tag_selector.split('.');
let el = document.createElementNS(SVG_NS, tag);
el.classList = classes.join(' ');
if (classes.length > 0) {
el.classList = classes.join(' ');
}
return _mk(el, children);
}