/**
 @file G3UI.cpp

 Dojo Game Engine

 Copyright 2005, Morgan McGuire
 All rights reserved.
 */

#include "dojo/G3UI.h"

namespace dojo {

// Window constants
const Color4 G3UI::activeBackColor         = Color4::fromARGB(0xD0B9C7D7);
const Color4 G3UI::inactiveBackColor       = Color4::fromARGB(0xA0B9C7D7);

const Color4 G3UI::activeTitleBarColor     = Color4::fromARGB(0xFFC29D69);
const Color4 G3UI::inactiveTitleBarColor   = Color4::fromARGB(0xA0B9C7D7);

const Color4 G3UI::activeBorderColor       = Color3::black();
const Color4 G3UI::inactiveBorderColor     = Color4::fromARGB(0xD0CCCCCC);

const Color4 G3UI::buttonColor             = Color4::fromARGB(0xFFE0E0E0);
const Color4 G3UI::buttonHilightColor      = Color4::fromARGB(0xFFFFFFFF);
const Color4 G3UI::buttonDarkColor         = Color4::fromARGB(0xFF707070);
const Color4 G3UI::buttonShadowColor       = Color4::fromARGB(0xFF000000);

const Color4 G3UI::buttonCaptionColor       = Color3::black();

const Color4 G3UI::activeTitleBarTitleColor = Color3::black();
const Color4 G3UI::inactiveTitleBarTitleColor= Color3::black();

const float  G3UI::titleBarHeight            = 14;

void G3UI::drawSlider(RenderDevice* rd, const Rect2D& rect, float f, bool thumbPushed) {

    // Groove
    float midline = floor(rect.center().y);

    Draw::fastRect2D(Rect2D::xywh(rect.x0(), midline - 1, rect.width(), 1), rd, buttonDarkColor);
    Draw::fastRect2D(Rect2D::xywh(rect.x0(), midline, 1, 2), rd, buttonDarkColor);

    Draw::fastRect2D(Rect2D::xywh(rect.x0() + 1, midline, rect.width() - 2, 1), rd, buttonShadowColor);
    Draw::fastRect2D(Rect2D::xywh(rect.x0() + 1, midline + 1, rect.width() - 2, 1), rd, buttonColor);

    Draw::fastRect2D(Rect2D::xywh(rect.x1() - 1, midline - 1, 1, 3), rd, buttonHilightColor);
    Draw::fastRect2D(Rect2D::xywh(rect.x0(), midline + 2, rect.width(), 1), rd, buttonHilightColor);

    Rect2D thumb = Rect2D::xywh(0, 0, 8, 16);

    // Thumb
    drawButton(
        rd, 
        thumb + Vector2(G3D::lerp((float)rect.x0(), (float)(rect.x1() - thumb.width()), f), 
                        midline - thumb.height() / 2 + 1), 
        NULL, 
        thumbPushed);
}


void G3UI::drawButton(RenderDevice* rd, const Rect2D& rect, TextureRef icon, bool buttonPushed) {
    const Color4& UR = buttonPushed ? buttonShadowColor : buttonHilightColor;
    const Color4& LL = buttonPushed ? buttonHilightColor : buttonShadowColor;

    // Body
    if (buttonColor.a > 0) {
        Draw::fastRect2D(Rect2D::xyxy(rect.x0y0() + Vector2(1, 1), rect.x1y1() - Vector2(2, 2)), rd, buttonColor);
    }

    // Hilight
    Draw::fastRect2D(Rect2D::xywh(rect.x0(), rect.y0(), rect.width() - 1, 1), rd, UR);
    Draw::fastRect2D(Rect2D::xywh(rect.x0(), rect.y0() + 1, 1, rect.height() - 2), rd, UR);

    // Dark
    if (buttonPushed) {
        Draw::fastRect2D(Rect2D::xywh(rect.x0() + 1, rect.y0() + 1, rect.width() - 2, 1), rd, buttonDarkColor);
        Draw::fastRect2D(Rect2D::xywh(rect.x0() + 1, rect.y0() + 2, 1, rect.height() - 3), rd, buttonDarkColor);
    } else {
        Draw::fastRect2D(Rect2D::xywh(rect.x0() + 1, rect.y1() - 2, rect.width() - 2, 1), rd, buttonDarkColor);
        Draw::fastRect2D(Rect2D::xywh(rect.x1() - 2, rect.y0() + 1, 1, rect.height() - 3), rd, buttonDarkColor);
    }

    // Shadow
    Draw::fastRect2D(Rect2D::xywh(rect.x0(), rect.y1() - 1, rect.width() - 1, 1), rd, LL);
    Draw::fastRect2D(Rect2D::xywh(rect.x1() - 1, rect.y0(), 1, rect.height()), rd, LL);

    // Icon
    if (icon.notNull()) {
        rd->setTexture(0, icon);
        float shift = buttonPushed ? 1 : 0;
        Draw::fastRect2D(
            Rect2D::xyxy(rect.x0y0() + Vector2(3 + shift, 3 + shift), 
                         rect.x1y1() + Vector2(-3 + shift, -3 + shift)), rd);
        rd->setTexture(0, NULL);
    }
}


void G3UI::drawWindow(RenderDevice* rd, GFontRef titleFont, const std::string& title, const Rect2D& rect, bool active) {
    const Color4& backColor     = active ? activeBackColor : inactiveBackColor;
    const Color4& borderColor   = active ? activeBorderColor : inactiveBorderColor;
    const Color4& titleBarColor = active ? activeTitleBarColor : inactiveTitleBarColor;
    const Color4& titleColor    = active ? activeTitleBarTitleColor : inactiveTitleBarTitleColor;

    const float   border        = 1;

    bool hasBorders = (border > 0) && (borderColor.a > 0);

    Rect2D titleBar = Rect2D::xywh(rect.x0() + border, rect.y0() + border, rect.width() - 2 * border, titleBarHeight - 1);
    Rect2D inside   = Rect2D::xyxy(rect.x0() + border, titleBar.y1() + (hasBorders ? 1 : 0), titleBar.x1(), rect.y1() - border);

    // Back
    if (backColor.a > 0) {
        Draw::fastRect2D(inside, rd, backColor);
    }

    // Frame
    if (hasBorders) {
        rd->setColor(borderColor);
        rd->beginPrimitive(RenderDevice::QUADS);
            const Vector2& v0 = rect.x0y0();
            const Vector2& v1 = rect.x0y1();
            const Vector2& v2 = rect.x0y1() + Vector2(border, -border);
            const Vector2& v3 = rect.x0y0() + Vector2(border, border);

            const Vector2& v4 = rect.x1y0();
            const Vector2& v5 = rect.x1y1();
            const Vector2& v6 = rect.x1y1() + Vector2(-border, -border);
            const Vector2& v7 = rect.x1y0() + Vector2(-border, border);

            // left
            rd->sendVertex(v0);
            rd->sendVertex(v1);
            rd->sendVertex(v2);
            rd->sendVertex(v3);

            // right
            rd->sendVertex(v7);
            rd->sendVertex(v6);
            rd->sendVertex(v5);
            rd->sendVertex(v4);

            // top
            rd->sendVertex(v0);
            rd->sendVertex(v3);
            rd->sendVertex(v7);
            rd->sendVertex(v4);

            // bottom
            rd->sendVertex(v2);
            rd->sendVertex(v1);
            rd->sendVertex(v5);
            rd->sendVertex(v6);
        rd->endPrimitive();
    }

    // Title
    if (titleBarColor.a > 0) {
        Draw::fastRect2D(titleBar, rd, titleBarColor);
    }
    titleFont->draw2D(rd, title, titleBar.x0y0() + Vector2(4, 1), titleBarHeight - 6, titleColor);

    if (borderColor.a > 0) {
        Rect2D titleBarLine = Rect2D::xywh(titleBar.x0(), titleBar.y1(), titleBar.width(), 1);
        Draw::fastRect2D(titleBarLine, rd, borderColor);
    }
}


void G3UI::drawCloseButton(RenderDevice* rd, const Rect2D& windowRect, bool pushed) {
    float buttonSize = titleBarHeight - 3;
    Rect2D buttonRect = Rect2D::xywh(windowRect.x1() - 3 - buttonSize, windowRect.y0() + 2, buttonSize, buttonSize);

    drawButton(rd, buttonRect, NULL, pushed);

    // Draw the X
    rd->setColor(Color3::black());
    rd->setLineWidth(1.5);
    rd->beginPrimitive(RenderDevice::LINES);
        rd->sendVertex(buttonRect.x0y0() + Vector2(2,2));
        rd->sendVertex(buttonRect.x1y1() + Vector2(-3,-3.5));

        rd->sendVertex(buttonRect.x1y0() + Vector2(-3,2));
        rd->sendVertex(buttonRect.x0y1() + Vector2(3,-3.5));
    rd->endPrimitive();
}


Rect2D G3UI::windowClientArea(const Rect2D& windowRect) {
    return Rect2D::xyxy(
        windowRect.x0() + 2,
        windowRect.y0() + 2 + titleBarHeight,
        windowRect.x1() - 2,
        windowRect.y1() - 2);
}


bool G3UI::inWindowTitleBar(const Vector2& pos, const Rect2D& windowRect) {
    return
        windowRect.contains(pos) &&
        (pos.y < windowRect.y0() + titleBarHeight);
}


bool G3UI::inCloseButton(const Vector2& pos, const Rect2D& windowRect) {
    float buttonSize = titleBarHeight - 3;
    Rect2D buttonRect = Rect2D::xywh(windowRect.x1() - 3 - buttonSize, windowRect.y0() + 2, buttonSize, buttonSize);
    return buttonRect.contains(pos);
}

}