Home Reference Source

cables_dev/cables_ui/src/ui/glpatch/glport.js


import { Logger } from "cables-shared-client";
import gluiconfig from "./gluiconfig.js";
import GlRect from "../gldraw/glrect.js";
import MouseState from "./mousestate.js";
import { updateHoverToolTip } from "../elements/tooltips.js";

/**
 * rendering ports on {@link GlOp} on  {@link GlPatch}
 *
 * @export
 * @class GlPort
 */
export default class GlPort
{
    constructor(glpatch, glop, rectInstancer, p, posCount, oprect)
    {
        this._log = new Logger("glPort");

        this._port = p;
        this._name = p.name;
        this._id = p.id;
        this._parent = oprect;
        this.groupIndex = 0;

        this._direction = p.direction;

        this._glop = glop;
        this._type = p.type;
        this._glPatch = glpatch;
        this._rectInstancer = rectInstancer;
        this._rect = new GlRect(this._rectInstancer, { "parent": this._parent, "interactive": true });
        this._longPortRect = null;

        this._dot = null;
        this._rect.colorHoverMultiply = 0.0;
        this._mouseButtonRightTimeDown = 0;
        this._posX = posCount * (gluiconfig.portWidth + gluiconfig.portPadding);

        if (!this._parent) this._log.warn("no parent rect given");
        else this._parent.addChild(this._rect);

        this.portIndex = posCount;

        this._updateColor();
        this._activity = 1;

        this._mouseEvents = [];

        this._mouseEvents.push(this._rect.on("mousedown", this._onMouseDown.bind(this)));
        this._mouseEvents.push(this._rect.on("mouseup", this._onMouseUp.bind(this)));
        this._mouseEvents.push(this._rect.on("hover", this._onHover.bind(this)));
        this._mouseEvents.push(this._rect.on("unhover", this._onUnhover.bind(this)));

        this._port.on("onLinkChanged", this._onLinkChanged.bind(this));
        this._port.on("onValueChangeUi", () =>
        {
            if (this._glop.op && this._glop.op.uiAttribs.mathTitle) this._glop.setTitle();
        });

        p.on("onUiAttrChange", this._onUiAttrChange.bind(this));

        this._onUiAttrChange(p.uiAttribs);

        this.setFlowModeActivity(1);
        this.updateSize();
        this._updateColor();
    }

    _onUiAttrChange(attribs)
    {
        if (this.disposed) return;
        if (attribs.hasOwnProperty("isAnimated") || attribs.hasOwnProperty("useVariable") || attribs.hasOwnProperty("notWorking")) this._updateColor();
        if (attribs.hasOwnProperty("expose")) this._updateColor();

        if (attribs.hasOwnProperty("addPort"))
        {
            this._updateColor();
        }

        if (attribs.hasOwnProperty("longPort") && attribs.longPort == 0 && this._longPortRect) this._longPortRect = this._longPortRect.dispose();
        if (attribs.hasOwnProperty("longPort") && attribs.longPort > 0)
        {
            if (!this._rect) return;
            if (!this._longPortRect) this._longPortRect = new GlRect(this._rectInstancer, { "parent": this._parent, "interactive": false });



            const col = GlPort.getColor(this._type, false, false, false);
            this._longPortRect.setColor([col[0], col[1], col[2], 0.5]);

            this.updateSize();
        }
    }

    updateShape()
    {
        if (this._port.isLinked())
        {
            this._rect.setShape(0);
        }
        else
        {
            if (this._direction == CABLES.PORT_DIR_OUT) this._rect.setShape(9);
            else this._rect.setShape(10);
        }
        // this._rect.setShape(6);
    }

    _updateColor()
    {
        if (!this._rect) return;

        const isAssigned = this._port.uiAttribs.useVariable || this._port.uiAttribs.isAnimated;
        const dotSize = gluiconfig.portHeight * 0.75;

        const showDot = isAssigned || this._port.uiAttribs.notWorking || this._port.uiAttribs.addPort;

        if (!this._dot && showDot)
        {
            this._dot = new GlRect(this._rectInstancer, { "parent": this._rect, "interactive": false });
            this._dot.setSize(0, 0);
            this._rect.addChild(this._dot);
        }



        if (this._dot)
        {
            if (showDot)
            {
                if (this._port.uiAttribs.notWorking) this._dot.setColor(0.8, 0.2, 0.2, 1);
                else this._dot.setColor(0.24, 0.24, 0.24, 1);

                let dotPosY = gluiconfig.portHeight / 2 - dotSize / 2;
                if (this.direction == CABLES.PORT_DIR_IN) dotPosY += gluiconfig.portHeight;

                if (this._port.uiAttribs.addPort) this._dot.setShape(12);
                else this._dot.setShape(6);

                this._dot.setSize(dotSize, dotSize);
                this._dot.setPosition(gluiconfig.portWidth / 2 - dotSize / 2, dotPosY);
            }
            else
            {
                this._dot = this._dot.dispose();
            }
        }

        let hover = this._hover;

        for (const i in this._glop._links)
            if (this._glop._links[i].portIdIn == this._id || this._glop._links[i].portIdOut == this._id)
                if (this._glop._links[i].hovering) { hover = true; break; }

        const col = GlPort.getColor(this._type, hover, false, this._activity);
        this._rect.setColor(col);

        if (this._port.uiAttribs.addPort) this._rect.setOpacity(0.7);
        else this._rect.setOpacity(1);

        if (this._port.uiAttribs.hasOwnProperty("opacity")) this._rect.setOpacity(this._port.uiAttribs.opacity);
    }

    get direction()
    {
        return this._direction;
    }

    get width()
    {
        return this._rect.w;
    }

    updateSize()
    {
        if (!this._rect) return;

        let h = gluiconfig.portHeight * 2;
        let y = 0;

        if (this._port.direction == CABLES.PORT_DIR_OUT) y = this._glop.h;

        if (this._port.isLinked())
        {
            if (this._port.direction == CABLES.PORT_DIR_IN) y += gluiconfig.portHeight * 0.5;
            h = gluiconfig.portHeight * 1.5;
        }

        y -= gluiconfig.portHeight;

        if (this._glop.displayType === this._glop.DISPLAY_REROUTE_DOT)
        {
            h = 0;
            if (this._port.direction == CABLES.PORT_DIR_IN) y = 0;
            else y = this._glop.h;
        }

        this.updateShape();

        this._posX = this._glop.getPortPos(this._name, false);

        this._rect.setPosition(this._posX, y, -0.001);
        this._rect.setSize(gluiconfig.portWidth, h);

        if (this._longPortRect)
        {
            let n = this._port.op.getNumVisiblePortsIn();
            if (this._direction == CABLES.PORT_DIR_OUT) n = this._port.op.getNumVisiblePortsOut();

            const lastposX = this._port.op.posByIndex(this._port.uiAttribs.longPort + this.portIndex - 1, n);


            this._longPortRect.setSize(lastposX - this._posX, gluiconfig.portLongPortHeight);
            // (this._port.uiAttribs.longPort) * (gluiconfig.portPadding + gluiconfig.portWidth) - gluiconfig.portPadding

            let yl = gluiconfig.portHeight - gluiconfig.portLongPortHeight;
            if (this._direction == CABLES.PORT_DIR_OUT) yl = this._parent.h - gluiconfig.portHeight;

            this._longPortRect.setPosition(this._posX, yl, -0.0001);
        }
    }

    _onLinkChanged()
    {
        if (this._glop.op && this._glop.op.uiAttribs.mathTitle) this._glop.setTitle();
        this.updateSize();
    }

    _onMouseDown(e, rect)
    {
        if (e.buttons == MouseState.BUTTON_RIGHT) this._mouseButtonRightTimeDown = performance.now();

        this._glPatch.emitEvent("mouseDownOverPort", this, this._glop.id, this._port.name, e);
    }

    _onMouseUp(e, rect)
    {
        if (this._mouseButtonRightTimeDown)
        {
            if (performance.now() - this._mouseButtonRightTimeDown < gluiconfig.clickMaxDuration)
            {
                this._port.removeLinks();
                this._mouseButtonRightTimeDown = 0;
                return;
            }
        }
        this._glPatch.emitEvent("mouseUpOverPort", this._port.op.id, this._port, e);
    }

    _onHover(rect)
    {
        if (!this._glPatch.hasFocus) return;

        this._hover = true;
        const event = {
            "clientX": this._glPatch.viewBox.mouseX,
            "clientY": this._glPatch.viewBox.mouseY - 25
        };

        this._glPatch.emitEvent("mouseOverPort", this._glop.id, this._port.name);

        for (const i in this._glop._links)
            if (this._glop._links[i].portIdIn == this._id || this._glop._links[i].portIdOut == this._id)
                this._glop._links[i].highlight(true);


        updateHoverToolTip(event, this._port, false);
        this._updateColor();
    }

    _onUnhover(rect)
    {
        this._hover = false;
        clearInterval(CABLES.UI.hoverInterval);
        CABLES.UI.hoverInterval = -1;
        CABLES.UI.hideToolTip();

        for (const i in this._glop._links)
            this._glop._links[i].highlight(false);

        this._updateColor();
    }

    get hovering() { return this._hover; }

    get type() { return this._port.type; }

    get port() { return this._port; }

    get id() { return this._id; }

    get name() { return this._name; }

    get glOp() { return this._glop; }

    get rect() { return this._rect; }

    setFlowModeActivity(a)
    {
        if (this._activity != this._port.apf)
        {
            this._activity = this._port.apf;
            this._updateColor();
        }
    }

    dispose()
    {
        this.disposed = true;
        for (const i in this._glop._links)
            if (this._glop._links[i].portIdIn == this._id || this._glop._links[i].portIdOut == this._id)
                this._glop._links[i].visible = false;

        for (let i = 0; i < this._mouseEvents.length; i++)
            this._rect.off(this._mouseEvents[i]);

        this._mouseEvents.length = 0;
        if (this._rect) this._rect = this._rect.dispose();
        if (this._dot) this._dot = this._dot.dispose();
        if (this._longPortRect) this._longPortRect = this._longPortRect.dispose();
    }
}


GlPort.getInactiveColor = (type) =>
{
    const perf = CABLES.UI.uiProfiler.start("[glport] getInactiveColor");
    let portname = "";

    if (type == CABLES.OP_PORT_TYPE_VALUE) portname = "num";
    else if (type == CABLES.OP_PORT_TYPE_FUNCTION) portname = "trigger";
    else if (type == CABLES.OP_PORT_TYPE_OBJECT) portname = "obj";
    else if (type == CABLES.OP_PORT_TYPE_ARRAY) portname = "array";
    else if (type == CABLES.OP_PORT_TYPE_STRING) portname = "string";
    else if (type == CABLES.OP_PORT_TYPE_DYNAMIC) portname = "dynamic";

    const name = portname + "_inactive";

    let col = gui.theme.colors_types[name] || gui.theme.colors_types[portname] || [0, 0, 0, 1];

    perf.finish();

    return col;
};

GlPort.getColorBorder = (type, hovering, selected) =>
{
    const perf = CABLES.UI.uiProfiler.start("[glport] getcolorBorder");
    let name = "";
    let portname = "";

    if (type == CABLES.OP_PORT_TYPE_VALUE) portname = "num";
    else if (type == CABLES.OP_PORT_TYPE_FUNCTION) portname = "trigger";
    else if (type == CABLES.OP_PORT_TYPE_OBJECT) portname = "obj";
    else if (type == CABLES.OP_PORT_TYPE_ARRAY) portname = "array";
    else if (type == CABLES.OP_PORT_TYPE_STRING) portname = "string";
    else if (type == CABLES.OP_PORT_TYPE_DYNAMIC) portname = "dynamic";

    let coll = [1, 0.9, 0.8, 0];
    if (hovering)
    {
        name = portname + "_hover";
        coll = gui.theme.colors_types[name] || gui.theme.colors_types[portname] || [1, 0, 0, 1];
    }
    else if (selected)
    {
        // name = portname + "_selected";
        coll = gui.theme.colors_patch.selectedCable;
    }
    else return coll;

    let col = [coll[0], coll[1], coll[2], coll[3]];

    if (!hovering && !selected)col[3] = 0;
    perf.finish();

    return col;
};

GlPort.getColor = (type, hovering, selected, activity) =>
{
    const perf = CABLES.UI.uiProfiler.start("[glport] getcolor");

    let name = "";
    let portname = "";

    if (type == CABLES.OP_PORT_TYPE_VALUE) portname = "num";
    else if (type == CABLES.OP_PORT_TYPE_FUNCTION) portname = "trigger";
    else if (type == CABLES.OP_PORT_TYPE_OBJECT) portname = "obj";
    else if (type == CABLES.OP_PORT_TYPE_ARRAY) portname = "array";
    else if (type == CABLES.OP_PORT_TYPE_STRING) portname = "string";
    else if (type == CABLES.OP_PORT_TYPE_DYNAMIC) portname = "dynamic";

    if (activity == 0)name = portname + "_inactive";

    if (hovering)name = portname + "_hover";
    // else if (selected)name = portname + "_selected";

    let col = gui.theme.colors_types[name] || gui.theme.colors_types[portname] || [1, 0, 0, 1];

    perf.finish();

    return col;
};