/*
 * PanedWindow.cpp
 *
 * Copyright (C) 1999 Stephen F. White
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program (see the file "COPYING" for details); if 
 * not, write to the Free Software Foundation, Inc., 675 Mass Ave, 
 * Cambridge, MA 02139, USA.
 */

#include "stdafx.h"
#include "swt.h"
#include "PanedWindow.h"

#define SASH_WIDTH 5

enum {
    NORMAL,
    TRACK_TOP,
    TRACK_BOTTOM,
    TRACK_LEFT,
    TRACK_RIGHT
};

PanedWindow::PanedWindow(Scene *scene, SWND wnd, bool sashes)
  : SceneView(scene, wnd)
{
    _sashes = sashes;
    _top = _left = _bottom = _right = _center = NULL;
    _state = NORMAL;
    _cursorH = swLoadCursor(SW_CURSOR_DBL_ARROW_HORZ);
    _cursorV = swLoadCursor(SW_CURSOR_DBL_ARROW_VERT);
    _cursorNormal = swLoadCursor(SW_CURSOR_ARROW);
}

PanedWindow::~PanedWindow()
{
    swDestroyCursor(_cursorH);
    swDestroyCursor(_cursorV);
    swDestroyCursor(_cursorNormal);
}

void
PanedWindow::OnSize(int width, int height)
{
    Layout();
}

void
PanedWindow::Layout(bool maximize)
{
    int width, height, rw, rh;
    int w, h, left = 0, top = 0;
#ifdef _WIN32
    if (maximize) {
        swGetScreenSize(&width, &height);
        swSetSize(_wnd,width,height);
    } else {
        swGetSize(_wnd, &width, &height);
        // otherwise problems with iconify/deiconify ... 
        if ((width==0) && (height==0))
            swGetScreenSize(&width, &height);
    }
//    return;
#else
    swGetSize(_wnd, &width, &height);
#endif
    bool showTop = _top && swIsVisible(_top->GetWindow());
    bool showBottom = _bottom && swIsVisible(_bottom->GetWindow());
    bool showLeft = _left && swIsVisible(_left->GetWindow());
    bool showRight = _right && swIsVisible(_right->GetWindow());
    bool showCenter = _center && swIsVisible(_center->GetWindow());

    swInvalidateRect(_wnd, 0, 0, width, height);
    rw = width;  
    rh = height;

    if (showLeft && _sashes) rw -= SASH_WIDTH;
    if (showRight && _sashes) rw -= SASH_WIDTH;
    if (rw < 0) rw = 0;

    if (showTop && _sashes) rh -= SASH_WIDTH;
    if (showBottom && _sashes) rh -= SASH_WIDTH;
    if (rh < 0) rh = 0;

    if (showTop) {
        swGetSize(_top->GetWindow(), &w, &h);
        if (h > rh) h = rh;
        swSetSize(_top->GetWindow(), width, h);
        top = h;
        if (_sashes) top += SASH_WIDTH;
        rh -= h;
        if (rh < 1) rh = 1;
    }
    if (showBottom) {
        swGetSize(_bottom->GetWindow(), &w, &h);
        if (h > rh) h = rh;
        swMoveWindow(_bottom->GetWindow(), 0, height - h, width, h);
        rh -= h;
        if (rh < 1) rh = 1;
    }
    if (showLeft) {
        swGetSize(_left->GetWindow(), &w, &h);
        if (w > rw) w = rw;
        swMoveWindow(_left->GetWindow(), 0, top, w, rh);
        left = w;
        if (_sashes) left += SASH_WIDTH;
        rw -= w;
        if (rw < 1) rw = 1;
    }
    if (showRight) {
        swGetSize(_right->GetWindow(), &w, &h);
        if (w > rw) w = rw;
        swMoveWindow(_right->GetWindow(), width - w, top, w, rh);
        rw -= w;
        if (rw < 1) rw = 1;
    }
    if (showCenter) {
        swMoveWindow(_center->GetWindow(), left, top, rw, rh);
    }
}

void
PanedWindow::SetPane(SceneView *pane, int direction)
{
    switch (direction) {
      case PW_TOP:
        _top = pane;
        break;
      case PW_BOTTOM:
        _bottom = pane;
        break;
      case PW_LEFT:
        _left = pane;
        break;
      case PW_RIGHT:
        _right = pane;
        break;
      case PW_CENTER:
        _center = pane;
        break;
    }
}

int
PanedWindow::HitTest(int x, int y)
{
    int width, height;
    int twidth = 0, theight = 0;
    int bwidth = 0, bheight = 0;
    int lwidth = 0, lheight = 0;
    int rwidth = 0, rheight = 0;

    swGetSize(_wnd, &width, &height);
    if (_top) swGetSize(_top->GetWindow(), &twidth, &theight);
    if (_bottom) swGetSize(_bottom->GetWindow(), &bwidth, &bheight);
    if (_left) swGetSize(_left->GetWindow(), &lwidth, &lheight);
    if (_right) swGetSize(_right->GetWindow(), &rwidth, &rheight);
    if (_top && y >= theight && y < theight + SASH_WIDTH) {
        return TRACK_TOP;
    } else if (_bottom && y >= height - bheight - SASH_WIDTH && y < height - bheight) {
        return TRACK_BOTTOM;
    } else if (_left && x >= lwidth && x < lwidth + SASH_WIDTH) {
        return TRACK_LEFT;
    } else if (_right && x >= width - rwidth - SASH_WIDTH && x < width - rwidth) {
        return TRACK_RIGHT;
    } else {
        return NORMAL;
    }
}

void
PanedWindow::UpdateCursor(int state)
{
#ifndef _WIN32
    if (!TheApp->useStereo()) {
        if (state == TRACK_TOP || state == TRACK_BOTTOM) {
            swSetCursor(_wnd, _cursorV);
        } else if (state == TRACK_LEFT || state == TRACK_RIGHT) {
            swSetCursor(_wnd, _cursorH);
        } else {
            swSetCursor(_wnd, _cursorNormal);
        }
    }
#endif
}

void
PanedWindow::OnMouseMove(int x, int y, int modifiers)
{
    int width, height;
    int lwidth = 0, lheight = 0;

    if (!_sashes) return;

    if (_state == NORMAL) {
        UpdateCursor(HitTest(x, y));
    } else {
        swGetSize(_wnd, &width, &height);
        x = CLAMP(x, 1, width - 1);
        y = CLAMP(y, 1, height - 1);
        if (_left) swGetSize(_left->GetWindow(), &lwidth, &lheight);
        if (_state == TRACK_TOP) {
            swSetSize(_top->GetWindow(), width, y);
        } else if (_state == TRACK_BOTTOM) {
            swSetSize(_bottom->GetWindow(), width, height - y);
        } else if (_state == TRACK_LEFT) {
            swSetSize(_left->GetWindow(), x, lheight);
        } else if (_state == TRACK_RIGHT) {
            int rwidth, rheight;
            swGetSize(_right->GetWindow(), &rwidth, &rheight);
            swSetSize(_right->GetWindow(), width - x, rheight);
        }
        Layout();
    }
}

void
PanedWindow::OnMouseLeave()
{
    UpdateCursor(_state);
}

void
PanedWindow::OnLButtonDown(int x, int y, int modifiers)
{
    if (!_sashes) return;

    _state = HitTest(x, y);
    UpdateCursor(_state);
    if (_state != NORMAL) swSetCapture(_wnd);
}

void
PanedWindow::OnLButtonUp(int x, int y, int modifiers)
{
    if (!_sashes) return;

    _state = NORMAL;
    swReleaseCapture(_wnd);
    swSetCursor(_wnd, _cursorNormal);
}

void
PanedWindow::OnDraw(int x, int y, int width, int height)
{
    if (!_sashes) return;

    int top = 0;
    SDC dc = swCreateDC(_wnd);

    swGetSize(_wnd, &width, &height);
    if (_top && swIsVisible(_top->GetWindow())) {
        int w, h;
        swGetSize(_top->GetWindow(), &w, &h);
        DrawHSash(dc, 0, h, width, SASH_WIDTH);
        top = h + SASH_WIDTH;
    }
    if (_bottom && swIsVisible(_bottom->GetWindow())) {
        int w, h;
        swGetSize(_bottom->GetWindow(), &w, &h);
        DrawHSash(dc, 0, height - h - SASH_WIDTH, width, SASH_WIDTH);
    }
    if (_left && swIsVisible(_left->GetWindow())) {
        int w, h;
        swGetSize(_left->GetWindow(), &w, &h);
        DrawVSash(dc, w, top, SASH_WIDTH, h);
    }
    if (_right && swIsVisible(_right->GetWindow())) {
        int w, h;
        swGetSize(_right->GetWindow(), &w, &h);
        DrawVSash(dc, width - w - SASH_WIDTH, top, SASH_WIDTH, h);
    }
    swDestroyDC(dc);
}

void
PanedWindow::DrawVSash(SDC dc, int x, int y, int w, int h)
{
    swSetFGColor(dc, swGetWindowColor(_wnd, SW_COLOR_TSHADOW));
    swDrawLine(dc, x, y, x, y + h - 1);
    swSetFGColor(dc, swGetWindowColor(_wnd, SW_COLOR_BSHADOW));
    swDrawLine(dc, x + w - 1, y, x + w - 1, y + h - 1);
    swSetFGColor(dc, swGetWindowColor(_wnd, SW_COLOR_FACE));
    swFillRect(dc, x + 1, y, w - 2, h - 1);
}

void
PanedWindow::DrawHSash(SDC dc, int x, int y, int w, int h)
{
    swSetFGColor(dc, swGetWindowColor(_wnd, SW_COLOR_TSHADOW));
    swDrawLine(dc, x, y, x + w - 1, y);
    swSetFGColor(dc, swGetWindowColor(_wnd, SW_COLOR_BSHADOW));
    swDrawLine(dc, x, y + h - 1, x + w - 1, y + h - 1);
    swSetFGColor(dc, swGetWindowColor(_wnd, SW_COLOR_FACE));
    swFillRect(dc, x, y + 1, w - 1, h - 2);
}
