Home Reference Source

cables_dev/cables_ui/src/ui/gldraw/glrect.js

import { Logger, Events } from "cables-shared-client";

/**
 * rectangle data structure for {@link GlRectInstancer}
 *
 * @export
 * @class GlRect
 * @extends {Events}
 */
export default class GlRect extends Events
{
    constructor(instancer, options)
    {
        super();

        this._log = new Logger("GlRect");

        if (!instancer || !instancer.getIndex)
            this._log.warn("no instancer given!");

        options = options || {};
        this._visible = true;
        this._hovering = false;
        this._rectInstancer = instancer;
        this._attrIndex = instancer.getIndex();

        this.childs = [];
        this._shape = false;
        this._x = 0;
        this._y = 0;
        this._z = 0;
        this._absX = 0;
        this._absY = 0;
        this._absZ = 0;
        this._w = 110;
        this._h = 110;
        this._rectInstancer.setSize(this._attrIndex, this._w, this._h);
        this._data = {};
        this.color = vec4.create();
        this.colorHover = null;
        // this.colorHoverMultiply = 1.0;
        this._texture = null;
        // draggable stuff
        this._draggable = false;
        this.draggableX = true;
        this.draggableY = true;
        this._isDragging = false;
        this._dragStartX = 0;
        this._dragStartY = 0;
        this._dragOffsetX = 0;
        this._dragOffsetY = 0;
        this.draggableMove = false;
        this.interactive = true;
        if (options.hasOwnProperty("interactive")) this.interactive = options.interactive;

        this._parent = null;
        if (options.parent) this.setParent(options.parent);
    }

    get x() { return this._x; }

    get y() { return this._y; }

    get z() { return this._z; }

    get w() { return this._w; }

    get h() { return this._h; }

    get dragOffsetX() { return this._dragOffsetX; }

    get dragOffsetY() { return this._dragOffsetY; }

    get data() { return this._data; }

    set data(r) { this._data = r; }

    set draggable(b) { this._draggable = b; }

    get draggable() { return this._draggable; }

    get isDragging() { return this._isDragging; }

    get idx() { return this._attrIndex; }

    hasChild(c)
    {
        return this.childs.indexOf(c) > -1;
    }

    addChild(c)
    {
        if (!this.hasChild(c)) this.childs.push(c);
    }

    setShape(c)
    {
        if (this._shape != c)
        {
            this._shape = c;
            this._rectInstancer.setShape(this._attrIndex, c);
        }

        if (this._border != 0) this._rectInstancer.setBorder(this._attrIndex, 0);
        if (this._selected != 0) this._rectInstancer.setSelected(this._attrIndex, 0);
    }

    setBorder(c)
    {
        if (this._border != c)
        {
            this._border = c;
            this._rectInstancer.setBorder(this._attrIndex, c);
        }
    }

    setSelected(c)
    {
        if (this._selected != c)
        {
            this._selected = c;
            this._rectInstancer.setSelected(this._attrIndex, c);
        }
    }

    get visible() { return this._visible; }

    set visible(v)
    {
        const changed = this._visible != v;
        this._visible = v;

        if (changed)
        {
            this._updateSize();

            if (!this.visible) this._hovering = false;
            for (let i = 0; i < this.childs.length; i++) this.childs[i].visible = v;
        }
    }

    _updateSize()
    {
        if (!this._visible) this._rectInstancer.setSize(this._attrIndex, 0, 0);
        else this._rectInstancer.setSize(this._attrIndex, this._w, this._h);
    }

    setSize(w, h)
    {
        if (this._w == w && this._h == h) return;
        this._w = w;
        this._h = h;
        this._updateSize();
    }

    setColorHover(r, g, b, a)
    {
        this.colorHover = vec4.create();
        vec4.set(this.colorHover, r, g, b, a);
    }

    setColor(r, g, b, a)
    {
        if (r === undefined)r = g = b = a = 1.0;
        if (r.length) vec4.set(this.color, r[0], r[1], r[2], r[3]);
        else vec4.set(this.color, r, g, b, a);
        this._rectInstancer.setColor(this._attrIndex, this.color);
    }

    setOpacity(a, childs)
    {
        this.setColor(this.color[0], this.color[1], this.color[2], a);

        if (childs !== false)
            for (let i = 0; i < this.childs.length; i++) this.childs[i].setOpacity(a);
    }

    setTexRect(x, y, w, h)
    {
        this._rectInstancer.setTexRect(this._attrIndex, x, y, w, h);
    }

    setParent(p)
    {
        this._parent = p;
        p.addChild(this);
        this._visible = p.visible;
        this.setPosition(this._x, this._y, this._z);
    }

    get texture()
    {
        return this._texture;
    }

    setTexture(t)
    {
        if (this._texture == t) return;
        this._texture = t;
        this.emitEvent("textureChanged");
    }

    setPosition(_x, _y, _z)
    {
        this._x = _x;
        this._y = _y;
        this._z = _z || 0;

        this._absX = this._x;
        this._absY = this._y;
        this._absZ = this._z;

        if (this._parent)
        {
            this._absX += this.getParentX();
            this._absY += this.getParentY();
            this._absZ += this.getParentZ();
        }

        this._rectInstancer.setPosition(this._attrIndex, this._absX, this._absY, this._absZ);

        for (let i = 0; i < this.childs.length; i++) this.childs[i].setPosition(this.childs[i].x, this.childs[i].y, this.childs[i].z);
        this.emitEvent("positionChanged");
    }

    isPointInside(x, y)
    {
        return x > this._absX && x < this._absX + this._w && y > this._absY && y < this._absY + this._h;
    }

    mouseUp(e)
    {
        if (this._hovering) this.emitEvent("mouseup", e, this);
        for (let i = 0; i < this.childs.length; i++) this.childs[i].mouseUp(e);

        if (this._isDragging) this.mouseDragEnd();
    }

    mouseDown(e)
    {
        if (this._hovering) this.emitEvent("mousedown", e, this);
        for (let i = 0; i < this.childs.length; i++) this.childs[i].mouseDown(e);
    }

    isHovering()
    {
        return this._hovering;
    }

    getParentX()
    {
        // todo: add up all parents
        if (!this._parent) return 0;
        return this._parent._absX;
    }

    getParentY()
    {
        // todo: add up all parents
        if (!this._parent) return 0;
        return this._parent._absY;
    }

    getParentZ()
    {
        // todo: add up all parents
        if (!this._parent) return 0;
        return this._parent._absZ;
    }

    mouseDrag(x, y, button)
    {
        if (!this.interactive) return;

        this._dragOffsetX = 0;
        this._dragOffsetY = 0;
        if (this.draggableX) this._dragOffsetX = x - this._dragStartX;
        if (this.draggableY) this._dragOffsetY = y - this._dragStartY;

        if (this.draggableMove)
        {
            this.setPosition(this.x + this._dragOffsetX + this.getParentX(), this.y + this._dragOffsetY + this.getParentY());
            this._dragStartX = this.x;
            this._dragStartY = this.y;
        }
        // this.setPosition( x - this._dragOffsetX, y - this._dragOffsetY);
        this.emitEvent("drag", this);
    }

    mouseDragEnd()
    {
        if (!this.interactive) return;
        this.emitEvent("dragEnd", this);
        this._isDragging = false;
    }

    mouseMove(x, y, button)
    {
        if (!this.interactive) return;
        if (!this._visible) return;

        const hovering = this.isPointInside(x, y);
        const isHovered = this._hovering;

        const hoverChanged = this._hovering != hovering;
        this._hovering = hovering;

        if (hovering && !isHovered) this.emitEvent("hover", this);
        else if (!hovering && isHovered) this.emitEvent("unhover", this);

        if (hoverChanged)
        {
            if (this.colorHover)
            {
                if (!this._hovering) this._rectInstancer.setColor(this._attrIndex, this.color[0], this.color[1], this.color[2], this.color[3]);
                else this._rectInstancer.setColor(this._attrIndex, this.colorHover[0], this.colorHover[1], this.colorHover[2], this.colorHover[3]);
            }
            else this._rectInstancer.setColor(this._attrIndex, this.color[0], this.color[1], this.color[2], this.color[3]);

            // if (this.colorHoverMultiply)
            // {
            //     if (!this._hovering) this._rectInstancer.setColor(this._attrIndex, this.color[0], this.color[1], this.color[2], this.color[3]);
            //     else this._rectInstancer.setColor(this._attrIndex, this.color[0] * this.colorHoverMultiply, this.color[1] * this.colorHoverMultiply, this.color[2] * this.colorHoverMultiply, this.color[3] * this.colorHoverMultiply);
            // }
        }


        for (let i = 0; i < this.childs.length; i++)
        {
            this.childs[i].mouseMove(x, y, button);
            if (this.childs[i].isHovering()) this._hovering = false;
        }

        if (this._hovering)
        {
            if (button == 1 && this._rectInstancer.allowDragging)
            {
                if (!this._isDragging)
                {
                    this._isDragging = true;
                    this._dragStartX = x;
                    this._dragStartY = y;
                    this.emitEvent("dragStart", this);
                }
                this._dragOffsetX = x;
                this._dragOffsetY = y;
            }
        }
    }

    removeChild(child)
    {
        const idx = this.childs.indexOf(child);
        child._parent = null;
        if (idx >= 0) this.childs.splice(idx, 1);
    }

    dispose()
    {
        this.visible = false;
        if (this._parent) this._parent.removeChild(this);
        this.setShape(0);
        this.setSize(0, 0);
        this.setPosition(0, 0);
    }
}