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

    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/OXWidgets.h>
#include <xclass/OXClient.h>
#include <xclass/OString.h>

#include <X11/cursorfont.h>
#include <X11/keysym.h>


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

OXTabElt::OXTabElt(const OXWindow *p, OString *text, int w, int h,
                   GC norm, XFontStruct *font,
                   unsigned int options, unsigned long back) :
  OXFrame(p, w, h, options, back) {

    _text = text;
    _bw = 0;
    _normGC = norm;
    _fontStruct = font;

    _tw = XTextWidth(_fontStruct, _text->GetString(), _text->GetLength());
    _th = _fontStruct->max_bounds.ascent + _fontStruct->max_bounds.descent;
    Resize(max(_tw+12, 45), _th+6);
}

OXTabElt::~OXTabElt() {
  if (_text) delete _text;
}

void OXTabElt::DrawBorder() {
  XDrawLine (GetDisplay(), _id, _hilightGC, 0, _h-1, 0, 2);
  XDrawLine (GetDisplay(), _id, _hilightGC, 0, 2, 2, 0);
  XDrawLine (GetDisplay(), _id, _hilightGC, 2, 0, _w-3, 0);    
  XDrawLine (GetDisplay(), _id, _shadowGC,  _w-2, 1, _w-2, _h-1);
  XDrawLine (GetDisplay(), _id, _blackGC, _w-2, 1, _w-1, 2);
  XDrawLine (GetDisplay(), _id, _blackGC, _w-1, 2, _w-1, _h-2);

  if (_text)
    _text->Draw(GetDisplay(), _id, _normGC, 6, _fontStruct->max_bounds.ascent+3);
}

ODimension OXTabElt::GetDefaultSize() const {
  return ODimension(max(_tw+12, 45), _th+6);
}

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

OTabLayout::OTabLayout(OXTab *main) {
  _main = main;
  _list = _main->GetListAddr();
}

void OTabLayout::Layout() {
  SListFrameElt *ptr;
  int i, tw, xtab;
  int _tabh = ((OXTab *)_main)->GetTabHeight(), _bw = _main->GetBorderWidth();
  int _w = _main->GetWidth();
  int _h = _main->GetHeight();

  xtab = 2;

  ((OXTab *)_main)->GetContainer()->MoveResize(0, _tabh, _w, _h - _tabh);

  // first frame is the container, so take next...
  for (ptr=(*_list)->next, i=0; ptr != NULL; ptr=ptr->next->next, ++i) {
    tw = ptr->frame->GetDefaultWidth();
    if (i == ((OXTab *)_main)->GetCurrent()) {
      ptr->frame->MoveResize(xtab-2, 0, tw+3, _tabh+1);
      ptr->next->frame->RaiseWindow();
      ptr->frame->RaiseWindow();
    } else {
      ptr->frame->MoveResize(xtab, 2, tw, _tabh-1);
      ptr->frame->LowerWindow();
    }
    //ptr->next->frame->MoveResize(_bw, _tabh + _bw, _w - (_bw << 1), _h - _tabh - (_bw << 1));
    ptr->next->frame->MoveResize(_bw-1, _tabh + _bw-1, _w+1 - (_bw << 1), _h+1 - _tabh - (_bw << 1));
    ptr->next->frame->Layout();
    xtab += tw;
  }
}

ODimension OTabLayout::GetDefaultSize() const {
  SListFrameElt *ptr;
  ODimension dsize;
  ODimension size(0,0);
  int tab_elt_width = 0;
 
  for (ptr=(*_list)->next; ptr; ptr=ptr->next->next) {
    dsize = ptr->next->frame->GetDefaultSize();
    if (size.w < dsize.w) size.w = dsize.w;
    if (size.h < dsize.h) size.h = dsize.h;
    tab_elt_width += ptr->frame->GetDefaultSize().w;
  }
  if (size.w < tab_elt_width)
    size.w = tab_elt_width;
  size.w += _main->GetBorderWidth() << 1;
  size.h += ((OXTab *)_main)->GetTabHeight() + 
            (_main->GetBorderWidth() << 1);
  return size;
}

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

OXTab::OXTab(const OXWindow *p, int w, int h,
             GC norm, XFontStruct *font,
             unsigned int options, unsigned long back) :
  OXCompositeFrame(p, w, h, options, back) {

    _bw = 2;
    _current = 0;

    _normGC = norm;
    _fontStruct = font;

    _tabh = _fontStruct->max_bounds.ascent + _fontStruct->max_bounds.descent + 6;

    SetLayoutManager(new OTabLayout(this));
    // we need this in order to avoid border blinking when switching tabs...
    _container = new OXCompositeFrame(this, _w, _h - _tabh,
                       VERTICAL_FRAME | RAISED_FRAME | DOUBLE_BORDER);
    OXCompositeFrame::AddFrame(_container, NULL);

    XSelectInput(GetDisplay(), _id, ButtonPressMask);
}

// Remove tab windows, etc. Labels are destroyed by OXTabElt

OXTab::~OXTab() {
  SListFrameElt *ptr, *next;

  ptr = _flist;
  while(ptr) {
    next = ptr->next;
    delete ptr->frame;
    // delete ptr->layout; // ptr->layout is NULL!
    delete ptr;
    ptr = next;
  }
  _flist = NULL; // so not to confuse OXCompositeFrame's cleanup...
}

OXCompositeFrame *OXTab::AddTab(OString *text) {
  OXCompositeFrame *cf;

  OXCompositeFrame::AddFrame(new OXTabElt(this, text, 50, 20, _normGC, _fontStruct), NULL);
  cf = new OXCompositeFrame(this, _w, _h-21);
  OXCompositeFrame::AddFrame(cf, NULL);

  return cf;
}


/*
const OString *GetCurrent() const {
  SListFrameElt *ptr;
  OXTabElt *te;

  for (ptr=_flist->next, int i=0;
       ptr != NULL; i != _current;
       ptr=ptr->next->next, ++i);

  if (ptr == NULL) return NULL;

  te = (OXTabElt *) ptr->frame;
  return te->GetText();
}
*/

int OXTab::HandleButton(XButtonEvent *event) {
  SListFrameElt *ptr;
  int i, c, tw, xtab;

  xtab = 2;
  if (event->type == ButtonPress) {

    c = _current;
    for (ptr=_flist->next, i=0; ptr != NULL; ptr=ptr->next->next, ++i)
      if (ptr->frame->GetId() == event->subwindow) c = i;

    if (c != _current) {
      _current = c;
      Layout();
    }
  }

  return True;
}
