Newer
Older
lostmynuts / shared / js / Engine / Display / DrawableButton.js
var DrawableButtonStatics = {};
DrawableButtonStatics.MinClickRegionPosition = {"CENTER": 0, "LEFT_ALIGN": 1, "Right_ALIGN": 2}

Engine.DrawableButton = class extends Engine.Drawable
{
	constructor(graphicName, text)
	{
		super();

        if (graphicName === undefined) graphicName = "";
        if (text === undefined) text = "";

		this.onClick = null;

		this._isTwoStateToggle = false;
		this._isToggle = false;
		this._toggled = false;
		this.mousedOver = false;

        this.disabledFrame = 0;
	    this.normalFrame = 1;
	    this.hoverFrame = 2;

	    this.toggledStateNormalFrame = 3;
	    this.toggledStateHoverFrame = 4;

	    this._bySequence = false;
	    this.matchTextSize = true;
	    this.constrainText = false;
	    this.minAutoWidth = 60;

	    this._enabled = true;
    	this.desiredFrame = 1;

        this.clickRegionDebugClip;
        this.showClickRegionDebug = false;

        this._minimumClickRegionSize = 40;
        this.clickRegionPosition = DrawableButtonStatics.MinClickRegionPosition.CENTER;

        this.sized = false;
        this.textOffsetX = 0;
        this.textOffsetY = -2;
        this.shadowOffsetX = 1;
        this.shadowOffsetY = 1;

        this.showClickHighlight = true;
        this.fadeTime = 0.5;
        this.highlightFadeTween = new Engine.SimpleTween();

        this._text = new Engine.DrawableText;
        this._text.setDropShadow();
        this.backgroundHighlight = new Engine.Drawable();
        this.backgroundHighlight.additive = true;

        this.background = new Engine.Drawable();
        this.backgroundDelight = new Engine.Drawable();
        this.backgroundDelight.x = 2;
        this.backgroundDelight.alpha = 0.4;
        this.dulled = false;

        // this.background.interactive = true;
        // this.background.on('pointertap', (event) => { this.clicked(event); } );
        // this.background.on('pointerover', (event) => { this.mouseOver(event); } );
        // this.background.on('pointerout', (event) => { this.mouseOut(event); } );
        // this.background.on('pointerdown', (event) => { this.mouseDown(event); } );
        // this.background.on('pointerup', (event) => { this.mouseUp(event); } );
        this.background.mouseEnabled = true;
        this.background.events.onClick.addListener(this, this.clicked);
		this.background.events.onMouseOver.addListener(this, this.mouseOver);
        this.background.events.onMouseOut.addListener(this, this.mouseOut);
        this.background.events.onMouseDown.addListener(this, this.mouseDown);
        this.background.events.onMouseUp.addListener(this, this.mouseUp);
        
        this.iconIsSet = false;
        this.iconInset = 3;
        this._iconOffsetX = 0;
        this._iconOffsetY = 0;
        this.icon = null;
		
		this.repeatOnHold = false;
		this.repeatOnHoldTime = 0.5;
		this.repeatOnHoldRatePerSecond = 4;
		this.clickAndHoldTimer = 0;

        if (graphicName && graphicName != "")
        {
            this.init(graphicName, text);
        }
	}

    get text() { return this._text; } 

    get isTwoStateToggle() { return this._isTwoStateToggle; }
	set isTwoStateToggle(value)
	{
        this._isTwoStateToggle = value;
        if (this._isTwoStateToggle) this._isToggle = false;
        this._toggled = false;
        this.calculateFrame();
    }

    get isToggle() { return this._isToggle; }
    set isToggle(value) {
        this._isToggle = value;
        if (this._isToggle) this._isTwoStateToggle = false;
        this._toggled = false;
        this.calculateFrame();
    }

    get toggled(){ return this._toggled; }
   	set toggled(value) {
        this._toggled = value;
        this.calculateFrame();
    }

    get bySequence() { return this._bySequence; }
    set bySequence(value) { this._bySequence = value; this.calculateFrame(); }

    calculateFrame()
    {
        var frame;
        if (this.enabled)
        {
            if (this.isTwoStateToggle)
            {
                frame = this.toggled ? this.toggledStateNormalFrame : this.normalFrame;
                if (this.mousedOver) frame = this.toggled ? this.toggledStateHoverFrame : this.hoverFrame;
            }
            else
            {
                frame = this.normalFrame;
                if (this.isToggle && !this.toggled) frame = this.disabledFrame;
                if (this.mousedOver) frame = this.hoverFrame;
            }
        } 
        else 
        {
            frame = this.disabledFrame;
            if (this.isToggle && this.toggled) frame = this.normalFrame;
        }
        if (!this.bySequence)
        {
            if (frame != this.background.frame) this.background.gotoAndStop(frame);
        } 
        else 
        {
            if (frame != this.background.sequence) this.background.setSequence(frame);
        }
    }

    get enabled() { return this._enabled; }
    set enabled(value)
    {
        this._enabled = value;
        this.calculateFrame();
    }

    init(bgGraphicName, text, font, fontSize)
    {
        if (text === undefined) text = "";
        if (font === undefined) font = "Tiamat";
        if (fontSize === undefined) fontSize = 14;

        this.name = "Button_" + text;

        this.background.onGraphicLoaded.setListener(this, (graphic) => { this.background_OnGraphicLoaded(graphic); });
        this.background.setGraphicDataByName(bgGraphicName);

        this.setButtonText(text, font, fontSize);

        this.addChild(this.background);
        this.addChild(this._text);

        this.calculateFrame();
    }

    setBackgroundGraphic(bgGraphicName)
    {
        this.background.loadFromGraphicName(bgGraphicName);
    }

    background_OnGraphicLoaded(drawable)
    {
        this.resizeClickRegion();
    }

    get minimumClickRegionSize() { return this._minimumClickRegionSize; }
    set minimumClickRegionSize(value) { this._minimumClickRegionSize = value; this.resizeClickRegion(); }  

    resizeClickRegion()
    {
        if (this.clickRegionDebugClip != null && this.clickRegionDebugClip.parent != null)
        {
            this.clickRegionDebugClip.parent.removeChild(this.clickRegionDebugClip);
        }

        var clickRect = this.background.getLocalBounds();
        if (clickRect.width < this.minimumClickRegionSize)
        {
            var difx = this.minimumClickRegionSize - Math.floor(clickRect.width);
            if (this.clickRegionPosition == DrawableButtonStatics.MinClickRegionPosition.CENTER)
            {
                var ratio = (clickRect.left / clickRect.width);
                if (Math.abs(clickRect.left) < 5) ratio = -0.5;
                var leftDif = Math.floor(ratio * difx);
                clickRect.x += leftDif; // difx / 2;
            }
            else if (this.clickRegionPosition == DrawableButtonStatics.MinClickRegionPosition.LEFT_ALIGN)
            {
                // DO NOTHING
            }
            else if (this.clickRegionPosition == DrawableButtonStatics.MinClickRegionPosition.RIGHT_ALIGN)
            {
                clickRect.x -= difx;
            }

            clickRect.width = this.minimumClickRegionSize;
        }

        if (clickRect.height < this.minimumClickRegionSize)
        {
            var dify = this.minimumClickRegionSize - Math.floor(clickRect.height);
            var ratio = (clickRect.top / clickRect.height);
            if (Math.abs(clickRect.top) < 5) ratio = -0.5;

            var topDif = Math.floor(ratio * dify);
            clickRect.y += topDif;// dify / 2;
            clickRect.height = this.minimumClickRegionSize;
        }

        this.background.hitArea = clickRect;

        this.fixHighlight();

        if (this.showClickRegionDebug)
        {
            if (this.clickRegionDebugClip == null) this.clickRegionDebugClip = new PIXI.Graphics();
            this.background.addChild(this.clickRegionDebugClip);
            this.clickRegionDebugClip.x = clickRect.x;
            this.clickRegionDebugClip.y = clickRect.y;
            this.clickRegionDebugClip.clear();
            this.clickRegionDebugClip.beginFill(0xFFFFFF, 0.5);
            this.clickRegionDebugClip.drawRect(0, 0, Math.floor(clickRect.width), Math.floor(clickRect.height));
        }
    }

    fixHighlight()
    {
        if (this.backgroundHighlight.graphicName != this.background.graphicName)
        {
            this.backgroundHighlight.setGraphicDataByName(this.background.graphicName); 
        }
        if (this.sized)
        {
            this.backgroundHighlight.setNineRect();
            this.backgroundHighlight.additive = true;
            this.backgroundHighlight.width = this.background.width;
            this.backgroundHighlight.height = this.background.height;
        }
    }

    setButtonText(text, font, fontSize, align)
    {
        if (font === undefined) font = "Tiamat";
        if (fontSize === undefined) fontSize = 14;

        if (align === undefined) this._text.setText(text, font, fontSize);
        else this._text.setText(text, font, fontSize, align);
        var textWidth = this.constrainText ? this._text.textAreaWidth : this._text.width;

        this._text.x = this.textOffsetX + (this.background.width - textWidth) / 2;
        this._text.y = this.textOffsetY + (this.background.height - this._text.height) / 2;

        if (text && text.length > 0 && this.matchTextSize)
        {
            this.setWidth(Math.floor(Math.max(this.minAutoWidth, this._text.width + 10)));
        }

        this._text.x = Math.floor(this._text.x);
        this._text.y = Math.floor(this._text.y);
    }

    setDimensions(width, height)
    {
        if (width === undefined) width = -1;
        if (height === undefined) height = -1;

        this.setWidth(width);
        this.setHeight(height);
    }

    setWidth(width)
    {
        this.sized = true;
        this.background.setNineRect();
        this.background.width = width;
        this.backgroundDelight.setAsBox(this.backgroundDelight.graphics, Math.floor(this.background.width) - 3, Math.floor(this.background.height) - 3, Colors.grey, 1);
        //this.background.cacheAsBitmap = true;

        var textWidth = this._text.width;
        this._text.x = this.textOffsetX + (this.background.width - textWidth) / 2;
        this._text.y = this.textOffsetY + (this.background.height - this._text.height) / 2;

        if (this.iconIsSet)
        {
            this.setIconSize(Math.floor(this.background.width), Math.floor(this.background.height), this.iconInset);
        }

        this.resizeClickRegion();
        
        //this._text.x = Math.floor(this._text.x);
        //this._text.y = Math.floor(this._text.y);
    }

   	setHeight(height)
    {
        this.sized = true;
        this.background.setNineRect();
        this.background.height = height;
        this.backgroundDelight.setAsBox(this.backgroundDelight.graphics, Math.floor(this.background.width) - 3, Math.floor(this.background.height) - 3, Colors.grey, 1);

        this._text.x = this.textOffsetX + (this.background.width - this._text.width) / 2;
        this._text.y = this.textOffsetY + (this.background.height - this._text.height) / 2;

        if (this.iconIsSet)
        {
            this.setIconSize(Math.floor(this.background.width), Math.floor(this.background.height), this.iconInset);
        }

        this.resizeClickRegion();

        //this._text.x = Math.floor(this._text.x);
        //this._text.y = Math.floor(this._text.y);
    }

    get width()
    {
        return this.background.width;
    }

    get height()
    {
        return this.background.height;
    }

    // ============= Icon Stuff ==========================
    get iconOffsetX() { return this._iconOffsetX; }
    set iconOffsetX(value) { this._iconOffsetX = value; this.icon.x = this.iconInset + value; }
    get iconOffsetY() { return this._iconOffsetY; }
    set iconOffsetY(value) { this._iconOffsetY = value; this.icon.y = this.iconInset + value; }

    setIcon(icon, inset)
    {
        if (inset === undefined) inset = 3;

        if (this.icon == null) this.icon = new Engine.UniformScaleGraphic();
        this.iconInset = inset;

        if (Number.isInteger(icon)) { this.icon.setGraphicByID(icon); }
        else { this.icon.setGraphicByName(icon); }

        this.setIconInternal();
    }

    setIconInternal()
    {
        this.setIconSize(Math.floor(this.background.width), Math.floor(this.background.height), this.iconInset);
        this.addChild(this.icon);
        this.icon.greyscale = !this.enabled;
        this.iconIsSet = true;
    }

    removeIcon()
    {
        if (this.icon == null) return;
        this.removeChild(this.icon);
        this.iconIsSet = false;
    }

    setIconSize(width, height, inset)
    {
        if (this.icon == null) return;
        this.icon.setSize(width - inset * 2, height - inset * 2);
        this.icon.x = inset + this.iconOffsetX;
        this.icon.y = inset + this.iconOffsetY;
    }

    // ============= Highlight stuff ==========================

    showHighlight()
    {
        if (this.highlightFadeTween.active) this.highlightFadeTween.stop();
        this.backgroundHighlight.gotoAndStop(this.background.frame);
        this.backgroundHighlight.alpha = 1;
        this.addChildAt(this.backgroundHighlight, this.getChildIndex(this.background) + 1);
    }

    fadeHighlight()
    {
        this.highlightFadeTween.init( (a) => { this.backgroundHighlight.alpha = a;}, Engine.SimpleTween.easeLinear, 1, 0, this.fadeTime);
        this.highlightFadeTween.onFinish = () => { this.highlightFaded(); };
    }

    highlightFaded()
    {
        this.removeChild(this.backgroundHighlight);
    }

    // ============= Dull stuff ==========================
    showDelight()
    {
        if (this.dulled) return;
        this.dulled = true;

        if (this.backgroundHighlight.hasParent)
        {
            this.addChildAt(this.backgroundDelight, this.getChildIndex(this.backgroundHighlight) + 1);
        }
        else
        {
            this.addChildAt(this.backgroundDelight, this.getChildIndex(this.background) + 1);
        }
    }

    hideDelight()
    {
        if (!this.dulled) return;
        this.dulled = false;

        this.removeChild(this.backgroundDelight);
    }

    ///============== Mouse Events =============================
    clicked(d)
    {
        if (!this.enabled) return;

        if (this.isToggle || this.isTwoStateToggle)
        {
            this.toggled = !this.toggled;
            this.mousedOver = false;
            this.calculateFrame();
        }
        if (this.onClick != null) this.onClick();
        //Engine.SoundPlayerInstance.playSound(13, 0.5); 13 is baaad
    }

    mouseOver(d)
    {
        this.mousedOver = true;
        this.calculateFrame();

        if (this.enabled) Engine.SoundPlayerInstance.playSound(15, 0.5);
    }

    mouseDown(d)
    {
        if (this.enabled && this.showClickHighlight)
        {
            Engine.Mouse.addEventListener("mouseup", this, this.globalMouseUp);
            this.showHighlight();
			if (this.repeatOnHold) this.startClickAndHold();
        }
    }

    mouseUp(d)
    {
        //this.fadeHighlight();
        //this.globalMouseUp();
    }

    globalMouseUp(v)
    {
        Engine.Mouse.removeEventListener("mouseup", this);
        this.fadeHighlight();
		if (this.repeatOnHold) this.stopClickAndHold();
    }

    mouseOut(d)
    {
        this.mousedOver = false;
        this.calculateFrame();
    }
	
	startClickAndHold()
	{
		this.clickAndHoldTimer = 1 / this.repeatOnHoldRatePerSecond;
		Engine.EnterFrameManagerInstance.add(this, this.updateClickAndHold);
	}

	updateClickAndHold(dt)
	{
		this.clickAndHoldTimer += dt;
		if (this.clickAndHoldTimer > this.repeatOnHoldTime + (1 / this.repeatOnHoldRatePerSecond))
		{
			this.clicked(null);
			this.clickAndHoldTimer = this.repeatOnHoldTime;
		}
	}

	stopClickAndHold()
	{
		Engine.EnterFrameManagerInstance.remove(this);
	}
}