// @(#)root/gui:$Name: $:$Id: TGTextEntry.cxx,v 1.3 2000/07/11 09:29:10 rdm Exp $
// Author: Fons Rademakers 08/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.
**************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// 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. //
// Hitting the enter key will generate: //
// kC_TEXTENTRY, kTE_ENTER, widget id, 0. //
// //
// This widget has the behaviour e.g. of the "Location" field in //
// netscape. That includes handling Control/Shift key modifiers and //
// scrolling the text. //
//
//
// enum TGTextEntry::EEchoMode
//
// This enum type describes the ways in which TGTextEntry can display
// its contents. The currently defined values are:
//
/*
- kNormal - display characters as they are entered. This is the default.
- kNoEcho - do not display anything.
- kPassword - display asterisks instead of the characters actually entered.
*/
//
// See also SetEchoMode(), GetEchoMode().
//
// enum TGTextEntry::EInsertMode
//
// This enum type describes the way how typed characters are
// inserted in the text entry. This mode is switched by "Insert" key.
//
/*
- kInsert - typed character are inserted (cursor has shape of short line).
- kReplace - typed characters substitute already typed ones
(cursor has the shape of filled rectangle).
*/
//
//
// enum TGWidget::ETextJustification
//
// This enum type (defined in TGWidget.h) describes the text alignment modes.
// These modes are valid untill text fits the frame width
//
/*
- kTextLeft - left-side text alignment
- kTextRight - right-side text alignment
- kTextCenterX - center text alignment
*/
//
//
//
// The key press event handler converts a key press to some line editor action.
// Here are the default key bindings:
//
/*
- Left Arrow
Move the cursor one character leftwards.
Scroll the text when cursor is out of frame.
- Right Arrow
Move the cursor one character rightwards
Scroll the text when cursor is out of frame.
- Backspace
Deletes the character on the left side of the text cursor and moves the
cursor one position to the left. If a text has been marked by the user
(e.g. by clicking and dragging) the cursor will be put at the beginning
of the marked text and the marked text will be removed.
- Home
Moves the text cursor to the left end of the line. If mark is TRUE text
will be marked towards the first position, if not any marked text will
be unmarked if the cursor is moved.
- End
Moves the text cursor to the right end of the line. If mark is TRUE text
will be marked towards the last position, if not any marked text will
be unmarked if the cursor is moved.
- Delete
Deletes the character on the right side of the text cursor. If a text
has been marked by the user (e.g. by clicking and dragging) the cursor
will be put at the beginning of the marked text and the marked text will
be removed.
- Insert
Switches character insert mode.
- Shift - Left Arrow
Mark text one character leftwards
- Shift - Right Arrow
Mark text one character rightwards
- Control - Left Arrow
Move the cursor one word leftwards
- Control - Right Arrow
Move the cursor one word rightwards.
- Control - Shift - Left Arrow
Mark text one word leftwards
- Control - Shift - Right Arrow
Mark text one word rightwards
- Control-A
Move the cursor to the beginning of the line
- Control-B
Move the cursor one character leftwards
- Control-C
Copy the marked text to the clipboard.
- Control-D
Delete the character to the right of the cursor
- Control-E
Move the cursor to the end of the line
- Control-F
Move the cursor one character rightwards
- Control-H
Delete the character to the left of the cursor
- Control-K
Delete marked text if any or delete all
characters to the right of the cursor
- Control-U
Delete all characters on the line
- Control-V
Paste the clipboard text into line edit.
- Control-X
Cut the marked text, copy to clipboard.
- Control-Y
Paste the clipboard text into line edit.
All other keys with valid ASCII codes insert themselves into the line.
*/
//
//
////////////////////////////////////////////////////////////////////////////////
//******************* TGTextEntry signals *************************************
//______________________________________________________________________________
// TGTextEntry::ReturnPressed()
//
// This signal is emitted when the return or enter key is pressed.
//______________________________________________________________________________
// TGTextEntry::TextChanged(const Text* text)
//
// This signal is emitted every time the text has changed.
// The argument is the new text.
//
#include "TGTextEntry.h"
#include "TSystem.h"
#include "TMath.h"
#include "TTimer.h"
#include "KeySymbols.h"
//______________________________________________________________________________
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)
TString *TGTextEntry::fgClipboardText = 0; // application clipboard prototype
//______________________________________________________________________________
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;
fMsgWindow = p;
fNormGC = norm;
fFontStruct = font;
fText = text;
Init();
}
//______________________________________________________________________________
TGTextEntry::TGTextEntry(const TGWindow *parent, const char *text, Int_t id):
TGFrame(parent, 1, 1, kSunkenFrame | kDoubleBorder, fgWhitePixel)
{
// Simple text entry constructor.
fWidgetId = id;
fMsgWindow = parent;
fNormGC = fgDefaultGC;
fFontStruct = fgDefaultFontStruct;
fText = new TGTextBuffer();
fText->AddText(0, text);
Init(); // default initialization
}
//______________________________________________________________________________
TGTextEntry::TGTextEntry(const TString &contents, const TGWindow *parent, Int_t id) :
TGFrame(parent, 1, 1, kSunkenFrame | kDoubleBorder, fgWhitePixel)
{
// Simple test entry constructor. Notice TString argument comes before the
// parent argument (to make this ctor different from the first one taking a
// const char*).
fWidgetId = id;
fMsgWindow = parent;
fNormGC = fgDefaultGC;
fFontStruct = fgDefaultFontStruct;
fText = new TGTextBuffer();
fText->AddText(0, contents.Data());
Init(); // default initialization
}
//______________________________________________________________________________
TGTextEntry::~TGTextEntry()
{
// Delete a text entry widget.
if (fDeleteGC) {
gVirtualX->DeleteGC(fNormGC);
gVirtualX->DeleteGC(fSelGC);
}
delete fText;
delete fCurBlink;
}
//______________________________________________________________________________
void TGTextEntry::Init()
{
// Do default initialization.
fWidgetFlags = kWidgetWantFocus | kWidgetIsEnabled;
fSelGC = fgDefaultSelectedGC;
fSelbackGC = fgDefaultSelectedBackgroundGC;
fDeleteGC = kFALSE;
fOffset = 0;
fMaxLen = 255; // TString::Length() can not exceed 255 characters
fFrameDrawn = kTRUE;
fEdited = kFALSE;
fEchoMode = kNormal;
fAlignment= kTextLeft;
fInsertMode = kInsert;
int tw, max_ascent, max_descent;
tw = gVirtualX->TextWidth(fFontStruct, GetText(), fText->GetTextLength());
gVirtualX->GetFontProperties(fFontStruct, max_ascent, max_descent);
Resize(tw + 8, max_ascent + max_descent + 7);
Int_t offset = IsFrameDrawn() ? 4 : 0;
fCursorX = offset ;
fCursorIX = fStartIX = fEndIX = fOffset = 0;
fSelectionOn = fCursorOn = kFALSE;
fCurBlink = 0;
fClipboard = fgClipboard;
gVirtualX->SetCursor(fId, fgDefaultCursor);
gVirtualX->GrabButton(fId, kAnyButton, kAnyModifier,
kButtonPressMask | kButtonReleaseMask | kPointerMotionMask, kNone, kNone);
gVirtualX->SelectInput(fId, kKeyPressMask | kExposureMask | kFocusChangeMask);
}
//______________________________________________________________________________
void TGTextEntry::ReturnPressed()
{
// This signal is emitted when the return or enter key is pressed.
SendMessage(fMsgWindow, MK_MSG(kC_TEXTENTRY, kTE_ENTER), fWidgetId, 0);
fClient->ProcessLine(fCommand, MK_MSG(kC_TEXTENTRY, kTE_ENTER),fWidgetId, 0);
// Emit("ReturnPressed()");
}
//______________________________________________________________________________
void TGTextEntry::TextChanged(const char *)
{
// This signal is emitted every time the text has changed.
SendMessage(fMsgWindow, MK_MSG(kC_TEXTENTRY, kTE_TEXTCHANGED),fWidgetId, 0);
fClient->ProcessLine(fCommand, MK_MSG(kC_TEXTENTRY, kTE_TEXTCHANGED),fWidgetId, 0);
// Emit("TextChanged(char*)", GetText()); // The argument is the new text.
}
//______________________________________________________________________________
TString TGTextEntry::GetDisplayText() const
{
// Returns the text that's currently displayed. This is normally
// the same as GetText(), but can be e.g.
// "*****" if EEchoMode is kPassword or
// "" if it is kNoEcho.
TString res;
switch (GetEchoMode()) {
case kNormal:
res = GetText();
break;
case kNoEcho:
res = "";
break;
case kPassword:
res.Prepend('*', fText->GetTextLength()); // fill with '*'
break;
}
return res;
}
//______________________________________________________________________________
void TGTextEntry::SetFont(FontStruct_t font)
{
// Changes text entry font.
if (font != fFontStruct) {
GCValues_t gval;
fFontStruct = font;
// get unique copies of the norm GC and the sel GC (if not already copied)
if (!fDeleteGC) {
GContext_t norm = gVirtualX->CreateGC(fId, 0);
gVirtualX->CopyGC(fNormGC, norm, 0);
fNormGC = norm;
GContext_t sel = gVirtualX->CreateGC(fId, 0);
gVirtualX->CopyGC(fSelGC, sel, 0);
fSelGC = sel;
}
gval.fMask = kGCFont;
gval.fFont = gVirtualX->GetFontHandle(fFontStruct);
gVirtualX->ChangeGC(fNormGC,&gval);
gVirtualX->ChangeGC(fSelGC,&gval);
fClient->NeedRedraw(this);
fDeleteGC = kTRUE;
}
}
//______________________________________________________________________________
void TGTextEntry::SetFont(const char *fontName)
{
// Changes text entry font specified by name.
FontStruct_t tfont = gClient->GetFontByName(fontName);
if (!tfont) return;
SetFont(tfont);
}
//______________________________________________________________________________
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);
}
//______________________________________________________________________________
Int_t TGTextEntry::GetCharacterIndex(Int_t xcoord)
{
// Returns the index of the character to whose left edge goalx is closest.
int tw, ix, up, down, len;
// check for out of boundaries first...
TString dt = GetDisplayText();
len = dt.Length();
tw = gVirtualX->TextWidth(fFontStruct, dt.Data(), 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 = gVirtualX->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;
}
//______________________________________________________________________________
void TGTextEntry::SetFrameDrawn(Bool_t enable)
{
// Sets the text entry to draw itself inside a two-pixel frame if
// enable is kTRUE, and to draw itself without any frame if enable is
// kFALSE. The default is kTRUE.
if (fFrameDrawn == enable) return;
fFrameDrawn = enable;
fClient->NeedRedraw(this);
// ChangedBy("SetFrameDrawn"); // emit signal ChangedBy
}
//______________________________________________________________________________
void TGTextEntry::SetAlignment(ETextJustification mode)
{
// Sets the alignment of the text entry.
// Possible values are kTextLeft(default), kTextRight, kTextCenterX.
// See also GetAlignment().
if ((mode == kTextRight ||
mode == kTextCenterX ||
mode == kTextLeft) &&
(mode != fAlignment)) {
fAlignment = mode;
UpdateOffset();
fClient->NeedRedraw(this);
// ChangedBy("SetAlignment"); // emit signal ChangedBy
}
}
//______________________________________________________________________________
void TGTextEntry::SetInsertMode(EInsertMode mode)
{
// Sets the mode how characters are entered to the text entry.
if (fInsertMode == mode) return;
fInsertMode = mode;
fClient->NeedRedraw(this);
// ChangedBy("SetInsertMode"); // emit signal ChangedBy
}
//______________________________________________________________________________
void TGTextEntry::SetText(const char *text)
{
// Sets text entry to text, clears the selection and moves
// the cursor to the end of the line.
// If necessary the text is truncated to fit MaxLength().
// See also GetText().
TString oldText(GetText());
fText->Clear();
fText->AddText(0, text); // new text
Int_t dif = fText->GetTextLength() - fMaxLen;
if (dif>0) fText->RemoveText(fMaxLen, dif); // truncate
End(kFALSE);
if (oldText != GetText()) {
TextChanged(); // emit signal
fClient->NeedRedraw(this);
}
}
//______________________________________________________________________________
void TGTextEntry::SetMaxLength(Int_t maxlen)
{
// Set the maximum length of the text in the editor. If the text is
// currently too long, it is chopped off at the limit. Any marked text will
// be unmarked. The cursor position is set to 0 and the first part of the
// string is shown. The range of maxlen is (0,255)
// See also GetMaxLength().
fMaxLen = maxlen<0 ? 0 : TMath::Min(255,maxlen) ; // safety check for maxlen<0 and maxlen>255
Int_t dif = fText->GetTextLength() - fMaxLen;
if (dif>0) fText->RemoveText(fMaxLen, dif); // truncate
SetCursorPosition(0);
Deselect();
// ChangedBy("SetMaxLength"); // emit signal ChangedBy
}
//______________________________________________________________________________
void TGTextEntry::SetEchoMode(EEchoMode mode)
{
// The echo modes available are:
//
//
// kNormal - display characters as they are entered. This is the default.
// kNoEcho - do not display anything.
// kPassword - display asterisks instead of the characters actually entered.
//
//
// It is always possible to cut and paste any marked text; only the widget's own
// display is affected.
// See also GetEchoMode(), GetDisplayText()
if (fEchoMode == mode) return;
Int_t offset = IsFrameDrawn() ? 4 : 0;
fEchoMode = mode;
if (GetEchoMode() == kNoEcho) { fCursorX = offset; }
UpdateOffset();
fClient->NeedRedraw(this);
// ChangedBy("SetEchoMode"); // emit signal ChangedBy
}
//______________________________________________________________________________
TString TGTextEntry::GetMarkedText() const
{
// Returns the text marked by the user (e.g. by clicking and
// dragging), or zero if no text is marked.
// See also HasMarkedText()
Int_t minP = MinMark();
Int_t len = MaxMark() - minP;
TString res(GetText()+minP,len);
return res;
}
//______________________________________________________________________________
void TGTextEntry::NewMark(Int_t newPos)
{
// New character mark at position pos
// See also SetCursorPosition()
TString dt = GetDisplayText();
Int_t offset = IsFrameDrawn() ? 4 : 0;
Int_t x = fOffset + offset;
Int_t len = dt.Length();
Int_t pos = newPos < len ? newPos : len;
fEndIX = pos < 0 ? 0 : pos;
fSelectionOn = fSelectionOn && (fEndIX != fStartIX) && (GetEchoMode() != kNoEcho) ;
SetCursorPosition(pos);
if (fSelectionOn) {
fEndX = x + gVirtualX->TextWidth(fFontStruct, dt.Data() , fEndIX);
fStartX = x + gVirtualX->TextWidth(fFontStruct, dt.Data() , fStartIX);
}
}
//______________________________________________________________________________
void TGTextEntry::SetCursorPosition(Int_t newPos)
{
// Set the cursor position to newPos.
// See also NewMark().
Int_t offset = IsFrameDrawn() ? 4 : 0;
if (GetEchoMode() == kNoEcho) { fCursorX = offset; return; }
TString dt = GetDisplayText();
Int_t x = fOffset + offset;
Int_t len = dt.Length();
Int_t pos = newPos < len ? newPos : len;
fCursorIX = pos < 0 ? 0 : pos;
fCursorX = x + gVirtualX->TextWidth(fFontStruct, dt.Data() , fCursorIX);
if (!fSelectionOn){
fStartIX = fCursorIX;
fStartX = fCursorX;
}
}
//______________________________________________________________________________
void TGTextEntry::MarkWord(Int_t pos)
{
// Marks the word nearest to cursor position
// See also HandleDoubleClick()
Int_t i = pos - 1;
while (i >= 0 && isprint(GetText()[i]) && !isspace(GetText()[i])) i--;
i++;
Int_t newStartIX = i;
i = pos;
while (isprint(GetText()[i]) && !isspace(GetText()[i])) i++;
while(isspace(GetText()[i])) i++;
fSelectionOn = kTRUE;
fStartIX = newStartIX;
fEndIX = i;
NewMark(i);
}
//______________________________________________________________________________
void TGTextEntry::Insert(const char *newText)
{
// Removes any currently selected text, inserts newText,
// sets it as the new contents of the text entry.
TString old(GetText());
TString t(newText);
if (t.IsNull()) return;
for (int i=0; i<t.Length(); i++) {
if (t[i] < ' ') t[i] = ' '; // unprintable/linefeed becomes space
}
Int_t minP = MinMark();
Int_t maxP = MaxMark();
Int_t cp = fCursorIX;
if (HasMarkedText()) {
fText->RemoveText(minP, maxP-minP);
cp = minP;
}
if (fInsertMode == kReplace) fText->RemoveText(cp,t.Length());
Int_t ncp = TMath::Min(cp+t.Length(), GetMaxLength());
fText->AddText(cp, t.Data());
Int_t dlen = fText->GetTextLength()-GetMaxLength();
if (dlen>0) fText->RemoveText(GetMaxLength(),dlen); // truncate
SetCursorPosition(ncp);
if (old != GetText()) TextChanged();
}
//______________________________________________________________________________
void TGTextEntry::CursorRight(Bool_t mark, Int_t steps)
{
// Moves the cursor rightwards one or more characters.
// See also CursorLeft().
Int_t cp = fCursorIX + steps;
if (cp == fCursorIX) {
if (!mark) {
fSelectionOn = kFALSE;
fEndIX = fStartIX = fCursorIX;
}
} else if (mark) {
fSelectionOn = kTRUE;
NewMark(cp);
} else {
fSelectionOn = kFALSE;
SetCursorPosition(cp);
}
}
//______________________________________________________________________________
void TGTextEntry::CursorLeft(Bool_t mark, Int_t steps)
{
// Moves the cursor leftwards one or more characters.
// See also CursorRight().
CursorRight(mark, -steps);
}
//______________________________________________________________________________
void TGTextEntry::CursorWordForward(Bool_t mark)
{
// Moves the cursor one word to the right. If mark is kTRUE, the text
// is marked.
// See also CursorWordBackward().
Int_t i = fCursorIX;
while (i < (Int_t)fText->GetTextLength() && !isspace(GetText()[i])) ++i;
while (i < (Int_t)fText->GetTextLength() && isspace(GetText()[i])) ++i;
CursorRight(mark, i - fCursorIX);
}
//______________________________________________________________________________
void TGTextEntry::CursorWordBackward(Bool_t mark)
{
// Moves the cursor one word to the left. If mark is kTRUE, the text
// is marked.
// See also CursorWordForward().
Int_t i = fCursorIX;
while (i > 0 && isspace(GetText()[i-1])) --i;
while (i > 0 && !isspace(GetText()[i-1])) --i;
CursorLeft(mark, fCursorIX - i);
}
//______________________________________________________________________________
void TGTextEntry::Backspace()
{
// Deletes the character on the left side of the text cursor and moves the
// cursor one position to the left. If a text has been marked by the user
// (e.g. by clicking and dragging) the cursor will be put at the beginning
// of the marked text and the marked text will be removed.
// See also Del().
if (HasMarkedText()) {
Del();
} else if (fCursorIX > 0) {
CursorLeft(kFALSE);
Del();
}
}
//______________________________________________________________________________
void TGTextEntry::Del()
{
// Deletes the character on the right side of the text cursor. If a text
// has been marked by the user (e.g. by clicking and dragging) the cursor
// will be put at the beginning of the marked text and the marked text will
// be removed.
// See also Backspace().
Int_t minP = MinMark();
Int_t maxP = MaxMark();
if (HasMarkedText()) {
fText->RemoveText(minP, maxP-minP);
fSelectionOn = kFALSE;
SetCursorPosition(minP);
} else if (fCursorIX != (Int_t)fText->GetTextLength()) {
fSelectionOn = kFALSE;
fText->RemoveText(fCursorIX , 1);
SetCursorPosition(fCursorIX);
}
TextChanged();
}
//______________________________________________________________________________
void TGTextEntry::Remove()
{
// Deletes all characters on the right side of the cursor
// See also Del() Backspace().
if (fCursorIX < (Int_t)fText->GetTextLength()) {
fText->RemoveText(fCursorIX , fText->GetTextLength() - fCursorIX);
SetCursorPosition(fCursorIX);
TextChanged(); // emit signal
}
}
//______________________________________________________________________________
void TGTextEntry::CopyText() const
{
// Copies the marked text to the clipboard, if there is any and
// GetEchoMode() is kNormal.
// See also Cut() Paste().
if (HasMarkedText() && GetEchoMode() == kNormal) {
if (!fgClipboardText) fgClipboardText = new TString();
*fgClipboardText = GetMarkedText(); // assign
}
}
//______________________________________________________________________________
void TGTextEntry::Paste()
{
// Inserts text at the cursor position, deleting any
// previous marked text.
// See also CopyText() Cut().
if (fgClipboardText) Insert(fgClipboardText->Data());
}
//______________________________________________________________________________
void TGTextEntry::Cut()
{
// Copies the marked text to the clipboard and deletes it, if there is any.
// See also CopyText() Paste().
if (HasMarkedText()) {
CopyText();
Del();
}
}
//______________________________________________________________________________
void TGTextEntry::Clear(Option_t *)
{
// Clears up the text entry.
SetText("");
}
//______________________________________________________________________________
void TGTextEntry::Home(Bool_t mark)
{
// Moves the text cursor to the left end of the line. If mark is kTRUE text
// will be marked towards the first position, if not any marked text will
// be unmarked if the cursor is moved.
// See also End().
fOffset = 0;
if (mark){
fSelectionOn = kTRUE;
fStartIX = fCursorIX;
NewMark(0);
} else {
fSelectionOn = kFALSE;
SetCursorPosition(0);
}
}
//______________________________________________________________________________
void TGTextEntry::End(Bool_t mark)
{
// Moves the text cursor to the right end of the line. If mark is kTRUE text
// will be marked towards the last position, if not any marked text will
// be unmarked if the cursor is moved.
// See also Home().
TString dt = GetDisplayText();
Int_t len = dt.Length();
fOffset = (Int_t)GetWidth() - gVirtualX->TextWidth(fFontStruct, dt.Data(), len);
if (fOffset > 0) fOffset = 0;
if (mark){
fSelectionOn = kTRUE;
fStartIX = fCursorIX;
NewMark(len);
} else {
fSelectionOn = kFALSE;
SetCursorPosition(len);
}
}
//______________________________________________________________________________
void TGTextEntry::SelectAll()
{
// Selects all text (i.e. marks it) and moves the cursor to the
// end. Useful when a default value has been inserted. If the user
// types before clicking on the widget the selected text will be
// erased.
fSelectionOn = kTRUE;
fStartIX = 0;
NewMark(fText->GetTextLength());
DoRedraw();
}
//______________________________________________________________________________
void TGTextEntry::Deselect()
{
// Deselects all text (i.e. removes marking) and leaves the cursor at the
// current position.
fSelectionOn = kFALSE;
fEndIX = fStartIX = fCursorIX;
DoRedraw();
}
//______________________________________________________________________________
void TGTextEntry::DrawBorder()
{
// Draw the border of the text entry widget.
switch (fOptions & (kSunkenFrame | kRaisedFrame | kDoubleBorder)) {
case kSunkenFrame | kDoubleBorder:
gVirtualX->DrawLine(fId, fgShadowGC, 0, 0, fWidth-2, 0);
gVirtualX->DrawLine(fId, fgShadowGC, 0, 0, 0, fHeight-2);
gVirtualX->DrawLine(fId, fgBlackGC, 1, 1, fWidth-3, 1);
gVirtualX->DrawLine(fId, fgBlackGC, 1, 1, 1, fHeight-3);
gVirtualX->DrawLine(fId, fgHilightGC, 0, fHeight-1, fWidth-1, fHeight-1);
gVirtualX->DrawLine(fId, fgHilightGC, fWidth-1, fHeight-1, fWidth-1, 0);
gVirtualX->DrawLine(fId, fgBckgndGC, 1, fHeight-2, fWidth-2, fHeight-2);
gVirtualX->DrawLine(fId, fgBckgndGC, fWidth-2, 1, fWidth-2, fHeight-2);
break;
default:
TGFrame::DrawBorder();
break;
}
}
//______________________________________________________________________________
void TGTextEntry::DoRedraw()
{
// Draw the text entry widget.
Int_t x, y, max_ascent, max_descent;
Int_t offset = IsFrameDrawn() ? 4 : 0;
TString dt = GetDisplayText(); // text to be displayed
Int_t len = dt.Length(); // length of displayed text
// TGFrame::DoRedraw() == drawing border twice
Int_t border = IsFrameDrawn() ? fBorderWidth : 0;
gVirtualX->ClearArea(fId, border, border,
fWidth - (border << 1), fHeight - (border << 1));
gVirtualX->GetFontProperties(fFontStruct, max_ascent, max_descent);
y = (GetHeight() - (max_ascent + max_descent))/2 ; // center y
x = fOffset + offset;
if (fEchoMode == kNoEcho) {
fSelectionOn = kFALSE;
fCursorX = offset;
}
if ((GetInsertMode() == kInsert) || (fEchoMode == kNoEcho)) { // line cursor
if (fCursorOn) {
gVirtualX->DrawLine(fId, fgBlackGC, fCursorX, 3,
fCursorX, max_ascent + max_descent + 3);
}
gVirtualX->DrawString(fId, fNormGC, x , y + max_ascent, dt.Data(), len);
} else { // filled rectangle cursor (not perfect)
gVirtualX->DrawString(fId, fNormGC, x , y + max_ascent, dt.Data(), len);
if (fCursorOn) {
Int_t ind = fCursorIX < len-1 ? fCursorIX : len-1;
Int_t charWidth = ind < 0 || fCursorIX > len -1 ? 4 :
gVirtualX->TextWidth(fFontStruct, &dt[ind],1);
Int_t before = gVirtualX->TextWidth(fFontStruct, dt, fCursorIX) + x;
gVirtualX->FillRectangle(fId, fSelbackGC , before, y-1 ,
charWidth , max_ascent + max_descent + 1);
if (fCursorIX < len)
gVirtualX->DrawString(fId, fSelGC, before , y + max_ascent, &dt[ind], 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);
gVirtualX->FillRectangle(fId, fSelbackGC, xs , y-1, ws,
max_ascent + max_descent +1);
gVirtualX->DrawString(fId, fSelGC, xs, y + max_ascent,
dt.Data()+ixs, iws);
}
if (IsFrameDrawn()) DrawBorder();
}
//______________________________________________________________________________
Bool_t TGTextEntry::HandleKey(Event_t* event)
{
// The key press event handler converts a key press to some line editor action.
// Here are the default key bindings:
//
//
// Left Arrow
// Move the cursor one character leftwards.
// Scroll the text when cursor is out of frame.
// Right Arrow
// Move the cursor one character rightwards
// Scroll the text when cursor is out of frame.
// Backspace
// Deletes the character on the left side of the text cursor and moves the
// cursor one position to the left. If a text has been marked by the user
// (e.g. by clicking and dragging) the cursor will be put at the beginning
// of the marked text and the marked text will be removed.
// Home
// Moves the text cursor to the left end of the line. If mark is TRUE text
// will be marked towards the first position, if not any marked text will
// be unmarked if the cursor is moved.
// End
// Moves the text cursor to the right end of the line. If mark is TRUE text
// will be marked towards the last position, if not any marked text will
// be unmarked if the cursor is moved.
// Delete
// Deletes the character on the right side of the text cursor. If a text
// has been marked by the user (e.g. by clicking and dragging) the cursor
// will be put at the beginning of the marked text and the marked text will
// be removed.
// Insert
// Switches character insert mode.
// Shift - Left Arrow
// Mark text one character leftwards
// Shift - Right Arrow
// Mark text one character rightwards
// Control - Left Arrow
// Move the cursor one word leftwards
// Control - Right Arrow
// Move the cursor one word rightwards.
// Control - Shift - Left Arrow
// Mark text one word leftwards
// Control - Shift - Right Arrow
// Mark text one word rightwards
// Control-A
// Move the cursor to the beginning of the line
// Control-B
// Move the cursor one character leftwards
// Control-C
// Copy the marked text to the clipboard.
// Control-D
// Delete the character to the right of the cursor
// Control-E
// Move the cursor to the end of the line
// Control-F
// Move the cursor one character rightwards
// Control-H
// Delete the character to the left of the cursor
// Control-K
// Delete marked text if any or delete all
// characters to the right of the cursor
// Control-U
// Delete all characters on the line
// Control-V
// Paste the clipboard text into line edit.
// Control-X
// Cut the marked text, copy to clipboard.
// Control-Y
// Paste the clipboard text into line edit.
//
//
// All other keys with valid ASCII codes insert themselves into the line.
Int_t n;
char tmp[10];
UInt_t keysym;
if (!IsEnabled()) return kTRUE;
gVirtualX->LookupString(event, tmp, sizeof(tmp), keysym);
n = strlen(tmp);
Int_t unknown = 0;
if ((EKeySym)keysym == kKey_Enter || (EKeySym)keysym == kKey_Return) {
ReturnPressed(); // emit signal
if (!TestBit(kNotDeleted)) return kTRUE;
fSelectionOn = kFALSE;
} else if (event->fState & kKeyControlMask) { // Cntrl key modifier pressed
switch ((EKeySym)keysym & ~0x20) { // treat upper and lower the same
case kKey_A:
Home(event->fState & kKeyShiftMask);
break;
case kKey_B:
CursorLeft(event->fState & kKeyShiftMask);
break;
case kKey_C:
CopyText();
break;
case kKey_D:
Del();
break;
case kKey_E:
End(event->fState & kKeyShiftMask);
break;
case kKey_F:
CursorRight(event->fState & kKeyShiftMask);
break;
case kKey_H:
Backspace();
break;
case kKey_K:
HasMarkedText() ? Del() : Remove();
break;
case kKey_U:
Home();
Remove();
break;
case kKey_V:
Paste();
break;
case kKey_X:
Cut();
break;
case kKey_Y:
Paste();
break;
case kKey_Right:
CursorWordForward(event->fState & kKeyShiftMask);
break;
case kKey_Left:
CursorWordBackward(event->fState & kKeyShiftMask);
break;
default:
unknown++;
}
} else if (n && keysym <127 && keysym >=32 && // printable keys
(EKeySym)keysym != kKey_Delete &&
(EKeySym)keysym != kKey_Backspace) {
Insert(tmp);
fSelectionOn = kFALSE;
} else {
switch ((EKeySym)keysym) {
case kKey_Left:
CursorLeft(event->fState & kKeyShiftMask);
break;
case kKey_Right:
CursorRight(event->fState & kKeyShiftMask);
break;
case kKey_Backspace:
Backspace();
break;
case kKey_Home:
Home(event->fState & kKeyShiftMask);
break;
case kKey_End:
End(event->fState & kKeyShiftMask);
break;
case kKey_Delete:
Del();
break;
case kKey_Insert: // switch on/off insert mode
SetInsertMode(GetInsertMode() == kInsert ? kReplace : kInsert);
break;
default:
unknown++;
}
}
UpdateOffset();
fClient->NeedRedraw(this);
return kTRUE;
}
//______________________________________________________________________________
Bool_t TGTextEntry::HandleButton(Event_t *event)
{
// Handle mouse button event in text entry widget.
if (!IsEnabled()) return kTRUE;
if (event->fType == kButtonPress) {
SetFocus();
if (fEchoMode == kNoEcho) return kTRUE;
if (event->fCode == kButton1) {
Int_t offset = IsFrameDrawn() ? 4 : 0;
Int_t x = fOffset + offset;
Int_t position = GetCharacterIndex(event->fX - x);
fSelectionOn = kFALSE;
SetCursorPosition(position);
DoRedraw();
} else if (event->fCode == kButton2) {
if (gVirtualX->GetPrimarySelectionOwner() == kNone) {
// No primary selection, so use the cut buffer
PastePrimary(fClient->GetRoot()->GetId(), kCutBuffer, kFALSE);
} else {
gVirtualX->ConvertPrimarySelection(fId, fClipboard, event->fTime);
}
}
}
return kTRUE;
}
//______________________________________________________________________________
Bool_t TGTextEntry::HandleMotion(Event_t *event)
{
// Handle mouse motion event in the text entry widget.
if (!IsEnabled() || (GetEchoMode() == kNoEcho)) return kTRUE;
Int_t offset = IsFrameDrawn() ? 4 : 0;
Int_t x = fOffset + offset ;
Int_t position = GetCharacterIndex(event->fX - x); // + 1;
fSelectionOn = kTRUE;
NewMark(position);
UpdateOffset();
DoRedraw();
return kTRUE;
}
//______________________________________________________________________________
Bool_t TGTextEntry::HandleDoubleClick(Event_t *event)
{
// Handle mouse double click event in the text entry widge
if (!IsEnabled()) return kTRUE;
Int_t offset = IsFrameDrawn() ? 4 : 0;
Int_t x = fOffset + offset ;
SetFocus();
if (fEchoMode == kNoEcho) return kTRUE;
Int_t position = GetCharacterIndex(event->fX - x);
MarkWord(position);
return kTRUE;
}
//______________________________________________________________________________
Bool_t TGTextEntry::HandleConfigureNotify(Event_t* event)
{
// Handles resize events for this widget.
TGFrame::HandleConfigureNotify(event);
UpdateOffset();
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; // "netscape location behavior"
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;
gVirtualX->GetPasteBuffer(wid, property, data, nchar, del);
if (nchar) Insert(data.Data());
fClient->NeedRedraw(this);
}
//______________________________________________________________________________
Bool_t TGTextEntry::HandleTimer(TTimer *)
{
// Handle cursor blink timer.
fCursorOn = !fCursorOn;
DoRedraw();
return kTRUE;
}
//______________________________________________________________________________
Bool_t TGTextEntry::IsCursorOutOfFrame()
{
// Returns kTRUE if cursor is out of frame.
// fCursorX = fOffset + 4 + gVirtualX->TextWidth(fFontStruct,
// GetDisplayText(), fCursorIX);
Int_t offset = IsFrameDrawn() ? 4 : 0;
Int_t w = GetWidth();
return ((fCursorX < offset) || (fCursorX > w-offset));
}
//______________________________________________________________________________
void TGTextEntry::ScrollByChar()
{
// Shift position of cursor by one character.
if (GetEchoMode() == kNoEcho) return;
TString dt = GetDisplayText();
Int_t len = dt.Length();
Int_t ind = fCursorIX < len-1 ? fCursorIX : len-1;
Int_t charWidth = gVirtualX->TextWidth(fFontStruct, &dt[ind],1);
Int_t w = GetWidth();
Int_t d;
Int_t offset = IsFrameDrawn() ? 4 : 0;
if (fCursorX < offset) {
fOffset += charWidth;
fCursorX += charWidth;
d = fCursorX;
if (d < offset){ // correction
d -= offset;
fOffset -= d;
fCursorX -= d;
charWidth += d;
}
} else if (fCursorX > w-offset) {
fOffset -= charWidth;
fCursorX -= charWidth;
d = w - fCursorX;
if (d < offset) { // correction
d -= offset;
fOffset += d;
fCursorX += d;
charWidth += d;
}
}
}
//______________________________________________________________________________
void TGTextEntry::UpdateOffset()
{
// Updates start text offset according GetAlignment() mode,
// if cursor is out of frame => scroll the text.
// See also SetAlignment() and ScrollByChar().
TString dt = GetDisplayText();
Int_t textWidth = gVirtualX->TextWidth(fFontStruct, dt.Data() , dt.Length());
Int_t w = GetWidth();
if (textWidth > w) { // may need to scroll.
if (IsCursorOutOfFrame()) ScrollByChar();
}
else if (fAlignment == kTextRight) fOffset = w - textWidth;
else if (fAlignment == kTextCenterX) fOffset = (w - textWidth)/2;
else if (fAlignment == kTextLeft) fOffset = 0;
}
//______________________________________________________________________________
void TGTextEntry::SetFocus()
{
// Gives the keyboard input focus to this text entry widget.
gVirtualX->SetInputFocus(fId);
}
//_____________________________________________________________________
void TGTextEntry::InsertText(const char *text, Int_t pos)
{
// Inserts text at position pos, clears the selection and moves
// the cursor to the end of the line.
// If necessary the text is truncated to fit MaxLength().
// See also GetText(), SetText(), AppendText(), RemoveText().
Int_t position = TMath::Min((Int_t)fText->GetTextLength(), pos);
TString newText(GetText());
newText.Insert(position, text);
SetText(newText.Data());
}
//_____________________________________________________________________
void TGTextEntry::AppendText(const char *text)
{
// Appends text to the end of text entry, clears the selection
// and moves the cursor to the end of the line.
// If necessary the text is truncated to fit MaxLength().
// See also GetText(), InsertText(), SetText(), RemoveText().
InsertText(text, fText->GetTextLength());
}
//_____________________________________________________________________
void TGTextEntry::RemoveText(Int_t start, Int_t end)
{
// Removes text at the range, clears the selection and moves
// the cursor to the end of the line.
// See also GetText(), InsertText(), SetText(), AppendText().
Int_t pos = TMath::Min(start, end);
Int_t len = TMath::Abs(end-start);
TString newText(GetText());
newText.Remove(pos, len);
SetText(newText.Data());
}
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.