Skip to content

Commit

Permalink
🚧 Objects list in room edirtor
Browse files Browse the repository at this point in the history
  • Loading branch information
CosmoMyzrailGorynych committed Sep 27, 2024
1 parent 3c9959e commit 14b308a
Show file tree
Hide file tree
Showing 10 changed files with 218 additions and 36 deletions.
4 changes: 3 additions & 1 deletion app/data/i18n/English.json
Original file line number Diff line number Diff line change
Expand Up @@ -1527,7 +1527,9 @@
"addTiles": "Add tiles",
"manageBackgrounds": "Manage backgrounds",
"uiTools": "UI tools",
"roomProperties": "Room properties"
"roomProperties": "Room properties",
"copiesList": "List of copies",
"tilesList": "List of tiles"
}
},
"styleView": {
Expand Down
6 changes: 5 additions & 1 deletion src/node_requires/roomEditor/IRoomEditorRiotTag.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ export interface IRoomEditorRiotTag extends IRiotTag {
tileEditor?: IRiotTag,
backgroundsEditor?: IRiotTag,
zoomLabel: HTMLSpanElement,
uiTools?: IRiotTag
uiTools?: IRiotTag,
entriesList?: IRiotTag & {
updateTileEntries(): void;
resetLastSelected(): void;
}
};
pixiEditor: RoomEditor;
zoom: number;
Expand Down
1 change: 1 addition & 0 deletions src/node_requires/roomEditor/entityClasses/Copy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class Copy extends PIXI.Container {
this.on('pointerover', () => {
const {name} = getById('template', copyInfo.uid);
(this.editor as RoomEditor).updateMouseoverHint(name, this);
(this.editor as RoomEditor).setHoverSelection(this);
});
this.on('pointerout', () => {
(this.editor as RoomEditor).mouseoverOut(this);
Expand Down
3 changes: 3 additions & 0 deletions src/node_requires/roomEditor/entityClasses/Tile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ class Tile extends PIXI.Sprite {
this.alpha *= 0.5;
} else {
editor.tiles.add(this);
this.on('pointerover', () => {
(this.editor as RoomEditor).setHoverSelection(this);
});
}
}
destroy(): void {
Expand Down
86 changes: 59 additions & 27 deletions src/node_requires/roomEditor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ class RoomEditor extends PIXI.Application {
ctRoom: IRoom;
currentSelection: Set<Copy | Tile> = new Set();
currentUiSelection: Copy | void;
/**
* Used to highlight an entity in a room editor
* when a user hovers over it in copy/template lists
*/
currentHoveredEntity: Copy | Tile | void = void 0;
clipboard: Set<tileClipboardData | copyClipboardData> = new Set();
/** A sprite that catches any click events */
clicktrap = new PIXI.Sprite(PIXI.Texture.WHITE);
Expand Down Expand Up @@ -96,6 +101,11 @@ class RoomEditor extends PIXI.Application {
* See this.drawSelection method to actually draw it.
*/
selectionOverlay = new PIXI.Graphics();
/**
* A Graphics instance used like selectionOverlay
* to highlight hovered copies, through the entities list or in a room.
*/
hoverOverlay = new PIXI.Graphics();
/** A free transform widget that exists in **global** coordinates. */
transformer = new Transformer(this);
primaryViewport: Viewport;
Expand Down Expand Up @@ -194,6 +204,8 @@ class RoomEditor extends PIXI.Application {
this.stage.addChild(this.overlays);
this.deserialize(editor.room as IRoom);
this.stage.addChild(this.selectionOverlay);
this.stage.addChild(this.hoverOverlay);
this.selectionOverlay.eventMode = this.hoverOverlay.eventMode = 'none';
this.stage.addChild(this.transformer);

this.pointerCoords.zIndex = Infinity;
Expand All @@ -219,6 +231,9 @@ class RoomEditor extends PIXI.Application {
if (this.transformer.visible) {
this.transformer.updateFrame();
}
if (this.currentHoveredEntity) {
this.drawSelection([this.currentHoveredEntity], true);
}
// Redraw selection frame
if (this.riotEditor.currentTool === 'uiTools' && this.currentUiSelection) {
this.drawSelection([this.currentUiSelection]);
Expand Down Expand Up @@ -506,9 +521,9 @@ class RoomEditor extends PIXI.Application {
deleted: changes
});
this.transformer.clear();
if (this.riotEditor.refs.propertiesPanel) {
this.riotEditor.refs.propertiesPanel.updatePropList();
}
this.riotEditor.refs.propertiesPanel?.updatePropList?.();
this.riotEditor.refs.entriesList?.updateTileEntries?.();
this.riotEditor.refs.entriesList?.resetLastSelected?.();
}
copySelection(): void {
if (this.riotEditor.currentTool !== 'select' || !this.currentSelection.size) {
Expand Down Expand Up @@ -608,9 +623,9 @@ class RoomEditor extends PIXI.Application {
this.transformer.applyTranslateY += dy;
this.transformer.applyTransforms();
this.transformer.setup();
if (this.riotEditor.refs.propertiesPanel) {
this.riotEditor.refs.propertiesPanel.updatePropList();
}
this.riotEditor.refs.propertiesPanel?.updatePropList?.();
this.riotEditor.refs.entriesList?.resetLastSelected?.();
this.riotEditor.refs.entriesList?.updateTileEntries?.();
this.transformer.blink();
}
sort(method: 'x' | 'y' | 'toFront' | 'toBack'): void {
Expand Down Expand Up @@ -689,9 +704,20 @@ class RoomEditor extends PIXI.Application {
});
this.transformer.setup();
}
drawSelection(entities: Iterable<Copy | Tile>): void {
this.selectionOverlay.clear();
this.selectionOverlay.visible = true;
/**
* Updates selection visualization and snapshots transforms
* for future manipulations and history management.
*/
prepareSelection() {
this.transformer.setup();
this.marqueeBox.visible = false;
this.riotEditor.refs.propertiesPanel?.updatePropList?.();
this.riotEditor.refs.entriesList?.update?.();
}
drawSelection(entities: Iterable<Copy | Tile>, hover?: boolean): void {
const overlay = hover ? this.hoverOverlay : this.selectionOverlay;
overlay.clear();
overlay.visible = true;
for (const entity of entities) {
const w = entity.width,
h = entity.height,
Expand All @@ -706,28 +732,34 @@ class RoomEditor extends PIXI.Application {
tr = rotateRad(w * (1 - px), -h * py, entity.rotation),
bl = rotateRad(-w * px, h * (1 - py), entity.rotation),
br = rotateRad(w * (1 - px), h * (1 - py), entity.rotation);
// this.selectionOverlay.lineStyle(3, getPixiSwatch('act'));
this.selectionOverlay.lineStyle(1, getPixiSwatch('background'));
this.selectionOverlay.beginFill(getPixiSwatch('act'), 0.15);
this.selectionOverlay.moveTo(x + tl[0] / sx, y + tl[1] / sy);
this.selectionOverlay.lineTo(x + tr[0] / sx, y + tr[1] / sy);
this.selectionOverlay.lineTo(x + br[0] / sx, y + br[1] / sy);
this.selectionOverlay.lineTo(x + bl[0] / sx, y + bl[1] / sy);
this.selectionOverlay.lineTo(x + tl[0] / sx, y + tl[1] / sy);
this.selectionOverlay.endFill();
// this.selectionOverlay.lineStyle(1, getPixiSwatch('background'));
// this.selectionOverlay.moveTo(x + tl[0] / sx, y + tl[1] / sy);
// this.selectionOverlay.lineTo(x + tr[0] / sx, y + tr[1] / sy);
// this.selectionOverlay.lineTo(x + br[0] / sx, y + br[1] / sy);
// this.selectionOverlay.lineTo(x + bl[0] / sx, y + bl[1] / sy);
// this.selectionOverlay.lineTo(x + tl[0] / sx, y + tl[1] / sy);
// overlay.lineStyle(3, getPixiSwatch('act'));
overlay.lineStyle(1, getPixiSwatch('background'));
overlay.beginFill(getPixiSwatch('act'), 0.15);
overlay.moveTo(x + tl[0] / sx, y + tl[1] / sy);
overlay.lineTo(x + tr[0] / sx, y + tr[1] / sy);
overlay.lineTo(x + br[0] / sx, y + br[1] / sy);
overlay.lineTo(x + bl[0] / sx, y + bl[1] / sy);
overlay.lineTo(x + tl[0] / sx, y + tl[1] / sy);
overlay.endFill();
// overlay.lineStyle(1, getPixiSwatch('background'));
// overlay.moveTo(x + tl[0] / sx, y + tl[1] / sy);
// overlay.lineTo(x + tr[0] / sx, y + tr[1] / sy);
// overlay.lineTo(x + br[0] / sx, y + br[1] / sy);
// overlay.lineTo(x + bl[0] / sx, y + bl[1] / sy);
// overlay.lineTo(x + tl[0] / sx, y + tl[1] / sy);
}
}
/** Cleans the graphic overlay used to highlight selected copies. */
clearSelectionOverlay(): void {
this.selectionOverlay.clear();
this.selectionOverlay.visible = false;
clearSelectionOverlay(hover?: boolean): void {
const overlay = hover ? this.hoverOverlay : this.selectionOverlay;
overlay.clear();
overlay.visible = false;
}
setHoverSelection(entity: Copy | Tile): void {
this.currentHoveredEntity = entity;
this.drawSelection([entity], true);
}

/**
* Rounds up the values of current selection to fix rounding errors
* that appear due to global-to-local transformations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,7 @@ const select: IRoomEditorInteraction<IAffixedData> = {
}
modifySet(this.currentSelection, delta, affixedData.mode);
}
this.transformer.setup();
this.marqueeBox.visible = false;
if (this.riotEditor.refs.propertiesPanel) {
this.riotEditor.refs.propertiesPanel.updatePropList();
}
this.prepareSelection();
callback();
}
}
Expand Down
37 changes: 36 additions & 1 deletion src/riotTags/editors/room-editor/room-editor.tag
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

room-editor.aPanel.aView(data-hotkey-scope="{asset.uid}")
canvas(ref="canvas" oncontextmenu="{openMenus}")
// Toolbar
.room-editor-aToolsetHolder
// Toolbar
.room-editor-aToolbar.aButtonGroup.vertical
button.forcebackground(
onclick="{setTool('select')}"
Expand Down Expand Up @@ -150,6 +150,34 @@ room-editor.aPanel.aView(data-hotkey-scope="{asset.uid}")
use(xlink:href="#check")
span {vocGlob.apply}

// Additional contextual panels on the right side
room-entities-list.room-editor-aContextPanel.np(
if="{currentTool === 'select' && currentEntityList}"
entitytype="{currentEntityList}"
room="{asset}"
editor="{pixiEditor}"
ref="entriesList"
)
// Additional contextual tools
.room-editor-aToolbar.aButtonGroup.vertical(if="{currentTool === 'select'}")
button.forcebackground(
onclick="{setEntityList('copies')}"
class="{active: currentEntityList === 'copies'}"
title="{voc.tools.copiesList} (A)"
data-hotkey="a"
data-hotkey-require-scope="{asset.uid}"
)
svg.feather
use(xlink:href="#template")
button.forcebackground(
onclick="{setEntityList('tiles')}"
class="{active: currentEntityList === 'tiles'}"
title="{voc.tools.tilesList} (S)"
data-hotkey="s"
data-hotkey-require-scope="{asset.uid}"
)
svg.feather
use(xlink:href="#grid")
room-events-editor(if="{editingEvents}" room="{room}" onsave="{closeRoomEvents}")
context-menu(menu="{gridMenu}" ref="gridMenu")
context-menu(menu="{zoomMenu}" ref="zoomMenu")
Expand Down Expand Up @@ -373,6 +401,13 @@ room-editor.aPanel.aView(data-hotkey-scope="{asset.uid}")
[this.currentTileLayer] = this.pixiEditor.tileLayers;
}
};
this.setEntityList = entityType => () => {
if (this.currentEntityList !== entityType) {
this.currentEntityList = entityType;
} else {
this.currentEntityList = void 0;
}
};

/* These are used to describe current template selection when the addCopy tool is on */
this.currentTemplate = -1;
Expand Down
104 changes: 104 additions & 0 deletions src/riotTags/editors/room-editor/room-entities-list.tag
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//-
@attribute entitytype (resourceType)
@attribute room (IRoom)
@attribute editor (RoomEditor)
room-entities-list(onpointerout="{clearHover}")
ul.aMenu(if="{opts.entitytype === 'copies'}")
li(
each="{copy, ind in opts.editor.copies}"
class="{active: parent.opts.editor.currentSelection.has(copy)}"
onclick="{select}"
onpointerenter="{drawHover}"
)
img.room-entities-list-aThumbnail(src="{getThumbnail(copy.cachedTemplate)}")
span {copy.cachedTemplate.name}
|
|
span.small.dim \#{ind}
ul.aMenu(if="{opts.entitytype === 'tiles'}")
li(
each="{tile, ind in tilesEntries}"
class="{active: parent.opts.editor.currentSelection.has(tile)}"
onclick="{select}"
onpointerenter="{drawHover}"
)
span {getById(tile.tileTexture).name}
|
|
span {tile.tileFrame}
|
|
span.small.dim \#{ind}
script.
const {getThumbnail, getById} = require('src/node_requires/resources');
this.getThumbnail = getThumbnail;
this.getById = getById;

let lastSelected;
this.select = e => {
const {copy, tile, ind} = e.item;
const object = copy ?? tile;
const set = this.opts.editor.currentSelection;
if (e.ctrlKey) {
// Toggle selection
if (set.has(object)) {
set.delete(object);
} else {
set.add(object);
}
} else if (e.shiftKey) {
// Add a range of objects to selection
if (lastSelected) {
let ind2, from, to, array;
if (copy) {
array = this.opts.editor.copies;
} else if (tile) {
array = this.tilesEntries;
}
ind2 = array.indexOf(lastSelected);
from = Math.min(ind, ind2);
to = Math.max(ind, ind2);
for (const rangeObj of array.slice(from, to)) {
set.add(rangeObj);
}
}
set.add(object);
} else {
// Override selection
set.clear();
set.add(object);
}
lastSelected = object;
this.opts.editor.prepareSelection();
};
this.drawHover = e => {
const {copy, tile} = e.item;
this.opts.editor.setHoverSelection(copy ?? tile);
e.preventUpdate = true;
};
this.clearHover = e => {
e.preventUpdate = true;
if (e.target !== this.root) {
return;
}
this.opts.editor.clearSelectionOverlay(true);
this.resetLastSelected();
};

// Cache the result of RoomEditor.tiles.entries()
let lastMode = this.opts.entitytype;
this.updateTileEntries = () => {
this.tilesEntries = this.opts.editor.tiles.entries();
};
this.on('beforeupdate', () => {
if (lastMode !== this.opts.entitytype) {
lastSelected = void 0;
if (this.opts.entitytype === 'tiles') {
this.updateTileEntries();
}
}
});

this.resetLastSelected = () => {
lastSelected = void 0;
};
2 changes: 1 addition & 1 deletion src/styl/tags/editors/room-editor/room-editor.styl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ room-editor
overflow hidden
padding 1rem
display grid
grid-template-columns auto auto 1fr
grid-template-columns auto auto 1fr auto auto
grid-gap 0 1rem
align-items start
.&-aToolbar
Expand Down
5 changes: 5 additions & 0 deletions src/styl/tags/editors/room-editor/room-entities-list.styl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
room-entities-list
.&-aThumbnail
width 1.5rem
vertical-align text-bottom
margin-right 0.5ch

0 comments on commit 14b308a

Please sign in to comment.