/**************************************************************************

    This file is part of Xclass95, a Win95-looking GUI toolkit.
    Copyright (C) 1996, 1997 David Barth, Hector Peraza.

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

**************************************************************************/

#include <xclass/utils.h>
#include <xclass/OXClient.h>
#include <xclass/OXWidgets.h>
#include <xclass/OXCanvas.h>


//-----------------------------------------------------------------

OXCanvas::OXCanvas(const OXWindow *p, int w, int h,
           unsigned int options, unsigned long back) :
    OXFrame(p, w, h, options, back) {
    
  _vport = new OXViewPort(this, w-4, h-4, CHILD_FRAME | OWN_BKGND,
                                _whitePixel);
  _hscrollbar = new OXHScrollBar(this, w-4, SB_WIDTH);
  _vscrollbar = new OXVScrollBar(this, SB_WIDTH, h-4);

  _hscrollbar->Associate(this);
  _vscrollbar->Associate(this);

}
           
OXCanvas::~OXCanvas() {
  delete _hscrollbar;
  delete _vscrollbar;
  delete _vport;
}

void OXCanvas::MapSubwindows() {
  OXWindow::MapSubwindows();
  _hscrollbar->MapSubwindows();
  _vscrollbar->MapSubwindows();
  _vport->MapSubwindows();
}

void OXCanvas::AddFrame(OXFrame *f, OLayoutHints *l) {
  ((OXCompositeFrame *)(_vport->GetContainer()))->AddFrame(f, l);
}

void OXCanvas::DrawBorder() {
  switch (_options & (SUNKEN_FRAME | RAISED_FRAME | DOUBLE_BORDER)) {
  case SUNKEN_FRAME | DOUBLE_BORDER:
    XDrawLine (GetDisplay(), _id, _shadowGC, 0, 0, _w-2, 0);
    XDrawLine (GetDisplay(), _id, _shadowGC, 0, 0, 0, _h-2);
    XDrawLine (GetDisplay(), _id, _blackGC, 1, 1, _w-3, 1);
    XDrawLine (GetDisplay(), _id, _blackGC, 1, 1, 1, _h-3);

    XDrawLine (GetDisplay(), _id, _hilightGC, 0, _h-1, _w-1, _h-1);
    XDrawLine (GetDisplay(), _id, _hilightGC, _w-1, _h-1, _w-1, 0);
    XDrawLine (GetDisplay(), _id, _bckgndGC,  1, _h-2, _w-2, _h-2);
    XDrawLine (GetDisplay(), _id, _bckgndGC,  _w-2, 1, _w-2, _h-2);
    break;

  default:
    OXFrame::DrawBorder();
    break;
  }
}

void OXCanvas::Layout() {
  OXFrame *_container;
  int need_vsb, need_hsb, cw, ch, tcw, tch;

  need_vsb = need_hsb = False;

  _container = (OXFrame *) _vport->GetContainer();    

  // test whether we need scrollbars

  cw = _w-(_bw << 1);
  ch = _h-(_bw << 1);

  _container->SetWidth(cw);
  _container->SetHeight(ch);

  if (_container->GetDefaultWidth() > cw) {
    need_hsb = True;
    ch = _h-(_bw << 1)-_vscrollbar->GetDefaultWidth(); 
    _container->SetHeight(ch);
  }

  if (_container->GetDefaultHeight() > ch) {
    need_vsb = True;
    cw = _w-(_bw << 1)-_hscrollbar->GetDefaultHeight();
    _container->SetWidth(cw);
  }

  // re-check again (putting the scrollbar
  // could have changed things)

  if (_container->GetDefaultWidth() > cw) {
    if (!need_hsb) {
      need_hsb = True;
      ch = _h-(_bw << 1)-_vscrollbar->GetDefaultWidth();
      _container->SetHeight(ch);
    }
  }

  if (need_hsb) {
    _hscrollbar->MoveResize(_bw, ch+_bw, cw, _hscrollbar->GetDefaultHeight());
    _hscrollbar->MapWindow();
  } else {
    _hscrollbar->UnmapWindow();
    _hscrollbar->SetPosition(0);
  }

  if (need_vsb) {
    _vscrollbar->MoveResize(cw+_bw, _bw, _vscrollbar->GetDefaultWidth(), ch);
    _vscrollbar->MapWindow();
  } else {
    _vscrollbar->UnmapWindow();
    _vscrollbar->SetPosition(0);
  }

  _vport->MoveResize(_bw, _bw, cw, ch);

  tcw = max(_container->GetDefaultWidth(), cw);
  tch = max(_container->GetDefaultHeight(), ch);
  _container->SetHeight(0); // force a resize in OXFrame::Resize
  _container->Resize(tcw, tch);

  _hscrollbar->SetRange(_container->GetWidth(), _vport->GetWidth());
  _vscrollbar->SetRange(_container->GetHeight(), _vport->GetHeight());
}

int OXCanvas::ProcessMessage(long msg, long parm1, long parm2) {

  switch(GET_MSG(msg)) {
    case XC_HSCROLL:
      switch(GET_SUBMSG(msg)) {
        case SB_SLIDERTRACK:
        case SB_SLIDERPOS:
          _vport->SetHPos(-parm1);
          break;
      }
      break;

    case XC_VSCROLL:
      switch(GET_SUBMSG(msg)) {
        case SB_SLIDERTRACK:
        case SB_SLIDERPOS:
          _vport->SetVPos(-parm1);
          break;
      }
      break;

    default:
      break;
   
  }

  return True;
}


//-----------------------------------------------------------------

OXViewPort::OXViewPort(const OXWindow *p, int w, int h,
           unsigned int options, unsigned long back) :   
    OXCompositeFrame(p, w, h, options, back) {

    _container = NULL;
    _x0 = _y0 = 0;
    MapSubwindows();
}
