// @(#)root/gui:$Name:  $:$Id: TGString.cxx,v 1.2 2004/03/22 15:39:43 brun Exp $
// Author: Fons Rademakers   05/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.

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

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGString and TGHotString                                             //
//                                                                      //
// TGString wraps a TString and adds some graphics routines like        //
// drawing, size of string on screen depending on font, etc.            //
// TGHotString is a string with a "hot" character unerlined.            //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TGString.h"
#include "TVirtualX.h"
#include "ctype.h"


ClassImp(TGString)
ClassImp(TGHotString)

//______________________________________________________________________________
void TGString::Draw(Drawable_t id, GContext_t gc, Int_t x, Int_t y)
{
   // Draw string.

   gVirtualX->DrawString(id, gc, x, y, fString.Data(), fString.Length());
}

//______________________________________________________________________________
void TGString::DrawWrapped(Drawable_t id, GContext_t gc,
                           Int_t x, Int_t y, UInt_t w, FontStruct_t font)
{
   // Draw a string in a column with width w. If string is longer than
   // w wrap it to next line.

   const char *p     = fString.Data();
   const char *prev  = p;
   const char *chunk = p;
   int tw, th, len = fString.Length();

   tw = gVirtualX->TextWidth(font, p, len);
   if (tw <= (int)w) {
      gVirtualX->DrawString(id, gc, x, y, p, len);
      return;
   }

   int max_ascent, max_descent;
   gVirtualX->GetFontProperties(font, max_ascent, max_descent);
   th = max_ascent + max_descent + 1;

   while(1) {
      p = strchr(p, ' ');
      if (p == 0) {
         if (chunk) gVirtualX->DrawString(id, gc, x, y, chunk, strlen(chunk));
         break;
      }
      tw = gVirtualX->TextWidth(font, chunk, p-chunk);
      if (tw > (int)w) {
         if (prev == chunk)
            prev = ++p;
         else
            p = prev;
         gVirtualX->DrawString(id, gc, x, y, chunk, prev-chunk-1);
         chunk = prev;
         y += th;
      } else {
         prev = ++p;
      }
   }
}

//______________________________________________________________________________
Int_t TGString::GetLines(FontStruct_t font, UInt_t w)
{
   // Get number of lines of width w the string would take using a certain font.

   const char *p     = fString.Data();
   const char *prev  = p;
   const char *chunk = p;
   int tw, nlines, len = fString.Length();

   nlines = 1;

   tw = gVirtualX->TextWidth(font, p, len);
   if (tw <= (int)w) return nlines;

   while(1) {
      p = strchr(p, ' ');
      if (p == 0) break;
      tw = gVirtualX->TextWidth(font, chunk, p-chunk);
      if (tw > (int)w) {
         if (prev == chunk)
            chunk = prev = ++p;
         else
            p = chunk = prev;
         ++nlines;
      } else {
         prev = ++p;
      }
   }
   return nlines;
}


//______________________________________________________________________________
TGHotString::TGHotString(const char *s) : TGString(s)
{
   // Create a hot string.

   char *dup = StrDup(fString.Data());
   char *p;

   fLastGC = 0;
   fOff1 = fOff2 = 0;

   fHotChar = 0;
   fHotPos  = 0;    // No hotkey defaults the offset to zero

   for (p = dup; *p; p++) {
      if (*p == '&') {
         if (p[1] == '&') { // escaped & ?
            // copy the string down over it
            for (char *tmp = p; *tmp; tmp++)
               tmp[0] = tmp[1];
            continue; // and skip to the key char
         }
         // hot key marker - calculate the offset value
         fHotPos  = (p - dup) + 1;
         fHotChar = tolower(p[1]);
         for (; *p; p++) p[0] = p[1];  // copy down
         break;                        // allow only one hotkey per item
      }
   }
   fString = dup;
   delete [] dup;
}

//______________________________________________________________________________
void TGHotString::Draw(Drawable_t id, GContext_t gc, Int_t x, Int_t y)
{
   // Draw a hot string and underline the hot character.

   gVirtualX->DrawString(id, gc, x, y, fString.Data(), fString.Length());

   DrawHotChar(id, gc, x, y);
}

//______________________________________________________________________________
void TGHotString::DrawWrapped(Drawable_t id, GContext_t gc,
                              Int_t x, Int_t y, UInt_t w, FontStruct_t font)
{
   // Draw a hot string in a column with width w. If string is longer than
   // w wrap it to next line.

   const char *p     = fString.Data();
   const char *prev  = p;
   const char *chunk = p;
   int tw, th, len = fString.Length();

   tw = gVirtualX->TextWidth(font, p, len);
   if (tw <= (int)w) {
      gVirtualX->DrawString(id, gc, x, y, p, len);
      DrawHotChar(id, gc, x, y);
      return;
   }

   int max_ascent, max_descent;
   gVirtualX->GetFontProperties(font, max_ascent, max_descent);
   th = max_ascent + max_descent + 1;

   int pcnt = 0;
   while(1) {
      p = strchr(p, ' ');
      if (p == 0) {
         if (chunk) {
            gVirtualX->DrawString(id, gc, x, y, chunk, strlen(chunk));
            if (fHotPos > pcnt && fHotPos <= pcnt+(int)strlen(chunk))
               DrawHotChar(id, gc, x, y);
         }
         break;
      }
      tw = gVirtualX->TextWidth(font, chunk, p-chunk);
      if (tw > (int)w) {
         if (prev == chunk)
            prev = ++p;
         else
            p = prev;
         gVirtualX->DrawString(id, gc, x, y, chunk, prev-chunk-1);
         if (fHotPos > pcnt && fHotPos <= pcnt+prev-chunk-1)
            DrawHotChar(id, gc, x, y);
         pcnt = prev-chunk-1;
         chunk = prev;
         y += th;
      } else {
         prev = ++p;
      }
   }
}

//______________________________________________________________________________
void TGHotString::DrawHotChar(Drawable_t id, GContext_t gc, Int_t x, Int_t y)
{
   // Draw the underline under the hot character.

   if (fHotPos > 0) {
      if (fLastGC != gc) {
         GCValues_t   gcval;
         FontStruct_t font;

         gcval.fMask = kGCFont;
         gVirtualX->GetGCValues(gc, gcval);
         font = gVirtualX->GetFontStruct(gcval.fFont);

         fOff1   = gVirtualX->TextWidth(font, fString.Data(), fHotPos-1); //+1;
         fOff2   = gVirtualX->TextWidth(font, fString.Data(), fHotPos) - 1;

         gVirtualX->FreeFontStruct(font);
         fLastGC = gc;
      }
      gVirtualX->DrawLine(id, gc, x+fOff1, y+1, x+fOff2, y+1);
   }
}

