Home Reference Source

scripts/widgets/ui_curvewidget.js

import {Curve1DProperty} from "../path-controller/toolsys/toolprop.js";
import {UIBase, Icons} from '../core/ui_base.js';
import {ColumnFrame, RowFrame} from "../core/ui.js";
import * as util from '../path-controller/util/util.js';
import {Vector2, Vector3} from "../path-controller/util/vectormath.js";
import {Curve1D,  mySafeJSONStringify} from "../path-controller/curve/curve1d.js";
import {makeGenEnum} from '../path-controller/curve/curve1d_utils.js';

export class Curve1DWidget extends ColumnFrame {
  constructor() {
    super();

    this.useDataPathUndo = false;

    this._on_draw = this._on_draw.bind(this);
    this.drawTransform = [1.0, [0, 0]];

    this._value = new Curve1D();
    this._value.on("draw", this._on_draw);

    this._value._on_change = (msg) => {
      if (this.onchange) {
        this.onchange(this._value);
      }

      if (this.hasAttribute("datapath")) {
        let path = this.getAttribute("datapath");
        if (this._value !== undefined) {
          let val = this.getPathValue(this.ctx, path);

          if (val) {
            val.load(this._value);
            this.setPathValue(this.ctx, path, val);
          } else {
            val = this._value.copy();
            this.setPathValue(this.ctx, path, val);
          }
        }
      }
    };

    this._gen_type = undefined;
    this._lastGen = undefined;

    this._last_dpi = undefined;
    this.canvas = document.createElement("canvas");

    this.g = this.canvas.getContext("2d");
    this.canvas.g = this.g;

    window.cw = this;
    this.shadow.appendChild(this.canvas);
  }

  get value() {
    return this._value;
  }

  _on_draw(e) {
    let curve = e.data;

    //console.log("draw");
    this._redraw();
  }

  set value(val) {
    this._value.load(val);
    this.update();
    this._redraw();
  }

  _on_change() {
    if (this.onchange) {
      this.onchange(this);
    }
  }

  init() {
    super.init();

    this.useDataPathUndo = false;
    let row = this.row();

    let prop = makeGenEnum();

    prop.setValue(this.value.generatorType);

    this.dropbox = row.listenum(undefined, "Type", prop, this.value.generatorType, (id) => {
      console.warn("SELECT", id, prop.keys[id]);

      this.value.setGenerator(id);
      this.value._on_change("curve type change");
    });
    this.dropbox._init();

    row.iconbutton(Icons.ZOOM_OUT, "Zoom Out", () => {
      let curve = this._value;
      if (!curve) return;
      //if (isNaN(curve.uiZoom))
      //  curve.uiZoom = 1.0;

      curve.uiZoom *= 0.9;
      if (this.getAttribute("datapath")) {
        this.setPathValue(this.ctx, this.getAttribute("datapath"), curve);
      }

      this._redraw();
    }).iconsheet = 0;
    row.iconbutton(Icons.ZOOM_IN, "Zoom In", () => {
      let curve = this._value;
      if (!curve) return;
      //if (isNaN(curve.uiZoom))
      //  curve.uiZoom = 1.0;

      curve.uiZoom *= 1.1;
      if (this.getAttribute("datapath")) {
        this.setPathValue(this.ctx, this.getAttribute("datapath"), curve);
      }

      this._redraw();

    }).iconsheet = 0;

    this.container = this.col();
  }

  setCSS() {
    super.setCSS();

    this.style["width"] = "min-contents";
    this.style["height"] = "min-contents";
    this.updateSize();
  }

  updateSize() {
    let dpi = UIBase.getDPI();
    let w = ~~(this.getDefault("CanvasWidth")*dpi);
    let h = ~~(this.getDefault("CanvasHeight")*dpi);

    let bad = w !== this.canvas.width || h !== this.canvas.height;
    bad = bad || dpi !== this._last_dpi;

    if (!bad) {
      return;
    }

    this._last_dpi = dpi;
    this.canvas.width = w;
    this.canvas.height = h;

    this.canvas.style["width"] = (w/dpi) + "px";
    this.canvas.style["height"] = (h/dpi) + "px";

    this._redraw();
  }

  _redraw() {
    //forcibly clear canvas, works better then clearRect
    this.canvas.width = this.canvas.width;
    this.canvas.height = this.canvas.height;

    let canvas = this.canvas, g = this.g;

    //g.clearRect(0, 0, canvas.width, canvas.height);
    g.beginPath();
    g.rect(0, 0, canvas.width, canvas.height);
    g.fillStyle = this.getDefault("CanvasBG");
    g.fill();

    g.save();

    let zoom = this._value.uiZoom;
    let scale = Math.max(canvas.width, canvas.height);

    g.lineWidth /= scale;


    this.drawTransform[0] = scale*zoom;
    this.drawTransform[1][0] =  0.0;
    this.drawTransform[1][1] = -1.0;

    this.drawTransform[1][0] -= 0.5 - 0.5/zoom;
    this.drawTransform[1][1] += 0.5 - 0.5/zoom;

    //g.scale(scale, scale);

    g.scale(this.drawTransform[0], -this.drawTransform[0]);
    g.translate(this.drawTransform[1][0], this.drawTransform[1][1]);

    g.lineWidth /= zoom;

    this._value.draw(this.canvas, this.g, this.drawTransform);
    g.restore();
  }

  rebuild() {
    let ctx = this.ctx;
    if (ctx === undefined || this.container === undefined) {
      return;
    }


    this._gen_type = this.value.generatorType;
    let col = this.container;

    if (this._lastGen !== undefined) {
      this._lastGen.killGUI(col, this.canvas);
    }

    let onchange = this.dropbox.onchange;
    this.dropbox.onchange = undefined
    this.dropbox.setValue(this.value.generatorType);
    this.dropbox.onchange = onchange;

    col.clear();

    let gen = this.value.generators.active;
    gen.makeGUI(col, this.canvas);

    this._lastGen = gen;

    this._redraw();
  }

  updateDataPath() {
    if (!this.hasAttribute("datapath")) {
      return;
    }

    let path = this.getAttribute("datapath");
    let val = this.getPathValue(this.ctx, path);

    if (this._lastu === undefined) {
      this._lastu = 0;
    }

    if (val && !val.equals(this._value) && util.time_ms() - this._lastu > 200) {
      this._lastu = util.time_ms();

      this._value.load(val);
      this.update();
      this._redraw();
    }
  }

  updateGenUI() {
    let bad = this._lastGen !== this.value.generators.active;
    
    if (bad) {
      this.rebuild();
      this._redraw();
    }
  }
  update() {
    super.update();

    this.updateDataPath();
    this.updateSize();
    this.updateGenUI();
  }

  static define() {return {
    tagname : "curve-widget-x",
    style   : "curvewidget"
  }}
}
UIBase.internalRegister(Curve1DWidget);