flow: ui
This commit is contained in:
parent
76703cebf3
commit
65d5430ab0
|
@ -7,6 +7,9 @@ import {
|
|||
Rectangle,
|
||||
Vector,
|
||||
} from '@avocado/math';
|
||||
import {
|
||||
Vector as VectorComponent,
|
||||
} from '@avocado/math/persea';
|
||||
import {
|
||||
Context,
|
||||
redo,
|
||||
|
@ -44,7 +47,6 @@ const RoomComponent = ({
|
|||
const [side, setSide] = useState(0);
|
||||
const [room, setRoom] = useState();
|
||||
const [roomRenderable, setRoomRenderable] = useState();
|
||||
const [viewport, setViewport] = useState([0, 0]);
|
||||
const roomSides = flecks.get('$avocado/topdown/persea.room-sides');
|
||||
// Stage event stream.
|
||||
const onRef = useCallback((stage) => {
|
||||
|
@ -54,11 +56,11 @@ const RoomComponent = ({
|
|||
if (room) {
|
||||
const load = async () => {
|
||||
await Promise.all(
|
||||
resource.tiles.map(async (tiles, i) => {
|
||||
await room.tiles[i].load(tiles);
|
||||
const {area, tileSize} = room.tiles[i];
|
||||
room.tiles.map(async (tiles, i) => {
|
||||
await tiles.load(resource.tiles[i]);
|
||||
const {area, tileSize} = tiles;
|
||||
const viewport = Vector.mul(area, tileSize);
|
||||
room.tiles[i].emit('update', Rectangle.compose([0, 0], viewport));
|
||||
tiles.emit('update', Rectangle.compose([0, 0], viewport));
|
||||
}),
|
||||
);
|
||||
if (resource.entities.length !== previousResource.entities.length) {
|
||||
|
@ -82,12 +84,9 @@ const RoomComponent = ({
|
|||
uri,
|
||||
});
|
||||
const roomRenderable = new (room.constructor.Renderable)(room, renderer);
|
||||
const {area, tileSize} = room.tiles[0];
|
||||
const viewport = Vector.mul(area, tileSize);
|
||||
roomRenderable.renderChunksForExtent(Rectangle.compose([0, 0], viewport));
|
||||
roomRenderable.renderChunksForExtent(Rectangle.compose([0, 0], room.size));
|
||||
setRoom(room);
|
||||
setRoomRenderable(roomRenderable);
|
||||
setViewport(viewport);
|
||||
};
|
||||
loadRoom();
|
||||
}
|
||||
|
@ -105,7 +104,7 @@ const RoomComponent = ({
|
|||
renderer={renderer}
|
||||
renderable={roomRenderable}
|
||||
scale={3}
|
||||
size={viewport}
|
||||
size={room.size}
|
||||
styles={styles}
|
||||
/>
|
||||
<div className={styles.side}>
|
||||
|
@ -138,6 +137,14 @@ const RoomComponent = ({
|
|||
</button>
|
||||
</label>
|
||||
</div>
|
||||
<div className={styles.grower} />
|
||||
<label className={styles.size}>
|
||||
<span>Size</span>
|
||||
<VectorComponent
|
||||
onChange={() => {}}
|
||||
value={room.size}
|
||||
/>
|
||||
</label>
|
||||
<label className={styles.sides}>
|
||||
<span>Editing</span>
|
||||
<select
|
||||
|
|
|
@ -169,11 +169,31 @@ label.entities {
|
|||
align-items: center;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
margin: 1rem;
|
||||
label {
|
||||
margin: 0.25rem 0;
|
||||
button {
|
||||
margin: 0 1rem 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.size {
|
||||
|
||||
> span {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
&, label {
|
||||
align-items: baseline;
|
||||
display: flex;
|
||||
span {
|
||||
font-size: 0.6em;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.grower {
|
||||
flex-grow: 100;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable jsx-a11y/label-has-associated-control */
|
||||
/* eslint-disable jsx-a11y/control-has-associated-label */
|
||||
import {
|
||||
Color,
|
||||
|
@ -14,6 +15,7 @@ import {
|
|||
Rectangle,
|
||||
Vector,
|
||||
} from '@avocado/math';
|
||||
import {Vector as VectorComponent} from '@avocado/math/persea';
|
||||
import {useJsonPatcher} from '@avocado/resource/persea';
|
||||
import {
|
||||
classnames,
|
||||
|
@ -31,21 +33,6 @@ const container = new Container();
|
|||
const primitives = new Primitives();
|
||||
const renderer = new Renderer();
|
||||
|
||||
const calculateVisibility = (mute, solo) => {
|
||||
const visibility = Array(mute.length).fill(true);
|
||||
if (solo.some((is) => !!is)) {
|
||||
for (let i = 0; i < solo.length; i++) {
|
||||
visibility[i] = solo[i];
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < mute.length; i++) {
|
||||
if (mute[i]) {
|
||||
visibility[i] = false;
|
||||
}
|
||||
}
|
||||
return visibility;
|
||||
};
|
||||
|
||||
function TilesPage({
|
||||
events,
|
||||
resource,
|
||||
|
@ -53,22 +40,25 @@ function TilesPage({
|
|||
roomRenderable,
|
||||
}) {
|
||||
const patch = useJsonPatcher();
|
||||
const layerCount = resource.tiles.length;
|
||||
const [currentLayer, setCurrentLayer] = useState(0);
|
||||
const [tilesetEvents, setTilesetEvents] = useState();
|
||||
const [scale, setScale] = useState(3);
|
||||
const [solo, setSolo] = useState(Array(layerCount).fill(false));
|
||||
const [incident, setIncident] = useState([0, 0]);
|
||||
const [isHoldingPaint, setIsHoldingPaint] = useState(false);
|
||||
const [isHolding, setIsHolding] = useState(false);
|
||||
const [mute, setMute] = useState(Array(layerCount).fill(false));
|
||||
const [selection, setSelection] = useState([0, 0, 16, 16]);
|
||||
const [tilesetMode, setTilesetMode] = useState(0);
|
||||
const [fillMode, setFillMode] = useState(0);
|
||||
const [viewport, setViewport] = useState([0, 0]);
|
||||
const layerCount = resource.tiles?.length || 0;
|
||||
const [mute, setMute] = useState(Array(layerCount).fill(false));
|
||||
const [solo, setSolo] = useState(Array(layerCount).fill(false));
|
||||
// Get the event stream from the tileset stage.
|
||||
const onRef = useCallback((stage) => {
|
||||
setTilesetEvents(stage?.events());
|
||||
}, [setTilesetEvents]);
|
||||
// Global 'release' handler.
|
||||
// @todo useRelease()
|
||||
useEffect(() => {
|
||||
const onDone = () => {
|
||||
setIsHolding(false);
|
||||
|
@ -81,22 +71,42 @@ function TilesPage({
|
|||
window.removeEventListener('touchend', onDone);
|
||||
};
|
||||
}, []);
|
||||
// Calculate layer visibility.
|
||||
useEffect(() => {
|
||||
const calculateVisibility = (mute, solo) => {
|
||||
const visibility = Array(mute.length).fill(true);
|
||||
if (solo.some((is) => !!is)) {
|
||||
for (let i = 0; i < solo.length; i++) {
|
||||
visibility[i] = solo[i];
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < mute.length; i++) {
|
||||
if (mute[i]) {
|
||||
visibility[i] = false;
|
||||
}
|
||||
}
|
||||
return visibility;
|
||||
};
|
||||
const visibility = calculateVisibility(mute, solo);
|
||||
for (let i = 0; i < visibility.length; i++) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
roomRenderable.tilesRenderables[i].alpha = visibility[i] ? 1 : 0;
|
||||
}
|
||||
}, [mute, roomRenderable, solo]);
|
||||
// Update tileset container.
|
||||
useEffect(() => {
|
||||
const {image} = room.tiles[currentLayer].atlas;
|
||||
container.removeAllChildren();
|
||||
if (0 === room.tiles.length) {
|
||||
return;
|
||||
}
|
||||
const {image} = room.tiles[currentLayer].atlas;
|
||||
const sprite = new Sprite(image);
|
||||
sprite.anchor = [0, 0];
|
||||
container.addChild(sprite);
|
||||
container.addChild(primitives);
|
||||
setViewport(image.size);
|
||||
}, [currentLayer, room]);
|
||||
// Update primitives with selection.
|
||||
useEffect(() => {
|
||||
primitives.anchor = [0, 0];
|
||||
primitives.clear();
|
||||
|
@ -106,6 +116,7 @@ function TilesPage({
|
|||
Primitives.fillStyle(new Color(255, 0, 255, 0.2)),
|
||||
);
|
||||
}, [selection]);
|
||||
// Map events to tiles updates.
|
||||
useEffect(() => {
|
||||
if (!events) {
|
||||
return undefined;
|
||||
|
@ -192,6 +203,9 @@ function TilesPage({
|
|||
) => {
|
||||
const origin = Vector.floor(Vector.div(position, tileSize));
|
||||
const edit = () => {
|
||||
if (0 === room.tiles.length) {
|
||||
return;
|
||||
}
|
||||
const {data: originalData} = room.tiles[currentLayer].toJSON();
|
||||
switch (tilesetMode) {
|
||||
case 0: {
|
||||
|
@ -248,6 +262,7 @@ function TilesPage({
|
|||
events.offValue(onValue);
|
||||
};
|
||||
});
|
||||
// Map events to selection updates.
|
||||
useEffect(() => {
|
||||
if (!tilesetEvents) {
|
||||
return undefined;
|
||||
|
@ -293,10 +308,10 @@ function TilesPage({
|
|||
});
|
||||
return (
|
||||
<div className={classnames(styles.tilesPage, {[styles.holding]: isHolding})}>
|
||||
<div className={styles.label}>
|
||||
<div className={styles.layers}>
|
||||
<ul>
|
||||
{
|
||||
resource.tiles.map((tiles, i) => (
|
||||
room.tiles.map((tiles, i) => (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<li key={i}>
|
||||
<button
|
||||
|
@ -310,11 +325,40 @@ function TilesPage({
|
|||
type="button"
|
||||
>
|
||||
<div className={styles.info}>
|
||||
{i}
|
||||
{' '}
|
||||
-
|
||||
{' '}
|
||||
{tiles.tileImageUri}
|
||||
<label>
|
||||
<span>Area</span>
|
||||
<span>
|
||||
[
|
||||
{tiles.width}
|
||||
{' x '}
|
||||
{tiles.height}
|
||||
]
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Tile size</span>
|
||||
<span>
|
||||
[
|
||||
{tiles.tileSize[0]}
|
||||
{' x '}
|
||||
{tiles.tileSize[1]}
|
||||
]
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Full size</span>
|
||||
<span>
|
||||
[
|
||||
{tiles.tileSize[0] * tiles.width}
|
||||
{' x '}
|
||||
{tiles.tileSize[1] * tiles.height}
|
||||
]
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Tileset URI</span>
|
||||
<span>{tiles.atlas.image.uri}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div className={styles.visibility}>
|
||||
<label>
|
||||
|
@ -343,12 +387,22 @@ function TilesPage({
|
|||
type="checkbox"
|
||||
/>
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
</button>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
<button
|
||||
type="button"
|
||||
>
|
||||
Add layer
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<div className={styles.draw}>
|
||||
|
@ -380,6 +434,20 @@ function TilesPage({
|
|||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<label className={styles.area}>
|
||||
<span>Area</span>
|
||||
<VectorComponent
|
||||
onChange={() => {}}
|
||||
value={room.tiles[currentLayer].area}
|
||||
/>
|
||||
</label>
|
||||
<label className={styles.tileSize}>
|
||||
<span>Tile size</span>
|
||||
<VectorComponent
|
||||
onChange={() => {}}
|
||||
value={room.tiles[currentLayer].tileSize}
|
||||
/>
|
||||
</label>
|
||||
<div className={styles.grower} />
|
||||
<div className={styles.scale}>
|
||||
<label>
|
||||
|
@ -418,9 +486,6 @@ function TilesPage({
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.tilesetUri}>
|
||||
{resource.tiles[currentLayer].tileImageUri}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
border-color: rgba(255, 255, 255, 0.1);
|
||||
margin: 0.5rem;
|
||||
}
|
||||
label span {
|
||||
label > span {
|
||||
font-family: var(--system-font-family);
|
||||
font-size: 0.6em;
|
||||
font-weight: bold;
|
||||
|
@ -14,16 +14,20 @@
|
|||
}
|
||||
ul {
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
margin: 0 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.layers {
|
||||
margin: 0 1rem;
|
||||
}
|
||||
|
||||
.layerButton {
|
||||
align-items: baseline;
|
||||
align-items: center;
|
||||
border: none;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
font-family: var(--system-font-family);
|
||||
font-size: 0.8em;
|
||||
gap: 0.5rem;
|
||||
justify-content: space-between;
|
||||
margin: 0;
|
||||
|
@ -32,15 +36,36 @@
|
|||
background-color: rgb(0, 108, 134);
|
||||
}
|
||||
.info {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
> label {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-right: -0.5rem;
|
||||
> span {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
> span + span {
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
.visibility {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
gap: 1rem;
|
||||
button {
|
||||
margin: 0.5em;
|
||||
}
|
||||
label {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
input {
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,6 +85,18 @@
|
|||
flex-grow: 100;
|
||||
}
|
||||
|
||||
.area, .tileSize {
|
||||
input {
|
||||
width: 2.5em;
|
||||
}
|
||||
label + label {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
label {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.tilesetUri {
|
||||
margin: 1rem;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user