Skip to content

Commit

Permalink
refactor: added fields to widgets.
Browse files Browse the repository at this point in the history
Define properties of widgets as fields.
WIP.

Closes #47
  • Loading branch information
poirierlouis committed Nov 9, 2024
1 parent e030c5a commit 21938f8
Show file tree
Hide file tree
Showing 89 changed files with 1,663 additions and 1,025 deletions.
44 changes: 25 additions & 19 deletions src/app/formatters/lua-sol2.formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {FIGTableWidget} from "../models/widgets/table.widget";
import {FIGTableRowWidget} from "../models/widgets/table-row.widget";
import {FIGTableColumnWidget} from "../models/widgets/table-column.widget";
import {FIGMenuBarWidget} from "../models/widgets/menu-bar.widget";
import {SizeField} from "../models/fields/size.field";

interface InputNumberFormatItem {
readonly fn: string;
Expand Down Expand Up @@ -95,6 +96,22 @@ export class FIGLuaSol2Formatter extends FIGFormatter {
return `ImGuiDir.${capitalize(FIGDir[arrow])}`;
}

private formatSize(label: string,
type: FIGWidgetType,
size: SizeField): string[] {
const varWidth: string = this.formatVar(`${label} width`, type);
const varHeight: string = this.formatVar(`${label} height`, type);
let width: string = size.value!.width.toString();
let height: string = size.value!.height.toString();

if (size.isPercentage) {
this.append(`local ${varWidth}, ${varHeight} = ImGui.GetContentRegionAvail()`);
width += ` * ${varWidth}`;
height += ` * ${varHeight}`;
}
return [width, height];
}

protected override formatFlags<T>(flags: number, flagsList: T[], flagsType: any, flagName: string): string {
let varFlags: string = '';

Expand Down Expand Up @@ -143,24 +160,11 @@ export class FIGLuaSol2Formatter extends FIGFormatter {
}

protected override formatChildWindow(widget: FIGChildWindowWidget): void {
const isPercentage = (value: number) => value > 0.0 && value <= 1.0;
const varWidth: string = this.formatVar(`${widget.label} width`, widget.type);
const varHeight: string = this.formatVar(`${widget.label} height`, widget.type);
const varArgs: string[] = [this.formatString(widget.label)];
let width: string = widget.size.width.toString();
let height: string = widget.size.height.toString();
const varSize: string[] = this.formatSize(widget.label, widget.type, widget.getField('size') as SizeField);

if (isPercentage(widget.size.width) || isPercentage(widget.size.height)) {
this.append(`local ${varWidth}, ${varHeight} = ImGui.GetContentRegionAvail()`);
if (isPercentage(widget.size.width)) {
width += ` * ${varWidth}`;
}
if (isPercentage(widget.size.height)) {
height += ` * ${varHeight}`;
}
}
varArgs.push(width);
varArgs.push(height);
varArgs.push(varSize[0]);
varArgs.push(varSize[1]);
varArgs.push(widget.frameBorder.toString());
if (widget.flags !== 0) {
varArgs.push(this.formatFlags(widget.flags, FIGWindowWidget.flags, FIGWindowFlags, 'ImGuiWindowFlags'));
Expand Down Expand Up @@ -316,7 +320,9 @@ export class FIGLuaSol2Formatter extends FIGFormatter {
}

protected override formatDummy(widget: FIGDummyWidget): void {
this.append(`ImGui.Dummy(${widget.width}, ${widget.height})`);
const varSize: string[] = this.formatSize('dummy', widget.type, widget.getField('size') as SizeField);

this.append(`ImGui.Dummy(${varSize[0]}, ${varSize[1]})`);
this.formatTooltip(widget);
}

Expand Down Expand Up @@ -594,8 +600,8 @@ export class FIGLuaSol2Formatter extends FIGFormatter {
const isInteger: boolean = FIGInputNumberWidget.isInteger(widget.dataType);
let value: string;

if (size === 0) {
const number: number = widget.value as number;
if (size === 1) {
const number: number = widget.value[0];

value = isInteger ? number.toString() : number.toFixed(precision);
} else {
Expand Down
11 changes: 11 additions & 0 deletions src/app/models/fields/array.field.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {Field, FieldType} from "./field";

export class ArrayField extends Field<unknown[]> {
constructor(name: string,
label: string,
value?: unknown[],
isOptional: boolean = false,
defaultValue?: unknown[]) {
super(FieldType.array, name, label, value, isOptional, defaultValue);
}
}
11 changes: 11 additions & 0 deletions src/app/models/fields/bool.field.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {Field, FieldType} from "./field";

export class BoolField extends Field<boolean> {
constructor(name: string,
label: string,
value?: boolean,
isOptional: boolean = false,
defaultValue?: boolean) {
super(FieldType.bool, name, label, value, isOptional, defaultValue);
}
}
12 changes: 12 additions & 0 deletions src/app/models/fields/color.field.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {Field, FieldType} from "./field";
import {Color} from "../math";

export class ColorField extends Field<Color> {
constructor(name: string,
label: string,
value?: Color,
isOptional: boolean = false,
defaultValue?: Color) {
super(FieldType.color, name, label, value, isOptional, defaultValue);
}
}
22 changes: 22 additions & 0 deletions src/app/models/fields/enum.field.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {Field, FieldType} from "./field";

export type EnumFieldType = string | number;

export interface EnumOption {
readonly value: number;
readonly label: string;
}

export class EnumField<T extends EnumFieldType> extends Field<T> {
public readonly options: EnumOption[];

constructor(name: string,
label: string,
options: EnumOption[],
value?: T,
isOptional: boolean = false,
defaultValue?: T) {
super(FieldType.enum, name, label, value, isOptional, defaultValue);
this.options = options;
}
}
65 changes: 65 additions & 0 deletions src/app/models/fields/field.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
export enum FieldType {
bool,
integer,
float,
number,
string,
array,
size,
flags,
color,
enum,
}

export type FieldCallback = (value: any) => void;

export class Field<T = unknown> {
readonly type: FieldType;
readonly name: string;
readonly label: string;
readonly isOptional: boolean;

value?: T;
defaultValue?: T;

private readonly listeners: FieldCallback[];

protected constructor(type: FieldType,
name: string,
label: string,
value?: T,
isOptional: boolean = false,
defaultValue?: T) {
this.type = type;
this.name = name;
this.label = label;
this.value = value;
this.isOptional = isOptional;
this.defaultValue = defaultValue;

this.listeners = [];
}

get isRequired(): boolean {
return !this.isOptional;
}

public addListener(fn: FieldCallback): void {
this.listeners.push(fn);
}

public removeListener(fn: FieldCallback): void {
const index: number = this.listeners.findIndex((listener) => listener === fn);

if (index !== -1) {
this.listeners.splice(index, 1);
}
}

public emit(): void {
for (const listener of this.listeners) {
listener(this.value);
}
}

}
32 changes: 32 additions & 0 deletions src/app/models/fields/flags.field.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {Field, FieldType} from "./field";
import {EnumFieldType} from "./enum.field";

export interface FlagOption {
readonly value: number;
readonly label: string;
}

export function getOptions(flags: Record<EnumFieldType, EnumFieldType>): FlagOption[] {
return Object.keys(flags)
.filter((key: EnumFieldType) => !isNaN(Number(key)))
.map((key: EnumFieldType) => {
return {
value: Number.parseInt(key as string),
label: flags[key]
} as FlagOption;
});
}

export class FlagsField extends Field<number> {
readonly options: FlagOption[];

constructor(name: string,
label: string,
options: FlagOption[],
value?: number,
isOptional: boolean = false,
defaultValue?: number) {
super(FieldType.flags, name, label, value, isOptional, defaultValue);
this.options = options;
}
}
11 changes: 11 additions & 0 deletions src/app/models/fields/float.field.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {Field, FieldType} from "./field";

export class FloatField extends Field<number> {
constructor(name: string,
label: string,
value?: number,
isOptional: boolean = false,
defaultValue?: number) {
super(FieldType.float, name, label, value, isOptional, defaultValue);
}
}
11 changes: 11 additions & 0 deletions src/app/models/fields/integer.field.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {Field, FieldType} from "./field";

export class IntegerField extends Field<number> {
constructor(name: string,
label: string,
value?: number,
isOptional: boolean = false,
defaultValue?: number) {
super(FieldType.integer, name, label, value, isOptional, defaultValue);
}
}
11 changes: 11 additions & 0 deletions src/app/models/fields/number.field.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {Field, FieldType} from "./field";

export class NumberField extends Field<number> {
constructor(name: string,
label: string,
value?: number,
isOptional: boolean = false,
defaultValue?: number) {
super(FieldType.number, name, label, value, isOptional, defaultValue);
}
}
24 changes: 24 additions & 0 deletions src/app/models/fields/size.field.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {Field, FieldType} from "./field";
import {Size} from "../math";

export class SizeField extends Field<Size> {
readonly acceptRelative: boolean;

constructor(name: string,
label: string,
acceptRelative: boolean = false,
value?: Size,
isOptional: boolean = false,
defaultValue?: Size) {
super(FieldType.size, name, label, value, isOptional, defaultValue);
this.acceptRelative = acceptRelative;
}

public get isPercentage(): boolean {
if (!this.value) {
return false;
}
return (this.value.width > 0.0 && this.value.width <= 1.0) ||
(this.value.height > 0.0 && this.value.height <= 1.0);
}
}
11 changes: 11 additions & 0 deletions src/app/models/fields/string.field.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {Field, FieldType} from "./field";

export class StringField extends Field<string> {
constructor(name: string,
label: string,
value?: string,
isOptional: boolean = false,
defaultValue?: string) {
super(FieldType.string, name, label, value, isOptional, defaultValue);
}
}
8 changes: 6 additions & 2 deletions src/app/models/math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ export interface Vector4 {
w: number;
}

export interface Size {
export type Size = Record<'width' | 'height', number> & {
width: number;
height: number;
}
};

export interface Color {
r: number;
Expand Down Expand Up @@ -66,3 +66,7 @@ export function plotSin(size: number): number[] {
}
return data;
}

export function isFloat(value: number | null): boolean {
return (value === null) ? false : value % 1 !== 0;
}
8 changes: 8 additions & 0 deletions src/app/models/object.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export function hasFunction(obj: object | null, fnName: string): boolean {
while ((obj = Reflect.getPrototypeOf(obj as object)) !== null) {
if (Reflect.ownKeys(obj).find((key) => key === fnName)) {
return true;
}
}
return false;
}
4 changes: 2 additions & 2 deletions src/app/models/widgets/bloc-for.widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ export class FIGBlocForWidget extends FIGContainer {
{name: 'size', optional: true, default: 10}
];

size: number;
size: number = 10;

constructor(options?: FIGBlocForOptions) {
super(FIGWidgetType.blocFor, true);
this.size = options?.size ?? 10;
this.registerInteger('size', 'Size', options?.size, true, 10);
this._focusOffset.y = 0;
}

Expand Down
Loading

0 comments on commit 21938f8

Please sign in to comment.