scriptable-testlab
Version:
A lightweight, efficient tool designed to manage and update scripts for Scriptable.
237 lines (205 loc) • 5.61 kB
text/typescript
import {AbsRect} from 'scriptable-abstract';
import {MockPoint} from './point';
import {MockSize} from './size';
interface RectState {
x: number;
y: number;
width: number;
height: number;
minX: number;
minY: number;
maxX: number;
maxY: number;
midX: number;
midY: number;
origin: Point;
size: Size;
}
const _DEFAULT_STATE: RectState = {
x: 0,
y: 0,
width: 0,
height: 0,
minX: 0,
minY: 0,
maxX: 0,
maxY: 0,
midX: 0,
midY: 0,
origin: new MockPoint(0, 0) as unknown as Point,
size: new MockSize(0, 0) as unknown as Size,
};
export class MockRect extends AbsRect<RectState> {
constructor(x: number = 0, y: number = 0, width: number = 0, height: number = 0) {
if (Number.isNaN(x)) throw new Error('x coordinate must be a valid number');
if (!Number.isFinite(x)) throw new Error('x coordinate must be finite');
if (Number.isNaN(y)) throw new Error('y coordinate must be a valid number');
if (!Number.isFinite(y)) throw new Error('y coordinate must be finite');
if (Number.isNaN(width)) throw new Error('width must be a valid number');
if (!Number.isFinite(width)) throw new Error('width must be finite');
if (width < 0) throw new Error('width must be non-negative');
if (Number.isNaN(height)) throw new Error('height must be a valid number');
if (!Number.isFinite(height)) throw new Error('height must be finite');
if (height < 0) throw new Error('height must be non-negative');
super({
x,
y,
width,
height,
minX: x,
minY: y,
maxX: x + width,
maxY: y + height,
midX: x + width / 2,
midY: y + height / 2,
origin: new MockPoint(x, y) as unknown as Point,
size: new MockSize(width, height) as unknown as Size,
});
}
private validateCoordinate(value: number, name: string) {
if (Number.isNaN(value)) {
throw new Error(`${name} coordinate must be a valid number`);
}
if (!Number.isFinite(value)) {
throw new Error(`${name} coordinate must be finite`);
}
}
private validateDimension(value: number, name: string) {
if (Number.isNaN(value)) {
throw new Error(`${name} must be a valid number`);
}
if (!Number.isFinite(value)) {
throw new Error(`${name} must be finite`);
}
if (value < 0) {
throw new Error(`${name} must be non-negative`);
}
}
get x(): number {
return this.state.x;
}
set x(value: number) {
this.validateCoordinate(value, 'x');
const origin = new MockPoint(value, this.y) as unknown as Point;
this.setState({
x: value,
minX: value,
maxX: value + this.width,
midX: value + this.width / 2,
origin,
});
}
get y(): number {
return this.state.y;
}
set y(value: number) {
this.validateCoordinate(value, 'y');
const origin = new MockPoint(this.x, value) as unknown as Point;
this.setState({
y: value,
minY: value,
maxY: value + this.height,
midY: value + this.height / 2,
origin,
});
}
get width(): number {
return this.state.width;
}
set width(value: number) {
this.validateDimension(value, 'width');
const size = new MockSize(value, this.height) as unknown as Size;
this.setState({
width: value,
maxX: this.x + value,
midX: this.x + value / 2,
size,
});
}
get height(): number {
return this.state.height;
}
set height(value: number) {
this.validateDimension(value, 'height');
const size = new MockSize(this.width, value) as unknown as Size;
this.setState({
height: value,
maxY: this.y + value,
midY: this.y + value / 2,
size,
});
}
get origin(): Point {
return this.state.origin;
}
set origin(value: Point) {
this.setState({
x: value.x,
y: value.y,
minX: value.x,
minY: value.y,
maxX: value.x + this.width,
maxY: value.y + this.height,
midX: value.x + this.width / 2,
midY: value.y + this.height / 2,
origin: value,
});
}
get size(): Size {
return this.state.size;
}
set size(value: Size) {
this.setState({
width: value.width,
height: value.height,
maxX: this.x + value.width,
maxY: this.y + value.height,
midX: this.x + value.width / 2,
midY: this.y + value.height / 2,
size: value,
});
}
get minX(): number {
return this.state.minX;
}
get minY(): number {
return this.state.minY;
}
get maxX(): number {
return this.state.maxX;
}
get maxY(): number {
return this.state.maxY;
}
get midX(): number {
return this.state.midX;
}
get midY(): number {
return this.state.midY;
}
public setState(state: Partial<RectState>): this {
const newState = {
...this.state,
...state,
};
// Update derived properties
if ('x' in state || 'width' in state) {
newState.minX = newState.x;
newState.maxX = newState.x + newState.width;
newState.midX = newState.x + newState.width / 2;
}
if ('y' in state || 'height' in state) {
newState.minY = newState.y;
newState.maxY = newState.y + newState.height;
newState.midY = newState.y + newState.height / 2;
}
if ('x' in state || 'y' in state) {
newState.origin = new MockPoint(newState.x, newState.y) as unknown as Point;
}
if ('width' in state || 'height' in state) {
newState.size = new MockSize(newState.width, newState.height) as unknown as Size;
}
super.setState(newState);
return this;
}
}