//*CMZ :  2.00/12 01/10/98  01.39.45  by  Fons Rademakers
//*CMZ :  2.00/11 03/08/98  11.58.48  by  Fons Rademakers
//*CMZ :  2.00/08 22/05/98  00.41.03  by  Fons Rademakers
//*CMZ :  2.00/06 05/05/98  11.00.23  by  Fons Rademakers
//*CMZ :  2.00/04 30/03/98  19.06.57  by  Fons Rademakers
//*CMZ :  2.00/00 23/02/98  16.13.28  by  Fons Rademakers
//*-- Author :    Fons Rademakers   08/01/98

//*KEEP,CopyRight,T=C.
/*************************************************************************
 * Copyright(c) 1995-1999, The ROOT System, All rights reserved.         *
 * Authors: Rene Brun, Fons Rademakers.                                  *
 * For list of contributors see $ROOTSYS/AA_CREDITS.                     *
 *                                                                       *
 * Permission to use, copy, modify and distribute this software and its  *
 * documentation for non-commercial purposes is hereby granted without   *
 * fee, provided that the above copyright notice appears in all copies   *
 * and that both the copyright notice and this permission notice appear  *
 * in the supporting documentation. The authors make no claims about the *
 * suitability of this software for any purpose. It is provided "as is"  *
 * without express or implied warranty.                                  *
 *************************************************************************/
//*KEEP,CopyLeft.
/**************************************************************************

    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.

**************************************************************************/
//*KEND.

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGTextEntry                                                          //
//                                                                      //
// A TGTextEntry is a one line text input widget.                       //
//                                                                      //
// Changing text in the text entry widget will generate the event:      //
// kC_TEXTENTRY, kTE_TEXTCHANGED, widget id, 0.                         //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

//*KEEP,TGTextEntry.
#include "TGTextEntry.h"
//*KEEP,TSystem.
#include "TSystem.h"
//*KEEP,TMath.
#include "TMath.h"
//*KEEP,TTimer,T=C++.
#include "TTimer.h"
//*KEEP,KeySymbols.
#include "KeySymbols.h"
//*KEND.



//______________________________________________________________________________
class TBlinkTimer : public TTimer {
private:
   TGTextEntry   *fTextEntry;
public:
   TBlinkTimer(TGTextEntry *t, Long_t ms) : TTimer(ms, kTRUE) { fTextEntry = t; }
   Bool_t Notify();
};

//______________________________________________________________________________
Bool_t TBlinkTimer::Notify()
{
   fTextEntry->HandleTimer(0);
   Reset();
   return kFALSE;
}


ClassImp(TGTextEntry)

//______________________________________________________________________________
 TGTextEntry::TGTextEntry(const TGWindow *p, TGTextBuffer *text, Int_t id,
                         GContext_t norm, FontStruct_t font, UInt_t options,
                         ULong_t back) : TGFrame(p, 1, 1, options, back)
{
   // Create a text entry widget. It will adopt the TGTextBuffer object
   // (i.e. the text buffer will be deleted by the text entry widget).

   fWidgetId    = id;
   fWidgetFlags = kWidgetWantFocus | kWidgetIsEnabled;
   fMsgWindow   = p;

   fNormGC     = norm;
   fSelGC      = fgDefaultSelectedGC;
   fSelbackGC  = fgDefaultSelectedBackgroundGC;
   fFontStruct = font;
   fText       = text;

   int tw, max_ascent, max_descent;
   tw = gGXW->TextWidth(fFontStruct, fText->GetString(), fText->GetTextLength());
   gGXW->GetFontProperties(fFontStruct, max_ascent, max_descent);

   Resize(tw + 8, max_ascent + max_descent + 7);

   fCursorX     = 4;
   fCursorIX    = fStartIX = fEndIX = 0;
   fSelectionOn = fCursorOn = kFALSE;
   fCurBlink    = 0;

   gGXW->SetCursor(fId, fgDefaultCursor);

   gGXW->GrabButton(fId, kAnyButton, kAnyModifier,
                    kButtonPressMask | kButtonReleaseMask | kPointerMotionMask,
                    kNone, kNone);

   gGXW->SelectInput(fId, kKeyPressMask | kExposureMask | kFocusChangeMask);
}

//______________________________________________________________________________
 TGTextEntry::~TGTextEntry()
{
   // Delete a text entry widget.

   delete fText;
   delete fCurBlink;
}

//______________________________________________________________________________
 void TGTextEntry::SetState(Bool_t state)
{
   // Set state of widget. If kTRUE=enabled, kFALSE=disabled.

   if (state) {
      SetFlags(kWidgetIsEnabled);
      SetBackgroundColor(fgWhitePixel);
   } else {
      ClearFlags(kWidgetIsEnabled);
      SetBackgroundColor(fgDefaultFrameBackground);
   }

   fClient->NeedRedraw(this);
}

//______________________________________________________________________________
 void TGTextEntry::DoRedraw()
{
   // Draw the text entry widget.

   int x, y, max_ascent, max_descent;

   TGFrame::DoRedraw();

   x = 4; // do not center text
   y = 4;

   gGXW->GetFontProperties(fFontStruct, max_ascent, max_descent);
   gGXW->DrawString(fId, fNormGC, x, y + max_ascent,
                    fText->GetString(), fText->GetTextLength());

   if (fCursorOn) {
      gGXW->DrawLine(fId, fgBlackGC, fCursorX, 3,
                     fCursorX, max_ascent + max_descent + 3);
//  } else {
//     gGXW->DrawLine(fId, fgWhiteGC, fCursorX, 4,
//                    fCursorX, max_ascent + max_descent + 1);
   }

   if (fSelectionOn) {
      int xs, ws, ixs, iws;

      xs  = TMath::Min(fStartX, fEndX);
      ws  = TMath::Abs(fEndX - fStartX);
      ixs = TMath::Min(fStartIX, fEndIX);
      iws = TMath::Abs(fEndIX - fStartIX);

      gGXW->FillRectangle(fId, fSelbackGC, x+xs, y-1,
                          ws, max_ascent + max_descent +1);

      // fText->Draw(fId, fNormGC, x, y + max_ascent);

      gGXW->DrawString(fId, fSelGC, x+xs, y + max_ascent,
                       (fText->GetString())+ixs, iws);
   }

   // hmmm...
   DrawBorder();
}

//______________________________________________________________________________
 void TGTextEntry::DrawBorder()
{
   // Draw the border of the text entry widget.

   switch (fOptions & (kSunkenFrame | kRaisedFrame | kDoubleBorder)) {
      case kSunkenFrame | kDoubleBorder:
         gGXW->DrawLine(fId, fgShadowGC, 0, 0, fWidth-2, 0);
         gGXW->DrawLine(fId, fgShadowGC, 0, 0, 0, fHeight-2);
         gGXW->DrawLine(fId, fgBlackGC, 1, 1, fWidth-3, 1);
         gGXW->DrawLine(fId, fgBlackGC, 1, 1, 1, fHeight-3);

         gGXW->DrawLine(fId, fgHilightGC, 0, fHeight-1, fWidth-1, fHeight-1);
         gGXW->DrawLine(fId, fgHilightGC, fWidth-1, fHeight-1, fWidth-1, 0);
         gGXW->DrawLine(fId, fgBckgndGC,  1, fHeight-2, fWidth-2, fHeight-2);
         gGXW->DrawLine(fId, fgBckgndGC,  fWidth-2, 1, fWidth-2, fHeight-2);
         break;

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

//______________________________________________________________________________
 Int_t TGTextEntry::GetCharacterIndex(Int_t xcoord)
{
   // Get character position at pixel position xcoord.

   int tw, ix, up, down, len;

   // check for out of boundaries first...
   len = fText->GetTextLength();
   tw = gGXW->TextWidth(fFontStruct, fText->GetString(), len);
   if (xcoord < 0) return 0;
   if (xcoord > tw) return len; // len-1

   // do a binary approximation
   up = len; //-1
   down = 0;
   while (up-down > 1) {
      ix = (up+down) >> 1;
      tw = gGXW->TextWidth(fFontStruct, fText->GetString(), ix);
      if (tw > xcoord)
         up = ix;
      else
         down = ix;
      if (tw == xcoord) break;
   }
   ix = down;

   // safety check...
   ix = TMath::Max(ix, 0);
   ix = TMath::Min(ix, len); // len-1

   return ix;
}

//______________________________________________________________________________
 Bool_t TGTextEntry::HandleButton(Event_t *event)
{
   // Handle mouse button event in text entry widget.

   if (!IsEnabled()) return kTRUE;

   int x;

   if (event->fType == kButtonPress) {

      gGXW->SetInputFocus(fId);

      if (event->fCode == kButton1) {

         x = 4;
         fStartIX     = GetCharacterIndex(event->fX - x);
         fStartX      = gGXW->TextWidth(fFontStruct, fText->GetString(), fStartIX);
         fCursorIX    = fStartIX;
         fCursorX     = fStartX + x;
         fSelectionOn = kFALSE;
         DoRedraw();

      } else if (event->fCode == kButton2) {

         if (gGXW->GetPrimarySelectionOwner() == kNone) {
            // No primary selection, so use the cut buffer
            PastePrimary(fClient->GetRoot()->GetId(), kCutBuffer, kFALSE);
         } else {
            gGXW->ConvertPrimarySelection(fId, event->fTime);
         }

      }
   }
   return kTRUE;
}

//______________________________________________________________________________
 Bool_t TGTextEntry::HandleDoubleClick(Event_t *)
{
   // Handle double click event in the text entry widget.

   if (!IsEnabled()) return kTRUE;

   gGXW->SetInputFocus(fId);

   int x        = 4;
   fStartIX     = 0;
   fStartX      = gGXW->TextWidth(fFontStruct, fText->GetString(), fStartIX);
   fEndIX       = fText->GetTextLength();
   fEndX        = gGXW->TextWidth(fFontStruct, fText->GetString(), fEndIX);
   fCursorIX    = fEndIX;
   fCursorX     = fEndX + x;
   fSelectionOn = kTRUE;

   DoRedraw();

   return kTRUE;
}

//______________________________________________________________________________
 Bool_t TGTextEntry::HandleMotion(Event_t *event)
{
   // Handle mouse motion event in the text entry widget.

   if (!IsEnabled()) return kTRUE;

   int x = 4;

   fEndIX       = GetCharacterIndex(event->fX - x); // + 1;
   fEndX        = gGXW->TextWidth(fFontStruct, fText->GetString(), fEndIX);
   fCursorIX    = fEndIX;
   fCursorX     = fEndX + x;
   fSelectionOn = kTRUE;

   DoRedraw();

   return kTRUE;
}

//______________________________________________________________________________
 Bool_t TGTextEntry::HandleKey(Event_t *event)
{
   // Handle keyboard event in text entry widget.

   Int_t  n, len;
   Bool_t text_changed = kFALSE;
   Bool_t text_enter = kFALSE;
   char   tmp[10];
   UInt_t keysym;

   if (!IsEnabled()) return kTRUE;

   len = fText->GetTextLength();
   gGXW->LookupString(event, tmp, sizeof(tmp), keysym);
   n = strlen(tmp);

   switch ((EKeySym)keysym) {
      case kKey_Right:
         if (fSelectionOn) fSelectionOn = kFALSE;
         if (fCursorIX < len) ++fCursorIX;
         break;

      case kKey_Left:
         if (fSelectionOn) fSelectionOn = kFALSE;
         if (fCursorIX > 0) --fCursorIX;
         break;

      case kKey_Home:
         if (fSelectionOn) fSelectionOn = kFALSE;
         fCursorIX = 0;
         break;

      case kKey_End:
         if (fSelectionOn) fSelectionOn = kFALSE;
         fCursorIX = len;
         break;

      case kKey_Delete:
         if (fSelectionOn) {
            int start, ns;

            start = TMath::Min(fStartIX, fEndIX);
            ns = TMath::Abs(fEndIX - fStartIX);
            fText->RemoveText(start, ns);
            fSelectionOn = kFALSE;
            fCursorIX = start;
         } else {
            fText->RemoveText(fCursorIX, 1);
         }
         text_changed = kTRUE;
         break;

      case kKey_Backspace:
         if (fSelectionOn) {
            int start, ns;

            start = TMath::Min(fStartIX, fEndIX);
            ns = TMath::Abs(fEndIX - fStartIX);
            fText->RemoveText(start, ns);
            fSelectionOn = kFALSE;
            fCursorIX = start;
         } else {
            if (fCursorIX > 0) {
               --fCursorIX;
               fText->RemoveText(fCursorIX, 1);
            }
         }
         text_changed = kTRUE;
         break;

      case kKey_Return:
         text_enter = kTRUE;
         break;

      default:
         if (keysym < 127) {
            if (fSelectionOn) {
               int start, ns;

               start = TMath::Min(fStartIX, fEndIX);
               ns = TMath::Abs(fEndIX - fStartIX);
               fText->RemoveText(start, ns);
               fSelectionOn = kFALSE;
               fCursorIX = start;
            }
            fText->AddText(fCursorIX, tmp);
            len = fText->GetTextLength();
            fCursorIX += n;
            if (fCursorIX > len) fCursorIX = len;
            text_changed = kTRUE;
         }
         break;
   }

   fCursorX = 4 + gGXW->TextWidth(fFontStruct, fText->GetString(), fCursorIX);
   fClient->NeedRedraw(this);

   if (text_changed) {
      SendMessage(fMsgWindow, MK_MSG(kC_TEXTENTRY, kTE_TEXTCHANGED),
                  fWidgetId, 0);
      fClient->ProcessLine(fCommand, MK_MSG(kC_TEXTENTRY, kTE_TEXTCHANGED),
                           fWidgetId, 0);
   }
   if (text_enter) {
      SendMessage(fMsgWindow, MK_MSG(kC_TEXTENTRY, kTE_ENTER),
                  fWidgetId, 0);
      fClient->ProcessLine(fCommand, MK_MSG(kC_TEXTENTRY, kTE_ENTER),
                           fWidgetId, 0);
   }

   return kTRUE;
}

//______________________________________________________________________________
 Bool_t TGTextEntry::HandleFocusChange(Event_t *event)
{
   // Handle focus change event in text entry widget.

   if (!IsEnabled()) return kTRUE;

   // check this when porting to Win32
   if ((event->fCode == kNotifyNormal) && (event->fState != kNotifyPointer)) {
      if (event->fType == kFocusIn) {
         fCursorOn = kTRUE;
         if (!fCurBlink) fCurBlink = new TBlinkTimer(this, 500);
         fCurBlink->Reset();
         gSystem->AddTimer(fCurBlink);
      } else {
          fCursorOn    = kFALSE;
          fSelectionOn = kFALSE;
          if (fCurBlink) fCurBlink->Remove();
      }
      fClient->NeedRedraw(this);
   }
   return kTRUE;
}

//______________________________________________________________________________
 Bool_t TGTextEntry::HandleSelection(Event_t *event)
{
   // Handle text selection event.

   PastePrimary((Window_t)event->fUser[0], (Atom_t)event->fUser[3], kTRUE);

   return kTRUE;
}

//______________________________________________________________________________
 void TGTextEntry::PastePrimary(Window_t wid, Atom_t property, Bool_t del)
{
   // Paste text from selection (either primary or cut buffer) into
   // text entry widget.

   TString data;
   Int_t   nchar;

   if (!IsEnabled()) return;

   gGXW->GetPasteBuffer(wid, property, data, nchar, del);

   if (nchar) {
      // remove any previous selected text
      if (fSelectionOn) {
         int start, ns;

         start = TMath::Min(fStartIX, fEndIX);
         ns = TMath::Abs(fEndIX - fStartIX);
         fText->RemoveText(start, ns);
         fSelectionOn = kFALSE;
         fCursorIX = start;
      }

      fText->AddText(fCursorIX, data.Data(), nchar);
      int len = fText->GetTextLength();
      fCursorIX += nchar;
      if (fCursorIX > len) fCursorIX = len;
   }

   fCursorX = 4 + gGXW->TextWidth(fFontStruct, fText->GetString(), fCursorIX);
   fClient->NeedRedraw(this);

   SendMessage(fMsgWindow, MK_MSG(kC_TEXTENTRY, kTE_TEXTCHANGED),
               fWidgetId, 0);
   fClient->ProcessLine(fCommand, MK_MSG(kC_TEXTENTRY, kTE_TEXTCHANGED),
                        fWidgetId, 0);
}

//______________________________________________________________________________
 Bool_t TGTextEntry::HandleTimer(TTimer *)
{
   // Handle cursor blink timer.

   fCursorOn = !fCursorOn;
   DoRedraw();

   return kTRUE;
}


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.