The scene view and the animation preview share one camera, the three form dialogs one base, and keys are found through one set of helpers (#85)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bf02c9e8b3
commit
2a390e52ff
22 files changed
+418
-452
No files matched your search
@@ -1,16 +1,15 @@
|
||||
import type { TextureAsset } from '../../core/model/Asset';
|
||||
import { DEFAULT_SLICE, type SliceOptions, sliceFrames } from '../../core/model/texture';
|
||||
import { Button, Checkbox, HStack, Label, NumberField, Popup, Spacer, Theme, type Widget } from '../../ui';
|
||||
import { type Button, Checkbox, Label, NumberField, Spacer, Theme, type Widget } from '../../ui';
|
||||
import { FormDialog } from '../FormDialog';
|
||||
|
||||
/** Matches the inspector's label column. */
|
||||
const LABEL_WIDTH = 76;
|
||||
const FIELD_WIDTH = 76;
|
||||
|
||||
/**
|
||||
* Cuts a sheet into a grid, asked for as columns and rows rather than a cell size: the counts are
|
||||
* what the user knows, and a cell size derived from the picture cannot disagree with them.
|
||||
*/
|
||||
export class SliceDialog extends Popup {
|
||||
export class SliceDialog extends FormDialog {
|
||||
private readonly options: SliceOptions = { ...DEFAULT_SLICE };
|
||||
private replace = true;
|
||||
private readonly summary: Label;
|
||||
@@ -20,37 +19,25 @@ export class SliceDialog extends Popup {
|
||||
private readonly asset: TextureAsset,
|
||||
onSlice: (options: SliceOptions, replace: boolean) => void,
|
||||
) {
|
||||
super({ modal: true, padding: Theme.padding * 2, gap: Theme.gap });
|
||||
this.minWidth = 340;
|
||||
this.content.add(new Label(`Slice "${asset.name}" into a grid`, { style: 'bodyBold' }));
|
||||
super(340, `Slice "${asset.name}" into a grid`);
|
||||
this.content.add(new Label(`Picture is ${asset.width} × ${asset.height} px`, { style: 'muted' }));
|
||||
|
||||
this.content.add(this.pair('Columns', 'columns', 1, 'Rows', 'rows', 1));
|
||||
this.content.add(this.pair('Offset X', 'offsetX', 0, 'Offset Y', 'offsetY', 0));
|
||||
this.content.add(this.pair('Spacing X', 'spacingX', 0, 'Spacing Y', 'spacingY', 0));
|
||||
|
||||
const replaceRow = new HStack({ gap: Theme.gap, align: 'center' });
|
||||
replaceRow.minHeight = Theme.rowHeight;
|
||||
const box = new Checkbox(this.replace);
|
||||
box.onChange = (value) => {
|
||||
this.replace = Boolean(value);
|
||||
};
|
||||
replaceRow.add(box);
|
||||
replaceRow.add(new Label('Replace the frames this texture already has', { style: 'muted' }));
|
||||
this.content.add(replaceRow);
|
||||
this.content.add(
|
||||
this.formRow(box, new Label('Replace the frames this texture already has', { style: 'muted' })),
|
||||
);
|
||||
|
||||
this.summary = new Label('', { style: 'muted' });
|
||||
this.content.add(this.summary);
|
||||
|
||||
const buttons = new HStack({ gap: Theme.gap, align: 'center' });
|
||||
buttons.add(new Spacer(), 1);
|
||||
const cancel = new Button('Cancel');
|
||||
cancel.onClick = this.closeThen();
|
||||
buttons.add(cancel);
|
||||
this.confirm = new Button('Slice', { variant: 'primary' });
|
||||
this.confirm.onClick = this.closeThen(() => onSlice({ ...this.options }, this.replace));
|
||||
buttons.add(this.confirm);
|
||||
this.content.add(buttons);
|
||||
this.confirm = this.addButtons('Slice', 'primary', () => onSlice({ ...this.options }, this.replace));
|
||||
|
||||
this.refreshSummary();
|
||||
}
|
||||
@@ -63,21 +50,13 @@ export class SliceDialog extends Popup {
|
||||
keyB: keyof SliceOptions,
|
||||
minB: number,
|
||||
): Widget {
|
||||
const row = new HStack({ gap: Theme.gap, align: 'center' });
|
||||
row.minHeight = Theme.rowHeight;
|
||||
row.add(this.labelFor(labelA));
|
||||
row.add(this.fieldFor(keyA, minA));
|
||||
row.add(new Spacer(Theme.padding));
|
||||
row.add(this.labelFor(labelB));
|
||||
row.add(this.fieldFor(keyB, minB));
|
||||
row.add(new Spacer(), 1);
|
||||
return row;
|
||||
}
|
||||
|
||||
private labelFor(text: string): Label {
|
||||
const label = new Label(text, { style: 'muted' });
|
||||
label.minWidth = LABEL_WIDTH;
|
||||
return label;
|
||||
return this.formRow(
|
||||
this.fieldLabel(labelA),
|
||||
this.fieldFor(keyA, minA),
|
||||
new Spacer(Theme.padding),
|
||||
this.fieldLabel(labelB),
|
||||
this.fieldFor(keyB, minB),
|
||||
);
|
||||
}
|
||||
|
||||
private fieldFor(key: keyof SliceOptions, min: number): NumberField {
|
||||
|
||||
Reference in new issue
Block a user