// @(#)root/gui:$Name:  $:$Id: TGTab.cxx,v 1.1.1.1 2000/05/16 17:00:42 rdm Exp $
// Author: Fons Rademakers   13/01/98

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/
/**************************************************************************

    This source is based on Xclass95, a Win95-looking GUI toolkit.
    Copyright (C) 1996, 1997 David Barth, Ricky Ralston, Hector Peraza.

    Xclass95 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.

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

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGTab, TGTabElement, TGTabLayout                                     //
//                                                                      //
// A tab widget contains a set of composite frames each with a little   //
// tab with a name (like a set of folders with tabs).                   //
//                                                                      //
// The TGTab is user callable. The TGTabElement and TGTabLayout are     //
// is a service classes of the tab widget.                              //
//                                                                      //
// Clicking on a tab will bring the associated composite frame to the   //
// front and generate the following event:                              //
// kC_COMMAND, kCM_TAB, tab id, 0.                                      //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TGTab.h"
#include "TList.h"
#include "TMath.h"


ClassImp(TGTabElement)
ClassImp(TGTabLayout)
ClassImp(TGTab)


//______________________________________________________________________________
TGTabElement::TGTabElement(const TGWindow *p, TGString *text, UInt_t w, UInt_t h,
                           GContext_t norm, FontStruct_t font,
                           UInt_t options, ULong_t back) :
   TGFrame(p, w, h, options, back)
{
   // Create a tab element. Text is adopted by tab element.

   fText        = text;
   fBorderWidth = 0;
   fNormGC      = norm;
   fFontStruct  = font;

   int max_ascent, max_descent;
   fTWidth = gVirtualX->TextWidth(fFontStruct, fText->GetString(), fText->GetLength());
   gVirtualX->GetFontProperties(fFontStruct, max_ascent, max_descent);
   fTHeight = max_ascent + max_descent;
   Resize(TMath::Max(fTWidth+12, (UInt_t)45), fTHeight+6);
}

//______________________________________________________________________________
TGTabElement::~TGTabElement()
{
   // Delete tab element.

   if (fText) delete fText;
}

//______________________________________________________________________________
void TGTabElement::DrawBorder()
{
   // Draw little tab element.

   gVirtualX->DrawLine(fId, fgHilightGC, 0, fHeight-1, 0, 2);
   gVirtualX->DrawLine(fId, fgHilightGC, 0, 2, 2, 0);
   gVirtualX->DrawLine(fId, fgHilightGC, 2, 0, fWidth-3, 0);
   gVirtualX->DrawLine(fId, fgShadowGC,  fWidth-2, 1, fWidth-2, fHeight-1);
   gVirtualX->DrawLine(fId, fgBlackGC, fWidth-2, 1, fWidth-1, 2);
   gVirtualX->DrawLine(fId, fgBlackGC, fWidth-1, 2, fWidth-1, fHeight-2);
   gVirtualX->DrawLine(fId, fgHilightGC, fWidth-1, fHeight-1, fWidth-1, fHeight-1);

   if (fText) {
      int max_ascent, max_descent;
      gVirtualX->GetFontProperties(fFontStruct, max_ascent, max_descent);
      fText->Draw(fId, fNormGC, 6, max_ascent+3);
   }
}

//______________________________________________________________________________
TGDimension TGTabElement::GetDefaultSize() const
{
   // Return default size of tab element.

   return TGDimension(TMath::Max(fTWidth+12, (UInt_t)45), fTHeight+6);
}

//______________________________________________________________________________
void TGTabElement::SetText(TGString *text)
{
   // Set new tab text.

   if (fText) delete fText;
   fText = text;

   int max_ascent, max_descent;
   fTWidth = gVirtualX->TextWidth(fFontStruct, fText->GetString(), fText->GetLength());
   gVirtualX->GetFontProperties(fFontStruct, max_ascent, max_descent);
   fTHeight = max_ascent + max_descent;

   fClient->NeedRedraw(this);
}


//______________________________________________________________________________
 TGTabLayout::TGTabLayout(TGTab *main)
{
   // Create a tab layout manager.

   fMain = main;
   fList = fMain->GetList();
}

//______________________________________________________________________________
 void TGTabLayout::Layout()
{
   // Layout the tab widget.

   Int_t  i, xtab;
   UInt_t tw;
   UInt_t tabh = fMain->GetTabHeight(), bw = fMain->GetBorderWidth();
   UInt_t w = fMain->GetWidth();
   UInt_t h = fMain->GetHeight();

   xtab = 2;

   fMain->GetContainer()->MoveResize(0, tabh, w, h - tabh);

   // first frame is the container, so take next...
   TGFrameElement *el, *elnxt;
   TIter next(fList);
   i = 0;
   next();   // skip first
   while ((el = (TGFrameElement *) next())) {
      elnxt = (TGFrameElement *) next();
      tw = el->fFrame->GetDefaultWidth();
      if (i == fMain->GetCurrent()) {
         el->fFrame->MoveResize(xtab-2, 0, tw+3, tabh+1);
         elnxt->fFrame->RaiseWindow();
         el->fFrame->RaiseWindow();
      } else {
         el->fFrame->MoveResize(xtab, 2, tw, tabh-1);
         el->fFrame->LowerWindow();
      }
      elnxt->fFrame->MoveResize(bw, tabh + bw, w - (bw << 1), h - tabh - (bw << 1));
      elnxt->fFrame->Layout();
      xtab += (Int_t)tw;
      i++;
   }
}

//______________________________________________________________________________
 TGDimension TGTabLayout::GetDefaultSize() const
{
   // Get default size of tab widget.

   TGDimension dsize, dsize_te;
   TGDimension size(0,0), size_te(0,0);

   TGFrameElement *el, *elnxt;
   TIter next(fList);
   next();   // skip first container
   while ((el = (TGFrameElement *)next())) {
      dsize_te = el->fFrame->GetDefaultSize();
      size_te.fWidth += dsize_te.fWidth;
      elnxt = (TGFrameElement *) next();
      dsize = elnxt->fFrame->GetDefaultSize();
      if (size.fWidth < dsize.fWidth) size.fWidth = dsize.fWidth;
      if (size.fHeight < dsize.fHeight) size.fHeight = dsize.fHeight;
   }

   // check if tab elements make a larger width than the containers
   if (size.fWidth < size_te.fWidth) size.fWidth = size_te.fWidth;

   size.fWidth += fMain->GetBorderWidth() << 1;
   size.fHeight += fMain->GetTabHeight() + (fMain->GetBorderWidth() << 1);

   return size;
}


//______________________________________________________________________________
TGTab::TGTab(const TGWindow *p, UInt_t w, UInt_t h,
             GContext_t norm, FontStruct_t font,
             UInt_t options, ULong_t back) :
   TGCompositeFrame(p, w, h, options, back)
{
   // Create tab widget.

   fMsgWindow  = p;

   fBorderWidth = 2;
   fCurrent     = 0;
   fRemoved     = new TList;

   fNormGC     = norm;
   fFontStruct = font;

   int max_ascent, max_descent;
   gVirtualX->GetFontProperties(fFontStruct, max_ascent, max_descent);
   fTabh = max_ascent + max_descent + 6;

   SetLayoutManager(new TGTabLayout(this));

   // we need this in order to avoid border blinking when switching tabs...
   fContainer = new TGCompositeFrame(this, fWidth, fHeight - fTabh,
                       kVerticalFrame | kRaisedFrame | kDoubleBorder);
   AddFrame(fContainer, 0);

   gVirtualX->SelectInput(fId, kButtonPressMask);
}

//______________________________________________________________________________
TGTab::~TGTab()
{
   // Delete tab widget. This deletes the tab windows and the containers.
   // The tab string is deleted by the TGTabElement dtor.

   TGFrameElement *el;
   TIter next(fList);

   while ((el = (TGFrameElement *) next())) {
      delete el->fFrame;
      // delete el->fLayout; // el->fLayout is NULL!
   }

   fRemoved->Delete();
   delete fRemoved;
}

//______________________________________________________________________________
TGCompositeFrame *TGTab::AddTab(TGString *text)
{
   // Add a tab to the tab widget. Returns the new container, which
   // is owned by the tab widget. The text is adopted by the tab widget.

   TGCompositeFrame *cf;

   AddFrame(new TGTabElement(this, text, 50, 20, fNormGC, fFontStruct), 0);
   cf = new TGCompositeFrame(this, fWidth, fHeight-21);
   AddFrame(cf, 0);

   return cf;
}

//______________________________________________________________________________
TGCompositeFrame *TGTab::AddTab(const char *text)
{
   // Add a tab to the tab widget. Returns the new container. The container
   // is owned by the tab widget.

   return AddTab(new TGString(text));
}

//______________________________________________________________________________
void TGTab::RemoveTab(Int_t tabIndex)
{
   // Remove container and tabtab of tab with index tabIndex.
   // Does NOT remove the container contents!

   if (tabIndex < 0) return;

   TGFrameElement *elTab, *elCont ;
   Int_t  count = 0 ;

   TIter next(fList) ;
   next() ; // skip first container

   while ((elTab = (TGFrameElement *) next())) {
      elCont = (TGFrameElement *) next();
      if (count == tabIndex) {
         elTab->fFrame->DestroyWindow();
         elCont->fFrame->DestroyWindow();
         delete elTab->fFrame;
         fRemoved->Add(elCont->fFrame);   // delete only in dtor
         RemoveFrame(elTab->fFrame);
         RemoveFrame(elCont->fFrame);
         if (tabIndex == fCurrent) {
           // select another tab only if the current is the one we delete
           SetTab(0) ;
         } else
            fCurrent--;
         break;
      }
      count++;
   }
}

//______________________________________________________________________________
void TGTab::ChangeTab(Int_t tabIndex)
{
   // Make tabIdx the current tab. Utility method called by SetTab and
   // HandleButton().

   if (tabIndex != fCurrent) {
      TGFrameElement *el, *elnxt;
      UInt_t tw;
      Int_t  xtab  = 2;
      Int_t  count = 0;

      TIter next(fList);
      next();           // skip first container

      fCurrent = tabIndex;
      while ((el = (TGFrameElement *) next())) {
         elnxt = (TGFrameElement *) next();
         tw = el->fFrame->GetDefaultWidth();
         if (count == fCurrent) {
            el->fFrame->MoveResize(xtab-2, 0, tw+3, fTabh+1);
            elnxt->fFrame->RaiseWindow();
            el->fFrame->RaiseWindow();
         } else {
            el->fFrame->MoveResize(xtab, 2, tw, fTabh-1);
            el->fFrame->LowerWindow();
         }
         xtab += tw;
         count++;
      }
      SendMessage(fMsgWindow, MK_MSG(kC_COMMAND, kCM_TAB), fCurrent, 0);
      fClient->ProcessLine(fCommand, MK_MSG(kC_COMMAND, kCM_TAB), fCurrent, 0);
   }
}

//______________________________________________________________________________
Bool_t TGTab::SetTab(Int_t tabIndex)
{
   // Brings the composite frame with the index tabIndex to the
   // front and generate the following event if the front tab has
   // changed:
   // kC_COMMAND, kCM_TAB, tab id, 0.
   // Returns kFALSE if tabIndex is a not valid index

   // check if tabIndex is a valid index
   if (tabIndex < 0)
      return kFALSE;

   // count the tabs
   TIter next(fList);
   Int_t count = 0;
   while (next())
      count++;

   count = count / 2 - 1;
   if (tabIndex > count)
      return kFALSE;

   // change tab and generate event
   ChangeTab(tabIndex);

   return kTRUE;
}

//______________________________________________________________________________
Bool_t TGTab::HandleButton(Event_t *event)
{
   // Handle button event in the tab widget. Basically we only handle
   // button events in the small tabs.

   if (event->fType == kButtonPress) {
      TGFrameElement *el;
      TIter next(fList);

      next();   // skip first container

      Int_t i = 0;
      Int_t c = fCurrent;
      while ((el = (TGFrameElement *) next())) {
         if (el->fFrame->GetId() == (Window_t)event->fUser[0])  // fUser[0] is child window
            c = i;
         next(); i++;
      }

      // change tab and generate event
      ChangeTab(c);
   }
   return kTRUE;
}

//______________________________________________________________________________
TGCompositeFrame *TGTab::GetTabContainer(Int_t tabIndex) const
{
   // Return container of tab with index tabIndex.
   // Returns 0 in case tabIndex is out of range.

   if (tabIndex < 0) return 0;

   TGFrameElement *el;
   Int_t  count = 0;

   TIter next(fList);
   next();           // skip first container

   while (next()) {
      el = (TGFrameElement *) next();
      if (count == tabIndex)
         return (TGCompositeFrame *) el->fFrame;
      count++;
   }

   return 0;
}

//______________________________________________________________________________
TGTabElement *TGTab::GetTabTab(Int_t tabIndex) const
{
   // Return container of tab with index tabIndex.
   // Returns 0 in case tabIndex is out of range.

   if (tabIndex < 0) return 0;

   TGFrameElement *el;
   Int_t  count = 0;

   TIter next(fList);
   next();           // skip first container

   while ((el = (TGFrameElement *) next())) {
      next();
      if (count == tabIndex)
         return (TGTabElement *) el->fFrame;
      count++;
   }

   return 0;
}

//______________________________________________________________________________
Int_t TGTab::GetNumberOfTabs() const
{
   // Return number of tabs.

   Int_t count = 0;

   TIter next(fList);
   next();           // skip first container

   while (next()) {
      next();
      count++;
   }

   return count;
}



ROOT page - Class index - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.