Final touches to UI refactor

This commit is contained in:
Lucas Dower 2023-03-20 22:21:43 +00:00
parent e9a913a615
commit 083dd8ded8
No known key found for this signature in database
GPG Key ID: B3EE6B8499593605
17 changed files with 299 additions and 219 deletions

View File

@ -249,10 +249,12 @@ export class AppContext {
this._ui.layoutDull['materials'].elements[`mat_${materialName}`] = new TexturedMaterialElement(materialName, material)
.setLabel(materialName)
.onChangeTypeDelegate(() => {
console.log('on change type');
this._materialManager.changeMaterialType(materialName, MaterialType.solid);
this._updateMaterialsAction();
})
.onChangeTransparencyTypeDelegate((newTransparency) => {
console.log('on change trans');
this._materialManager.changeTransparencyType(materialName, newTransparency);
this._updateMaterialsAction();
});

View File

@ -10,8 +10,8 @@ export class AppConfig {
public readonly RELEASE_MODE = true;
public readonly MAJOR_VERSION = 0;
public readonly MINOR_VERSION = 7;
public readonly HOTFIX_VERSION = 12;
public readonly MINOR_VERSION = 8;
public readonly HOTFIX_VERSION = 0;
public readonly VERSION_TYPE: 'd' | 'a' | 'r' = 'r'; // dev, alpha, or release build
public readonly MINECRAFT_VERSION = '1.19.3';

View File

@ -1,11 +1,17 @@
import { getRandomID } from '../../util';
import { UIUtil } from '../../util/ui_util';
export interface IInterfaceItem {
generateHTML: () => string;
registerEvents: () => void;
finalise: () => void;
}
/**
* The base UI class from which user interactable DOM elements are built from.
* Each `BaseUIElement` can be enabled/disabled.
*/
export abstract class BaseUIElement<T> {
export abstract class BaseUIElement<T> implements IInterfaceItem {
private _id: string;
private _isEnabled: boolean;
private _isHovered: boolean;

View File

@ -0,0 +1,29 @@
import { RGBA, RGBAUtil } from '../../colour';
import { ConfigUIElement } from './config_element';
export class ColourElement extends ConfigUIElement<RGBA, HTMLInputElement> {
public constructor(colour: RGBA) {
super(colour);
}
protected override _generateInnerHTML(): string {
return `<input class="colour-swatch" type="color" id="${this._getId()}" value="${RGBAUtil.toHexString(this.getValue())}">`;
}
public override registerEvents(): void {
this._getElement().addEventListener('change', () => {
const newColour = RGBAUtil.fromHexString(this._getElement().value);
this._setValue(newColour);
});
}
protected _onEnabledChanged(): void {
super._onEnabledChanged();
if (this.enabled) {
this._getElement().classList.add('enabled');
} else {
this._getElement().classList.remove('enabled');
}
}
}

View File

@ -11,12 +11,10 @@ export type ComboBoxItem<T> = {
export class ComboBoxElement<T> extends ConfigUIElement<T, HTMLSelectElement> {
private _items: ComboBoxItem<T>[];
private _small: boolean;
public constructor() {
super();
this._items = [];
this._small = false;
}
public addItems(items: ComboBoxItem<T>[]) {
@ -32,11 +30,6 @@ export class ComboBoxElement<T> extends ConfigUIElement<T, HTMLSelectElement> {
return this;
}
public setSmall() {
this._small = true;
return this;
}
public override registerEvents(): void {
this._getElement().addEventListener('mouseenter', () => {
this._setHovered(true);
@ -54,20 +47,6 @@ export class ComboBoxElement<T> extends ConfigUIElement<T, HTMLSelectElement> {
});
}
/*
public override setDefaultValue(value: T): this {
super.setDefaultValue(value);
const element = this._getElement();
const newSelectedIndex = this._items.findIndex((item) => item.payload === value);
ASSERT(newSelectedIndex !== -1, 'Invalid selected index');
element.selectedIndex = newSelectedIndex;
return this;
}
*/
public override _generateInnerHTML() {
const builder = new HTMLBuilder();
@ -86,6 +65,12 @@ export class ComboBoxElement<T> extends ConfigUIElement<T, HTMLSelectElement> {
return builder.toString();
}
protected _onValueChanged(): void {
super._onValueChanged();
console.log('combo changed');
}
protected _onEnabledChanged(): void {
super._onEnabledChanged();
this._getElement().disabled = this.disabled;

View File

@ -72,10 +72,12 @@ export abstract class ConfigUIElement<T, F> extends BaseUIElement<F> {
public override finalise(): void {
super.finalise();
/*
this._onValueChanged();
this._onValueChangedListeners.forEach((listener) => {
listener(this._value!);
});
*/
}
public override generateHTML() {
@ -100,9 +102,11 @@ export abstract class ConfigUIElement<T, F> extends BaseUIElement<F> {
const label = document.getElementById(this._getLabelId()) as (HTMLDivElement | null);
if (this.enabled) {
label?.classList.remove('text-standard');
label?.classList.remove('text-dark');
label?.classList.add('text-standard');
} else {
label?.classList.add('text-dark');
label?.classList.remove('text-standard');
}
this._onEnabledChangedListeners.forEach((listener) => {

View File

@ -59,7 +59,7 @@ export class HeaderUIElement extends BaseUIElement<HTMLDivElement> {
</div>
</div>
</div>
<div class="toolbar-group" style="margin-right: 0px;">
<div class="toolbar-group">
${this._githubButton.generateHTML()}
${this._bugButton.generateHTML()}
${this._discordButton.generateHTML()}

View File

@ -15,7 +15,6 @@ export class ImageElement extends ConfigUIElement<Promise<TImageRawWrap>, HTMLIm
super(Promise.resolve(param ?? { raw: '', filetype: 'png' }));
this._switchElement = new ToolbarItemElement({ id: 'sw', iconSVG: AppIcons.UPLOAD })
.setSmall()
.setLabel('Choose')
.onClick(() => {
const inputElement = UIUtil.getElementById(this._getId() + '-input') as HTMLInputElement;
@ -30,16 +29,18 @@ export class ImageElement extends ConfigUIElement<Promise<TImageRawWrap>, HTMLIm
<div class="row-container">
<div class="row-item">
<img id="${this._imageId}" alt="Texture Preview" class="texture-preview" loading="lazy"></img>
<div id="${this._imageId}-placeholder" class="texture-preview-placeholder">
<div class="row-container" style="align-items: center;">
<div class="row-item">${AppIcons.IMAGE_MISSING}</div>
<div class="row-item">No image loaded</div>
</div>
</div>
</div>
<div class="row-item">
<div class="col-container">
<div class="col-item">
<input type="file" accept="images/png" style="display: none;" id="${this._getId()}-input">
${this._switchElement.generateHTML()}
</div>
</div>
</div>
</div>
`;
}
@ -70,10 +71,15 @@ export class ImageElement extends ConfigUIElement<Promise<TImageRawWrap>, HTMLIm
}
protected override _onEnabledChanged(): void {
super._onEnabledChanged();
this._switchElement.setEnabled(this.enabled);
}
protected override _onValueChanged(): void {
const inputElement = UIUtil.getElementById(this._imageId) as HTMLImageElement;
const placeholderElement = UIUtil.getElementById(this._imageId + '-placeholder');
this.getValue()
.then((res) => {
if (res.raw === '') {
@ -82,11 +88,13 @@ export class ImageElement extends ConfigUIElement<Promise<TImageRawWrap>, HTMLIm
this._switchElement.setActive(false);
inputElement.src = res.raw;
inputElement.style.display = 'unset';
placeholderElement.style.display = 'none';
})
.catch((err) => {
this._switchElement.setActive(true);
inputElement.src = '';
inputElement.style.display = 'none';
placeholderElement.style.display = 'flex';
});
}
@ -94,5 +102,6 @@ export class ImageElement extends ConfigUIElement<Promise<TImageRawWrap>, HTMLIm
super.finalise();
this._onValueChanged();
this._onEnabledChanged();
}
}

View File

@ -4,48 +4,58 @@ import { ConfigUIElement } from './config_element';
import { ToolbarItemElement } from './toolbar_item';
export class MaterialTypeElement extends ConfigUIElement<MaterialType, HTMLDivElement> {
private _switchElement: ToolbarItemElement;
private _solidButton: ToolbarItemElement;
private _texturedButton: ToolbarItemElement;
private _material: SolidMaterial | TexturedMaterial;
public constructor(material: SolidMaterial | TexturedMaterial) {
super(material.type);
this._material = material;
this._switchElement = new ToolbarItemElement({ id: 'sw2', iconSVG: AppIcons.SWITCH })
.setSmall()
.setLabel('Switch')
this._solidButton = new ToolbarItemElement({ id: 'sw1', iconSVG: AppIcons.COLOUR_SWATCH })
.setLabel('Solid')
.onClick(() => {
if (this._material.type === MaterialType.textured) {
this._onClickChangeTypeDelegate?.();
}
});
this._texturedButton = new ToolbarItemElement({ id: 'sw2', iconSVG: AppIcons.IMAGE })
.setLabel('Textured')
.onClick(() => {
if (this._material.type === MaterialType.solid) {
this._onClickChangeTypeDelegate?.();
}
});
}
public override _generateInnerHTML() {
const material = this.getValue();
return `
<div class="row-container">
<div class="row-item">
${material === MaterialType.solid ? 'Solid' : 'Textured'}
</div>
<div class="row-item">
<div class="col-container">
<div class="col-item">
${this._switchElement.generateHTML()}
</div>
</div>
</div>
<div class="toolbar-group" style="width: 100%;">
${this._solidButton.generateHTML()}
${this._texturedButton.generateHTML()}
</div>
`;
}
public override finalise(): void {
this._switchElement.setActive(this._material.type === MaterialType.solid && this._material.canBeTextured);
this._solidButton.finalise();
this._texturedButton.finalise();
this._solidButton.setActive(this._material.type === MaterialType.solid);
this._texturedButton.setActive(this._material.type === MaterialType.textured);
}
public override registerEvents(): void {
this._switchElement.registerEvents();
this._solidButton.registerEvents();
this._texturedButton.registerEvents();
}
protected override _onEnabledChanged(): void {
super._onEnabledChanged();
this._solidButton.setEnabled(this.enabled);
this._texturedButton.setEnabled(this.enabled);
}
protected override _onValueChanged(): void {

View File

@ -8,10 +8,11 @@ import { AppConsole } from '../console';
import { AppIcons } from '../icons';
import { ButtonElement } from './button';
import { CheckboxElement } from './checkbox';
import { ConfigUIElement } from './config_element';
import { FullConfigUIElement } from './full_config_element';
import { ToolbarItemElement } from './toolbar_item';
export class PaletteElement extends FullConfigUIElement<Palette, HTMLDivElement> {
export class PaletteElement extends ConfigUIElement<Palette, HTMLDivElement> {
private _checkboxes: { block: string, element: CheckboxElement }[];
private _palette: Palette;
private _selectAll: ToolbarItemElement;
@ -135,7 +136,7 @@ export class PaletteElement extends FullConfigUIElement<Palette, HTMLDivElement>
return `
<div class="row-container" style="width: 100%; gap: 5px;">
<input class="struct-prop" type="text" style="width: 100%;" placeholder="Search..." id="${this._getId() + '-search'}"></input>
<input class="struct-prop" type="text" style="width: 100%; text-align: start;" placeholder="Search..." id="${this._getId() + '-search'}"></input>
<div class="col-container header-cols" style="padding-top: 0px;">
<div class="col-container">
<div class="col-item">
@ -180,6 +181,7 @@ export class PaletteElement extends FullConfigUIElement<Palette, HTMLDivElement>
this._exportTo.setEnabled(this.enabled);
this._onCountSelectedChanged();
this._updateStyles();
}
public override registerEvents(): void {
@ -226,6 +228,8 @@ export class PaletteElement extends FullConfigUIElement<Palette, HTMLDivElement>
this._exportTo.finalise();
this._onCountSelectedChanged();
this._updateStyles();
//this._selectAll.finalise();
//this._deselectAll.finalise();
//this._importFrom.finalise();

View File

@ -18,7 +18,7 @@ export class SliderElement extends ConfigUIElement<number, HTMLDivElement> {
private _step: number;
private _dragging: boolean;
private _internalValue: number;
private _small: boolean;
private _valueHovered: boolean;
public constructor() {
super();
@ -28,7 +28,7 @@ export class SliderElement extends ConfigUIElement<number, HTMLDivElement> {
this._step = 0.1;
this._internalValue = 0.5;
this._dragging = false;
this._small = false;
this._valueHovered = false;
}
public override setDefaultValue(value: number) {
@ -37,11 +37,6 @@ export class SliderElement extends ConfigUIElement<number, HTMLDivElement> {
return this;
}
public setSmall() {
this._small = true;
return this;
}
/**
* Set the minimum value the slider can be set to.
*/
@ -116,15 +111,25 @@ export class SliderElement extends ConfigUIElement<number, HTMLDivElement> {
elementValue.addEventListener('change', () => {
this._onTypedValue();
});
elementValue.addEventListener('mouseenter', () => {
this._valueHovered = true;
this._updateStyles();
});
elementValue.addEventListener('mouseleave', () => {
this._valueHovered = false;
this._updateStyles();
});
}
public override _generateInnerHTML() {
const norm = (this._internalValue - this._min) / (this._max - this._min);
return `
<input class="struct-prop" style="padding: 0px; width: 20%; margin-right: 5px;" type="number" id="${this._getSliderValueId()}" min="${this._min}" max="${this._max}" step="${this._step}" value="${this.getValue().toFixed(this._decimals)}">
<div class="struct-prop" id="${this._getId()}" style="flex-grow: 1; padding: 0px;">
<div class="struct-prop" id="${this._getSliderBarId()}" style="width: ${norm * 100}%;">
<input class="struct-prop comp-slider-value" type="number" id="${this._getSliderValueId()}" min="${this._min}" max="${this._max}" step="${this._step}" value="${this.getValue().toFixed(this._decimals)}">
<div class="struct-prop comp-slider comp-slider-outer" id="${this._getId()}">
<div class="struct-prop comp-slider comp-slider-inner" id="${this._getSliderBarId()}" style="width: ${norm * 100}%">
</div>
</div>
`;
@ -132,6 +137,20 @@ export class SliderElement extends ConfigUIElement<number, HTMLDivElement> {
protected override _onEnabledChanged() {
super._onEnabledChanged();
const elementValue = UIUtil.getElementById(this._getSliderValueId()) as HTMLInputElement;
elementValue.disabled = this.disabled;
const elementBar = UIUtil.getElementById(this._getSliderBarId());
const elementSlider = UIUtil.getElementById(this._getId());
if (this.enabled) {
elementBar.classList.add('enabled');
elementSlider.classList.add('enabled');
} else {
elementBar.classList.remove('enabled');
elementSlider.classList.remove('enabled');
}
this._updateStyles();
}
@ -201,7 +220,7 @@ export class SliderElement extends ConfigUIElement<number, HTMLDivElement> {
protected override _updateStyles(): void {
const elementValue = UIUtil.getElementById(this._getSliderValueId()) as HTMLInputElement;
UIUtil.updateStyles(elementValue, {
isHovered: false,
isHovered: this._valueHovered,
isActive: false,
isEnabled: this.enabled,
});

View File

@ -1,80 +1,64 @@
import { RGBAUtil } from '../../colour';
import { MaterialType, SolidMaterial } from '../../mesh';
import { getRandomID } from '../../util';
import { UIUtil } from '../../util/ui_util';
import { SolidMaterial } from '../../mesh';
import { ColourElement } from './colour_element';
import { ConfigUIElement } from './config_element';
import { MaterialTypeElement } from './material_type_element';
import { SliderElement } from './slider';
export class SolidMaterialElement extends ConfigUIElement<SolidMaterial, HTMLDivElement> {
private _materialName: string;
private _colourId: string;
private _typeElement: MaterialTypeElement;
private _colourElement: ColourElement;
private _alphaElement: SliderElement;
public constructor(materialName: string, material: SolidMaterial) {
super(material);
this._materialName = materialName;
this._colourId = getRandomID();
this._typeElement = new MaterialTypeElement(material);
this._typeElement = new MaterialTypeElement(material)
.setLabel('Type');
this._colourElement = new ColourElement(material.colour)
.setLabel('Colour');
this._alphaElement = new SliderElement()
.setLabel('Alpha')
.setMin(0.0)
.setMax(1.0)
.setDefaultValue(material.colour.a)
.setDecimals(2)
.setStep(0.01)
.setSmall();
.setStep(0.01);
}
public override registerEvents(): void {
this._typeElement.registerEvents();
this._colourElement.registerEvents();
this._alphaElement.registerEvents();
this._typeElement.onClickChangeTypeDelegate(() => {
this._onChangeTypeDelegate?.();
});
this._alphaElement.addValueChangedListener((newAlpha) => {
this.getValue().colour.a = newAlpha;
this._colourElement.addValueChangedListener((newColour) => {
this.getValue().colour.r = newColour.r;
this.getValue().colour.g = newColour.g;
this.getValue().colour.b = newColour.b;
});
const swatchElement = UIUtil.getElementById(this._colourId) as HTMLInputElement;
swatchElement.addEventListener('change', () => {
const material = this.getValue();
material.colour = RGBAUtil.fromHexString(swatchElement.value);
this._alphaElement.addValueChangedListener((newAlpha) => {
this.getValue().colour.a = newAlpha;
});
}
public override finalise(): void {
this._typeElement.finalise();
this._colourElement.finalise();
this._alphaElement.finalise();
}
protected override _generateInnerHTML(): string {
const material = this.getValue();
const subproperties: string[] = [];
const addSubproperty = (key: string, value: string) => {
subproperties.push(`
<div class="subproperty">
<div class="subprop-key-container">
${key}
</div>
<div class="subprop-value-container">
${value}
</div>
</div>
`);
};
addSubproperty('Type', this._typeElement._generateInnerHTML());
addSubproperty('Colour', `<input class="colour-swatch" type="color" id="${this._colourId}" value="${RGBAUtil.toHexString(material.colour)}">`);
addSubproperty('Alpha', this._alphaElement._generateInnerHTML());
return `
<div class="subproperty-container">
${subproperties.join('')}
<div class="component-group">
${this._typeElement.generateHTML()}
${this._colourElement.generateHTML()}
${this._alphaElement.generateHTML()}
</div>
`;
}
@ -84,6 +68,10 @@ export class SolidMaterialElement extends ConfigUIElement<SolidMaterial, HTMLDiv
protected override _onEnabledChanged(): void {
super._onEnabledChanged();
this._typeElement.setEnabled(this.enabled);
this._colourElement.setEnabled(this.enabled);
this._alphaElement.setEnabled(this.enabled);
}
private _onChangeTypeDelegate?: () => void;

View File

@ -4,6 +4,8 @@ import { MaterialType, TexturedMaterial } from '../../mesh';
import { EImageChannel, TTransparencyTypes } from '../../texture';
import { getRandomID } from '../../util';
import { ASSERT } from '../../util/error_util';
import { TTexelInterpolation } from '../../util/type_util';
import { HTMLBuilder } from '../misc';
import { ComboBoxElement } from './combobox';
import { ConfigUIElement } from './config_element';
import { ImageElement } from './image_element';
@ -11,64 +13,64 @@ import { MaterialTypeElement } from './material_type_element';
import { SliderElement } from './slider';
export class TexturedMaterialElement extends ConfigUIElement<TexturedMaterial, HTMLDivElement> {
private _materialName: string;
private _colourId: string;
private _typeElement: MaterialTypeElement;
private _filteringElement: ComboBoxElement<'nearest' | 'linear'>;
private _wrapElement: ComboBoxElement<'clamp' | 'repeat'>;
private _transparencyElement: ComboBoxElement<TTransparencyTypes>;
private _imageElement: ImageElement;
private _typeElement: MaterialTypeElement;
private _alphaValueElement?: SliderElement;
private _alphaMapElement?: ImageElement;
private _alphaChannelElement?: ComboBoxElement<EImageChannel>;
public constructor(materialName: string, material: TexturedMaterial) {
super(material);
this._materialName = materialName;
this._colourId = getRandomID();
this._filteringElement = new ComboBoxElement<'linear' | 'nearest'>()
this._typeElement = new MaterialTypeElement(material)
.setLabel('Type');
this._filteringElement = new ComboBoxElement<TTexelInterpolation>()
.setLabel('Filtering')
.addItem({ payload: 'linear', displayText: 'Linear' })
.addItem({ payload: 'nearest', displayText: 'Nearest' })
.setSmall()
.setDefaultValue(material.interpolation);
this._wrapElement = new ComboBoxElement<'clamp' | 'repeat'>()
.setLabel('Wrap')
.addItem({ payload: 'clamp', displayText: 'Clamp' })
.addItem({ payload: 'repeat', displayText: 'Repeat' })
.setSmall()
.setDefaultValue(material.extension);
this._transparencyElement = new ComboBoxElement<TTransparencyTypes>()
.setLabel('Transparency')
.addItem({ payload: 'None', displayText: 'None' })
.addItem({ payload: 'UseAlphaMap', displayText: 'Alpha map' })
.addItem({ payload: 'UseAlphaValue', displayText: 'Alpha constant' })
.addItem({ payload: 'UseDiffuseMapAlphaChannel', displayText: 'Diffuse map alpha channel' })
.setSmall()
.setDefaultValue(material.transparency.type);
this._imageElement = new ImageElement(material.diffuse);
this._typeElement = new MaterialTypeElement(material);
this._imageElement = new ImageElement(material.diffuse)
.setLabel('Diffuse map');
switch (material.transparency.type) {
case 'UseAlphaValue':
this._alphaValueElement = new SliderElement()
.setLabel('Alpha')
.setMin(0.0)
.setMax(1.0)
.setDefaultValue(material.transparency.alpha)
.setDecimals(2)
.setStep(0.01)
.setSmall();
.setStep(0.01);
break;
case 'UseAlphaMap':
this._alphaMapElement = new ImageElement(material.transparency.alpha);
this._alphaMapElement = new ImageElement(material.transparency.alpha)
.setLabel('Alpha map');
this._alphaChannelElement = new ComboBoxElement<EImageChannel>()
.setLabel('Alpha channel')
.addItem({ payload: EImageChannel.R, displayText: 'Red' })
.addItem({ payload: EImageChannel.G, displayText: 'Green' })
.addItem({ payload: EImageChannel.B, displayText: 'Blue' })
.addItem({ payload: EImageChannel.A, displayText: 'Alpha' })
.setSmall()
.setDefaultValue(material.transparency.channel);
break;
}
@ -139,39 +141,27 @@ export class TexturedMaterialElement extends ConfigUIElement<TexturedMaterial, H
}
protected override _generateInnerHTML(): string {
const subproperties: string[] = [];
const addSubproperty = (key: string, value: string) => {
subproperties.push(`
<div class="subproperty">
<div class="subprop-key-container">
${key}
</div>
<div class="subprop-value-container">
${value}
</div>
</div>
`);
};
const builder = new HTMLBuilder();
addSubproperty('Type', this._typeElement._generateInnerHTML());
addSubproperty('Diffuse map', this._imageElement._generateInnerHTML());
addSubproperty('Filtering', this._filteringElement._generateInnerHTML());
addSubproperty('Wrap', this._wrapElement._generateInnerHTML());
addSubproperty('Transparency', this._transparencyElement._generateInnerHTML());
builder.add('<div class="component-group">');
{
builder.add(this._typeElement.generateHTML());
builder.add(this._imageElement.generateHTML());
builder.add(this._filteringElement.generateHTML());
builder.add(this._wrapElement.generateHTML());
builder.add(this._transparencyElement.generateHTML());
if (this._alphaMapElement !== undefined) {
ASSERT(this._alphaChannelElement !== undefined);
addSubproperty('Alpha map', this._alphaMapElement._generateInnerHTML());
addSubproperty('Channel', this._alphaChannelElement._generateInnerHTML());
builder.add(this._alphaMapElement.generateHTML());
builder.add(this._alphaChannelElement.generateHTML());
}
if (this._alphaValueElement) {
addSubproperty('Alpha', this._alphaValueElement._generateInnerHTML());
if (this._alphaValueElement !== undefined) {
builder.add(this._alphaValueElement.generateHTML());
}
}
builder.add('</div>');
return `
<div class="subproperty-container">
${subproperties.join('')}
</div>
`;
return builder.toString();
}
protected override _onValueChanged(): void {
@ -179,6 +169,15 @@ export class TexturedMaterialElement extends ConfigUIElement<TexturedMaterial, H
protected override _onEnabledChanged(): void {
super._onEnabledChanged();
this._imageElement.setEnabled(this.enabled);
this._typeElement.setEnabled(this.enabled);
this._filteringElement.setEnabled(this.enabled);
this._wrapElement.setEnabled(this.enabled);
this._transparencyElement.setEnabled(this.enabled);
this._alphaValueElement?.setEnabled(this.enabled);
this._alphaMapElement?.setEnabled(this.enabled);
this._alphaChannelElement?.setEnabled(this.enabled);
}
public override finalise(): void {

View File

@ -14,7 +14,6 @@ export type TToolbarItemParams = {
export class ToolbarItemElement extends BaseUIElement<HTMLDivElement> {
private _iconSVG: SVGSVGElement;
private _small: boolean;
private _label: string;
private _onClick?: () => void;
private _isActive: boolean;
@ -34,19 +33,13 @@ export class ToolbarItemElement extends BaseUIElement<HTMLDivElement> {
this._iconSVG.id = this._getId() + '-svg';
}
this._small = false;
this._label = '';
}
public setActive(isActive: boolean) {
this._isActive = isActive;
}
public setSmall() {
this._small = true;
return this;
this._updateStyles();
}
public setLabel(label: string) {

View File

@ -1,3 +1,4 @@
// https://tablericons.com/
export namespace AppIcons {
export const MESH = `
@ -61,10 +62,11 @@ export namespace AppIcons {
`;
export const BULB = `
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-sun" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#00abfb" fill="none" stroke-linecap="round" stroke-linejoin="round" id="bulb-svg">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-bulb" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#2c3e50" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<circle cx="12" cy="12" r="4" />
<path d="M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7" />
<path d="M3 12h1m8 -9v1m8 8h1m-15.4 -6.4l.7 .7m12.1 -.7l-.7 .7" />
<path d="M9 16a5 5 0 1 1 6 0a3.5 3.5 0 0 0 -1 3a2 2 0 0 1 -4 0a3.5 3.5 0 0 0 -1 -3" />
<line x1="9.7" y1="17" x2="14.3" y2="17" />
</svg>
`;
@ -215,4 +217,35 @@ export namespace AppIcons {
<polyline points="6 9 12 15 18 9" />
</svg>
`;
export const COLOUR_SWATCH = `
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-color-swatch" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#2c3e50" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<path d="M19 3h-4a2 2 0 0 0 -2 2v12a4 4 0 0 0 8 0v-12a2 2 0 0 0 -2 -2" />
<path d="M13 7.35l-2 -2a2 2 0 0 0 -2.828 0l-2.828 2.828a2 2 0 0 0 0 2.828l9 9" />
<path d="M7.3 13h-2.3a2 2 0 0 0 -2 2v4a2 2 0 0 0 2 2h12" />
<line x1="17" y1="17" x2="17" y2="17.01" />
</svg>
`;
export const IMAGE = `
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-photo" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#2c3e50" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<line x1="15" y1="8" x2="15.01" y2="8" />
<rect x="4" y="4" width="16" height="16" rx="3" />
<path d="M4 15l4 -4a3 5 0 0 1 3 0l5 5" />
<path d="M14 14l1 -1a3 5 0 0 1 3 0l2 2" />
</svg>
`;
export const IMAGE_MISSING = `
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-photo-off" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="#2c3e50" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<line x1="3" y1="3" x2="21" y2="21" />
<line x1="15" y1="8" x2="15.01" y2="8" />
<path d="M19.121 19.122a3 3 0 0 1 -2.121 .878h-10a3 3 0 0 1 -3 -3v-10c0 -.833 .34 -1.587 .888 -2.131m3.112 -.869h9a3 3 0 0 1 3 3v9" />
<path d="M4 15l4 -4c.928 -.893 2.072 -.893 3 0l5 5" />
<path d="M16.32 12.34c.577 -.059 1.162 .162 1.68 .66l2 2" />
</svg>
`;
}

View File

@ -492,7 +492,7 @@ export class UI {
Split(['.column-sidebar', '.column-canvas'], {
sizes: [20, 80],
minSize: [450, 500],
minSize: [600, 500],
gutterSize: 5,
});

View File

@ -29,8 +29,6 @@
--border-radius: 5px;
--property-height: 32px;
--subproperty-height: 22px;
--subprop-value-width: 125px;
}
* {
@ -117,6 +115,7 @@ canvas {
padding: 5px 10px;
border: 1px solid var(--gray-400);
border-radius: 10px;
width: 100%;
}
.container-checkbox {
@ -165,7 +164,7 @@ canvas {
}
.group-heading {
color: var(--gray-600);
color: var(--gray-700);
letter-spacing: 4px;
font-size: 85%;
padding: 12px 0px;
@ -175,7 +174,7 @@ canvas {
display: flex;
align-items: center;
padding: 0px 5px;
width: 150px;
width: 40%;
height: var(--property-height);
overflow: auto;
}
@ -185,56 +184,23 @@ canvas {
display: flex;
align-items: center;
width: 0px;
}
.subproperty-container {
display: flex;
flex-direction: column;
width: 100%;
}
.subproperty {
display: flex;
flex-direction: row;
align-items: center;
color: var(--text-standard);
font-size: 85%;
width: 100%;
padding-top: 2px;
padding-bottom: 2px;
border-bottom: 1px solid var(--vertical-divider);
}
.subproperty:last-child {
border-bottom: 0px;
}
.subprop-key-container {
align-self: center;
width: 50%;
overflow: auto;
}
.subprop-value-container {
flex-grow: 1;
display: flex;
align-items: center;
min-height: var(--subproperty-height);
width: var(--subprop-value-width);
overflow: auto;
padding-left: 5px;
overflow-x: auto;
}
input {
font-family: 'Rubik', sans-serif;
text-align: center;
font-size: inherit;
outline: none;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type=number]:not(:disabled) {
cursor: text;
}
::placeholder {
color: var(--text-dark);
@ -262,6 +228,7 @@ select {
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.button-progress {
@ -390,7 +357,8 @@ select {
.toolbar-column {
display: flex;
flex-direction: row;
margin: 20px 10px;
margin: 20px;
gap: 20px;
}
.toolbar-column:last-child {
@ -402,12 +370,9 @@ select {
flex-direction: row;
box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 16px;
border-radius: var(--border-radius);
margin-left: 10px;
margin-right: 10px;
}
.container-icon-button {
width: var(--property-height);
height: var(--property-height);
display: flex;
align-items: center;
@ -481,19 +446,16 @@ svg {
}
.colour-swatch {
border: 1px solid #8C8C8C80;
border-radius: 5px;
border: none;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: none;
width: 100%;
height: var(--property-height);
margin: 0px;
padding: 0px;
}
.colour-swatch-hover {
border-color: var(--text-standard) !important;
}
.colour-swatch::-webkit-color-swatch-wrapper {
border: none;
@ -505,17 +467,34 @@ svg {
margin: 0px;
padding: 0px;
border-radius: 5px;
border: 1px solid var(--gray-600);
}
.enabled.colour-swatch::-webkit-color-swatch:hover {
border: 1px solid var(--gray-700);
filter: brightness(1.1);
cursor: pointer;
}
.texture-preview {
border: 1px solid #8C8C8C80;
border: 1px solid var(--gray-600);
border-radius: 5px;
width: calc(100% - 2px);
width: 100%;
}
.texture-preview-missing {
border-color: orange !important;
}
.texture-preview-placeholder {
border: 1px solid var(--gray-400);
color: var(--text-dim);
border-radius: 5px;
width: 100%;
aspect-ratio: 1/1;
display: flex;
align-items: center;
justify-content: center;
}
.texture-hover {
border-color: var(--text-standard) !important;
}
@ -556,6 +535,7 @@ svg {
display: flex;
flex-direction: column;
gap: 2px;
width: 100%;
}
.row-item {
@ -611,6 +591,9 @@ svg {
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
.struct-prop.container-icon-button:only-of-type {
border-radius: 5px;
}
.button-loading {
box-shadow: 0 0 0 0 rgba(0, 0, 0, 1);
@ -665,3 +648,19 @@ a {
::-webkit-scrollbar-corner {
background: rgb(20, 20, 20);
}
.comp-slider-value {
padding: 0px;
width: 40%;
margin-right: 5px;
}
.comp-slider-outer {
flex-grow: 1;
padding: 0px;
}
.comp-slider-inner {
padding: 0px;
}
.comp-slider.enabled {
cursor: e-resize;
}