/*
<ul>
<li> kNormal - display characters as they are entered. This is the default.
<li> kNoEcho - do not display anything.
<li> kPassword - display asterisks instead of the characters actually entered.
</ul>
*/
//End_Html
/*
<ul>
<li> kInsert - typed character are inserted (cursor has shape of short line).
<li> kReplace - typed characters substitute already typed ones
(cursor has the shape of filled rectangle).
</ul>
*/
//End_Html
/*
<ul>
<li> kTextLeft - left-side text alignment
<li> kTextRight - right-side text alignment
<li> kTextCenterX - center text alignment
</ul>
*/
//End_Html
/*
<ul>
<li><i> Left Arrow </i>
Move the cursor one character leftwards.
Scroll the text when cursor is out of frame.
<li><i> Right Arrow </i>
Move the cursor one character rightwards
Scroll the text when cursor is out of frame.
<li><i> Backspace </i>
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.
<li><i> Home </i>
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.
<li><i> End </i>
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.
<li><i> Delete </i>
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.
<li><i> Insert </i>
Switches character insert mode.
<li><i> Shift - Left Arrow </i>
Mark text one character leftwards
<li><i> Shift - Right Arrow </i>
Mark text one character rightwards
<li><i> Control - Left Arrow </i>
Move the cursor one word leftwards
<li><i> Control - Right Arrow </i>
Move the cursor one word rightwards.
<li><i> Control - Shift - Left Arrow </i>
Mark text one word leftwards
<li><i> Control - Shift - Right Arrow </i>
Mark text one word rightwards
<li><i> Control-A </i>
Move the cursor to the beginning of the line
<li><i> Control-B </i>
Move the cursor one character leftwards
<li><i> Control-C </i>
Copy the marked text to the clipboard.
<li><i> Control-D </i>
Delete the character to the right of the cursor
<li><i> Control-E </i>
Move the cursor to the end of the line
<li><i> Control-F </i>
Move the cursor one character rightwards
<li><i> Control-H </i>
Delete the character to the left of the cursor
<li><i> Control-K </i>
Delete marked text if any or delete all
characters to the right of the cursor
<li><i> Control-U </i>
Delete all characters on the line
<li><i> Control-V </i>
Paste the clipboard text into line edit.
<li><i> Control-X </i>
Cut the marked text, copy to clipboard.
<li><i> Control-Y </i>
Paste the clipboard text into line edit.
</ul>
All other keys with valid ASCII codes insert themselves into the line.
*/
//End_Html
#include "TGTextEntry.h"
#include "TGResourcePool.h"
#include "TGToolTip.h"
#include "TSystem.h"
#include "TTimer.h"
#include "TColor.h"
#include "KeySymbols.h"
#include "Riostream.h"
#include "TClass.h"
#include "TGMsgBox.h"
TString *TGTextEntry::fgClipboardText = 0;
const TGFont *TGTextEntry::fgDefaultFont = 0;
const TGGC *TGTextEntry::fgDefaultSelectedGC = 0;
const TGGC *TGTextEntry::fgDefaultSelectedBackgroundGC = 0;
const TGGC *TGTextEntry::fgDefaultGC = 0;
TGTextEntry *gBlinkingEntry = 0;
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 | kOwnBackground, back)
{
TGGC *normgc = fClient->GetResourcePool()->GetGCPool()->FindGC(norm);
fWidgetId = id;
fMsgWindow = p;
if (normgc)
fNormGC = *normgc;
else
fNormGC = GetDefaultGC();
fFontStruct = font;
fText = text;
Init();
}
TGTextEntry::TGTextEntry(const TGWindow *parent, const char *text, Int_t id) :
TGFrame(parent, 1, 1, kSunkenFrame | kDoubleBorder | kOwnBackground, fgWhitePixel)
{
fWidgetId = id;
fMsgWindow = parent;
fNormGC = GetDefaultGC();
fFontStruct = GetDefaultFontStruct();
fText = new TGTextBuffer();
fText->AddText(0, !text && !parent ? GetName() : text);
Init();
}
TGTextEntry::TGTextEntry(const TString &contents, const TGWindow *parent, Int_t id) :
TGFrame(parent, 1, 1, kSunkenFrame | kDoubleBorder | kOwnBackground, fgWhitePixel)
{
fWidgetId = id;
fMsgWindow = parent;
fNormGC = GetDefaultGC();
fFontStruct = GetDefaultFontStruct();
fText = new TGTextBuffer();
fText->AddText(0, contents.Data());
Init();
}
TGTextEntry::~TGTextEntry()
{
delete fText;
delete fCurBlink;
delete fTip;
if (this == gBlinkingEntry) gBlinkingEntry = 0;
}
void TGTextEntry::Init()
{
fWidgetFlags = kWidgetWantFocus | kWidgetIsEnabled;
fSelGC = GetDefaultSelectedGC();
fSelbackGC = GetDefaultSelectedBackgroundGC()();
fOffset = 0;
fMaxLen = 4096;
fFrameDrawn = kTRUE;
fEdited = kFALSE;
fEchoMode = kNormal;
fAlignment= kTextLeft;
fInsertMode = kInsert;
int tw, max_ascent, max_descent;
tw = gVirtualX->TextWidth(fFontStruct, GetText(), fText->GetTextLength());
if (tw < 1) {
TString dummy('w', fText->GetBufferLength());
tw = gVirtualX->TextWidth(fFontStruct, dummy.Data(), dummy.Length());
}
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;
fTip = 0;
fClipboard = fClient->GetResourcePool()->GetClipboard();
gVirtualX->SetCursor(fId, fClient->GetResourcePool()->GetTextCursor());
gVirtualX->GrabButton(fId, kAnyButton, kAnyModifier,
kButtonPressMask | kButtonReleaseMask |
kButtonMotionMask, kNone, kNone);
AddInput(kKeyPressMask | kFocusChangeMask |
kEnterWindowMask | kLeaveWindowMask);
SetWindowAttributes_t wattr;
wattr.fMask = kWAWinGravity | kWABitGravity;
wattr.fBitGravity = 1;
wattr.fWinGravity = 1;
gVirtualX->ChangeWindowAttributes(fId, &wattr);
SetWindowName();
fHasOwnFont = kFALSE;
fEditDisabled = kEditDisableHeight;
}
void TGTextEntry::ReturnPressed()
{
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::ShiftTabPressed()
{
Emit("ShiftTabPressed()");
}
void TGTextEntry::TabPressed()
{
SendMessage(fMsgWindow, MK_MSG(kC_TEXTENTRY, kTE_TAB), fWidgetId, 0);
fClient->ProcessLine(fCommand, MK_MSG(kC_TEXTENTRY, kTE_TAB), fWidgetId, 0);
Emit("TabPressed()");
}
void TGTextEntry::TextChanged(const char *)
{
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());
}
void TGTextEntry::CursorOutLeft()
{
Emit("CursorOutLeft()");
}
void TGTextEntry::CursorOutRight()
{
Emit("CursorOutRight()");
}
void TGTextEntry::CursorOutUp()
{
Emit("CursorOutUp()");
}
void TGTextEntry::CursorOutDown()
{
Emit("CursorOutDown()");
}
void TGTextEntry::DoubleClicked()
{
Emit("DoubleClicked()");
}
TString TGTextEntry::GetDisplayText() const
{
TString res;
switch (GetEchoMode()) {
case kNormal:
res = GetText();
break;
case kNoEcho:
res = "";
break;
case kPassword:
res.Prepend('*', fText->GetTextLength());
break;
}
return res;
}
void TGTextEntry::SetState(Bool_t state)
{
if (state) {
SetFlags(kWidgetIsEnabled);
SetBackgroundColor(fgWhitePixel);
} else {
ClearFlags(kWidgetIsEnabled);
SetBackgroundColor(GetDefaultFrameBackground());
fCursorOn = kFALSE;
if (fCurBlink) fCurBlink->Remove();
}
fClient->NeedRedraw(this);
}
Int_t TGTextEntry::GetCharacterIndex(Int_t xcoord)
{
int tw, ix, up, down, len;
TString dt = GetDisplayText();
len = dt.Length();
tw = gVirtualX->TextWidth(fFontStruct, dt.Data(), len);
if (xcoord < 0) return 0;
if (xcoord > tw) return len;
up = len;
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;
ix = TMath::Max(ix, 0);
ix = TMath::Min(ix, len);
return ix;
}
void TGTextEntry::SetFrameDrawn(Bool_t enable)
{
if (fFrameDrawn == enable) return;
fFrameDrawn = enable;
fClient->NeedRedraw(this);
}
void TGTextEntry::SetAlignment(ETextJustification mode)
{
if ((mode == kTextRight ||
mode == kTextCenterX ||
mode == kTextLeft)) {
SetWindowAttributes_t wattr;
wattr.fMask = kWAWinGravity | kWABitGravity;
wattr.fWinGravity = 1;
if (mode == kTextLeft) {
wattr.fBitGravity = 1;
} else if (mode == kTextRight) {
wattr.fBitGravity = 3;
} else {
wattr.fBitGravity = 5;
}
gVirtualX->ChangeWindowAttributes(fId, &wattr);
fAlignment = mode;
UpdateOffset();
fClient->NeedRedraw(this);
}
}
void TGTextEntry::SetInsertMode(EInsertMode mode)
{
if (fInsertMode == mode) return;
fInsertMode = mode;
fClient->NeedRedraw(this);
}
void TGTextEntry::SetText(const char *text, Bool_t emit)
{
TString oldText(GetText());
fText->Clear();
fText->AddText(0, text);
Int_t dif = fText->GetTextLength() - fMaxLen;
if (dif > 0) fText->RemoveText(fMaxLen, dif);
End(kFALSE);
if (oldText != GetText()) {
if (emit)
TextChanged();
fClient->NeedRedraw(this);
}
}
void TGTextEntry::SetMaxLength(Int_t maxlen)
{
fMaxLen = maxlen < 0 ? 0 : maxlen;
Int_t dif = fText->GetTextLength() - fMaxLen;
if (dif > 0) fText->RemoveText(fMaxLen, dif);
SetCursorPosition(0);
Deselect();
}
void TGTextEntry::SetEchoMode(EEchoMode mode)
{
// <ul>
// <li> kNormal - display characters as they are entered. This is the default.
// <li> kNoEcho - do not display anything.
// <li> kPassword - display asterisks instead of the characters actually entered.
// </ul>
//End_Html
if (fEchoMode == mode) return;
Int_t offset = IsFrameDrawn() ? 4 : 0;
fEchoMode = mode;
if (GetEchoMode() == kNoEcho) { fCursorX = offset; }
UpdateOffset();
fClient->NeedRedraw(this);
}
TString TGTextEntry::GetMarkedText() const
{
Int_t minP = MinMark();
Int_t len = MaxMark() - minP;
TString res(GetText()+minP,len);
return res;
}
void TGTextEntry::NewMark(Int_t newPos)
{
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)
{
Int_t offset = IsFrameDrawn() ? 4 : 0;
if (GetEchoMode() == kNoEcho) { fCursorX = offset; return; }
UpdateOffset();
TString dt = GetDisplayText();
Int_t x = fOffset + offset;
Int_t len = dt.Length();
Int_t pos;
if (newPos < len)
pos = newPos;
else {
pos = len;
if (newPos > len) CursorOutRight();
}
if (pos < 0) {
fCursorIX = 0;
CursorOutLeft();
} else
fCursorIX = pos;
fCursorX = x + gVirtualX->TextWidth(fFontStruct, dt.Data(), fCursorIX);
if (!fSelectionOn){
fStartIX = fCursorIX;
fStartX = fCursorX;
}
}
void TGTextEntry::MarkWord(Int_t pos)
{
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)
{
TString old(GetText());
TString t(newText);
if (t.IsNull()) return;
for (int i=0; i<t.Length(); i++) {
if (t[i] < ' ') t[i] = ' ';
}
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);
SetCursorPosition(ncp);
if (old != GetText()) TextChanged();
}
void TGTextEntry::CursorRight(Bool_t mark, Int_t steps)
{
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)
{
CursorRight(mark, -steps);
}
void TGTextEntry::CursorWordForward(Bool_t mark)
{
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)
{
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()
{
if (HasMarkedText()) {
Del();
} else if (fCursorIX > 0) {
CursorLeft(kFALSE);
Del();
}
}
void TGTextEntry::Del()
{
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()
{
if (fCursorIX < (Int_t)fText->GetTextLength()) {
fText->RemoveText(fCursorIX , fText->GetTextLength() - fCursorIX);
SetCursorPosition(fCursorIX);
TextChanged();
}
}
void TGTextEntry::CopyText() const
{
if (HasMarkedText() && GetEchoMode() == kNormal) {
if (!fgClipboardText) fgClipboardText = new TString();
*fgClipboardText = GetMarkedText();
gVirtualX->SetPrimarySelectionOwner(fId);
}
}
void TGTextEntry::Paste()
{
if (gVirtualX->GetPrimarySelectionOwner() == kNone) {
if (fgClipboardText) Insert(fgClipboardText->Data());
} else {
gVirtualX->ConvertPrimarySelection(fId, fClipboard, 0);
}
}
void TGTextEntry::Cut()
{
if (HasMarkedText()) {
CopyText();
Del();
}
}
void TGTextEntry::Clear(Option_t *)
{
SetText("");
}
void TGTextEntry::Home(Bool_t mark)
{
fOffset = 0;
if (mark){
fSelectionOn = kTRUE;
fStartIX = fCursorIX;
NewMark(0);
} else {
fSelectionOn = kFALSE;
SetCursorPosition(0);
}
}
void TGTextEntry::End(Bool_t mark)
{
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()
{
fSelectionOn = kTRUE;
fStartIX = 0;
NewMark(fText->GetTextLength());
DoRedraw();
}
void TGTextEntry::Deselect()
{
fSelectionOn = kFALSE;
fEndIX = fStartIX = fCursorIX;
DoRedraw();
}
void TGTextEntry::DrawBorder()
{
switch (fOptions & (kSunkenFrame | kRaisedFrame | kDoubleBorder)) {
case kSunkenFrame | kDoubleBorder:
gVirtualX->DrawLine(fId, GetShadowGC()(), 0, 0, fWidth-2, 0);
gVirtualX->DrawLine(fId, GetShadowGC()(), 0, 0, 0, fHeight-2);
gVirtualX->DrawLine(fId, GetBlackGC()(), 1, 1, fWidth-3, 1);
gVirtualX->DrawLine(fId, GetBlackGC()(), 1, 1, 1, fHeight-3);
gVirtualX->DrawLine(fId, GetHilightGC()(), 0, fHeight-1, fWidth-1, fHeight-1);
gVirtualX->DrawLine(fId, GetHilightGC()(), fWidth-1, fHeight-1, fWidth-1, 0);
gVirtualX->DrawLine(fId, GetBckgndGC()(), 1, fHeight-2, fWidth-2, fHeight-2);
gVirtualX->DrawLine(fId, GetBckgndGC()(), fWidth-2, 1, fWidth-2, fHeight-2);
break;
default:
TGFrame::DrawBorder();
break;
}
}
void TGTextEntry::DoRedraw()
{
Int_t x, y, max_ascent, max_descent, h;
Int_t offset = IsFrameDrawn() ? 4 : 0;
TString dt = GetDisplayText();
Int_t len = dt.Length();
Int_t border = IsFrameDrawn() ? fBorderWidth : 0;
gVirtualX->ClearArea(fId, border, border,
fWidth - (border << 1), fHeight - (border << 1));
gVirtualX->GetFontProperties(fFontStruct, max_ascent, max_descent);
h = max_ascent + max_descent;
y = (fHeight - h) >> 1 ;
x = fOffset + offset;
if (fEchoMode == kNoEcho) {
fSelectionOn = kFALSE;
fCursorX = offset;
}
if ((GetInsertMode() == kInsert) || (fEchoMode == kNoEcho)) {
if (fCursorOn) {
gVirtualX->DrawLine(fId, GetBlackGC()(), fCursorX, y - 1,
fCursorX, h + 2);
}
gVirtualX->DrawString(fId, fNormGC(), x, y + max_ascent, dt.Data(), len);
} else {
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 ,
charWidth , h + 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, ws, h + 1);
gVirtualX->DrawString(fId, fSelGC(), xs, y + max_ascent,
dt.Data() + ixs, iws);
}
if (IsFrameDrawn()) DrawBorder();
}
Bool_t TGTextEntry::HandleKey(Event_t* event)
{
// <ul>
// <li><i> Left Arrow </i>
// Move the cursor one character leftwards.
// Scroll the text when cursor is out of frame.
// <li><i> Right Arrow </i>
// Move the cursor one character rightwards
// Scroll the text when cursor is out of frame.
// <li><i> Backspace </i>
// 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.
// <li><i> Home </i>
// 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.
// <li><i> End </i>
// 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.
// <li><i> Delete </i>
// 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.
// <li><i> Insert </i>
// Switches character insert mode.
// <li><i> Shift - Left Arrow </i>
// Mark text one character leftwards
// <li><i> Shift - Right Arrow </i>
// Mark text one character rightwards
// <li><i> Control - Left Arrow </i>
// Move the cursor one word leftwards
// <li><i> Control - Right Arrow </i>
// Move the cursor one word rightwards.
// <li><i> Control - Shift - Left Arrow </i>
// Mark text one word leftwards
// <li><i> Control - Shift - Right Arrow </i>
// Mark text one word rightwards
// <li><i> Control-A </i>
// Move the cursor to the beginning of the line
// <li><i> Control-B </i>
// Move the cursor one character leftwards
// <li><i> Control-C </i>
// Copy the marked text to the clipboard.
// <li><i> Control-D </i>
// Delete the character to the right of the cursor
// <li><i> Control-E </i>
// Move the cursor to the end of the line
// <li><i> Control-F </i>
// Move the cursor one character rightwards
// <li><i> Control-H </i>
// Delete the character to the left of the cursor
// <li><i> Control-K </i>
// Delete marked text if any or delete all
// characters to the right of the cursor
// <li><i> Control-U </i>
// Delete all characters on the line
// <li><i> Control-V </i>
// Paste the clipboard text into line edit.
// <li><i> Control-X </i>
// Cut the marked text, copy to clipboard.
// <li><i> Control-Y </i>
// Paste the clipboard text into line edit.
// </ul>
//End_Html
Int_t n;
char tmp[10];
UInt_t keysym;
if (fTip && event->fType == kGKeyPress) fTip->Hide();
if (!IsEnabled() || event->fType != kGKeyPress) 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();
if (!TestBit(kNotDeleted)) return kTRUE;
fSelectionOn = kFALSE;
} else if (event->fState & kKeyShiftMask && (EKeySym)keysym == kKey_Backtab) {
ShiftTabPressed();
fSelectionOn = kFALSE;
return kTRUE;
} else if ((EKeySym)keysym == kKey_Tab) {
TabPressed();
fSelectionOn = kFALSE;
} else if (event->fState & kKeyControlMask) {
switch ((EKeySym)keysym & ~0x20) {
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 &&
(EKeySym)keysym != kKey_Delete &&
(EKeySym)keysym != kKey_Backspace) {
Insert(tmp);
fSelectionOn = kFALSE;
} else {
switch ((EKeySym)keysym) {
case kKey_Down:
CursorOutDown();
break;
case kKey_Up:
CursorOutUp();
break;
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:
SetInsertMode(GetInsertMode() == kInsert ? kReplace : kInsert);
break;
default:
unknown++;
}
}
UpdateOffset();
fClient->NeedRedraw(this);
return kTRUE;
}
Bool_t TGTextEntry::HandleButton(Event_t *event)
{
if (fTip) fTip->Hide();
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) {
PastePrimary(fClient->GetDefaultRoot()->GetId(), kCutBuffer, kFALSE);
} else {
gVirtualX->ConvertPrimarySelection(fId, fClipboard, event->fTime);
}
}
}
if (event->fType == kButtonRelease)
if (event->fCode == kButton1)
CopyText();
return kTRUE;
}
Bool_t TGTextEntry::HandleCrossing(Event_t *event)
{
if (event->fType == kEnterNotify) {
if (fTip) fTip->Reset();
} else {
if (fTip) fTip->Hide();
}
return kTRUE;
}
Bool_t TGTextEntry::HandleMotion(Event_t *event)
{
if (!IsEnabled() || (GetEchoMode() == kNoEcho)) return kTRUE;
Int_t offset = IsFrameDrawn() ? 4 : 0;
Int_t x = fOffset + offset;
Int_t position = GetCharacterIndex(event->fX - x);
fSelectionOn = kTRUE;
NewMark(position);
UpdateOffset();
DoRedraw();
return kTRUE;
}
Bool_t TGTextEntry::HandleDoubleClick(Event_t *event)
{
if (!IsEnabled()) return kTRUE;
Int_t offset = IsFrameDrawn() ? 4 : 0;
Int_t x = fOffset + offset ;
DoubleClicked();
SetFocus();
if (fEchoMode == kNoEcho) return kTRUE;
Int_t position = GetCharacterIndex(event->fX - x);
MarkWord(position);
return kTRUE;
}
Bool_t TGTextEntry::HandleConfigureNotify(Event_t* event)
{
TGFrame::HandleConfigureNotify(event);
UpdateOffset();
return kTRUE;
}
Bool_t TGTextEntry::HandleFocusChange(Event_t *event)
{
if (!IsEnabled()) return kTRUE;
if (event->fType == kFocusIn) {
fCursorOn = kTRUE;
if (!fCurBlink) fCurBlink = new TBlinkTimer(this, 500);
fCurBlink->Reset();
gBlinkingEntry = this;
gSystem->AddTimer(fCurBlink);
} else {
fCursorOn = kFALSE;
if (fCurBlink) fCurBlink->Remove();
gBlinkingEntry = 0;
}
fClient->NeedRedraw(this);
return kTRUE;
}
Bool_t TGTextEntry::HandleSelection(Event_t *event)
{
PastePrimary((Window_t)event->fUser[0], (Atom_t)event->fUser[3], kTRUE);
return kTRUE;
}
Bool_t TGTextEntry::HandleSelectionClear(Event_t * )
{
fSelectionOn = kFALSE;
fEndIX = fStartIX = fCursorIX;
fClient->NeedRedraw(this);
return kTRUE;
}
Bool_t TGTextEntry::HandleSelectionRequest(Event_t *event)
{
Event_t reply;
char *buffer;
Long_t len;
Atom_t targets[2];
Atom_t type;
reply.fType = kSelectionNotify;
reply.fTime = event->fTime;
reply.fUser[0] = event->fUser[0];
reply.fUser[1] = event->fUser[1];
reply.fUser[2] = event->fUser[2];
reply.fUser[3] = event->fUser[3];
targets[0] = gVirtualX->InternAtom("TARGETS", kFALSE);
targets[1] = gVirtualX->InternAtom("XA_STRING", kFALSE);
if ((Atom_t)event->fUser[2] == targets[0]) {
type = gVirtualX->InternAtom("XA_ATOM", kFALSE);
gVirtualX->ChangeProperty((Window_t) event->fUser[0], (Atom_t) event->fUser[3],
type, (UChar_t*) targets, (Int_t) 2);
gVirtualX->SendEvent((Window_t)event->fUser[0], &reply);
return kTRUE;
}
len = 0;
if (fgClipboardText) len = fgClipboardText->Length();
buffer = new char[len+1];
if (fgClipboardText) strcpy (buffer, fgClipboardText->Data());
buffer[len] = '\0';
gVirtualX->ChangeProperty((Window_t) event->fUser[0], (Atom_t) event->fUser[3],
(Atom_t) event->fUser[2], (UChar_t*) buffer,
(Int_t) len);
delete [] buffer;
gVirtualX->SendEvent((Window_t)event->fUser[0], &reply);
return kTRUE;
}
void TGTextEntry::PastePrimary(Window_t wid, Atom_t property, Bool_t del)
{
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 *)
{
fCursorOn = !fCursorOn;
DoRedraw();
return kTRUE;
}
Bool_t TGTextEntry::IsCursorOutOfFrame()
{
Int_t offset = IsFrameDrawn() ? 4 : 0;
Int_t w = GetWidth();
return ((fCursorX < offset) || (fCursorX > w-offset));
}
void TGTextEntry::ScrollByChar()
{
if (GetEchoMode() == kNoEcho) return;
TString dt = GetDisplayText();
Int_t len = dt.Length();
Int_t ind = fCursorIX < len-1 ? fCursorIX : len-1;
Int_t charWidth = ind < 0 ? 4 : 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){
d -= offset;
fOffset -= d;
fCursorX -= d;
charWidth += d;
}
} else if (fCursorX > w-offset) {
fOffset -= charWidth;
fCursorX -= charWidth;
d = w - fCursorX;
if (d < offset) {
d -= offset;
fOffset += d;
fCursorX += d;
charWidth += d;
}
}
}
void TGTextEntry::UpdateOffset()
{
TString dt = GetDisplayText();
Int_t textWidth = gVirtualX->TextWidth(fFontStruct, dt.Data() , dt.Length());
Int_t offset = IsFrameDrawn() ? 4 : 0;
Int_t w = GetWidth() - 2 * offset;
if (textWidth > 0 && textWidth > w) {
if (IsCursorOutOfFrame()) ScrollByChar();
}
else if (fAlignment == kTextRight) fOffset = w - textWidth - 1;
else if (fAlignment == kTextCenterX) fOffset = (w - textWidth)/2;
else if (fAlignment == kTextLeft) fOffset = 0;
}
void TGTextEntry::SetToolTipText(const char *text, Long_t delayms)
{
if (fTip) {
delete fTip;
fTip = 0;
}
if (text && strlen(text))
fTip = new TGToolTip(fClient->GetDefaultRoot(), this, text, delayms);
}
void TGTextEntry::SetFocus()
{
if (gBlinkingEntry && (gBlinkingEntry != this)) {
gBlinkingEntry->fCurBlink->Remove();
}
RequestFocus();
}
void TGTextEntry::InsertText(const char *text, Int_t pos)
{
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)
{
InsertText(text, fText->GetTextLength());
}
void TGTextEntry::RemoveText(Int_t start, Int_t end)
{
Int_t pos = TMath::Min(start, end);
Int_t len = TMath::Abs(end-start);
TString newText(GetText());
newText.Remove(pos, len);
SetText(newText.Data());
}
void TGTextEntry::SetFont(FontStruct_t font, Bool_t local)
{
if (font == fFontStruct) return;
FontH_t v = gVirtualX->GetFontHandle(font);
if (!v) return;
if (local) {
TGGC *gc = new TGGC(fNormGC);
fHasOwnFont = kTRUE;
fNormGC = *gc;
gc = new TGGC(fSelGC);
fSelGC = *gc;
}
fNormGC.SetFont(v);
fSelGC.SetFont(v);
fFontStruct = font;
fClient->NeedRedraw(this);
}
void TGTextEntry::SetFont(const char *fontName, Bool_t local)
{
TGFont *font = fClient->GetFont(fontName);
if (font) {
SetFont(font->GetFontStruct(), local);
}
}
void TGTextEntry::SetFont(TGFont *font, Bool_t local)
{
if (font) {
SetFont(font->GetFontStruct(), local);
}
}
void TGTextEntry::SetTextColor(Pixel_t color, Bool_t local)
{
if (local) {
TGGC *gc = new TGGC(fNormGC);
fHasOwnFont = kTRUE;
fNormGC = *gc;
}
fNormGC.SetForeground(color);
fClient->NeedRedraw(this);
}
void TGTextEntry::SetTextColor(TColor *color, Bool_t local)
{
if (color) {
SetTextColor(color->GetPixel(), local);
}
}
FontStruct_t TGTextEntry::GetDefaultFontStruct()
{
if (!fgDefaultFont)
fgDefaultFont = gClient->GetResourcePool()->GetDefaultFont();
return fgDefaultFont->GetFontStruct();
}
const TGGC &TGTextEntry::GetDefaultGC()
{
if (!fgDefaultGC)
fgDefaultGC = gClient->GetResourcePool()->GetFrameGC();
return *fgDefaultGC;
}
const TGGC &TGTextEntry::GetDefaultSelectedGC()
{
if (!fgDefaultSelectedGC)
fgDefaultSelectedGC = gClient->GetResourcePool()->GetSelectedGC();
return *fgDefaultSelectedGC;
}
const TGGC &TGTextEntry::GetDefaultSelectedBackgroundGC()
{
if (!fgDefaultSelectedBackgroundGC)
fgDefaultSelectedBackgroundGC = gClient->GetResourcePool()->GetSelectedBckgndGC();
return *fgDefaultSelectedBackgroundGC;
}
void TGTextEntry::SavePrimitive(ostream &out, Option_t *option )
{
char quote = '"';
option = GetName()+5;
char parGC[50], parFont[50];
sprintf(parFont,"%s::GetDefaultFontStruct()",IsA()->GetName());
sprintf(parGC,"%s::GetDefaultGC()()",IsA()->GetName());
if ((GetDefaultFontStruct() != fFontStruct) || (GetDefaultGC()() != fNormGC.GetGC())) {
TGFont *ufont = gClient->GetResourcePool()->GetFontPool()->FindFont(fFontStruct);
if (ufont) {
ufont->SavePrimitive(out, option);
sprintf(parFont,"ufont->GetFontStruct()");
}
TGGC *userGC = gClient->GetResourcePool()->GetGCPool()->FindGC(fNormGC.GetGC());
if (userGC) {
userGC->SavePrimitive(out, option);
sprintf(parGC,"uGC->GetGC()");
}
}
if (fBackground != GetWhitePixel()) SaveUserColor(out, option);
out << " TGTextEntry *";
out << GetName() << " = new TGTextEntry(" << fParent->GetName()
<< ", new TGTextBuffer(" << GetBuffer()->GetBufferLength() << ")";
if (fBackground == GetWhitePixel()) {
if (GetOptions() == (kSunkenFrame | kDoubleBorder)) {
if (fFontStruct == GetDefaultFontStruct()) {
if (fNormGC() == GetDefaultGC()()) {
if (fWidgetId == -1) {
out <<");" << endl;
} else {
out << "," << fWidgetId << ");" << endl;
}
} else {
out << "," << fWidgetId << "," << parGC << ");" << endl;
}
} else {
out << "," << fWidgetId << "," << parGC << "," << parFont
<<");" << endl;
}
} else {
out << "," << fWidgetId << "," << parGC << "," << parFont
<< "," << GetOptionString() << ");" << endl;
}
} else {
out << "," << fWidgetId << "," << parGC << "," << parFont
<< "," << GetOptionString() << ",ucolor);" << endl;
}
out << " " << GetName() << "->SetMaxLength(" << GetMaxLength() << ");" << endl;
out << " " << GetName() << "->SetAlignment(";
if (fAlignment == kTextLeft)
out << "kTextLeft);" << endl;
if (fAlignment == kTextRight)
out << "kTextRight);" << endl;
if (fAlignment == kTextCenterX)
out << "kTextCenterX);" << endl;
out << " " << GetName() << "->SetText(" << quote << GetText() << quote
<< ");" << endl;
out << " " << GetName() << "->Resize("<< GetWidth() << "," << GetName()
<< "->GetDefaultHeight());" << endl;
if (fTip) {
TString tiptext = fTip->GetText()->GetString();
tiptext.ReplaceAll("\n", "\\n");
out << " ";
out << GetName() << "->SetToolTipText(" << quote
<< tiptext << quote << ");" << endl;
}
}