diff --git a/button.ts b/button.ts index 40172496..6488d411 100644 --- a/button.ts +++ b/button.ts @@ -1,12 +1,11 @@ namespace user_interface_base { - export class Borders { constructor( public top: number, public bottom: number, public left: number, public right: number - ) {} + ) { } } export class ButtonStyle { @@ -14,7 +13,7 @@ namespace user_interface_base { public fill: number, public borders: Borders, public shadow: boolean - ) {} + ) { } } export namespace ButtonStyles { @@ -148,8 +147,8 @@ namespace user_interface_base { return !this.icon.invisible } - public hover(hov: boolean) {} - public update() {} + public hover(hov: boolean) { } + public update() { } isOffScreenX(): boolean { return this.icon.isOffScreenX() @@ -202,13 +201,11 @@ namespace user_interface_base { public selected: boolean private dynamicBoundaryColorsOn: boolean private boundaryColor: number + public state: number[] public pressable: boolean public get ariaId(): string { - return ( - this._ariaId || - (typeof this.iconId === "string" ? this.iconId : "") - ) + return this._ariaId } public set ariaId(value: string) { @@ -221,29 +218,30 @@ namespace user_interface_base { value: this.ariaId, force, } - accessibility.setLiveContent(msg) + accessibility.setLiveContent(msg) } constructor(opts: { parent?: IPlaceable style?: ButtonStyle - icon: string | Bitmap + icon?: string | Bitmap ariaId?: string - x: number - y: number + x?: number + y?: number onClick?: (button: Button) => void, dynamicBoundaryColorsOn?: boolean boundaryColor?: number, - flipIcon?: boolean + flipIcon?: boolean, + state?: number[] }) { super( - opts.x, - opts.y, + (opts.x != null) ? opts.x : 0, + (opts.y != null) ? opts.y : 0, opts.style || ButtonStyles.Transparent, opts.parent && opts.parent.xfrm ) this.iconId = opts.icon - this._ariaId = opts.ariaId + this._ariaId = (opts.ariaId != null) ? opts.ariaId : "" this.onClick = opts.onClick this.buildSprite(this.image_()) @@ -267,6 +265,8 @@ namespace user_interface_base { this.dynamicBoundaryColorsOn = true this.boundaryColor = opts.boundaryColor } + + this.state = opts.state } public getIcon() { @@ -283,10 +283,10 @@ namespace user_interface_base { private image_() { return typeof this.iconId == "string" - ? getIcon(this.iconId,false) + ? getIcon(this.iconId, false) : this.iconId } - + public setIcon(iconId: string, img?: Bitmap) { this.iconId = iconId if (img) this.icon.setImage(img) @@ -310,7 +310,7 @@ namespace user_interface_base { super.draw() if (this.dynamicBoundaryColorsOn) { - const boundaryColour = (this.selected && this.pressable) ? 7: this.boundaryColor + const boundaryColour = (this.selected && this.pressable) ? 7 : this.boundaryColor for (let dist = 1; dist <= 3; dist++) { Screen.outlineBoundsXfrm( diff --git a/cursor.ts b/cursor.ts index 953136d8..9fbc586b 100644 --- a/cursor.ts +++ b/cursor.ts @@ -23,7 +23,7 @@ namespace user_interface_base { } export interface CursorState { - navigator: INavigator + navigator: INavigator pos: Vec2 ariaId: string size: Bounds @@ -48,7 +48,7 @@ namespace user_interface_base { this.cancelHandlerStack = [] this.moveDest = new Vec2() this.setSize() - + this.cursorOutlineColour = DEFAULT_CURSOR_OUTLINE_COLOUR } @@ -70,7 +70,7 @@ namespace user_interface_base { public snapTo(x: number, y: number, ariaId: string, sizeHint: Bounds) { this.setSize( sizeHint || - new Bounds({ left: 0, top: 0, width: 16, height: 16 }) + new Bounds({ left: 0, top: 0, width: 16, height: 16 }) ) this.moveDest.x = this.xfrm.localPos.x = x this.moveDest.y = this.xfrm.localPos.y = y diff --git a/navigator.ts b/navigator.ts index 9b4f5119..ac691ce5 100644 --- a/navigator.ts +++ b/navigator.ts @@ -146,41 +146,64 @@ namespace user_interface_base { } + export class GridNavigator extends RowNavigator { private height: number; - private width: number; - - constructor(height: number, width: number) { + private widths: number[]; + + constructor(height: number, width?: number, widths?: number[]) { super() this.height = height - this.width = width + + if (widths != null) { + this.widths = widths + } + else { + width = (width != null) ? width : 1 + this.widths = [] + for (let _ = 0; _ < width; _++) + this.widths.push(width) + } + } + + public addButtons(btns: Button[]) { + this.buttonGroups.push(btns) } public move(dir: CursorDir) { switch (dir) { case CursorDir.Up: { this.row = (((this.row - 1) % this.height) + this.height) % this.height; // Non-negative modulo + + // Row above could have less cols, adjust if neccessary: + if (this.widths[this.row] <= this.col) + this.col = this.widths[this.row] - 1 + break } case CursorDir.Down: { this.row = (this.row + 1) % this.height; + + // Row below could have less cols, adjust if neccessary: + if (this.widths[this.row] <= this.col) + this.col = this.widths[this.row] - 1 break } case CursorDir.Left: { if (this.col == 0) - this.col = this.width - 1 + this.col = this.widths[this.row] - 1 else this.col -= 1 break } case CursorDir.Right: { - if (this.col == this.width) + if (this.col == this.widths[this.row]) this.col = 0 - else - this.col = (this.col + 1) % this.width + else + this.col = (this.col + 1) % this.widths[this.row] break } @@ -192,16 +215,19 @@ namespace user_interface_base { } } - const btn = this.buttonGroups[0][(this.row * this.width) + this.col] + const index = this.widths.slice(0, this.row).reduce((p, c) => p + c, 0) + const btn = this.buttonGroups[0][index + this.col] this.reportAria(btn) return btn } public getCurrent(): Button { - return this.buttonGroups[0][(this.row * this.width) + this.col] + const index = this.widths.slice(0, this.row).reduce((p, c) => p + c, 0) + return this.buttonGroups[0][index + this.col] } } + // mostly a matrix, except for last row, which may be ragged // also supports delete button // add support for aria @@ -210,7 +236,7 @@ namespace user_interface_base { protected row: number protected col: number - constructor(private picker: Picker) {} + constructor(private picker: Picker) { } private get width() { return this.picker.width @@ -257,7 +283,7 @@ namespace user_interface_base { this.deleteButton = undefined } - addButtons(btns: ButtonBase[]) {} + addButtons(btns: ButtonBase[]) { } addDelete(btn: Button) { this.deleteButton = btn @@ -346,11 +372,11 @@ namespace user_interface_base { if (this.row == -1) { accessibility.setLiveContent(< accessibility.TextAccessibilityMessage - >{ - type: "text", - value: "delete_tile", - force: true, - }) + >{ + type: "text", + value: "delete_tile", + force: true, + }) } } } @@ -368,13 +394,13 @@ namespace user_interface_base { const on = true // TODO: btn.getIcon() == "solid_red" accessibility.setLiveContent(< accessibility.LEDAccessibilityMessage - >{ - type: "led", - on, - x: this.col, - y: this.row, - force: true, - }) + >{ + type: "led", + on, + x: this.col, + y: this.row, + force: true, + }) } } @@ -392,12 +418,12 @@ namespace user_interface_base { const index = this.hasDelete ? this.row - 1 : this.row accessibility.setLiveContent(< accessibility.NoteAccessibilityMessage - >{ - type: "note", - on, - index, - force: true, - }) + >{ + type: "note", + on, + index, + force: true, + }) } } } diff --git a/scene.ts b/scene.ts index 1185842b..94f4b684 100644 --- a/scene.ts +++ b/scene.ts @@ -1,11 +1,10 @@ namespace user_interface_base { - const INPUT_PRIORITY = 10 const UPDATE_PRIORITY = 20 const RENDER_PRIORITY = 30 const SCREEN_PRIORITY = 100 - export abstract class Scene implements IComponent { + export abstract class Scene implements IComponent { private xfrm_: Affine private color_: number private backgroundCaptured_ = false @@ -22,7 +21,7 @@ namespace user_interface_base { this.color_ = v } - constructor(protected app: AppInterface, public name: string) { + constructor(public app?: AppInterface, public name?: string) { this.xfrm_ = new Affine() this.color_ = 12 } @@ -39,7 +38,7 @@ namespace user_interface_base { } } - /* abstract */ shutdown() {} + /* abstract */ shutdown() { } /* override */ activate() { profile() @@ -49,15 +48,15 @@ namespace user_interface_base { profile() } - /* abstract */ update() {} + /* abstract */ update() { } - /* abstract */ draw() {} + /* abstract */ draw() { } - protected handleClick(x: number, y: number) {} + protected handleClick(x: number, y: number) { } - protected handleMove(x: number, y: number) {} + protected handleMove(x: number, y: number) { } - protected handleWheel(dx: number, dy: number) {} + protected handleWheel(dx: number, dy: number) { } get backgroundCaptured() { return !!this.backgroundCaptured_