All files / src/gui draw-state-blade.ts

0% Statements 0/85
0% Branches 0/1
0% Functions 0/1
0% Lines 0/85

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114                                                                                                                                                                                                                                   
import { BladeApi, BladeController, View } from '@tweakpane/core';
import { createBlade } from '@tweakpane/core';
import { ViewProps } from '@tweakpane/core';
import { colorToRgb, getBrightness } from '../core/utils/color-utils';
import { ColorValue } from '../types';
 
interface DrawStateBladeConfig {
  numStates: number;
  palette: Record<number, ColorValue>;
  drawState: number;
  onStateChange: (state: number) => void;
}
 
class DrawStateBladeView implements View {
  public readonly element: HTMLElement;
  private buttons: HTMLElement[] = [];
 
  constructor(config: DrawStateBladeConfig) {
    this.element = document.createElement('div');
    this.element.style.display = 'flex';
    this.element.style.gap = '4px';
    this.element.style.flexWrap = 'wrap';
    this.element.style.padding = '4px 0';
 
    this.buildButtons(config);
  }
 
  private updateSelection(selectedState: number, numStates: number) {
    this.buttons.forEach((button, index) => {
      if (index < numStates) {
        if (index === selectedState) {
          button.style.border = '3px solid #ffff00';
          button.style.boxShadow = '0 0 5px rgba(255, 255, 0, 0.8)';
        } else {
          button.style.border = '2px solid #666';
          button.style.boxShadow = 'none';
        }
      }
    });
  }
 
  public update(config: DrawStateBladeConfig) {
    this.buildButtons(config);
  }
 
  private buildButtons(config: DrawStateBladeConfig) {
    this.buttons.forEach(btn => btn.remove());
    this.buttons = [];
 
    for (let i = 0; i < config.numStates; i++) {
      const button = document.createElement('button');
      button.style.width = '24px';
      button.style.height = '24px';
      button.style.border = '2px solid #666';
      button.style.borderRadius = '4px';
      button.style.cursor = 'pointer';
      button.style.padding = '0';
      button.style.margin = '0';
      button.title = `State ${i}`;
 
      const colorValue = config.palette[i] ?? '#000000';
      const colorStr = this.colorToCss(colorValue);
      button.style.backgroundColor = colorStr;
 
      const brightness = getBrightness(colorValue);
      button.style.color = brightness > 128 ? '#000000' : '#ffffff';
 
      button.addEventListener('click', () => {
        config.onStateChange(i);
        this.updateSelection(i, config.numStates);
      });
 
      this.element.appendChild(button);
      this.buttons.push(button);
    }
 
    this.updateSelection(config.drawState, config.numStates);
  }
 
  private colorToCss(color: ColorValue): string {
    if (typeof color === 'string') return color;
    const rgb = colorToRgb(color);
    const r = rgb.r.toString(16).padStart(2, '0');
    const g = rgb.g.toString(16).padStart(2, '0');
    const b = rgb.b.toString(16).padStart(2, '0');
    return `#${r}${g}${b}`;
  }
}
 
class DrawStateBladeController extends BladeController<DrawStateBladeView> {
  constructor(config: DrawStateBladeConfig) {
    super({
      blade: createBlade(),
      view: new DrawStateBladeView(config),
      viewProps: ViewProps.create(),
    });
  }
}
 
export class DrawStateBladeApi extends BladeApi<DrawStateBladeController> {
  constructor(controller: DrawStateBladeController) {
    super(controller);
  }
 
  public update(config: DrawStateBladeConfig) {
    this.controller.view.update(config);
  }
}
 
export function createDrawStateBlade(config: DrawStateBladeConfig): DrawStateBladeApi {
  const controller = new DrawStateBladeController(config);
  return new DrawStateBladeApi(controller);
}