forked from mirror/ObjToSchematic
Renamed elements to components
This commit is contained in:
parent
ac3bcc637c
commit
dd5227ad6e
@ -8,12 +8,10 @@ import { TExporters } from './exporters/exporters';
|
||||
import { MaterialMapManager } from './material-map';
|
||||
import { MaterialType } from './mesh';
|
||||
import { MeshType, Renderer } from './renderer';
|
||||
import { PlaceholderComponent } from './ui/components/placeholder';
|
||||
import { SolidMaterialComponent } from './ui/components/solid_material';
|
||||
import { TexturedMaterialComponent } from './ui/components/textured_material';
|
||||
import { AppConsole, TMessage } from './ui/console';
|
||||
import { ButtonElement } from './ui/elements/button';
|
||||
import { CheckboxElement } from './ui/elements/checkbox';
|
||||
import { PlaceholderElement } from './ui/elements/placeholder_element';
|
||||
import { SolidMaterialElement } from './ui/elements/solid_material_element';
|
||||
import { TexturedMaterialElement } from './ui/elements/textured_material_element';
|
||||
import { UI } from './ui/layout';
|
||||
import { ColourSpace, EAction } from './util';
|
||||
import { ASSERT } from './util/error_util';
|
||||
@ -152,7 +150,7 @@ export class AppContext {
|
||||
}
|
||||
|
||||
private async _import(): Promise<TWorkerJob> {
|
||||
const uiElements = this._ui.layout.import.elements;
|
||||
const uiElements = this._ui.layout.import.components;
|
||||
AppConsole.info('Importing mesh...');
|
||||
|
||||
const payload: TToWorkerMessage = {
|
||||
@ -230,41 +228,39 @@ export class AppContext {
|
||||
}
|
||||
|
||||
private _updateMaterialsAction() {
|
||||
this._ui.layoutDull['materials'].elements = {};
|
||||
this._ui.layoutDull['materials'].elementsOrder = [];
|
||||
this._ui.layoutDull['materials'].components = {};
|
||||
this._ui.layoutDull['materials'].componentOrder = [];
|
||||
|
||||
if (this._materialManager.materials.size == 0) {
|
||||
this._ui.layoutDull['materials'].elements[`placeholder_element`] = new PlaceholderElement('No materials loaded');
|
||||
this._ui.layoutDull['materials'].elementsOrder.push(`placeholder_element`);
|
||||
this._ui.layoutDull['materials'].components[`placeholder_element`] = new PlaceholderComponent('No materials loaded');
|
||||
this._ui.layoutDull['materials'].componentOrder.push(`placeholder_element`);
|
||||
} else {
|
||||
this._materialManager.materials.forEach((material, materialName) => {
|
||||
if (material.type === MaterialType.solid) {
|
||||
this._ui.layoutDull['materials'].elements[`mat_${materialName}`] = new SolidMaterialElement(materialName, material)
|
||||
this._ui.layoutDull['materials'].components[`mat_${materialName}`] = new SolidMaterialComponent(materialName, material)
|
||||
.setLabel(materialName)
|
||||
.onChangeTypeDelegate(() => {
|
||||
this._materialManager.changeMaterialType(materialName, MaterialType.textured);
|
||||
this._updateMaterialsAction();
|
||||
});
|
||||
} else {
|
||||
this._ui.layoutDull['materials'].elements[`mat_${materialName}`] = new TexturedMaterialElement(materialName, material)
|
||||
this._ui.layoutDull['materials'].components[`mat_${materialName}`] = new TexturedMaterialComponent(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();
|
||||
});
|
||||
}
|
||||
|
||||
this._ui.layoutDull['materials'].elementsOrder.push(`mat_${materialName}`);
|
||||
this._ui.layoutDull['materials'].componentOrder.push(`mat_${materialName}`);
|
||||
});
|
||||
}
|
||||
|
||||
this._ui.refreshSubcomponents(this._ui.layoutDull['materials']);
|
||||
this._ui.refreshComponents(EAction.Materials);
|
||||
}
|
||||
|
||||
private _renderMesh(): TWorkerJob {
|
||||
@ -302,7 +298,7 @@ export class AppContext {
|
||||
private _voxelise(): TWorkerJob {
|
||||
AppConsole.info('Loading voxel mesh...');
|
||||
|
||||
const uiElements = this._ui.layout.voxelise.elements;
|
||||
const uiElements = this._ui.layout.voxelise.components;
|
||||
|
||||
const payload: TToWorkerMessage = {
|
||||
action: 'Voxelise',
|
||||
@ -333,7 +329,7 @@ export class AppContext {
|
||||
AppConsole.info('Rendering voxel mesh...');
|
||||
}
|
||||
|
||||
const uiElements = this._ui.layout.voxelise.elements;
|
||||
const uiElements = this._ui.layout.voxelise.components;
|
||||
|
||||
const payload: TToWorkerMessage = {
|
||||
action: 'RenderNextVoxelMeshChunk',
|
||||
@ -374,7 +370,7 @@ export class AppContext {
|
||||
}
|
||||
|
||||
private _assign(): (TWorkerJob | undefined) {
|
||||
const uiElements = this._ui.layout.assign.elements;
|
||||
const uiElements = this._ui.layout.assign.components;
|
||||
|
||||
if (uiElements.blockPalette.getValue().count() <= 0) {
|
||||
AppConsole.error('No blocks selected');
|
||||
@ -417,7 +413,7 @@ export class AppContext {
|
||||
AppConsole.info('Rendering block mesh...');
|
||||
}
|
||||
|
||||
const uiElements = this._ui.layout.assign.elements;
|
||||
const uiElements = this._ui.layout.assign.components;
|
||||
|
||||
const payload: TToWorkerMessage = {
|
||||
action: 'RenderNextBlockMeshChunk',
|
||||
@ -459,7 +455,7 @@ export class AppContext {
|
||||
private _export(): (TWorkerJob | undefined) {
|
||||
AppConsole.info('Exporting structure...');
|
||||
|
||||
const exporterID: TExporters = this._ui.layout.export.elements.export.getValue();
|
||||
const exporterID: TExporters = this._ui.layout.export.components.export.getValue();
|
||||
const filepath = '';
|
||||
|
||||
const payload: TToWorkerMessage = {
|
||||
|
@ -9,9 +9,9 @@ export interface IInterfaceItem {
|
||||
|
||||
/**
|
||||
* The base UI class from which user interactable DOM elements are built from.
|
||||
* Each `BaseUIElement` can be enabled/disabled.
|
||||
* Each `BaseComponent` can be enabled/disabled.
|
||||
*/
|
||||
export abstract class BaseUIElement<T> implements IInterfaceItem {
|
||||
export abstract class BaseComponent<T> implements IInterfaceItem {
|
||||
private _id: string;
|
||||
private _isEnabled: boolean;
|
||||
private _isHovered: boolean;
|
||||
@ -76,7 +76,7 @@ export abstract class BaseUIElement<T> implements IInterfaceItem {
|
||||
|
||||
/**
|
||||
* The actual HTML that represents this UI element. It is recommended to
|
||||
* give the outermost element that ID generated for this BaseUIElement so
|
||||
* give the outermost element that ID generated for this BaseComponent so
|
||||
* that `getElement()` returns all elements created here.
|
||||
*/
|
||||
public abstract generateHTML(): string;
|
||||
@ -93,7 +93,7 @@ export abstract class BaseUIElement<T> implements IInterfaceItem {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the actual DOM element that this BaseUIElement refers to.
|
||||
* Returns the actual DOM element that this BaseComponent refers to.
|
||||
* Calling this before the element is created (i.e. before `generateHTML`)
|
||||
* is called will throw an error.
|
||||
*/
|
||||
@ -102,7 +102,7 @@ export abstract class BaseUIElement<T> implements IInterfaceItem {
|
||||
}
|
||||
|
||||
/**
|
||||
* Each BaseUIElement is assignd an ID that can be used a DOM element with.
|
||||
* Each BaseComponent is assignd an ID that can be used a DOM element with.
|
||||
*/
|
||||
protected _getId() {
|
||||
return this._id;
|
@ -1,123 +1,123 @@
|
||||
import { UIUtil } from '../../util/ui_util';
|
||||
import { BaseUIElement } from './base_element';
|
||||
|
||||
export class ButtonElement extends BaseUIElement<HTMLDivElement> {
|
||||
private _label: string;
|
||||
private _onClick: () => void;
|
||||
|
||||
public constructor() {
|
||||
super();
|
||||
this._label = 'Unknown';
|
||||
this._onClick = () => { };
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the delegate that is called when this button is clicked.
|
||||
*/
|
||||
public setOnClick(delegate: () => void) {
|
||||
this._onClick = delegate;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the label of this button.
|
||||
*/
|
||||
public setLabel(label: string) {
|
||||
this._label = label;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the current label with a new value.
|
||||
*/
|
||||
public setLabelOverride(label: string) {
|
||||
this._getElement().innerHTML = label;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the label override and set the label back to its default
|
||||
*/
|
||||
public removeLabelOverride() {
|
||||
this._getElement().innerHTML = this._label;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the loading animation
|
||||
*/
|
||||
public startLoading() {
|
||||
this._getElement().classList.add('button-loading');
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the progress bar progress.
|
||||
* @param progress A number between 0.0 and 1.0 inclusive.
|
||||
*/
|
||||
public setProgress(progress: number) {
|
||||
const progressBarElement = UIUtil.getElementById(this._getProgressBarId());
|
||||
progressBarElement.style.width = `${progress * 100}%`;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the loading animation
|
||||
*/
|
||||
public stopLoading() {
|
||||
this._getElement().classList.remove('button-loading');
|
||||
return this;
|
||||
}
|
||||
|
||||
public override generateHTML() {
|
||||
return `
|
||||
<div class="container-button">
|
||||
<div class="struct-prop button" id="${this._getId()}">
|
||||
<div class="button-label">${this._label}</div>
|
||||
<div class="button-progress" id="${this._getProgressBarId()}"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
public override registerEvents(): void {
|
||||
this._getElement().addEventListener('click', () => {
|
||||
if (this.enabled) {
|
||||
this._onClick?.();
|
||||
}
|
||||
});
|
||||
|
||||
this._getElement().addEventListener('mouseenter', () => {
|
||||
this._setHovered(true);
|
||||
this._updateStyles();
|
||||
});
|
||||
|
||||
this._getElement().addEventListener('mouseleave', () => {
|
||||
this._setHovered(false);
|
||||
this._updateStyles();
|
||||
});
|
||||
}
|
||||
|
||||
protected override _onEnabledChanged() {
|
||||
this._updateStyles();
|
||||
}
|
||||
|
||||
public override finalise(): void {
|
||||
this._updateStyles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ID of the DOM element for the button's progress bar.
|
||||
*/
|
||||
private _getProgressBarId() {
|
||||
return this._getId() + '-progress';
|
||||
}
|
||||
|
||||
protected _updateStyles(): void {
|
||||
UIUtil.updateStyles(this._getElement(), {
|
||||
isActive: true,
|
||||
isEnabled: this.enabled,
|
||||
isHovered: this.hovered,
|
||||
});
|
||||
}
|
||||
}
|
||||
import { UIUtil } from '../../util/ui_util';
|
||||
import { BaseComponent } from './base';
|
||||
|
||||
export class ButtonComponent extends BaseComponent<HTMLDivElement> {
|
||||
private _label: string;
|
||||
private _onClick: () => void;
|
||||
|
||||
public constructor() {
|
||||
super();
|
||||
this._label = 'Unknown';
|
||||
this._onClick = () => { };
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the delegate that is called when this button is clicked.
|
||||
*/
|
||||
public setOnClick(delegate: () => void) {
|
||||
this._onClick = delegate;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the label of this button.
|
||||
*/
|
||||
public setLabel(label: string) {
|
||||
this._label = label;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the current label with a new value.
|
||||
*/
|
||||
public setLabelOverride(label: string) {
|
||||
this._getElement().innerHTML = label;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the label override and set the label back to its default
|
||||
*/
|
||||
public removeLabelOverride() {
|
||||
this._getElement().innerHTML = this._label;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the loading animation
|
||||
*/
|
||||
public startLoading() {
|
||||
this._getElement().classList.add('button-loading');
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the progress bar progress.
|
||||
* @param progress A number between 0.0 and 1.0 inclusive.
|
||||
*/
|
||||
public setProgress(progress: number) {
|
||||
const progressBarElement = UIUtil.getElementById(this._getProgressBarId());
|
||||
progressBarElement.style.width = `${progress * 100}%`;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the loading animation
|
||||
*/
|
||||
public stopLoading() {
|
||||
this._getElement().classList.remove('button-loading');
|
||||
return this;
|
||||
}
|
||||
|
||||
public override generateHTML() {
|
||||
return `
|
||||
<div class="container-button">
|
||||
<div class="struct-prop button" id="${this._getId()}">
|
||||
<div class="button-label">${this._label}</div>
|
||||
<div class="button-progress" id="${this._getProgressBarId()}"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
public override registerEvents(): void {
|
||||
this._getElement().addEventListener('click', () => {
|
||||
if (this.enabled) {
|
||||
this._onClick?.();
|
||||
}
|
||||
});
|
||||
|
||||
this._getElement().addEventListener('mouseenter', () => {
|
||||
this._setHovered(true);
|
||||
this._updateStyles();
|
||||
});
|
||||
|
||||
this._getElement().addEventListener('mouseleave', () => {
|
||||
this._setHovered(false);
|
||||
this._updateStyles();
|
||||
});
|
||||
}
|
||||
|
||||
protected override _onEnabledChanged() {
|
||||
this._updateStyles();
|
||||
}
|
||||
|
||||
public override finalise(): void {
|
||||
this._updateStyles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ID of the DOM element for the button's progress bar.
|
||||
*/
|
||||
private _getProgressBarId() {
|
||||
return this._getId() + '-progress';
|
||||
}
|
||||
|
||||
protected _updateStyles(): void {
|
||||
UIUtil.updateStyles(this._getElement(), {
|
||||
isActive: true,
|
||||
isEnabled: this.enabled,
|
||||
isHovered: this.hovered,
|
||||
});
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import { UIUtil } from '../../util/ui_util';
|
||||
import { ConfigUIElement } from './config_element';
|
||||
import { ConfigComponent } from './config';
|
||||
|
||||
export class CheckboxElement extends ConfigUIElement<boolean, HTMLSelectElement> {
|
||||
export class CheckboxComponent extends ConfigComponent<boolean, HTMLSelectElement> {
|
||||
private _labelChecked: string;
|
||||
private _labelUnchecked: string;
|
||||
|
||||
@ -22,14 +22,14 @@ export class CheckboxElement extends ConfigUIElement<boolean, HTMLSelectElement>
|
||||
}
|
||||
|
||||
public override registerEvents(): void {
|
||||
const checkboxElement = this._getElement();
|
||||
const CheckboxComponent = this._getElement();
|
||||
const textElement = UIUtil.getElementById(this._getTextId());
|
||||
|
||||
checkboxElement.addEventListener('mouseenter', () => {
|
||||
CheckboxComponent.addEventListener('mouseenter', () => {
|
||||
this._onMouseEnterLeave(true);
|
||||
});
|
||||
|
||||
checkboxElement.addEventListener('mouseleave', () => {
|
||||
CheckboxComponent.addEventListener('mouseleave', () => {
|
||||
this._onMouseEnterLeave(false);
|
||||
});
|
||||
|
||||
@ -41,7 +41,7 @@ export class CheckboxElement extends ConfigUIElement<boolean, HTMLSelectElement>
|
||||
this._onMouseEnterLeave(false);
|
||||
});
|
||||
|
||||
checkboxElement.addEventListener('click', () => {
|
||||
CheckboxComponent.addEventListener('click', () => {
|
||||
this._onClick();
|
||||
});
|
||||
|
||||
@ -104,11 +104,11 @@ export class CheckboxElement extends ConfigUIElement<boolean, HTMLSelectElement>
|
||||
|
||||
protected _updateStyles() {
|
||||
{
|
||||
const checkboxElement = UIUtil.getElementById(this._getId());
|
||||
UIUtil.updateStyles(checkboxElement, {
|
||||
const CheckboxComponent = UIUtil.getElementById(this._getId());
|
||||
UIUtil.updateStyles(CheckboxComponent, {
|
||||
isEnabled: this.enabled,
|
||||
isHovered: this.hovered,
|
||||
isActive: false,
|
||||
isActive: this.getValue(),
|
||||
});
|
||||
}
|
||||
const checkboxPipElement = UIUtil.getElementById(this._getPipId());
|
@ -1,7 +1,7 @@
|
||||
import { RGBA, RGBAUtil } from '../../colour';
|
||||
import { ConfigUIElement } from './config_element';
|
||||
import { ConfigComponent } from './config';
|
||||
|
||||
export class ColourElement extends ConfigUIElement<RGBA, HTMLInputElement> {
|
||||
export class ColourComponent extends ConfigComponent<RGBA, HTMLInputElement> {
|
||||
public constructor(colour: RGBA) {
|
||||
super(colour);
|
||||
}
|
@ -1,112 +1,112 @@
|
||||
import { UIUtil } from '../../util/ui_util';
|
||||
import { AppIcons } from '../icons';
|
||||
import { HTMLBuilder } from '../misc';
|
||||
import { ConfigUIElement } from './config_element';
|
||||
|
||||
export type ComboBoxItem<T> = {
|
||||
payload: T;
|
||||
displayText: string;
|
||||
tooltip?: string;
|
||||
}
|
||||
|
||||
export class ComboBoxElement<T> extends ConfigUIElement<T, HTMLSelectElement> {
|
||||
private _items: ComboBoxItem<T>[];
|
||||
|
||||
public constructor() {
|
||||
super();
|
||||
this._items = [];
|
||||
}
|
||||
|
||||
public addItems(items: ComboBoxItem<T>[]) {
|
||||
items.forEach((item) => {
|
||||
this.addItem(item);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public addItem(item: ComboBoxItem<T>) {
|
||||
this._items.push(item);
|
||||
this._setValue(this._items[0].payload);
|
||||
return this;
|
||||
}
|
||||
|
||||
public override registerEvents(): void {
|
||||
this._getElement().addEventListener('mouseenter', () => {
|
||||
this._setHovered(true);
|
||||
this._updateStyles();
|
||||
});
|
||||
|
||||
this._getElement().addEventListener('mouseleave', () => {
|
||||
this._setHovered(false);
|
||||
this._updateStyles();
|
||||
});
|
||||
|
||||
this._getElement().addEventListener('change', (e: Event) => {
|
||||
const selectedValue = this._items[this._getElement().selectedIndex].payload;
|
||||
this._setValue(selectedValue);
|
||||
});
|
||||
}
|
||||
|
||||
public override _generateInnerHTML() {
|
||||
const builder = new HTMLBuilder();
|
||||
|
||||
builder.add('<div style="position: relative; width: 100%;">');
|
||||
builder.add(`<select class="struct-prop" name="${this._getId()}" id="${this._getId()}">`);
|
||||
for (const item of this._items) {
|
||||
builder.add(`<option value="${item.payload}" title="${item.tooltip || ''}">${item.displayText}</option>`);
|
||||
}
|
||||
builder.add('</select>');
|
||||
|
||||
builder.add(`<div id="${this._getId()}-arrow" class="checkbox-arrow">`);
|
||||
builder.add(AppIcons.ARROW_DOWN);
|
||||
builder.add(`</div>`);
|
||||
builder.add('</div>');
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
protected _onValueChanged(): void {
|
||||
super._onValueChanged();
|
||||
|
||||
console.log('combo changed');
|
||||
}
|
||||
|
||||
protected _onEnabledChanged(): void {
|
||||
super._onEnabledChanged();
|
||||
this._getElement().disabled = this.disabled;
|
||||
this._updateStyles();
|
||||
}
|
||||
|
||||
protected override _updateStyles(): void {
|
||||
UIUtil.updateStyles(this._getElement(), {
|
||||
isHovered: this.hovered,
|
||||
isEnabled: this.enabled,
|
||||
isActive: false,
|
||||
});
|
||||
|
||||
const arrowElement = UIUtil.getElementById(this._getId() + '-arrow');
|
||||
arrowElement.classList.remove('text-dark');
|
||||
arrowElement.classList.remove('text-standard');
|
||||
arrowElement.classList.remove('text-light');
|
||||
if (this.enabled) {
|
||||
if (this.hovered) {
|
||||
arrowElement.classList.add('text-light');
|
||||
} else {
|
||||
arrowElement.classList.add('text-standard');
|
||||
}
|
||||
} else {
|
||||
arrowElement.classList.add('text-dark');
|
||||
}
|
||||
}
|
||||
|
||||
public override finalise(): void {
|
||||
super.finalise();
|
||||
|
||||
const selectedIndex = this._items.findIndex((item) => item.payload === this.getValue());
|
||||
const element = this._getElement();
|
||||
|
||||
element.selectedIndex = selectedIndex;
|
||||
|
||||
this._updateStyles();
|
||||
}
|
||||
}
|
||||
import { UIUtil } from '../../util/ui_util';
|
||||
import { AppIcons } from '../icons';
|
||||
import { HTMLBuilder } from '../misc';
|
||||
import { ConfigComponent } from './config';
|
||||
|
||||
export type ComboBoxItem<T> = {
|
||||
payload: T;
|
||||
displayText: string;
|
||||
tooltip?: string;
|
||||
}
|
||||
|
||||
export class ComboboxComponent<T> extends ConfigComponent<T, HTMLSelectElement> {
|
||||
private _items: ComboBoxItem<T>[];
|
||||
|
||||
public constructor() {
|
||||
super();
|
||||
this._items = [];
|
||||
}
|
||||
|
||||
public addItems(items: ComboBoxItem<T>[]) {
|
||||
items.forEach((item) => {
|
||||
this.addItem(item);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public addItem(item: ComboBoxItem<T>) {
|
||||
this._items.push(item);
|
||||
this._setValue(this._items[0].payload);
|
||||
return this;
|
||||
}
|
||||
|
||||
public override registerEvents(): void {
|
||||
this._getElement().addEventListener('mouseenter', () => {
|
||||
this._setHovered(true);
|
||||
this._updateStyles();
|
||||
});
|
||||
|
||||
this._getElement().addEventListener('mouseleave', () => {
|
||||
this._setHovered(false);
|
||||
this._updateStyles();
|
||||
});
|
||||
|
||||
this._getElement().addEventListener('change', (e: Event) => {
|
||||
const selectedValue = this._items[this._getElement().selectedIndex].payload;
|
||||
this._setValue(selectedValue);
|
||||
});
|
||||
}
|
||||
|
||||
public override _generateInnerHTML() {
|
||||
const builder = new HTMLBuilder();
|
||||
|
||||
builder.add('<div style="position: relative; width: 100%;">');
|
||||
builder.add(`<select class="struct-prop" name="${this._getId()}" id="${this._getId()}">`);
|
||||
for (const item of this._items) {
|
||||
builder.add(`<option value="${item.payload}" title="${item.tooltip || ''}">${item.displayText}</option>`);
|
||||
}
|
||||
builder.add('</select>');
|
||||
|
||||
builder.add(`<div id="${this._getId()}-arrow" class="checkbox-arrow">`);
|
||||
builder.add(AppIcons.ARROW_DOWN);
|
||||
builder.add(`</div>`);
|
||||
builder.add('</div>');
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
protected _onValueChanged(): void {
|
||||
super._onValueChanged();
|
||||
|
||||
console.log('combo changed');
|
||||
}
|
||||
|
||||
protected _onEnabledChanged(): void {
|
||||
super._onEnabledChanged();
|
||||
this._getElement().disabled = this.disabled;
|
||||
this._updateStyles();
|
||||
}
|
||||
|
||||
protected override _updateStyles(): void {
|
||||
UIUtil.updateStyles(this._getElement(), {
|
||||
isHovered: this.hovered,
|
||||
isEnabled: this.enabled,
|
||||
isActive: false,
|
||||
});
|
||||
|
||||
const arrowElement = UIUtil.getElementById(this._getId() + '-arrow');
|
||||
arrowElement.classList.remove('text-dark');
|
||||
arrowElement.classList.remove('text-standard');
|
||||
arrowElement.classList.remove('text-light');
|
||||
if (this.enabled) {
|
||||
if (this.hovered) {
|
||||
arrowElement.classList.add('text-light');
|
||||
} else {
|
||||
arrowElement.classList.add('text-standard');
|
||||
}
|
||||
} else {
|
||||
arrowElement.classList.add('text-dark');
|
||||
}
|
||||
}
|
||||
|
||||
public override finalise(): void {
|
||||
super.finalise();
|
||||
|
||||
const selectedIndex = this._items.findIndex((item) => item.payload === this.getValue());
|
||||
const element = this._getElement();
|
||||
|
||||
element.selectedIndex = selectedIndex;
|
||||
|
||||
this._updateStyles();
|
||||
}
|
||||
}
|
@ -1,12 +1,11 @@
|
||||
import { ASSERT } from '../../util/error_util';
|
||||
import { UIUtil } from '../../util/ui_util';
|
||||
import { BaseUIElement } from './base_element';
|
||||
import { BaseComponent } from './base';
|
||||
|
||||
/**
|
||||
* A `ConfigUIElement` is a UI element that has a value the user can change.
|
||||
* For example, sliders, comboboxes and checkboxes are `ConfigUIElement`.
|
||||
* A `ConfigComponent` is a UI element that has a value the user can change.
|
||||
* For example, sliders, comboboxes and checkboxes are `ConfigComponent`.
|
||||
*/
|
||||
export abstract class ConfigUIElement<T, F> extends BaseUIElement<F> {
|
||||
export abstract class ConfigComponent<T, F> extends BaseComponent<F> {
|
||||
protected _label: string;
|
||||
private _value?: T;
|
||||
private _cachedValue?: T;
|
@ -1,68 +1,68 @@
|
||||
import * as path from 'path';
|
||||
|
||||
import { ASSERT } from '../../util/error_util';
|
||||
import { UIUtil } from '../../util/ui_util';
|
||||
import { ConfigUIElement } from './config_element';
|
||||
|
||||
export class ObjFileInputElement extends ConfigUIElement<Promise<string>, HTMLDivElement> {
|
||||
private _loadedFilePath: string;
|
||||
|
||||
public constructor() {
|
||||
super(Promise.resolve(''));
|
||||
this._loadedFilePath = '';
|
||||
}
|
||||
|
||||
protected override _generateInnerHTML() {
|
||||
return `
|
||||
<div class="input-file struct-prop" id="${this._getId()}">
|
||||
<input type="file" accept=".obj" style="display: none;" id="${this._getId()}-input">
|
||||
${this._loadedFilePath}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
public override registerEvents(): void {
|
||||
this._getElement().addEventListener('mouseenter', () => {
|
||||
this._setHovered(true);
|
||||
this._updateStyles();
|
||||
});
|
||||
|
||||
this._getElement().addEventListener('mouseleave', () => {
|
||||
this._setHovered(false);
|
||||
this._updateStyles();
|
||||
});
|
||||
|
||||
const inputElement = UIUtil.getElementById(this._getId() + '-input') as HTMLInputElement;
|
||||
|
||||
inputElement.addEventListener('change', () => {
|
||||
const files = inputElement.files;
|
||||
if (files?.length === 1) {
|
||||
const file = files.item(0);
|
||||
ASSERT(file !== null);
|
||||
this._loadedFilePath = file.name;
|
||||
this._setValue(file.text());
|
||||
}
|
||||
});
|
||||
|
||||
this._getElement().addEventListener('click', () => {
|
||||
if (this.enabled) {
|
||||
inputElement.click();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected _onValueChanged(): void {
|
||||
this._updateStyles();
|
||||
}
|
||||
|
||||
protected override _updateStyles() {
|
||||
const parsedPath = path.parse(this._loadedFilePath);
|
||||
this._getElement().innerHTML = parsedPath.name + parsedPath.ext;
|
||||
|
||||
UIUtil.updateStyles(this._getElement(), {
|
||||
isHovered: this.hovered,
|
||||
isEnabled: this.enabled,
|
||||
isActive: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
import * as path from 'path';
|
||||
|
||||
import { ASSERT } from '../../util/error_util';
|
||||
import { UIUtil } from '../../util/ui_util';
|
||||
import { ConfigComponent } from './config';
|
||||
|
||||
export class ObjFileComponent extends ConfigComponent<Promise<string>, HTMLDivElement> {
|
||||
private _loadedFilePath: string;
|
||||
|
||||
public constructor() {
|
||||
super(Promise.resolve(''));
|
||||
this._loadedFilePath = '';
|
||||
}
|
||||
|
||||
protected override _generateInnerHTML() {
|
||||
return `
|
||||
<div class="input-file struct-prop" id="${this._getId()}">
|
||||
<input type="file" accept=".obj" style="display: none;" id="${this._getId()}-input">
|
||||
${this._loadedFilePath}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
public override registerEvents(): void {
|
||||
this._getElement().addEventListener('mouseenter', () => {
|
||||
this._setHovered(true);
|
||||
this._updateStyles();
|
||||
});
|
||||
|
||||
this._getElement().addEventListener('mouseleave', () => {
|
||||
this._setHovered(false);
|
||||
this._updateStyles();
|
||||
});
|
||||
|
||||
const inputElement = UIUtil.getElementById(this._getId() + '-input') as HTMLInputElement;
|
||||
|
||||
inputElement.addEventListener('change', () => {
|
||||
const files = inputElement.files;
|
||||
if (files?.length === 1) {
|
||||
const file = files.item(0);
|
||||
ASSERT(file !== null);
|
||||
this._loadedFilePath = file.name;
|
||||
this._setValue(file.text());
|
||||
}
|
||||
});
|
||||
|
||||
this._getElement().addEventListener('click', () => {
|
||||
if (this.enabled) {
|
||||
inputElement.click();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected _onValueChanged(): void {
|
||||
this._updateStyles();
|
||||
}
|
||||
|
||||
protected override _updateStyles() {
|
||||
const parsedPath = path.parse(this._loadedFilePath);
|
||||
this._getElement().innerHTML = parsedPath.name + parsedPath.ext;
|
||||
|
||||
UIUtil.updateStyles(this._getElement(), {
|
||||
isHovered: this.hovered,
|
||||
isEnabled: this.enabled,
|
||||
isActive: false,
|
||||
});
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
import { ConfigUIElement } from './config_element';
|
||||
import { ConfigComponent } from './config';
|
||||
|
||||
/**
|
||||
* A `FullConfigUIElement` is a UI element that has a value the user can change.
|
||||
* For example, sliders, comboboxes and checkboxes are `ConfigUIElement`.
|
||||
* A `FullConfigComponent` is a UI element that has a value the user can change.
|
||||
* For example, sliders, comboboxes and checkboxes are `ConfigComponent`.
|
||||
*/
|
||||
export abstract class FullConfigUIElement<T, F> extends ConfigUIElement<T, F> {
|
||||
export abstract class FullConfigComponent<T, F> extends ConfigComponent<T, F> {
|
||||
public override generateHTML() {
|
||||
return `
|
||||
<div class="property" style="flex-direction: column; align-items: start;">
|
@ -1,36 +1,33 @@
|
||||
import IMAGE_LOGO from '../../../res/static/icon.png';
|
||||
import { AppConfig } from '../../config';
|
||||
import { LOG, LOG_ERROR } from '../../util/log_util';
|
||||
import { AppPaths, PathUtil } from '../../util/path_util';
|
||||
import { UIUtil } from '../../util/ui_util';
|
||||
import { AppIcons } from '../icons';
|
||||
import { BaseUIElement } from './base_element';
|
||||
import { ToolbarItemElement } from './toolbar_item';
|
||||
import { BaseComponent } from './base';
|
||||
import { ToolbarItemComponent } from './toolbar_item';
|
||||
|
||||
export class HeaderUIElement extends BaseUIElement<HTMLDivElement> {
|
||||
private static _instance: HeaderUIElement;
|
||||
export class HeaderComponent extends BaseComponent<HTMLDivElement> {
|
||||
private static _instance: HeaderComponent;
|
||||
public static get Get() {
|
||||
return this._instance || (this._instance = new this());
|
||||
}
|
||||
|
||||
private _githubButton: ToolbarItemElement;
|
||||
private _bugButton: ToolbarItemElement;
|
||||
private _discordButton: ToolbarItemElement;
|
||||
private _githubButton: ToolbarItemComponent;
|
||||
private _bugButton: ToolbarItemComponent;
|
||||
private _discordButton: ToolbarItemComponent;
|
||||
|
||||
private constructor() {
|
||||
super();
|
||||
|
||||
this._githubButton = new ToolbarItemElement({ id: 'gh', iconSVG: AppIcons.GITHUB })
|
||||
this._githubButton = new ToolbarItemComponent({ id: 'gh', iconSVG: AppIcons.GITHUB })
|
||||
.onClick(() => {
|
||||
window.open('https://github.com/LucasDower/ObjToSchematic');
|
||||
});
|
||||
|
||||
this._bugButton = new ToolbarItemElement({ id: 'bug', iconSVG: AppIcons.BUG })
|
||||
this._bugButton = new ToolbarItemComponent({ id: 'bug', iconSVG: AppIcons.BUG })
|
||||
.onClick(() => {
|
||||
window.open('https://github.com/LucasDower/ObjToSchematic/issues');
|
||||
});
|
||||
|
||||
this._discordButton = new ToolbarItemElement({ id: 'disc', iconSVG: AppIcons.DISCORD })
|
||||
this._discordButton = new ToolbarItemComponent({ id: 'disc', iconSVG: AppIcons.DISCORD })
|
||||
.onClick(() => {
|
||||
window.open('https://discord.gg/McS2VrBZPD');
|
||||
});
|
@ -1,20 +1,20 @@
|
||||
import { TImageFiletype, TImageRawWrap } from '../../texture';
|
||||
import { TImageRawWrap } from '../../texture';
|
||||
import { getRandomID } from '../../util';
|
||||
import { ASSERT } from '../../util/error_util';
|
||||
import { UIUtil } from '../../util/ui_util';
|
||||
import { AppIcons } from '../icons';
|
||||
import { ConfigUIElement } from './config_element';
|
||||
import { ToolbarItemElement } from './toolbar_item';
|
||||
import { ConfigComponent } from './config';
|
||||
import { ToolbarItemComponent } from './toolbar_item';
|
||||
|
||||
export class ImageElement extends ConfigUIElement<Promise<TImageRawWrap>, HTMLImageElement> {
|
||||
private _switchElement: ToolbarItemElement;
|
||||
export class ImageComponent extends ConfigComponent<Promise<TImageRawWrap>, HTMLImageElement> {
|
||||
private _switchElement: ToolbarItemComponent;
|
||||
|
||||
private _imageId: string;
|
||||
|
||||
public constructor(param?: TImageRawWrap) {
|
||||
super(Promise.resolve(param ?? { raw: '', filetype: 'png' }));
|
||||
|
||||
this._switchElement = new ToolbarItemElement({ id: 'sw', iconSVG: AppIcons.UPLOAD })
|
||||
this._switchElement = new ToolbarItemComponent({ id: 'sw', iconSVG: AppIcons.UPLOAD })
|
||||
.setLabel('Choose')
|
||||
.onClick(() => {
|
||||
const inputElement = UIUtil.getElementById(this._getId() + '-input') as HTMLInputElement;
|
||||
@ -78,7 +78,7 @@ export class ImageElement extends ConfigUIElement<Promise<TImageRawWrap>, HTMLIm
|
||||
|
||||
protected override _onValueChanged(): void {
|
||||
const inputElement = UIUtil.getElementById(this._imageId) as HTMLImageElement;
|
||||
const placeholderElement = UIUtil.getElementById(this._imageId + '-placeholder');
|
||||
const PlaceholderComponent = UIUtil.getElementById(this._imageId + '-placeholder');
|
||||
|
||||
this.getValue()
|
||||
.then((res) => {
|
||||
@ -88,13 +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';
|
||||
PlaceholderComponent.style.display = 'none';
|
||||
})
|
||||
.catch((err) => {
|
||||
this._switchElement.setActive(true);
|
||||
inputElement.src = '';
|
||||
inputElement.style.display = 'none';
|
||||
placeholderElement.style.display = 'flex';
|
||||
PlaceholderComponent.style.display = 'flex';
|
||||
});
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
import { MaterialType, SolidMaterial, TexturedMaterial } from '../../mesh';
|
||||
import { AppIcons } from '../icons';
|
||||
import { ConfigUIElement } from './config_element';
|
||||
import { ToolbarItemElement } from './toolbar_item';
|
||||
import { ConfigComponent } from './config';
|
||||
import { ToolbarItemComponent } from './toolbar_item';
|
||||
|
||||
export class MaterialTypeElement extends ConfigUIElement<MaterialType, HTMLDivElement> {
|
||||
private _solidButton: ToolbarItemElement;
|
||||
private _texturedButton: ToolbarItemElement;
|
||||
export class MaterialTypeComponent extends ConfigComponent<MaterialType, HTMLDivElement> {
|
||||
private _solidButton: ToolbarItemComponent;
|
||||
private _texturedButton: ToolbarItemComponent;
|
||||
private _material: SolidMaterial | TexturedMaterial;
|
||||
|
||||
public constructor(material: SolidMaterial | TexturedMaterial) {
|
||||
super(material.type);
|
||||
this._material = material;
|
||||
|
||||
this._solidButton = new ToolbarItemElement({ id: 'sw1', iconSVG: AppIcons.COLOUR_SWATCH })
|
||||
this._solidButton = new ToolbarItemComponent({ id: 'sw1', iconSVG: AppIcons.COLOUR_SWATCH })
|
||||
.setLabel('Solid')
|
||||
.onClick(() => {
|
||||
if (this._material.type === MaterialType.textured) {
|
||||
@ -20,7 +20,7 @@ export class MaterialTypeElement extends ConfigUIElement<MaterialType, HTMLDivEl
|
||||
}
|
||||
});
|
||||
|
||||
this._texturedButton = new ToolbarItemElement({ id: 'sw2', iconSVG: AppIcons.IMAGE })
|
||||
this._texturedButton = new ToolbarItemComponent({ id: 'sw2', iconSVG: AppIcons.IMAGE })
|
||||
.setLabel('Textured')
|
||||
.onClick(() => {
|
||||
if (this._material.type === MaterialType.solid) {
|
@ -6,19 +6,17 @@ import { download } from '../../util/file_util';
|
||||
import { UIUtil } from '../../util/ui_util';
|
||||
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';
|
||||
import { CheckboxComponent } from './checkbox';
|
||||
import { ConfigComponent } from './config';
|
||||
import { ToolbarItemComponent } from './toolbar_item';
|
||||
|
||||
export class PaletteElement extends ConfigUIElement<Palette, HTMLDivElement> {
|
||||
private _checkboxes: { block: string, element: CheckboxElement }[];
|
||||
export class PaletteComponent extends ConfigComponent<Palette, HTMLDivElement> {
|
||||
private _checkboxes: { block: string, element: CheckboxComponent }[];
|
||||
private _palette: Palette;
|
||||
private _selectAll: ToolbarItemElement;
|
||||
private _deselectAll: ToolbarItemElement;
|
||||
private _importFrom: ToolbarItemElement;
|
||||
private _exportTo: ToolbarItemElement;
|
||||
private _selectAll: ToolbarItemComponent;
|
||||
private _deselectAll: ToolbarItemComponent;
|
||||
private _importFrom: ToolbarItemComponent;
|
||||
private _exportTo: ToolbarItemComponent;
|
||||
|
||||
public constructor() {
|
||||
super();
|
||||
@ -31,14 +29,14 @@ export class PaletteElement extends ConfigUIElement<Palette, HTMLDivElement> {
|
||||
PALETTE_ALL_RELEASE.forEach((block) => {
|
||||
this._checkboxes.push({
|
||||
block: block,
|
||||
element: new CheckboxElement()
|
||||
element: new CheckboxComponent()
|
||||
.setDefaultValue(true)
|
||||
.setCheckedText(block)
|
||||
.setUncheckedText(block),
|
||||
});
|
||||
});
|
||||
|
||||
this._selectAll = new ToolbarItemElement({ iconSVG: AppIcons.SELECT_ALL, id: 'select-all' })
|
||||
this._selectAll = new ToolbarItemComponent({ iconSVG: AppIcons.SELECT_ALL, id: 'select-all' })
|
||||
.onClick(() => {
|
||||
this._checkboxes.forEach((checkbox) => {
|
||||
checkbox.element.check();
|
||||
@ -47,7 +45,7 @@ export class PaletteElement extends ConfigUIElement<Palette, HTMLDivElement> {
|
||||
});
|
||||
|
||||
|
||||
this._deselectAll = new ToolbarItemElement({ iconSVG: AppIcons.DESELECT_ALL, id: 'deselect-all' })
|
||||
this._deselectAll = new ToolbarItemComponent({ iconSVG: AppIcons.DESELECT_ALL, id: 'deselect-all' })
|
||||
.onClick(() => {
|
||||
this._checkboxes.forEach((checkbox) => {
|
||||
checkbox.element.uncheck();
|
||||
@ -55,7 +53,7 @@ export class PaletteElement extends ConfigUIElement<Palette, HTMLDivElement> {
|
||||
this._onCountSelectedChanged();
|
||||
});
|
||||
|
||||
this._importFrom = new ToolbarItemElement({ iconSVG: AppIcons.IMPORT, id: 'import' })
|
||||
this._importFrom = new ToolbarItemComponent({ iconSVG: AppIcons.IMPORT, id: 'import' })
|
||||
.onClick(() => {
|
||||
const a = document.createElement('input');
|
||||
a.setAttribute('type', 'file');
|
||||
@ -76,7 +74,7 @@ export class PaletteElement extends ConfigUIElement<Palette, HTMLDivElement> {
|
||||
a.click();
|
||||
});
|
||||
|
||||
this._exportTo = new ToolbarItemElement({ iconSVG: AppIcons.EXPORT, id: 'export' })
|
||||
this._exportTo = new ToolbarItemComponent({ iconSVG: AppIcons.EXPORT, id: 'export' })
|
||||
.onClick(() => {
|
||||
const textPalette = this._checkboxes.filter((x) => x.element.getValue())
|
||||
.map((x) => x.block)
|
@ -1,6 +1,6 @@
|
||||
import { ConfigUIElement } from './config_element';
|
||||
import { ConfigComponent } from './config';
|
||||
|
||||
export class PlaceholderElement extends ConfigUIElement<undefined, HTMLDivElement> {
|
||||
export class PlaceholderComponent extends ConfigComponent<undefined, HTMLDivElement> {
|
||||
private _placeholderText: string;
|
||||
|
||||
public constructor(placeholderText: string) {
|
@ -1,242 +1,242 @@
|
||||
import { clamp, mapRange, wayThrough } from '../../math';
|
||||
import { ASSERT } from '../../util/error_util';
|
||||
import { UIUtil } from '../../util/ui_util';
|
||||
import { ConfigUIElement } from './config_element';
|
||||
|
||||
export type TSliderParams = {
|
||||
min: number,
|
||||
max: number,
|
||||
value: number,
|
||||
decimals: number,
|
||||
step: number,
|
||||
}
|
||||
|
||||
export class SliderElement extends ConfigUIElement<number, HTMLDivElement> {
|
||||
private _min: number;
|
||||
private _max: number;
|
||||
private _decimals: number;
|
||||
private _step: number;
|
||||
private _dragging: boolean;
|
||||
private _internalValue: number;
|
||||
private _valueHovered: boolean;
|
||||
|
||||
public constructor() {
|
||||
super();
|
||||
this._min = 0;
|
||||
this._max = 1;
|
||||
this._decimals = 1;
|
||||
this._step = 0.1;
|
||||
this._internalValue = 0.5;
|
||||
this._dragging = false;
|
||||
this._valueHovered = false;
|
||||
}
|
||||
|
||||
public override setDefaultValue(value: number) {
|
||||
super.setDefaultValue(value);
|
||||
this._internalValue = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum value the slider can be set to.
|
||||
*/
|
||||
public setMin(min: number) {
|
||||
this._min = min;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum value the slider can be set to.
|
||||
*/
|
||||
public setMax(max: number) {
|
||||
this._max = max;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of decimals to display the value to.
|
||||
*/
|
||||
public setDecimals(decimals: number) {
|
||||
this._decimals = decimals;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the step the value is increased/decreased by.
|
||||
*/
|
||||
public setStep(step: number) {
|
||||
this._step = step;
|
||||
return this;
|
||||
}
|
||||
|
||||
public override registerEvents() {
|
||||
const element = this._getElement();
|
||||
const elementBar = UIUtil.getElementById(this._getSliderBarId());
|
||||
const elementValue = UIUtil.getElementById(this._getSliderValueId()) as HTMLInputElement;
|
||||
|
||||
element.onmouseenter = () => {
|
||||
this._setHovered(true);
|
||||
this._updateStyles();
|
||||
};
|
||||
|
||||
element.onmouseleave = () => {
|
||||
this._setHovered(false);
|
||||
this._updateStyles();
|
||||
};
|
||||
|
||||
element.onmousedown = () => {
|
||||
this._dragging = true;
|
||||
};
|
||||
|
||||
document.addEventListener('mousemove', (e: MouseEvent) => {
|
||||
if (this._dragging) {
|
||||
this._onDragSlider(e);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('mouseup', (e: MouseEvent) => {
|
||||
if (this._dragging) {
|
||||
this._onDragSlider(e);
|
||||
}
|
||||
this._dragging = false;
|
||||
});
|
||||
|
||||
element.addEventListener('wheel', (e: WheelEvent) => {
|
||||
if (!this._dragging && this.getEnabled()) {
|
||||
e.preventDefault();
|
||||
this._onScrollSlider(e);
|
||||
}
|
||||
});
|
||||
|
||||
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 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>
|
||||
`;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
protected override _onValueChanged(): void {
|
||||
const percentage = wayThrough(this.getValue(), this._min, this._max);
|
||||
ASSERT(percentage >= 0.0 && percentage <= 1.0);
|
||||
|
||||
UIUtil.getElementById(this._getSliderBarId()).style.width = `${percentage * 100}%`;
|
||||
(UIUtil.getElementById(this._getSliderValueId()) as HTMLInputElement).value = this.getValue().toFixed(this._decimals);
|
||||
}
|
||||
|
||||
private _onScrollSlider(e: WheelEvent) {
|
||||
if (!this.getEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._internalValue -= (e.deltaY / 150) * this._step;
|
||||
this._internalValue = clamp(this._internalValue, this._min, this._max);
|
||||
|
||||
this._onInternalValueUpdated();
|
||||
}
|
||||
|
||||
private _onDragSlider(e: MouseEvent) {
|
||||
if (!this.getEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const box = this._getElement().getBoundingClientRect();
|
||||
const left = box.x;
|
||||
const right = box.x + box.width;
|
||||
|
||||
this._internalValue = mapRange(e.clientX, left, right, this._min, this._max);
|
||||
this._internalValue = clamp(this._internalValue, this._min, this._max);
|
||||
|
||||
this._onInternalValueUpdated();
|
||||
}
|
||||
|
||||
private _onTypedValue() {
|
||||
const elementValue = UIUtil.getElementById(this._getSliderValueId()) as HTMLInputElement;
|
||||
|
||||
const typedNumber = parseFloat(elementValue.value);
|
||||
if (!isNaN(typedNumber)) {
|
||||
this._internalValue = clamp(typedNumber, this._min, this._max);
|
||||
}
|
||||
this._onInternalValueUpdated();
|
||||
}
|
||||
|
||||
private _onInternalValueUpdated() {
|
||||
const displayString = this._internalValue!.toFixed(this._decimals);
|
||||
this._setValue(parseFloat(displayString));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ID of the DOM element for the slider's value.
|
||||
*/
|
||||
private _getSliderValueId() {
|
||||
return this._getId() + '-value';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ID of the DOM element for the slider's bar.
|
||||
*/
|
||||
private _getSliderBarId() {
|
||||
return this._getId() + '-bar';
|
||||
}
|
||||
|
||||
protected override _updateStyles(): void {
|
||||
const elementValue = UIUtil.getElementById(this._getSliderValueId()) as HTMLInputElement;
|
||||
UIUtil.updateStyles(elementValue, {
|
||||
isHovered: this._valueHovered,
|
||||
isActive: false,
|
||||
isEnabled: this.enabled,
|
||||
});
|
||||
|
||||
const elementBar = UIUtil.getElementById(this._getSliderBarId()) as HTMLInputElement;
|
||||
UIUtil.updateStyles(elementBar, {
|
||||
isHovered: this.hovered,
|
||||
isActive: true,
|
||||
isEnabled: this.enabled,
|
||||
});
|
||||
|
||||
const elementSlider = UIUtil.getElementById(this._getId()) as HTMLInputElement;
|
||||
UIUtil.updateStyles(elementSlider, {
|
||||
isHovered: this.hovered,
|
||||
isActive: false,
|
||||
isEnabled: this.enabled,
|
||||
});
|
||||
}
|
||||
}
|
||||
import { clamp, mapRange, wayThrough } from '../../math';
|
||||
import { ASSERT } from '../../util/error_util';
|
||||
import { UIUtil } from '../../util/ui_util';
|
||||
import { ConfigComponent } from './config';
|
||||
|
||||
export type TSliderParams = {
|
||||
min: number,
|
||||
max: number,
|
||||
value: number,
|
||||
decimals: number,
|
||||
step: number,
|
||||
}
|
||||
|
||||
export class SliderComponent extends ConfigComponent<number, HTMLDivElement> {
|
||||
private _min: number;
|
||||
private _max: number;
|
||||
private _decimals: number;
|
||||
private _step: number;
|
||||
private _dragging: boolean;
|
||||
private _internalValue: number;
|
||||
private _valueHovered: boolean;
|
||||
|
||||
public constructor() {
|
||||
super();
|
||||
this._min = 0;
|
||||
this._max = 1;
|
||||
this._decimals = 1;
|
||||
this._step = 0.1;
|
||||
this._internalValue = 0.5;
|
||||
this._dragging = false;
|
||||
this._valueHovered = false;
|
||||
}
|
||||
|
||||
public override setDefaultValue(value: number) {
|
||||
super.setDefaultValue(value);
|
||||
this._internalValue = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum value the slider can be set to.
|
||||
*/
|
||||
public setMin(min: number) {
|
||||
this._min = min;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum value the slider can be set to.
|
||||
*/
|
||||
public setMax(max: number) {
|
||||
this._max = max;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of decimals to display the value to.
|
||||
*/
|
||||
public setDecimals(decimals: number) {
|
||||
this._decimals = decimals;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the step the value is increased/decreased by.
|
||||
*/
|
||||
public setStep(step: number) {
|
||||
this._step = step;
|
||||
return this;
|
||||
}
|
||||
|
||||
public override registerEvents() {
|
||||
const element = this._getElement();
|
||||
const elementBar = UIUtil.getElementById(this._getSliderBarId());
|
||||
const elementValue = UIUtil.getElementById(this._getSliderValueId()) as HTMLInputElement;
|
||||
|
||||
element.onmouseenter = () => {
|
||||
this._setHovered(true);
|
||||
this._updateStyles();
|
||||
};
|
||||
|
||||
element.onmouseleave = () => {
|
||||
this._setHovered(false);
|
||||
this._updateStyles();
|
||||
};
|
||||
|
||||
element.onmousedown = () => {
|
||||
this._dragging = true;
|
||||
};
|
||||
|
||||
document.addEventListener('mousemove', (e: MouseEvent) => {
|
||||
if (this._dragging) {
|
||||
this._onDragSlider(e);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('mouseup', (e: MouseEvent) => {
|
||||
if (this._dragging) {
|
||||
this._onDragSlider(e);
|
||||
}
|
||||
this._dragging = false;
|
||||
});
|
||||
|
||||
element.addEventListener('wheel', (e: WheelEvent) => {
|
||||
if (!this._dragging && this.getEnabled()) {
|
||||
e.preventDefault();
|
||||
this._onScrollSlider(e);
|
||||
}
|
||||
});
|
||||
|
||||
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 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>
|
||||
`;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
protected override _onValueChanged(): void {
|
||||
const percentage = wayThrough(this.getValue(), this._min, this._max);
|
||||
ASSERT(percentage >= 0.0 && percentage <= 1.0);
|
||||
|
||||
UIUtil.getElementById(this._getSliderBarId()).style.width = `${percentage * 100}%`;
|
||||
(UIUtil.getElementById(this._getSliderValueId()) as HTMLInputElement).value = this.getValue().toFixed(this._decimals);
|
||||
}
|
||||
|
||||
private _onScrollSlider(e: WheelEvent) {
|
||||
if (!this.getEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._internalValue -= (e.deltaY / 150) * this._step;
|
||||
this._internalValue = clamp(this._internalValue, this._min, this._max);
|
||||
|
||||
this._onInternalValueUpdated();
|
||||
}
|
||||
|
||||
private _onDragSlider(e: MouseEvent) {
|
||||
if (!this.getEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const box = this._getElement().getBoundingClientRect();
|
||||
const left = box.x;
|
||||
const right = box.x + box.width;
|
||||
|
||||
this._internalValue = mapRange(e.clientX, left, right, this._min, this._max);
|
||||
this._internalValue = clamp(this._internalValue, this._min, this._max);
|
||||
|
||||
this._onInternalValueUpdated();
|
||||
}
|
||||
|
||||
private _onTypedValue() {
|
||||
const elementValue = UIUtil.getElementById(this._getSliderValueId()) as HTMLInputElement;
|
||||
|
||||
const typedNumber = parseFloat(elementValue.value);
|
||||
if (!isNaN(typedNumber)) {
|
||||
this._internalValue = clamp(typedNumber, this._min, this._max);
|
||||
}
|
||||
this._onInternalValueUpdated();
|
||||
}
|
||||
|
||||
private _onInternalValueUpdated() {
|
||||
const displayString = this._internalValue!.toFixed(this._decimals);
|
||||
this._setValue(parseFloat(displayString));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ID of the DOM element for the slider's value.
|
||||
*/
|
||||
private _getSliderValueId() {
|
||||
return this._getId() + '-value';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the ID of the DOM element for the slider's bar.
|
||||
*/
|
||||
private _getSliderBarId() {
|
||||
return this._getId() + '-bar';
|
||||
}
|
||||
|
||||
protected override _updateStyles(): void {
|
||||
const elementValue = UIUtil.getElementById(this._getSliderValueId()) as HTMLInputElement;
|
||||
UIUtil.updateStyles(elementValue, {
|
||||
isHovered: this._valueHovered,
|
||||
isActive: false,
|
||||
isEnabled: this.enabled,
|
||||
});
|
||||
|
||||
const elementBar = UIUtil.getElementById(this._getSliderBarId()) as HTMLInputElement;
|
||||
UIUtil.updateStyles(elementBar, {
|
||||
isHovered: this.hovered,
|
||||
isActive: true,
|
||||
isEnabled: this.enabled,
|
||||
});
|
||||
|
||||
const elementSlider = UIUtil.getElementById(this._getId()) as HTMLInputElement;
|
||||
UIUtil.updateStyles(elementSlider, {
|
||||
isHovered: this.hovered,
|
||||
isActive: false,
|
||||
isEnabled: this.enabled,
|
||||
});
|
||||
}
|
||||
}
|
@ -1,24 +1,24 @@
|
||||
import { SolidMaterial } from '../../mesh';
|
||||
import { ColourElement } from './colour_element';
|
||||
import { ConfigUIElement } from './config_element';
|
||||
import { MaterialTypeElement } from './material_type_element';
|
||||
import { SliderElement } from './slider';
|
||||
import { ColourComponent } from './colour';
|
||||
import { ConfigComponent } from './config';
|
||||
import { MaterialTypeComponent } from './material_type';
|
||||
import { SliderComponent } from './slider';
|
||||
|
||||
export class SolidMaterialElement extends ConfigUIElement<SolidMaterial, HTMLDivElement> {
|
||||
private _typeElement: MaterialTypeElement;
|
||||
private _colourElement: ColourElement;
|
||||
private _alphaElement: SliderElement;
|
||||
export class SolidMaterialComponent extends ConfigComponent<SolidMaterial, HTMLDivElement> {
|
||||
private _typeElement: MaterialTypeComponent;
|
||||
private _ColourComponent: ColourComponent;
|
||||
private _alphaElement: SliderComponent;
|
||||
|
||||
public constructor(materialName: string, material: SolidMaterial) {
|
||||
super(material);
|
||||
|
||||
this._typeElement = new MaterialTypeElement(material)
|
||||
this._typeElement = new MaterialTypeComponent(material)
|
||||
.setLabel('Type');
|
||||
|
||||
this._colourElement = new ColourElement(material.colour)
|
||||
this._ColourComponent = new ColourComponent(material.colour)
|
||||
.setLabel('Colour');
|
||||
|
||||
this._alphaElement = new SliderElement()
|
||||
this._alphaElement = new SliderComponent()
|
||||
.setLabel('Alpha')
|
||||
.setMin(0.0)
|
||||
.setMax(1.0)
|
||||
@ -29,14 +29,14 @@ export class SolidMaterialElement extends ConfigUIElement<SolidMaterial, HTMLDiv
|
||||
|
||||
public override registerEvents(): void {
|
||||
this._typeElement.registerEvents();
|
||||
this._colourElement.registerEvents();
|
||||
this._ColourComponent.registerEvents();
|
||||
this._alphaElement.registerEvents();
|
||||
|
||||
this._typeElement.onClickChangeTypeDelegate(() => {
|
||||
this._onChangeTypeDelegate?.();
|
||||
});
|
||||
|
||||
this._colourElement.addValueChangedListener((newColour) => {
|
||||
this._ColourComponent.addValueChangedListener((newColour) => {
|
||||
this.getValue().colour.r = newColour.r;
|
||||
this.getValue().colour.g = newColour.g;
|
||||
this.getValue().colour.b = newColour.b;
|
||||
@ -49,7 +49,7 @@ export class SolidMaterialElement extends ConfigUIElement<SolidMaterial, HTMLDiv
|
||||
|
||||
public override finalise(): void {
|
||||
this._typeElement.finalise();
|
||||
this._colourElement.finalise();
|
||||
this._ColourComponent.finalise();
|
||||
this._alphaElement.finalise();
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ export class SolidMaterialElement extends ConfigUIElement<SolidMaterial, HTMLDiv
|
||||
return `
|
||||
<div class="component-group">
|
||||
${this._typeElement.generateHTML()}
|
||||
${this._colourElement.generateHTML()}
|
||||
${this._ColourComponent.generateHTML()}
|
||||
${this._alphaElement.generateHTML()}
|
||||
</div>
|
||||
`;
|
||||
@ -70,7 +70,7 @@ export class SolidMaterialElement extends ConfigUIElement<SolidMaterial, HTMLDiv
|
||||
super._onEnabledChanged();
|
||||
|
||||
this._typeElement.setEnabled(this.enabled);
|
||||
this._colourElement.setEnabled(this.enabled);
|
||||
this._ColourComponent.setEnabled(this.enabled);
|
||||
this._alphaElement.setEnabled(this.enabled);
|
||||
}
|
||||
|
@ -1,46 +1,43 @@
|
||||
import path from 'path';
|
||||
|
||||
import { MaterialType, TexturedMaterial } from '../../mesh';
|
||||
import { 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';
|
||||
import { MaterialTypeElement } from './material_type_element';
|
||||
import { SliderElement } from './slider';
|
||||
import { ComboboxComponent } from './combobox';
|
||||
import { ConfigComponent } from './config';
|
||||
import { ImageComponent } from './image_element';
|
||||
import { MaterialTypeComponent } from './material_type';
|
||||
import { SliderComponent } from './slider';
|
||||
|
||||
export class TexturedMaterialElement extends ConfigUIElement<TexturedMaterial, HTMLDivElement> {
|
||||
private _typeElement: MaterialTypeElement;
|
||||
private _filteringElement: ComboBoxElement<'nearest' | 'linear'>;
|
||||
private _wrapElement: ComboBoxElement<'clamp' | 'repeat'>;
|
||||
private _transparencyElement: ComboBoxElement<TTransparencyTypes>;
|
||||
private _imageElement: ImageElement;
|
||||
private _alphaValueElement?: SliderElement;
|
||||
private _alphaMapElement?: ImageElement;
|
||||
private _alphaChannelElement?: ComboBoxElement<EImageChannel>;
|
||||
export class TexturedMaterialComponent extends ConfigComponent<TexturedMaterial, HTMLDivElement> {
|
||||
private _typeElement: MaterialTypeComponent;
|
||||
private _filteringElement: ComboboxComponent<'nearest' | 'linear'>;
|
||||
private _wrapElement: ComboboxComponent<'clamp' | 'repeat'>;
|
||||
private _transparencyElement: ComboboxComponent<TTransparencyTypes>;
|
||||
private _ImageComponent: ImageComponent;
|
||||
private _alphaValueElement?: SliderComponent;
|
||||
private _alphaMapElement?: ImageComponent;
|
||||
private _alphaChannelElement?: ComboboxComponent<EImageChannel>;
|
||||
|
||||
public constructor(materialName: string, material: TexturedMaterial) {
|
||||
super(material);
|
||||
|
||||
this._typeElement = new MaterialTypeElement(material)
|
||||
this._typeElement = new MaterialTypeComponent(material)
|
||||
.setLabel('Type');
|
||||
|
||||
this._filteringElement = new ComboBoxElement<TTexelInterpolation>()
|
||||
this._filteringElement = new ComboboxComponent<TTexelInterpolation>()
|
||||
.setLabel('Filtering')
|
||||
.addItem({ payload: 'linear', displayText: 'Linear' })
|
||||
.addItem({ payload: 'nearest', displayText: 'Nearest' })
|
||||
.setDefaultValue(material.interpolation);
|
||||
|
||||
this._wrapElement = new ComboBoxElement<'clamp' | 'repeat'>()
|
||||
this._wrapElement = new ComboboxComponent<'clamp' | 'repeat'>()
|
||||
.setLabel('Wrap')
|
||||
.addItem({ payload: 'clamp', displayText: 'Clamp' })
|
||||
.addItem({ payload: 'repeat', displayText: 'Repeat' })
|
||||
.setDefaultValue(material.extension);
|
||||
|
||||
this._transparencyElement = new ComboBoxElement<TTransparencyTypes>()
|
||||
this._transparencyElement = new ComboboxComponent<TTransparencyTypes>()
|
||||
.setLabel('Transparency')
|
||||
.addItem({ payload: 'None', displayText: 'None' })
|
||||
.addItem({ payload: 'UseAlphaMap', displayText: 'Alpha map' })
|
||||
@ -48,12 +45,12 @@ export class TexturedMaterialElement extends ConfigUIElement<TexturedMaterial, H
|
||||
.addItem({ payload: 'UseDiffuseMapAlphaChannel', displayText: 'Diffuse map alpha channel' })
|
||||
.setDefaultValue(material.transparency.type);
|
||||
|
||||
this._imageElement = new ImageElement(material.diffuse)
|
||||
this._ImageComponent = new ImageComponent(material.diffuse)
|
||||
.setLabel('Diffuse map');
|
||||
|
||||
switch (material.transparency.type) {
|
||||
case 'UseAlphaValue':
|
||||
this._alphaValueElement = new SliderElement()
|
||||
this._alphaValueElement = new SliderComponent()
|
||||
.setLabel('Alpha')
|
||||
.setMin(0.0)
|
||||
.setMax(1.0)
|
||||
@ -62,10 +59,10 @@ export class TexturedMaterialElement extends ConfigUIElement<TexturedMaterial, H
|
||||
.setStep(0.01);
|
||||
break;
|
||||
case 'UseAlphaMap':
|
||||
this._alphaMapElement = new ImageElement(material.transparency.alpha)
|
||||
this._alphaMapElement = new ImageComponent(material.transparency.alpha)
|
||||
.setLabel('Alpha map');
|
||||
|
||||
this._alphaChannelElement = new ComboBoxElement<EImageChannel>()
|
||||
this._alphaChannelElement = new ComboboxComponent<EImageChannel>()
|
||||
.setLabel('Alpha channel')
|
||||
.addItem({ payload: EImageChannel.R, displayText: 'Red' })
|
||||
.addItem({ payload: EImageChannel.G, displayText: 'Green' })
|
||||
@ -77,7 +74,7 @@ export class TexturedMaterialElement extends ConfigUIElement<TexturedMaterial, H
|
||||
}
|
||||
|
||||
public override registerEvents(): void {
|
||||
this._imageElement.registerEvents();
|
||||
this._ImageComponent.registerEvents();
|
||||
this._typeElement.registerEvents();
|
||||
this._filteringElement.registerEvents();
|
||||
this._wrapElement.registerEvents();
|
||||
@ -86,7 +83,7 @@ export class TexturedMaterialElement extends ConfigUIElement<TexturedMaterial, H
|
||||
this._alphaMapElement?.registerEvents();
|
||||
this._alphaChannelElement?.registerEvents();
|
||||
|
||||
this._imageElement.addValueChangedListener((newPath) => {
|
||||
this._ImageComponent.addValueChangedListener((newPath) => {
|
||||
const material = this.getValue();
|
||||
// TODO Unimplemented, promise should be resolved where it is used
|
||||
newPath.then((res) => {
|
||||
@ -146,7 +143,7 @@ export class TexturedMaterialElement extends ConfigUIElement<TexturedMaterial, H
|
||||
builder.add('<div class="component-group">');
|
||||
{
|
||||
builder.add(this._typeElement.generateHTML());
|
||||
builder.add(this._imageElement.generateHTML());
|
||||
builder.add(this._ImageComponent.generateHTML());
|
||||
builder.add(this._filteringElement.generateHTML());
|
||||
builder.add(this._wrapElement.generateHTML());
|
||||
builder.add(this._transparencyElement.generateHTML());
|
||||
@ -170,7 +167,7 @@ export class TexturedMaterialElement extends ConfigUIElement<TexturedMaterial, H
|
||||
protected override _onEnabledChanged(): void {
|
||||
super._onEnabledChanged();
|
||||
|
||||
this._imageElement.setEnabled(this.enabled);
|
||||
this._ImageComponent.setEnabled(this.enabled);
|
||||
this._typeElement.setEnabled(this.enabled);
|
||||
this._filteringElement.setEnabled(this.enabled);
|
||||
this._wrapElement.setEnabled(this.enabled);
|
||||
@ -183,7 +180,7 @@ export class TexturedMaterialElement extends ConfigUIElement<TexturedMaterial, H
|
||||
public override finalise(): void {
|
||||
super.finalise();
|
||||
|
||||
this._imageElement.finalise();
|
||||
this._ImageComponent.finalise();
|
||||
this._typeElement.finalise();
|
||||
this._filteringElement.finalise();
|
||||
this._wrapElement.finalise();
|
@ -1,135 +1,132 @@
|
||||
import { getRandomID } from '../../util';
|
||||
import { ASSERT } from '../../util/error_util';
|
||||
import { AppPaths } from '../../util/path_util';
|
||||
import { PathUtil } from '../../util/path_util';
|
||||
import { UIUtil } from '../../util/ui_util';
|
||||
import { BaseUIElement } from './base_element';
|
||||
|
||||
export type TToolbarBooleanProperty = 'enabled' | 'active';
|
||||
|
||||
export type TToolbarItemParams = {
|
||||
id: string,
|
||||
iconSVG: string;
|
||||
}
|
||||
|
||||
export class ToolbarItemElement extends BaseUIElement<HTMLDivElement> {
|
||||
private _iconSVG: SVGSVGElement;
|
||||
private _label: string;
|
||||
private _onClick?: () => void;
|
||||
private _isActive: boolean;
|
||||
|
||||
public constructor(params: TToolbarItemParams) {
|
||||
super();
|
||||
|
||||
this._isActive = false;
|
||||
|
||||
{
|
||||
const parser = new DOMParser();
|
||||
const svgParse = parser.parseFromString(params.iconSVG, 'text/html');
|
||||
const svgs = svgParse.getElementsByTagName('svg');
|
||||
ASSERT(svgs.length === 1, 'Missing SVG');
|
||||
|
||||
this._iconSVG = svgs[0];
|
||||
this._iconSVG.id = this._getId() + '-svg';
|
||||
}
|
||||
|
||||
this._label = '';
|
||||
}
|
||||
|
||||
|
||||
public setActive(isActive: boolean) {
|
||||
this._isActive = isActive;
|
||||
this._updateStyles();
|
||||
}
|
||||
|
||||
public setLabel(label: string) {
|
||||
this._label = label;
|
||||
return this;
|
||||
}
|
||||
|
||||
public tick() {
|
||||
if (this._isEnabledDelegate !== undefined) {
|
||||
const newIsEnabled = this._isEnabledDelegate();
|
||||
if (newIsEnabled != this.enabled) {
|
||||
this.setEnabled(newIsEnabled);
|
||||
this._updateStyles();
|
||||
}
|
||||
}
|
||||
|
||||
if (this._isActiveDelegate !== undefined) {
|
||||
const newIsActive = this._isActiveDelegate();
|
||||
if (newIsActive !== this._isActive) {
|
||||
this._isActive = newIsActive;
|
||||
this._updateStyles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected _onEnabledChanged(): void {
|
||||
this._updateStyles();
|
||||
}
|
||||
|
||||
private _isActiveDelegate?: () => boolean;
|
||||
public isActive(delegate: () => boolean) {
|
||||
this._isActiveDelegate = delegate;
|
||||
return this;
|
||||
}
|
||||
|
||||
private _isEnabledDelegate?: () => boolean;
|
||||
public isEnabled(delegate: () => boolean) {
|
||||
this._isEnabledDelegate = delegate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public onClick(delegate: () => void) {
|
||||
this._onClick = delegate;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public generateHTML() {
|
||||
return `
|
||||
<div class="struct-prop container-icon-button" id="${this._getId()}">
|
||||
${this._iconSVG.outerHTML} ${this._label}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
public registerEvents(): void {
|
||||
const element = document.getElementById(this._getId()) as HTMLDivElement;
|
||||
ASSERT(element !== null);
|
||||
|
||||
element.addEventListener('click', () => {
|
||||
if (this.enabled && this._onClick) {
|
||||
this._onClick();
|
||||
}
|
||||
});
|
||||
|
||||
element.addEventListener('mouseenter', () => {
|
||||
this._setHovered(true);
|
||||
this._updateStyles();
|
||||
});
|
||||
|
||||
element.addEventListener('mouseleave', () => {
|
||||
this._setHovered(false);
|
||||
this._updateStyles();
|
||||
});
|
||||
}
|
||||
|
||||
public override finalise(): void {
|
||||
this._updateStyles();
|
||||
}
|
||||
|
||||
private _getSVGElement() {
|
||||
const svgId = this._getId() + '-svg';
|
||||
return UIUtil.getElementById(svgId);
|
||||
}
|
||||
|
||||
protected override _updateStyles() {
|
||||
UIUtil.updateStyles(this._getElement(), {
|
||||
isActive: this._isActive,
|
||||
isEnabled: this.enabled,
|
||||
isHovered: this.hovered,
|
||||
});
|
||||
}
|
||||
}
|
||||
import { ASSERT } from '../../util/error_util';
|
||||
import { UIUtil } from '../../util/ui_util';
|
||||
import { BaseComponent } from './base';
|
||||
|
||||
export type TToolbarBooleanProperty = 'enabled' | 'active';
|
||||
|
||||
export type TToolbarItemParams = {
|
||||
id: string,
|
||||
iconSVG: string;
|
||||
}
|
||||
|
||||
export class ToolbarItemComponent extends BaseComponent<HTMLDivElement> {
|
||||
private _iconSVG: SVGSVGElement;
|
||||
private _label: string;
|
||||
private _onClick?: () => void;
|
||||
private _isActive: boolean;
|
||||
|
||||
public constructor(params: TToolbarItemParams) {
|
||||
super();
|
||||
|
||||
this._isActive = false;
|
||||
|
||||
{
|
||||
const parser = new DOMParser();
|
||||
const svgParse = parser.parseFromString(params.iconSVG, 'text/html');
|
||||
const svgs = svgParse.getElementsByTagName('svg');
|
||||
ASSERT(svgs.length === 1, 'Missing SVG');
|
||||
|
||||
this._iconSVG = svgs[0];
|
||||
this._iconSVG.id = this._getId() + '-svg';
|
||||
}
|
||||
|
||||
this._label = '';
|
||||
}
|
||||
|
||||
|
||||
public setActive(isActive: boolean) {
|
||||
this._isActive = isActive;
|
||||
this._updateStyles();
|
||||
}
|
||||
|
||||
public setLabel(label: string) {
|
||||
this._label = label;
|
||||
return this;
|
||||
}
|
||||
|
||||
public tick() {
|
||||
if (this._isEnabledDelegate !== undefined) {
|
||||
const newIsEnabled = this._isEnabledDelegate();
|
||||
if (newIsEnabled != this.enabled) {
|
||||
this.setEnabled(newIsEnabled);
|
||||
this._updateStyles();
|
||||
}
|
||||
}
|
||||
|
||||
if (this._isActiveDelegate !== undefined) {
|
||||
const newIsActive = this._isActiveDelegate();
|
||||
if (newIsActive !== this._isActive) {
|
||||
this._isActive = newIsActive;
|
||||
this._updateStyles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected _onEnabledChanged(): void {
|
||||
this._updateStyles();
|
||||
}
|
||||
|
||||
private _isActiveDelegate?: () => boolean;
|
||||
public isActive(delegate: () => boolean) {
|
||||
this._isActiveDelegate = delegate;
|
||||
return this;
|
||||
}
|
||||
|
||||
private _isEnabledDelegate?: () => boolean;
|
||||
public isEnabled(delegate: () => boolean) {
|
||||
this._isEnabledDelegate = delegate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public onClick(delegate: () => void) {
|
||||
this._onClick = delegate;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public generateHTML() {
|
||||
return `
|
||||
<div class="struct-prop container-icon-button" id="${this._getId()}">
|
||||
${this._iconSVG.outerHTML} ${this._label}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
public registerEvents(): void {
|
||||
const element = document.getElementById(this._getId()) as HTMLDivElement;
|
||||
ASSERT(element !== null);
|
||||
|
||||
element.addEventListener('click', () => {
|
||||
if (this.enabled && this._onClick) {
|
||||
this._onClick();
|
||||
}
|
||||
});
|
||||
|
||||
element.addEventListener('mouseenter', () => {
|
||||
this._setHovered(true);
|
||||
this._updateStyles();
|
||||
});
|
||||
|
||||
element.addEventListener('mouseleave', () => {
|
||||
this._setHovered(false);
|
||||
this._updateStyles();
|
||||
});
|
||||
}
|
||||
|
||||
public override finalise(): void {
|
||||
this._updateStyles();
|
||||
}
|
||||
|
||||
private _getSVGElement() {
|
||||
const svgId = this._getId() + '-svg';
|
||||
return UIUtil.getElementById(svgId);
|
||||
}
|
||||
|
||||
protected override _updateStyles() {
|
||||
UIUtil.updateStyles(this._getElement(), {
|
||||
isActive: this._isActive,
|
||||
isEnabled: this.enabled,
|
||||
isHovered: this.hovered,
|
||||
});
|
||||
}
|
||||
}
|
@ -1,193 +1,193 @@
|
||||
import { ASSERT } from '../../util/error_util';
|
||||
import { TAxis } from '../../util/type_util';
|
||||
import { UIUtil } from '../../util/ui_util';
|
||||
import { Vector3 } from '../../vector';
|
||||
import { ConfigUIElement } from './config_element';
|
||||
|
||||
export class VectorSpinboxElement extends ConfigUIElement<Vector3, HTMLDivElement> {
|
||||
private _mouseover: TAxis | null;
|
||||
private _dragging: TAxis | null;
|
||||
private _lastClientX: number;
|
||||
private _showY: boolean;
|
||||
private _wrap: number;
|
||||
private _units: string | null;
|
||||
|
||||
public constructor() {
|
||||
super(new Vector3(0, 0, 0));
|
||||
this._mouseover = null;
|
||||
this._dragging = null;
|
||||
this._lastClientX = 0.0;
|
||||
this._showY = true;
|
||||
this._wrap = Infinity;
|
||||
this._units = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not the Y axis has a UI element
|
||||
*/
|
||||
public setShowY(showY: boolean) {
|
||||
this._showY = showY;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setWrap(wrap: number) {
|
||||
this._wrap = wrap;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setUnits(units: string) {
|
||||
this._units = units;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected override _generateInnerHTML() {
|
||||
let html = '';
|
||||
html += '<div class="spinbox-main-container">';
|
||||
html += `
|
||||
<div class="spinbox-element-container">
|
||||
<div class="spinbox-key" id="${this._getKeyId('x')}">X</div>
|
||||
<div class="spinbox-value struct-prop" id="${this._getValueId('x')}">
|
||||
${this.getValue().x}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
if (this._showY) {
|
||||
html += `
|
||||
<div class="spinbox-element-container">
|
||||
<div class="spinbox-key" id="${this._getKeyId('y')}">Y</div>
|
||||
<div class="spinbox-value struct-prop" id="${this._getValueId('y')}">
|
||||
${this.getValue().y}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
html += `
|
||||
<div class="spinbox-element-container">
|
||||
<div class="spinbox-key" id="${this._getKeyId('z')}">Z</div>
|
||||
<div class="spinbox-value struct-prop" id="${this._getValueId('z')}">
|
||||
${this.getValue().z}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
html += '</div>';
|
||||
return html;
|
||||
}
|
||||
|
||||
private _getKeyId(axis: TAxis) {
|
||||
return this._getId() + '-k' + axis;
|
||||
}
|
||||
|
||||
private _getValueId(axis: TAxis) {
|
||||
return this._getId() + '-v' + axis;
|
||||
}
|
||||
|
||||
private _registerAxis(axis: TAxis) {
|
||||
const elementValue = UIUtil.getElementById(this._getValueId(axis));
|
||||
|
||||
elementValue.onmouseenter = () => {
|
||||
this._mouseover = axis;
|
||||
this._updateStyles();
|
||||
};
|
||||
|
||||
elementValue.onmouseleave = () => {
|
||||
this._mouseover = null;
|
||||
this._updateStyles();
|
||||
};
|
||||
}
|
||||
|
||||
public registerEvents() {
|
||||
this._registerAxis('x');
|
||||
if (this._showY) {
|
||||
this._registerAxis('y');
|
||||
}
|
||||
this._registerAxis('z');
|
||||
|
||||
document.addEventListener('mousedown', (e: any) => {
|
||||
if (this.enabled && this._mouseover !== null) {
|
||||
this._dragging = this._mouseover;
|
||||
this._lastClientX = e.clientX;
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('mousemove', (e: any) => {
|
||||
if (this.enabled && this._dragging !== null) {
|
||||
this._updateValue(e);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('mouseup', () => {
|
||||
this._dragging = null;
|
||||
this._updateStyles();
|
||||
});
|
||||
}
|
||||
|
||||
private _updateValue(e: MouseEvent) {
|
||||
ASSERT(this.enabled, 'Not enabled');
|
||||
ASSERT(this._dragging !== null, 'Dragging nothing');
|
||||
|
||||
const deltaX = e.clientX - this._lastClientX;
|
||||
this._lastClientX = e.clientX;
|
||||
|
||||
const current = this.getValue().copy();
|
||||
|
||||
switch (this._dragging) {
|
||||
case 'x':
|
||||
current.x = (current.x + deltaX) % this._wrap;
|
||||
break;
|
||||
case 'y':
|
||||
current.y = (current.y + deltaX) % this._wrap;
|
||||
break;
|
||||
case 'z':
|
||||
current.z = (current.z + deltaX) % this._wrap;
|
||||
break;
|
||||
}
|
||||
this._setValue(current);
|
||||
}
|
||||
|
||||
protected override _updateStyles(): void {
|
||||
const elementXV = UIUtil.getElementById(this._getValueId('x'));
|
||||
const elementYV = UIUtil.getElementById(this._getValueId('y'));
|
||||
const elementZV = UIUtil.getElementById(this._getValueId('z'));
|
||||
|
||||
// Update text
|
||||
{
|
||||
const current = this.getValue().copy();
|
||||
|
||||
elementXV.innerHTML = current.x.toString() + this._units;
|
||||
if (elementYV) {
|
||||
elementYV.innerHTML = current.y.toString() + this._units;
|
||||
}
|
||||
elementZV.innerHTML = current.z.toString() + this._units;
|
||||
}
|
||||
|
||||
// Update styles
|
||||
{
|
||||
UIUtil.updateStyles(elementXV, {
|
||||
isActive: false,
|
||||
isEnabled: this.enabled,
|
||||
isHovered: this._dragging === 'x' || (this._mouseover === 'x' && this._dragging === null),
|
||||
});
|
||||
|
||||
UIUtil.updateStyles(elementYV, {
|
||||
isActive: false,
|
||||
isEnabled: this.enabled,
|
||||
isHovered: this._dragging === 'y' || (this._mouseover === 'y' && this._dragging === null),
|
||||
});
|
||||
|
||||
UIUtil.updateStyles(elementZV, {
|
||||
isActive: false,
|
||||
isEnabled: this.enabled,
|
||||
isHovered: this._dragging === 'z' || (this._mouseover === 'z' && this._dragging === null),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected override _onEnabledChanged() {
|
||||
super._onEnabledChanged();
|
||||
this._updateStyles();
|
||||
}
|
||||
|
||||
protected override _onValueChanged(): void {
|
||||
this._updateStyles();
|
||||
}
|
||||
}
|
||||
import { ASSERT } from '../../util/error_util';
|
||||
import { TAxis } from '../../util/type_util';
|
||||
import { UIUtil } from '../../util/ui_util';
|
||||
import { Vector3 } from '../../vector';
|
||||
import { ConfigComponent } from './config';
|
||||
|
||||
export class VectorSpinboxComponent extends ConfigComponent<Vector3, HTMLDivElement> {
|
||||
private _mouseover: TAxis | null;
|
||||
private _dragging: TAxis | null;
|
||||
private _lastClientX: number;
|
||||
private _showY: boolean;
|
||||
private _wrap: number;
|
||||
private _units: string | null;
|
||||
|
||||
public constructor() {
|
||||
super(new Vector3(0, 0, 0));
|
||||
this._mouseover = null;
|
||||
this._dragging = null;
|
||||
this._lastClientX = 0.0;
|
||||
this._showY = true;
|
||||
this._wrap = Infinity;
|
||||
this._units = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not the Y axis has a UI element
|
||||
*/
|
||||
public setShowY(showY: boolean) {
|
||||
this._showY = showY;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setWrap(wrap: number) {
|
||||
this._wrap = wrap;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setUnits(units: string) {
|
||||
this._units = units;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected override _generateInnerHTML() {
|
||||
let html = '';
|
||||
html += '<div class="spinbox-main-container">';
|
||||
html += `
|
||||
<div class="spinbox-element-container">
|
||||
<div class="spinbox-key" id="${this._getKeyId('x')}">X</div>
|
||||
<div class="spinbox-value struct-prop" id="${this._getValueId('x')}">
|
||||
${this.getValue().x}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
if (this._showY) {
|
||||
html += `
|
||||
<div class="spinbox-element-container">
|
||||
<div class="spinbox-key" id="${this._getKeyId('y')}">Y</div>
|
||||
<div class="spinbox-value struct-prop" id="${this._getValueId('y')}">
|
||||
${this.getValue().y}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
html += `
|
||||
<div class="spinbox-element-container">
|
||||
<div class="spinbox-key" id="${this._getKeyId('z')}">Z</div>
|
||||
<div class="spinbox-value struct-prop" id="${this._getValueId('z')}">
|
||||
${this.getValue().z}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
html += '</div>';
|
||||
return html;
|
||||
}
|
||||
|
||||
private _getKeyId(axis: TAxis) {
|
||||
return this._getId() + '-k' + axis;
|
||||
}
|
||||
|
||||
private _getValueId(axis: TAxis) {
|
||||
return this._getId() + '-v' + axis;
|
||||
}
|
||||
|
||||
private _registerAxis(axis: TAxis) {
|
||||
const elementValue = UIUtil.getElementById(this._getValueId(axis));
|
||||
|
||||
elementValue.onmouseenter = () => {
|
||||
this._mouseover = axis;
|
||||
this._updateStyles();
|
||||
};
|
||||
|
||||
elementValue.onmouseleave = () => {
|
||||
this._mouseover = null;
|
||||
this._updateStyles();
|
||||
};
|
||||
}
|
||||
|
||||
public registerEvents() {
|
||||
this._registerAxis('x');
|
||||
if (this._showY) {
|
||||
this._registerAxis('y');
|
||||
}
|
||||
this._registerAxis('z');
|
||||
|
||||
document.addEventListener('mousedown', (e: any) => {
|
||||
if (this.enabled && this._mouseover !== null) {
|
||||
this._dragging = this._mouseover;
|
||||
this._lastClientX = e.clientX;
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('mousemove', (e: any) => {
|
||||
if (this.enabled && this._dragging !== null) {
|
||||
this._updateValue(e);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('mouseup', () => {
|
||||
this._dragging = null;
|
||||
this._updateStyles();
|
||||
});
|
||||
}
|
||||
|
||||
private _updateValue(e: MouseEvent) {
|
||||
ASSERT(this.enabled, 'Not enabled');
|
||||
ASSERT(this._dragging !== null, 'Dragging nothing');
|
||||
|
||||
const deltaX = e.clientX - this._lastClientX;
|
||||
this._lastClientX = e.clientX;
|
||||
|
||||
const current = this.getValue().copy();
|
||||
|
||||
switch (this._dragging) {
|
||||
case 'x':
|
||||
current.x = (current.x + deltaX) % this._wrap;
|
||||
break;
|
||||
case 'y':
|
||||
current.y = (current.y + deltaX) % this._wrap;
|
||||
break;
|
||||
case 'z':
|
||||
current.z = (current.z + deltaX) % this._wrap;
|
||||
break;
|
||||
}
|
||||
this._setValue(current);
|
||||
}
|
||||
|
||||
protected override _updateStyles(): void {
|
||||
const elementXV = UIUtil.getElementById(this._getValueId('x'));
|
||||
const elementYV = UIUtil.getElementById(this._getValueId('y'));
|
||||
const elementZV = UIUtil.getElementById(this._getValueId('z'));
|
||||
|
||||
// Update text
|
||||
{
|
||||
const current = this.getValue().copy();
|
||||
|
||||
elementXV.innerHTML = current.x.toString() + this._units;
|
||||
if (elementYV) {
|
||||
elementYV.innerHTML = current.y.toString() + this._units;
|
||||
}
|
||||
elementZV.innerHTML = current.z.toString() + this._units;
|
||||
}
|
||||
|
||||
// Update styles
|
||||
{
|
||||
UIUtil.updateStyles(elementXV, {
|
||||
isActive: false,
|
||||
isEnabled: this.enabled,
|
||||
isHovered: this._dragging === 'x' || (this._mouseover === 'x' && this._dragging === null),
|
||||
});
|
||||
|
||||
UIUtil.updateStyles(elementYV, {
|
||||
isActive: false,
|
||||
isEnabled: this.enabled,
|
||||
isHovered: this._dragging === 'y' || (this._mouseover === 'y' && this._dragging === null),
|
||||
});
|
||||
|
||||
UIUtil.updateStyles(elementZV, {
|
||||
isActive: false,
|
||||
isEnabled: this.enabled,
|
||||
isHovered: this._dragging === 'z' || (this._mouseover === 'z' && this._dragging === null),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected override _onEnabledChanged() {
|
||||
super._onEnabledChanged();
|
||||
this._updateStyles();
|
||||
}
|
||||
|
||||
protected override _onValueChanged(): void {
|
||||
this._updateStyles();
|
||||
}
|
||||
}
|
339
src/ui/layout.ts
339
src/ui/layout.ts
@ -14,30 +14,30 @@ import { TDithering } from '../util/type_util';
|
||||
import { UIUtil } from '../util/ui_util';
|
||||
import { TVoxelOverlapRule } from '../voxel_mesh';
|
||||
import { TVoxelisers } from '../voxelisers/voxelisers';
|
||||
import { ButtonComponent } from './components/button';
|
||||
import { CheckboxComponent } from './components/checkbox';
|
||||
import { ComboboxComponent, ComboBoxItem } from './components/combobox';
|
||||
import { ConfigComponent } from './components/config';
|
||||
import { ObjFileComponent } from './components/file_input';
|
||||
import { HeaderComponent } from './components/header';
|
||||
import { PaletteComponent } from './components/palette';
|
||||
import { SliderComponent } from './components/slider';
|
||||
import { ToolbarItemComponent } from './components/toolbar_item';
|
||||
import { VectorSpinboxComponent } from './components/vector_spinbox';
|
||||
import { AppConsole } from './console';
|
||||
import { ButtonElement } from './elements/button';
|
||||
import { CheckboxElement } from './elements/checkbox';
|
||||
import { ComboBoxElement, ComboBoxItem } from './elements/combobox';
|
||||
import { ConfigUIElement } from './elements/config_element';
|
||||
import { ObjFileInputElement } from './elements/file_input';
|
||||
import { HeaderUIElement } from './elements/header_element';
|
||||
import { PaletteElement } from './elements/palette_element';
|
||||
import { SliderElement } from './elements/slider';
|
||||
import { ToolbarItemElement } from './elements/toolbar_item';
|
||||
import { VectorSpinboxElement } from './elements/vector_spinbox';
|
||||
import { AppIcons } from './icons';
|
||||
import { HTMLBuilder, MiscComponents } from './misc';
|
||||
|
||||
export interface Group {
|
||||
export type Group = {
|
||||
label: string;
|
||||
elements: { [key: string]: ConfigUIElement<any, any> };
|
||||
elementsOrder: string[];
|
||||
submitButton: ButtonElement;
|
||||
components: { [key: string]: ConfigComponent<any, any> };
|
||||
componentOrder: string[];
|
||||
execButton: ButtonComponent;
|
||||
}
|
||||
|
||||
export interface ToolbarGroup {
|
||||
elements: { [key: string]: ToolbarItemElement };
|
||||
elementsOrder: string[];
|
||||
components: { [key: string]: ToolbarItemComponent };
|
||||
componentOrder: string[];
|
||||
}
|
||||
|
||||
export class UI {
|
||||
@ -45,16 +45,16 @@ export class UI {
|
||||
private _ui = {
|
||||
'import': {
|
||||
label: '1. Import',
|
||||
elements: {
|
||||
'input': new ObjFileInputElement()
|
||||
components: {
|
||||
'input': new ObjFileComponent()
|
||||
.setLabel('Wavefront .obj file'),
|
||||
'rotation': new VectorSpinboxElement()
|
||||
'rotation': new VectorSpinboxComponent()
|
||||
.setLabel('Rotation')
|
||||
.setWrap(360)
|
||||
.setUnits('°'),
|
||||
},
|
||||
elementsOrder: ['input', 'rotation'],
|
||||
submitButton: new ButtonElement()
|
||||
componentOrder: ['input', 'rotation'],
|
||||
execButton: new ButtonComponent()
|
||||
.setOnClick(() => {
|
||||
this._appContext.do(EAction.Import);
|
||||
})
|
||||
@ -62,10 +62,10 @@ export class UI {
|
||||
},
|
||||
'materials': {
|
||||
label: '2. Materials',
|
||||
elements: {
|
||||
components: {
|
||||
},
|
||||
elementsOrder: [],
|
||||
submitButton: new ButtonElement()
|
||||
componentOrder: [],
|
||||
execButton: new ButtonComponent()
|
||||
.setOnClick(() => {
|
||||
this._appContext.do(EAction.Materials);
|
||||
})
|
||||
@ -73,8 +73,8 @@ export class UI {
|
||||
},
|
||||
'voxelise': {
|
||||
label: '3. Voxelise',
|
||||
elements: {
|
||||
'constraintAxis': new ComboBoxElement<TAxis>()
|
||||
components: {
|
||||
'constraintAxis': new ComboboxComponent<TAxis>()
|
||||
.addItem({ payload: 'y', displayText: 'Y (height) (green)' })
|
||||
.addItem({ payload: 'x', displayText: 'X (width) (red)' })
|
||||
.addItem({ payload: 'z', displayText: 'Z (depth) (blue)' })
|
||||
@ -83,40 +83,40 @@ export class UI {
|
||||
/*
|
||||
switch (value) {
|
||||
case 'x':
|
||||
this._ui.voxelise.elements.size.setMax(this._appContext.maxConstraint?.x ?? 400);
|
||||
this._ui.voxelise.components.size.setMax(this._appContext.maxConstraint?.x ?? 400);
|
||||
break;
|
||||
case 'y':
|
||||
this._ui.voxelise.elements.size.setMax(this._appContext.maxConstraint?.y ?? AppConfig.Get.CONSTRAINT_MAXIMUM_HEIGHT);
|
||||
this._ui.voxelise.components.size.setMax(this._appContext.maxConstraint?.y ?? AppConfig.Get.CONSTRAINT_MAXIMUM_HEIGHT);
|
||||
break;
|
||||
case 'z':
|
||||
this._ui.voxelise.elements.size.setMax(this._appContext.maxConstraint?.z ?? 400);
|
||||
this._ui.voxelise.components.size.setMax(this._appContext.maxConstraint?.z ?? 400);
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}),
|
||||
'size': new SliderElement()
|
||||
'size': new SliderComponent()
|
||||
.setMin(3)
|
||||
.setMax(380)
|
||||
.setDefaultValue(80)
|
||||
.setDecimals(0)
|
||||
.setStep(1)
|
||||
.setLabel('Size'),
|
||||
'voxeliser': new ComboBoxElement<TVoxelisers>()
|
||||
'voxeliser': new ComboboxComponent<TVoxelisers>()
|
||||
.addItem({ payload: 'ray-based', displayText: 'Ray-based' })
|
||||
.addItem({ payload: 'bvh-ray', displayText: 'BVH Ray-based' })
|
||||
.addItem({ payload: 'ncrb', displayText: 'NCRB' })
|
||||
.setLabel('Algorithm'),
|
||||
'ambientOcclusion': new CheckboxElement()
|
||||
'ambientOcclusion': new CheckboxComponent()
|
||||
.setCheckedText('On (recommended)')
|
||||
.setUncheckedText('Off (faster)')
|
||||
.setDefaultValue(true)
|
||||
.setLabel('Ambient occlusion'),
|
||||
'multisampleColouring': new CheckboxElement()
|
||||
'multisampleColouring': new CheckboxComponent()
|
||||
.setCheckedText('On (recommended)')
|
||||
.setUncheckedText('Off (faster)')
|
||||
.setDefaultValue(true)
|
||||
.setLabel('Multisampling'),
|
||||
'voxelOverlapRule': new ComboBoxElement<TVoxelOverlapRule>()
|
||||
'voxelOverlapRule': new ComboboxComponent<TVoxelOverlapRule>()
|
||||
.addItem({
|
||||
displayText: 'Average (recommended)',
|
||||
payload: 'average',
|
||||
@ -129,7 +129,7 @@ export class UI {
|
||||
})
|
||||
.setLabel('Voxel overlap'),
|
||||
},
|
||||
elementsOrder: [
|
||||
componentOrder: [
|
||||
'constraintAxis',
|
||||
'size',
|
||||
'voxeliser',
|
||||
@ -137,7 +137,7 @@ export class UI {
|
||||
'multisampleColouring',
|
||||
'voxelOverlapRule',
|
||||
],
|
||||
submitButton: new ButtonElement()
|
||||
execButton: new ButtonComponent()
|
||||
.setOnClick(() => {
|
||||
this._appContext.do(EAction.Voxelise);
|
||||
})
|
||||
@ -145,14 +145,14 @@ export class UI {
|
||||
},
|
||||
'assign': {
|
||||
label: '4. Assign',
|
||||
elements: {
|
||||
'textureAtlas': new ComboBoxElement<string>()
|
||||
.addItems(this._getTextureAtlases())
|
||||
components: {
|
||||
'textureAtlas': new ComboboxComponent<string>()
|
||||
.addItem({ displayText: 'Vanilla', payload: 'vanilla' })
|
||||
.setLabel('Texture atlas')
|
||||
.setShouldObeyGroupEnables(false),
|
||||
'blockPalette': new PaletteElement()
|
||||
'blockPalette': new PaletteComponent()
|
||||
.setLabel('Block palette'),
|
||||
'dithering': new ComboBoxElement<TDithering>()
|
||||
'dithering': new ComboboxComponent<TDithering>()
|
||||
.addItems([{
|
||||
displayText: 'Ordered',
|
||||
payload: 'ordered',
|
||||
@ -166,7 +166,7 @@ export class UI {
|
||||
payload: 'off',
|
||||
}])
|
||||
.setLabel('Dithering'),
|
||||
'fallable': new ComboBoxElement<FallableBehaviour>()
|
||||
'fallable': new ComboboxComponent<FallableBehaviour>()
|
||||
.addItems([{
|
||||
displayText: 'Replace falling with solid',
|
||||
payload: 'replace-falling',
|
||||
@ -183,39 +183,39 @@ export class UI {
|
||||
tooltip: 'Let the block fall',
|
||||
}])
|
||||
.setLabel('Fallable blocks'),
|
||||
'colourAccuracy': new SliderElement()
|
||||
'colourAccuracy': new SliderComponent()
|
||||
.setMin(1)
|
||||
.setMax(8)
|
||||
.setDefaultValue(5)
|
||||
.setDecimals(1)
|
||||
.setStep(0.1)
|
||||
.setLabel('Colour accuracy'),
|
||||
'contextualAveraging': new CheckboxElement()
|
||||
'contextualAveraging': new CheckboxComponent()
|
||||
.setCheckedText('On (recommended)')
|
||||
.setUncheckedText('Off (faster)')
|
||||
.setDefaultValue(true)
|
||||
.setLabel('Smart averaging'),
|
||||
'errorWeight': new SliderElement()
|
||||
'errorWeight': new SliderComponent()
|
||||
.setMin(0.0)
|
||||
.setMax(2.0)
|
||||
.setDefaultValue(0.2)
|
||||
.setDecimals(2)
|
||||
.setStep(0.01)
|
||||
.setLabel('Smoothness'),
|
||||
'calculateLighting': new CheckboxElement()
|
||||
'calculateLighting': new CheckboxComponent()
|
||||
.setCheckedText('On')
|
||||
.setUncheckedText('Off')
|
||||
.setDefaultValue(false)
|
||||
.setLabel('Calculate lighting')
|
||||
.addValueChangedListener((newValue: boolean) => {
|
||||
const isEnabled = this._ui.assign.elements.calculateLighting.getEnabled();
|
||||
this._ui.assign.elements.lightThreshold.setEnabled(newValue && isEnabled, false);
|
||||
const isEnabled = this._ui.assign.components.calculateLighting.getEnabled();
|
||||
this._ui.assign.components.lightThreshold.setEnabled(newValue && isEnabled, false);
|
||||
})
|
||||
.addEnabledChangedListener((isEnabled: boolean) => {
|
||||
const value = this._ui.assign.elements.calculateLighting.getValue();
|
||||
this._ui.assign.elements.lightThreshold.setEnabled(value && isEnabled, false);
|
||||
const value = this._ui.assign.components.calculateLighting.getValue();
|
||||
this._ui.assign.components.lightThreshold.setEnabled(value && isEnabled, false);
|
||||
}),
|
||||
'lightThreshold': new SliderElement()
|
||||
'lightThreshold': new SliderComponent()
|
||||
.setMin(0)
|
||||
.setMax(14)
|
||||
.setDefaultValue(1)
|
||||
@ -224,7 +224,7 @@ export class UI {
|
||||
.setLabel('Light threshold')
|
||||
.setShouldObeyGroupEnables(false),
|
||||
},
|
||||
elementsOrder: [
|
||||
componentOrder: [
|
||||
'textureAtlas',
|
||||
'blockPalette',
|
||||
'dithering',
|
||||
@ -235,7 +235,7 @@ export class UI {
|
||||
'calculateLighting',
|
||||
'lightThreshold',
|
||||
],
|
||||
submitButton: new ButtonElement()
|
||||
execButton: new ButtonComponent()
|
||||
.setOnClick(() => {
|
||||
this._appContext.do(EAction.Assign);
|
||||
})
|
||||
@ -243,8 +243,8 @@ export class UI {
|
||||
},
|
||||
'export': {
|
||||
label: '5. Export',
|
||||
elements: {
|
||||
'export': new ComboBoxElement<TExporters>()
|
||||
components: {
|
||||
'export': new ComboboxComponent<TExporters>()
|
||||
.addItems([
|
||||
{
|
||||
displayText: 'Litematic (.litematic)',
|
||||
@ -271,8 +271,8 @@ export class UI {
|
||||
])
|
||||
.setLabel('Exporter'),
|
||||
},
|
||||
elementsOrder: ['export'],
|
||||
submitButton: new ButtonElement()
|
||||
componentOrder: ['export'],
|
||||
execButton: new ButtonComponent()
|
||||
.setLabel('Export structure')
|
||||
.setOnClick(() => {
|
||||
this._appContext.do(EAction.Export);
|
||||
@ -283,8 +283,8 @@ export class UI {
|
||||
private _toolbarLeft = {
|
||||
groups: {
|
||||
'viewmode': {
|
||||
elements: {
|
||||
'mesh': new ToolbarItemElement({ id: 'mesh', iconSVG: AppIcons.MESH })
|
||||
components: {
|
||||
'mesh': new ToolbarItemComponent({ id: 'mesh', iconSVG: AppIcons.MESH })
|
||||
.onClick(() => {
|
||||
Renderer.Get.setModelToUse(MeshType.TriangleMesh);
|
||||
})
|
||||
@ -294,7 +294,7 @@ export class UI {
|
||||
.isEnabled(() => {
|
||||
return Renderer.Get.getModelsAvailable() >= MeshType.TriangleMesh;
|
||||
}),
|
||||
'voxelMesh': new ToolbarItemElement({ id: 'voxelMesh', iconSVG: AppIcons.VOXEL })
|
||||
'voxelMesh': new ToolbarItemComponent({ id: 'voxelMesh', iconSVG: AppIcons.VOXEL })
|
||||
.onClick(() => {
|
||||
Renderer.Get.setModelToUse(MeshType.VoxelMesh);
|
||||
})
|
||||
@ -304,7 +304,7 @@ export class UI {
|
||||
.isEnabled(() => {
|
||||
return Renderer.Get.getModelsAvailable() >= MeshType.VoxelMesh;
|
||||
}),
|
||||
'blockMesh': new ToolbarItemElement({ id: 'blockMesh', iconSVG: AppIcons.BLOCK })
|
||||
'blockMesh': new ToolbarItemComponent({ id: 'blockMesh', iconSVG: AppIcons.BLOCK })
|
||||
.onClick(() => {
|
||||
Renderer.Get.setModelToUse(MeshType.BlockMesh);
|
||||
})
|
||||
@ -315,11 +315,11 @@ export class UI {
|
||||
return Renderer.Get.getModelsAvailable() >= MeshType.BlockMesh;
|
||||
}),
|
||||
},
|
||||
elementsOrder: ['mesh', 'voxelMesh', 'blockMesh'],
|
||||
componentOrder: ['mesh', 'voxelMesh', 'blockMesh'],
|
||||
},
|
||||
'debug': {
|
||||
elements: {
|
||||
'grid': new ToolbarItemElement({ id: 'grid', iconSVG: AppIcons.GRID })
|
||||
components: {
|
||||
'grid': new ToolbarItemComponent({ id: 'grid', iconSVG: AppIcons.GRID })
|
||||
.onClick(() => {
|
||||
Renderer.Get.toggleIsGridEnabled();
|
||||
})
|
||||
@ -329,14 +329,14 @@ export class UI {
|
||||
.isEnabled(() => {
|
||||
return Renderer.Get.getActiveMeshType() !== MeshType.None;
|
||||
}),
|
||||
'axes': new ToolbarItemElement({ id: 'axes', iconSVG: AppIcons.AXES })
|
||||
'axes': new ToolbarItemComponent({ id: 'axes', iconSVG: AppIcons.AXES })
|
||||
.onClick(() => {
|
||||
Renderer.Get.toggleIsAxesEnabled();
|
||||
})
|
||||
.isActive(() => {
|
||||
return Renderer.Get.isAxesEnabled();
|
||||
}),
|
||||
'night-vision': new ToolbarItemElement({ id: 'night', iconSVG: AppIcons.BULB })
|
||||
'night-vision': new ToolbarItemComponent({ id: 'night', iconSVG: AppIcons.BULB })
|
||||
.onClick(() => {
|
||||
Renderer.Get.toggleIsNightVisionEnabled();
|
||||
})
|
||||
@ -347,7 +347,7 @@ export class UI {
|
||||
return Renderer.Get.canToggleNightVision();
|
||||
}),
|
||||
},
|
||||
elementsOrder: ['grid', 'axes', 'night-vision'],
|
||||
componentOrder: ['grid', 'axes', 'night-vision'],
|
||||
},
|
||||
|
||||
},
|
||||
@ -357,32 +357,32 @@ export class UI {
|
||||
private _toolbarRight = {
|
||||
groups: {
|
||||
'zoom': {
|
||||
elements: {
|
||||
'zoomOut': new ToolbarItemElement({ id: 'zout', iconSVG: AppIcons.MINUS })
|
||||
components: {
|
||||
'zoomOut': new ToolbarItemComponent({ id: 'zout', iconSVG: AppIcons.MINUS })
|
||||
.onClick(() => {
|
||||
ArcballCamera.Get.onZoomOut();
|
||||
}),
|
||||
'zoomIn': new ToolbarItemElement({ id: 'zin', iconSVG: AppIcons.PLUS })
|
||||
'zoomIn': new ToolbarItemComponent({ id: 'zin', iconSVG: AppIcons.PLUS })
|
||||
.onClick(() => {
|
||||
ArcballCamera.Get.onZoomIn();
|
||||
}),
|
||||
'reset': new ToolbarItemElement({ id: 'reset', iconSVG: AppIcons.CENTRE })
|
||||
'reset': new ToolbarItemComponent({ id: 'reset', iconSVG: AppIcons.CENTRE })
|
||||
.onClick(() => {
|
||||
ArcballCamera.Get.reset();
|
||||
}),
|
||||
},
|
||||
elementsOrder: ['zoomOut', 'zoomIn', 'reset'],
|
||||
componentOrder: ['zoomOut', 'zoomIn', 'reset'],
|
||||
},
|
||||
'camera': {
|
||||
elements: {
|
||||
'perspective': new ToolbarItemElement({ id: 'pers', iconSVG: AppIcons.PERSPECTIVE })
|
||||
components: {
|
||||
'perspective': new ToolbarItemComponent({ id: 'pers', iconSVG: AppIcons.PERSPECTIVE })
|
||||
.onClick(() => {
|
||||
ArcballCamera.Get.setCameraMode('perspective');
|
||||
})
|
||||
.isActive(() => {
|
||||
return ArcballCamera.Get.isPerspective();
|
||||
}),
|
||||
'orthographic': new ToolbarItemElement({ id: 'orth', iconSVG: AppIcons.ORTHOGRAPHIC })
|
||||
'orthographic': new ToolbarItemComponent({ id: 'orth', iconSVG: AppIcons.ORTHOGRAPHIC })
|
||||
.onClick(() => {
|
||||
ArcballCamera.Get.setCameraMode('orthographic');
|
||||
})
|
||||
@ -390,7 +390,7 @@ export class UI {
|
||||
return ArcballCamera.Get.isOrthographic();
|
||||
}),
|
||||
},
|
||||
elementsOrder: ['perspective', 'orthographic'],
|
||||
componentOrder: ['perspective', 'orthographic'],
|
||||
},
|
||||
},
|
||||
groupsOrder: ['camera', 'zoom'],
|
||||
@ -422,15 +422,15 @@ export class UI {
|
||||
|
||||
for (const groupName in this._toolbarLeftDull) {
|
||||
const toolbarGroup = this._toolbarLeftDull[groupName];
|
||||
for (const toolbarItem of toolbarGroup.elementsOrder) {
|
||||
toolbarGroup.elements[toolbarItem].tick();
|
||||
for (const toolbarItem of toolbarGroup.componentOrder) {
|
||||
toolbarGroup.components[toolbarItem].tick();
|
||||
}
|
||||
}
|
||||
|
||||
for (const groupName in this._toolbarRightDull) {
|
||||
const toolbarGroup = this._toolbarRightDull[groupName];
|
||||
for (const toolbarItem of toolbarGroup.elementsOrder) {
|
||||
toolbarGroup.elements[toolbarItem].tick();
|
||||
for (const toolbarItem of toolbarGroup.componentOrder) {
|
||||
toolbarGroup.components[toolbarItem].tick();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -442,7 +442,7 @@ export class UI {
|
||||
|
||||
sidebarHTML.add(`<div class="container-properties">`);
|
||||
{
|
||||
sidebarHTML.add(HeaderUIElement.Get.generateHTML());
|
||||
sidebarHTML.add(HeaderComponent.Get.generateHTML());
|
||||
|
||||
for (const groupName of this.uiOrder) {
|
||||
const group = this._uiDull[groupName];
|
||||
@ -463,8 +463,8 @@ export class UI {
|
||||
for (const toolbarGroupName of this._toolbarLeft.groupsOrder) {
|
||||
toolbarHTML.add('<div class="toolbar-group">');
|
||||
const toolbarGroup = this._toolbarLeftDull[toolbarGroupName];
|
||||
for (const groupElementName of toolbarGroup.elementsOrder) {
|
||||
const groupElement = toolbarGroup.elements[groupElementName];
|
||||
for (const groupElementName of toolbarGroup.componentOrder) {
|
||||
const groupElement = toolbarGroup.components[groupElementName];
|
||||
toolbarHTML.add(groupElement.generateHTML());
|
||||
}
|
||||
toolbarHTML.add('</div>');
|
||||
@ -476,8 +476,8 @@ export class UI {
|
||||
for (const toolbarGroupName of this._toolbarRight.groupsOrder) {
|
||||
toolbarHTML.add('<div class="toolbar-group">');
|
||||
const toolbarGroup = this._toolbarRightDull[toolbarGroupName];
|
||||
for (const groupElementName of toolbarGroup.elementsOrder) {
|
||||
const groupElement = toolbarGroup.elements[groupElementName];
|
||||
for (const groupElementName of toolbarGroup.componentOrder) {
|
||||
const groupElement = toolbarGroup.components[groupElementName];
|
||||
toolbarHTML.add(groupElement.generateHTML());
|
||||
}
|
||||
toolbarHTML.add('</div>');
|
||||
@ -504,32 +504,44 @@ export class UI {
|
||||
});
|
||||
}
|
||||
|
||||
public cacheValues(action: EAction) {
|
||||
const group = this._getEActionGroup(action);
|
||||
for (const elementName of group.elementsOrder) {
|
||||
LOG(`[UI]: Caching ${elementName}`);
|
||||
const element = group.elements[elementName];
|
||||
element.cacheValue();
|
||||
private _forEachComponent(action: EAction, functor: (component: ConfigComponent<unknown, unknown>) => void) {
|
||||
const group = this._getGroup(action);
|
||||
for (const elementName of group.componentOrder) {
|
||||
const element = group.components[elementName];
|
||||
functor(element);
|
||||
}
|
||||
}
|
||||
|
||||
public refreshSubcomponents(group: Group) {
|
||||
/**
|
||||
* Caches the current value of each component in an action group.
|
||||
*/
|
||||
public cacheValues(action: EAction) {
|
||||
this._forEachComponent(action, (component) => {
|
||||
component.cacheValue();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuilds the HTML for all components in an action group.
|
||||
*/
|
||||
public refreshComponents(action: EAction) {
|
||||
const group = this._getGroup(action);
|
||||
|
||||
const element = document.getElementById(`subcomponents_${group.label}`);
|
||||
ASSERT(element !== null);
|
||||
|
||||
element.innerHTML = this._getGroupSubcomponentsHTML(group);
|
||||
element.innerHTML = this._getComponentsHTML(group);
|
||||
|
||||
for (const elementName in group.elements) {
|
||||
const element = group.elements[elementName];
|
||||
element.registerEvents();
|
||||
element.finalise();
|
||||
}
|
||||
this._forEachComponent(action, (component) => {
|
||||
component.registerEvents();
|
||||
component.finalise();
|
||||
});
|
||||
}
|
||||
|
||||
private _getGroupSubcomponentsHTML(group: Group) {
|
||||
private _getComponentsHTML(group: Group) {
|
||||
let groupHTML = '';
|
||||
for (const elementName of group.elementsOrder) {
|
||||
const element = group.elements[elementName];
|
||||
for (const elementName of group.componentOrder) {
|
||||
const element = group.components[elementName];
|
||||
ASSERT(element !== undefined, `No element for: ${elementName}`);
|
||||
groupHTML += element.generateHTML();
|
||||
}
|
||||
@ -540,37 +552,37 @@ export class UI {
|
||||
return `
|
||||
${MiscComponents.createGroupHeader(group.label.toUpperCase())}
|
||||
<div class="component-group" id="subcomponents_${group.label}">
|
||||
${this._getGroupSubcomponentsHTML(group)}
|
||||
${this._getComponentsHTML(group)}
|
||||
</div>
|
||||
${group.submitButton.generateHTML()}
|
||||
${group.execButton.generateHTML()}
|
||||
`;
|
||||
}
|
||||
|
||||
public getActionButton(action: EAction) {
|
||||
const group = this._getEActionGroup(action);
|
||||
return group.submitButton;
|
||||
const group = this._getGroup(action);
|
||||
return group.execButton;
|
||||
}
|
||||
|
||||
public registerEvents() {
|
||||
HeaderUIElement.Get.registerEvents();
|
||||
HeaderUIElement.Get.finalise();
|
||||
HeaderComponent.Get.registerEvents();
|
||||
HeaderComponent.Get.finalise();
|
||||
|
||||
for (const groupName in this._ui) {
|
||||
const group = this._uiDull[groupName];
|
||||
for (const elementName in group.elements) {
|
||||
const element = group.elements[elementName];
|
||||
element.registerEvents();
|
||||
element.finalise();
|
||||
}
|
||||
group.submitButton.registerEvents();
|
||||
group.submitButton.finalise();
|
||||
for (let action = 0; action < EAction.MAX; ++action) {
|
||||
this._forEachComponent(action, (component) => {
|
||||
component.registerEvents();
|
||||
component.finalise();
|
||||
});
|
||||
|
||||
const group = this._getGroup(action);
|
||||
group.execButton.registerEvents();
|
||||
group.execButton.finalise();
|
||||
}
|
||||
|
||||
// Register toolbar left
|
||||
for (const toolbarGroupName of this._toolbarLeft.groupsOrder) {
|
||||
const toolbarGroup = this._toolbarLeftDull[toolbarGroupName];
|
||||
for (const groupElementName of toolbarGroup.elementsOrder) {
|
||||
const element = toolbarGroup.elements[groupElementName];
|
||||
for (const groupElementName of toolbarGroup.componentOrder) {
|
||||
const element = toolbarGroup.components[groupElementName];
|
||||
element.registerEvents();
|
||||
element.finalise();
|
||||
}
|
||||
@ -578,8 +590,8 @@ export class UI {
|
||||
// Register toolbar right
|
||||
for (const toolbarGroupName of this._toolbarRight.groupsOrder) {
|
||||
const toolbarGroup = this._toolbarRightDull[toolbarGroupName];
|
||||
for (const groupElementName of toolbarGroup.elementsOrder) {
|
||||
const element = toolbarGroup.elements[groupElementName];
|
||||
for (const groupElementName of toolbarGroup.componentOrder) {
|
||||
const element = toolbarGroup.components[groupElementName];
|
||||
element.registerEvents();
|
||||
element.finalise();
|
||||
}
|
||||
@ -594,79 +606,50 @@ export class UI {
|
||||
return this._uiDull;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable a specific action.
|
||||
*/
|
||||
public enable(action: EAction) {
|
||||
this._forEachComponent(action, (component) => {
|
||||
component.setEnabled(true);
|
||||
});
|
||||
this._getGroup(action).execButton.setEnabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable all actions up to and including a specific action.
|
||||
*/
|
||||
public enableTo(action: EAction) {
|
||||
for (let i = 0; i <= action; ++i) {
|
||||
this.enable(i);
|
||||
}
|
||||
}
|
||||
|
||||
public enable(action: EAction) {
|
||||
if (action >= EAction.MAX) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Disable a specific action and its dependent actions.
|
||||
*/
|
||||
public disable(action: EAction) {
|
||||
for (let i = action; i < EAction.MAX; ++i) {
|
||||
this._forEachComponent(action, (component) => {
|
||||
component.setEnabled(false);
|
||||
});
|
||||
|
||||
LOG('[UI]: Enabling', action);
|
||||
const group = this._getEActionGroup(action);
|
||||
for (const compName in group.elements) {
|
||||
group.elements[compName].setEnabled(true);
|
||||
this._getGroup(action).execButton.setEnabled(false);
|
||||
}
|
||||
group.submitButton.setEnabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables all the actions.
|
||||
*/
|
||||
public disableAll() {
|
||||
this.disable(EAction.Import);
|
||||
}
|
||||
|
||||
public disable(action: EAction) {
|
||||
if (action < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = action; i < EAction.MAX; ++i) {
|
||||
const group = this._getEActionGroup(i);
|
||||
//LOG('[UI]: Disabling', group.label);
|
||||
for (const compName in group.elements) {
|
||||
group.elements[compName].setEnabled(false);
|
||||
}
|
||||
group.submitButton.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
private _getEActionGroup(action: EAction): Group {
|
||||
/**
|
||||
* Util function to get the `Group` associated with an `EAction`.
|
||||
*/
|
||||
private _getGroup(action: EAction): Group {
|
||||
const key = this.uiOrder[action];
|
||||
return this._uiDull[key];
|
||||
}
|
||||
|
||||
private _getTextureAtlases(): ComboBoxItem<string>[] {
|
||||
const textureAtlases: ComboBoxItem<string>[] = [];
|
||||
|
||||
// TODO Unimplemented
|
||||
/*
|
||||
fs.readdirSync(AppPaths.Get.atlases).forEach((file) => {
|
||||
if (file.endsWith('.atlas')) {
|
||||
const paletteID = file.split('.')[0];
|
||||
let paletteName = paletteID.replace('-', ' ').toLowerCase();
|
||||
paletteName = paletteName.charAt(0).toUpperCase() + paletteName.slice(1);
|
||||
textureAtlases.push({ payload: paletteID, displayText: paletteName });
|
||||
}
|
||||
});
|
||||
*/
|
||||
textureAtlases.push({ payload: 'vanilla', displayText: 'Vanilla ' });
|
||||
|
||||
return textureAtlases;
|
||||
}
|
||||
|
||||
private _getBlockPalettes(): ComboBoxItem<TPalettes>[] {
|
||||
const blockPalettes: ComboBoxItem<TPalettes>[] = [];
|
||||
|
||||
const palettes = PaletteManager.getPalettesInfo();
|
||||
for (const palette of palettes) {
|
||||
blockPalettes.push({
|
||||
payload: palette.id,
|
||||
displayText: palette.name,
|
||||
});
|
||||
}
|
||||
|
||||
return blockPalettes;
|
||||
}
|
||||
}
|
||||
|
@ -512,7 +512,7 @@ svg {
|
||||
padding-left: 10px;
|
||||
color: var(--text-dim)
|
||||
}
|
||||
.checkbox-text-hover {
|
||||
.checkbox-text.text-light {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user