Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGTextEdit.cxx
Go to the documentation of this file.
1 // @(#)root/gui:$Id$
2 // Author: Fons Rademakers 3/7/2000
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 /**************************************************************************
12 
13  This source is based on Xclass95, a Win95-looking GUI toolkit.
14  Copyright (C) 1996, 1997 David Barth, Ricky Ralston, Hector Peraza.
15 
16  Xclass95 is free software; you can redistribute it and/or
17  modify it under the terms of the GNU Library General Public
18  License as published by the Free Software Foundation; either
19  version 2 of the License, or (at your option) any later version.
20 
21 **************************************************************************/
22 
23 //////////////////////////////////////////////////////////////////////////
24 // //
25 // TGTextEdit //
26 // //
27 // A TGTextEdit is a specialization of TGTextView. It provides the //
28 // text edit functionality to the static text viewing widget. //
29 // For the messages supported by this widget see the TGView class. //
30 // //
31 //////////////////////////////////////////////////////////////////////////
32 
33 #include "TGTextEdit.h"
34 #include "TGTextEditDialogs.h"
35 #include "TGResourcePool.h"
36 #include "TSystem.h"
37 #include "TMath.h"
38 #include "TTimer.h"
39 #include "TGMenu.h"
40 #include "TGMsgBox.h"
41 #include "TGFileDialog.h"
42 #include "TGScrollBar.h"
43 #include "KeySymbols.h"
44 #include "Riostream.h"
45 #include "RConfigure.h"
46 
47 
48 static const char *gFiletypes[] = { "All files", "*",
49  "Text files", "*.txt",
50  "ROOT macros", "*.C",
51  0, 0 };
52 static char *gPrinter = 0;
53 static char *gPrintCommand = 0;
54 
55 
56 TGGC *TGTextEdit::fgCursor0GC;
57 TGGC *TGTextEdit::fgCursor1GC;
58 
59 
60 ///////////////////////////////////////////////////////////////////////////////
61 class TGTextEditHist : public TList {
62 
63 public:
64  TGTextEditHist() {}
65  virtual ~TGTextEditHist() { Delete(); }
66 
67  Bool_t Notify() { //
68  TObject *obj = Last();
69  if (!obj) return kFALSE;
70 
71  obj->Notify(); // execute undo action
72  RemoveLast();
73  delete obj;
74  return kTRUE;
75  }
76 };
77 
78 ///////////////////////////////////////////////////////////////////////////////
79 class TGTextEditCommand : public TObject {
80 protected:
81  TGTextEdit *fEdit;
82  TGLongPosition fPos;
83 
84 public:
85  TGTextEditCommand(TGTextEdit *te) : fEdit(te) {
86  fPos = fEdit->GetCurrentPos();
87  fEdit->GetHistory()->Add(this);
88  }
89  void SetPos(TGLongPosition pos) { fPos = pos; }
90 };
91 
92 ///////////////////////////////////////////////////////////////////////////////
93 class TInsCharCom : public TGTextEditCommand {
94 
95 public:
96  TInsCharCom(TGTextEdit *te, char ch) : TGTextEditCommand(te) {
97  fEdit->InsChar(ch);
98  }
99  Bool_t Notify() { //
100  fEdit->SetCurrent(fPos);
101  fEdit->NextChar();
102  fEdit->DelChar();
103  return kTRUE;
104  }
105 };
106 
107 ///////////////////////////////////////////////////////////////////////////////
108 class TDelCharCom : public TGTextEditCommand {
109 
110 private:
111  char fChar;
112 
113 public:
114  TDelCharCom(TGTextEdit *te) : TGTextEditCommand(te) {
115  fPos.fX--;
116  fChar = fEdit->GetText()->GetChar(fPos);
117  fEdit->DelChar();
118  }
119  Bool_t Notify() { //
120  if (fChar > 0) {
121  fEdit->SetCurrent(fPos);
122  fEdit->InsChar(fChar);
123  } else {
124  fPos.fY--;
125  fEdit->BreakLine();
126  }
127  return kTRUE;
128  }
129 };
130 
131 ///////////////////////////////////////////////////////////////////////////////
132 class TBreakLineCom : public TGTextEditCommand {
133 
134 public:
135  TBreakLineCom(TGTextEdit *te) : TGTextEditCommand(te) {
136  fEdit->BreakLine();
137  fPos.fX = 0;
138  fPos.fY++;
139  }
140 
141  Bool_t Notify() { //
142  fEdit->SetCurrent(fPos);
143  fEdit->DelChar();
144  return kTRUE;
145  }
146 };
147 
148 ///////////////////////////////////////////////////////////////////////////////
149 class TInsTextCom : public TGTextEditCommand {
150 private:
151  TGLongPosition fEndPos;
152 
153 public:
154  char fChar;
155 
156  TInsTextCom(TGTextEdit *te) : TGTextEditCommand(te), fChar(0) {
157  }
158 
159  void SetEndPos(TGLongPosition end) {
160  fEndPos = end;
161  }
162 
163  Bool_t Notify() { //
164  fEdit->GetText()->DelText(fPos, fEndPos);
165 
166  if (fChar > 0) {
167  fEdit->GetText()->InsChar(fPos, fChar);
168  } else if (fPos.fY != fEndPos.fY) {
169  fEdit->GetText()->BreakLine(fPos);
170  }
171  fEdit->SetCurrent(fPos);
172  fEdit->Update();
173  return kTRUE;
174  }
175 };
176 
177 ///////////////////////////////////////////////////////////////////////////////
178 class TDelTextCom : public TGTextEditCommand {
179 
180 private:
181  TGText *fText;
182  TGLongPosition fEndPos;
183  Bool_t fBreakLine;
184 
185 public:
186  TDelTextCom(TGTextEdit *te, TGText *txt) : TGTextEditCommand(te) {
187  fText = new TGText(txt);
188  fBreakLine = kFALSE;
189  }
190  TDelTextCom(const TDelTextCom &dtc) : TGTextEditCommand(dtc) {
191  fText = new TGText(dtc.fText);
192  fBreakLine = dtc.fBreakLine;
193  }
194  virtual ~TDelTextCom() { delete fText; }
195 
196  TDelTextCom &operator=(const TDelTextCom &dtc) {
197  if (this != &dtc) {
198  if (fText) delete fText;
199  fText = new TGText(dtc.fText);
200  fBreakLine = dtc.fBreakLine;
201  }
202  return *this;
203  }
204 
205  void SetEndPos(TGLongPosition end) {
206  fEndPos = end;
207  }
208 
209  void SetBreakLine(Bool_t on) { fBreakLine = on; }
210 
211  Bool_t Notify() { //
212  TGLongPosition start_src, end_src;
213  start_src.fX = start_src.fY = 0;
214  end_src.fY = fText->RowCount() - 1;
215  end_src.fX = fText->GetLineLength(end_src.fY) - 1;
216 
217  fEdit->GetText()->InsText(fPos, fText, start_src, end_src);
218 
219  if (fBreakLine) {
220  fEndPos.fY++;
221  fEdit->GetText()->BreakLine(fEndPos);
222  fEndPos.fX = fEdit->GetText()->GetLineLength(fEndPos.fY);
223  } else {
224  fEndPos.fX++;
225  }
226 
227  fEdit->SetCurrent(fEndPos);
228  fEdit->Update();
229  return kTRUE;
230  }
231 };
232 
233 
234 ClassImp(TGTextEdit);
235 
236 
237 ////////////////////////////////////////////////////////////////////////////////
238 /// Create a text edit widget.
239 
240 TGTextEdit::TGTextEdit(const TGWindow *parent, UInt_t w, UInt_t h, Int_t id,
241  UInt_t sboptions, ULong_t back) :
242  TGTextView(parent, w, h, id, sboptions, back)
243 {
244  Init();
245 }
246 
247 ////////////////////////////////////////////////////////////////////////////////
248 /// Create a text edit widget. Initialize it with the specified text buffer.
249 
250 TGTextEdit::TGTextEdit(const TGWindow *parent, UInt_t w, UInt_t h, TGText *text,
251  Int_t id, UInt_t sboptions, ULong_t back) :
252  TGTextView(parent, w, h, text, id, sboptions, back)
253 {
254  Init();
255 }
256 
257 ////////////////////////////////////////////////////////////////////////////////
258 /// Create a text edit widget. Initialize it with the specified string.
259 
260 TGTextEdit::TGTextEdit(const TGWindow *parent, UInt_t w, UInt_t h,
261  const char *string, Int_t id, UInt_t sboptions,
262  ULong_t back) :
263  TGTextView(parent, w, h, string, id, sboptions, back)
264 {
265  Init();
266 }
267 
268 ////////////////////////////////////////////////////////////////////////////////
269 /// Cleanup text edit widget.
270 
271 TGTextEdit::~TGTextEdit()
272 {
273  if (TGSearchDialog::SearchDialog()) {
274  TQObject::Disconnect(TGSearchDialog::SearchDialog(), 0, this);
275  }
276  delete fCurBlink;
277  delete fMenu;
278  delete fHistory;
279 }
280 
281 ////////////////////////////////////////////////////////////////////////////////
282 /// Initiliaze a text edit widget.
283 
284 void TGTextEdit::Init()
285 {
286  fCursor0GC = GetCursor0GC()();
287  fCursor1GC = GetCursor1GC()();
288  fCursorState = 1;
289  fCurrent.fY = fCurrent.fX = 0;
290  fInsertMode = kInsert;
291  fCurBlink = 0;
292  fSearch = 0;
293  fEnableMenu = kTRUE;
294  fEnableCursorWithoutFocus = kTRUE;
295 
296  gVirtualX->SetCursor(fCanvas->GetId(), fClient->GetResourcePool()->GetTextCursor());
297 
298  // create popup menu with default editor actions
299  fMenu = new TGPopupMenu(fClient->GetDefaultRoot());
300  fMenu->AddEntry("New", kM_FILE_NEW);
301  fMenu->AddEntry("Open...", kM_FILE_OPEN);
302  fMenu->AddSeparator();
303  fMenu->AddEntry("Close", kM_FILE_CLOSE);
304  fMenu->AddEntry("Save", kM_FILE_SAVE);
305  fMenu->AddEntry("Save As...", kM_FILE_SAVEAS);
306  fMenu->AddSeparator();
307  fMenu->AddEntry("Print...", kM_FILE_PRINT);
308  fMenu->AddSeparator();
309  fMenu->AddEntry("Cut", kM_EDIT_CUT);
310  fMenu->AddEntry("Copy", kM_EDIT_COPY);
311  fMenu->AddEntry("Paste", kM_EDIT_PASTE);
312  fMenu->AddEntry("Select All", kM_EDIT_SELECTALL);
313  fMenu->AddSeparator();
314  fMenu->AddEntry("Find...", kM_SEARCH_FIND);
315  fMenu->AddEntry("Find Again", kM_SEARCH_FINDAGAIN);
316  fMenu->AddEntry("Goto...", kM_SEARCH_GOTO);
317 
318  fMenu->Associate(this);
319 
320  fHistory = new TGTextEditHist();
321 }
322 
323 ////////////////////////////////////////////////////////////////////////////////
324 /// Enable/disable menu items in function of what is possible.
325 
326 void TGTextEdit::SetMenuState()
327 {
328  if (fText->RowCount() == 1 && fText->GetLineLength(0) <= 0) {
329  fMenu->DisableEntry(kM_FILE_CLOSE);
330  fMenu->DisableEntry(kM_FILE_SAVE);
331  fMenu->DisableEntry(kM_FILE_SAVEAS);
332  fMenu->DisableEntry(kM_FILE_PRINT);
333  fMenu->DisableEntry(kM_EDIT_SELECTALL);
334  fMenu->DisableEntry(kM_SEARCH_FIND);
335  fMenu->DisableEntry(kM_SEARCH_FINDAGAIN);
336  fMenu->DisableEntry(kM_SEARCH_GOTO);
337  } else {
338  fMenu->EnableEntry(kM_FILE_CLOSE);
339  fMenu->EnableEntry(kM_FILE_SAVE);
340  fMenu->EnableEntry(kM_FILE_SAVEAS);
341  fMenu->EnableEntry(kM_FILE_PRINT);
342  fMenu->EnableEntry(kM_EDIT_SELECTALL);
343  fMenu->EnableEntry(kM_SEARCH_FIND);
344  fMenu->EnableEntry(kM_SEARCH_FINDAGAIN);
345  fMenu->EnableEntry(kM_SEARCH_GOTO);
346  }
347 
348  if (IsSaved())
349  fMenu->DisableEntry(kM_FILE_SAVE);
350  else
351  fMenu->EnableEntry(kM_FILE_SAVE);
352 
353  if (fIsMarked) {
354  fMenu->EnableEntry(kM_EDIT_CUT);
355  fMenu->EnableEntry(kM_EDIT_COPY);
356  } else {
357  fMenu->DisableEntry(kM_EDIT_CUT);
358  fMenu->DisableEntry(kM_EDIT_COPY);
359  }
360 }
361 
362 ////////////////////////////////////////////////////////////////////////////////
363 /// Return width of longest line in widget.
364 
365 Long_t TGTextEdit::ReturnLongestLineWidth()
366 {
367  Long_t linewidth = TGTextView::ReturnLongestLineWidth();
368  linewidth += 3*fScrollVal.fX;
369  return linewidth;
370 }
371 
372 ////////////////////////////////////////////////////////////////////////////////
373 /// Clear text edit widget.
374 
375 void TGTextEdit::Clear(Option_t *)
376 {
377  fCursorState = 1;
378  fCurrent.fY = fCurrent.fX = 0;
379  TGTextView::Clear();
380 }
381 
382 ////////////////////////////////////////////////////////////////////////////////
383 /// Save file. If filename==0 ask user via dialog for a filename, if in
384 /// addition saveas==kTRUE always ask for new filename. Returns
385 /// kTRUE if file was correctly saved, kFALSE otherwise.
386 
387 Bool_t TGTextEdit::SaveFile(const char *filename, Bool_t saveas)
388 {
389  if (!filename) {
390  Bool_t untitled = !strlen(fText->GetFileName()) ? kTRUE : kFALSE;
391  if (untitled || saveas) {
392  static TString dir(".");
393  static Bool_t overwr = kFALSE;
394  TGFileInfo fi;
395  fi.fFileTypes = gFiletypes;
396  fi.fIniDir = StrDup(dir);
397  fi.fOverwrite = overwr;
398  new TGFileDialog(fClient->GetDefaultRoot(), this, kFDSave, &fi);
399  overwr = fi.fOverwrite;
400  if (fi.fFilename && strlen(fi.fFilename)) {
401  dir = fi.fIniDir;
402  return fText->Save(fi.fFilename);
403  }
404  return kFALSE;
405  }
406  return fText->Save(fText->GetFileName());
407  }
408 
409  return fText->Save(filename);
410 }
411 
412 ////////////////////////////////////////////////////////////////////////////////
413 /// Copy text.
414 
415 Bool_t TGTextEdit::Copy()
416 {
417  if (!fIsMarked || ((fMarkedStart.fX == fMarkedEnd.fX) &&
418  (fMarkedStart.fY == fMarkedEnd.fY))) {
419  return kFALSE;
420  }
421 
422  TGTextView::Copy();
423 
424  Bool_t del = !fCurrent.fX && (fCurrent.fY == fMarkedEnd.fY) && !fMarkedEnd.fX;
425  del = del || (!fMarkedEnd.fX && (fCurrent.fY != fMarkedEnd.fY));
426  del = del && fClipText->AsString().Length() > 0;
427 
428  if (del) {
429  TGLongPosition pos;
430  pos.fY = fClipText->RowCount();
431  pos.fX = 0;
432  fClipText->InsText(pos, 0);
433  }
434 
435  return kTRUE;
436 }
437 
438 ////////////////////////////////////////////////////////////////////////////////
439 /// Cut text.
440 
441 Bool_t TGTextEdit::Cut()
442 {
443  if (!Copy()) {
444  return kFALSE;
445  }
446  Delete();
447 
448  return kTRUE;
449 }
450 
451 ////////////////////////////////////////////////////////////////////////////////
452 /// Paste text into widget.
453 
454 Bool_t TGTextEdit::Paste()
455 {
456  if (fReadOnly) {
457  return kFALSE;
458  }
459 
460  if (fIsMarked) {
461  TString sav = fClipText->AsString();
462  TGTextView::Copy();
463  Delete();
464  fClipText->Clear();
465  fClipText->LoadBuffer(sav.Data());
466  }
467 
468  gVirtualX->ConvertPrimarySelection(fId, fClipboard, 0);
469 
470  return kTRUE;
471 }
472 
473 ////////////////////////////////////////////////////////////////////////////////
474 /// Send current buffer to printer.
475 
476 void TGTextEdit::Print(Option_t *) const
477 {
478  TString msg;
479 
480  msg.Form("%s -P%s\n", gPrintCommand, gPrinter);
481  FILE *p = gSystem->OpenPipe(msg.Data(), "w");
482  if (p) {
483  char *buf1, *buf2;
484  Long_t len;
485  ULong_t i = 0;
486  TGLongPosition pos;
487 
488  pos.fX = pos.fY = 0;
489  while (pos.fY < fText->RowCount()) {
490  len = fText->GetLineLength(pos.fY);
491  if (len < 0) len = 0;
492  buf1 = fText->GetLine(pos, len);
493  buf2 = new char[len + 2];
494  strncpy(buf2, buf1, (UInt_t)len);
495  buf2[len] = '\n';
496  buf2[len+1] = '\0';
497  while (buf2[i] != '\0') {
498  if (buf2[i] == '\t') {
499  ULong_t j = i+1;
500  while (buf2[j] == 16)
501  j++;
502  // coverity[secure_coding]
503  strcpy(buf2+i+1, buf2+j);
504  }
505  i++;
506  }
507  fwrite(buf2, sizeof(char), strlen(buf2)+1, p);
508 
509  delete [] buf1;
510  delete [] buf2;
511  pos.fY++;
512  }
513  gSystem->ClosePipe(p);
514 
515  Bool_t untitled = !strlen(fText->GetFileName()) ? kTRUE : kFALSE;
516  msg.Form("Printed: %s\nLines: %ld\nUsing: %s -P%s",
517  untitled ? "Untitled" : fText->GetFileName(),
518  fText->RowCount() - 1, gPrintCommand, gPrinter);
519  new TGMsgBox(fClient->GetDefaultRoot(), this, "Editor", msg.Data(),
520  kMBIconAsterisk, kMBOk, 0);
521  } else {
522  msg.Form("Could not execute: %s -P%s\n", gPrintCommand, gPrinter);
523  new TGMsgBox(fClient->GetDefaultRoot(), this, "Editor", msg.Data(),
524  kMBIconExclamation, kMBOk, 0);
525  }
526 }
527 
528 ////////////////////////////////////////////////////////////////////////////////
529 /// Delete selection.
530 
531 void TGTextEdit::Delete(Option_t *)
532 {
533  if (!fIsMarked || fReadOnly) {
534  return;
535  }
536 
537  if (fMarkedStart.fX == fMarkedEnd.fX &&
538  fMarkedStart.fY == fMarkedEnd.fY) {
539  Long_t len = fText->GetLineLength(fCurrent.fY);
540 
541  if (fCurrent.fY == fText->RowCount()-1 && fCurrent.fX == len) {
542  gVirtualX->Bell(0);
543  return;
544  }
545 
546  new TDelCharCom(this);
547  return;
548  }
549 
550  TGLongPosition pos, endPos;
551  Bool_t delast = kFALSE;
552 
553  endPos.fX = fMarkedEnd.fX - 1;
554  endPos.fY = fMarkedEnd.fY;
555 
556  if (endPos.fX == -1) {
557  pos = fCurrent;
558  if (endPos.fY > 0) {
559  SetCurrent(endPos);
560  DelChar();
561  endPos.fY--;
562  SetCurrent(pos);
563  }
564  endPos.fX = fText->GetLineLength(endPos.fY);
565  if (endPos.fX < 0) {
566  endPos.fX = 0;
567  }
568  delast = kTRUE;
569  }
570 
571  // delete command for undo
572  TDelTextCom *dcom = new TDelTextCom(this, fClipText);
573  dcom->SetPos(fMarkedStart);
574  dcom->SetEndPos(endPos);
575 
576  if (delast || ((fText->GetLineLength(endPos.fY) == endPos.fX+1) &&
577  (fClipText->RowCount() > 1))) {
578  TGLongPosition p = endPos;
579 
580  p.fY--;
581  if (!delast) p.fX++;
582  dcom->SetEndPos(p);
583  dcom->SetBreakLine(kTRUE);
584  }
585 
586  fText->DelText(fMarkedStart, endPos);
587 
588  pos.fY = ToObjYCoord(fVisible.fY);
589 
590  if (fMarkedStart.fY < pos.fY) {
591  pos.fY = fMarkedStart.fY;
592  }
593  pos.fX = ToObjXCoord(fVisible.fX, pos.fY);
594  if (fMarkedStart.fX < pos.fX) {
595  pos.fX = fMarkedStart.fX;
596  }
597 
598  Int_t th = (Int_t)ToScrYCoord(fText->RowCount());
599  Int_t ys = (Int_t)ToScrYCoord(fMarkedStart.fY);
600  th = th < 0 ? 0 : th;
601  ys = ys < 0 ? 0 : ys;
602 
603  // clear
604  if ((th < 0) || (th < (Int_t)fCanvas->GetHeight())) {
605  gVirtualX->ClearArea(fCanvas->GetId(), 0, ys,
606  fCanvas->GetWidth(), fCanvas->GetHeight() - ys);
607  }
608 
609  UpdateRegion(0, ys, fCanvas->GetWidth(), UInt_t(fCanvas->GetHeight() - ys));
610 
611  SetVsbPosition((ToScrYCoord(pos.fY) + fVisible.fY)/fScrollVal.fY);
612  SetHsbPosition((ToScrXCoord(pos.fX, pos.fY) + fVisible.fX)/fScrollVal.fX);
613  SetSBRange(kHorizontal);
614  SetSBRange(kVertical);
615  SetCurrent(fMarkedStart);
616 
617  SendMessage(fMsgWindow, MK_MSG(kC_TEXTVIEW, kTXT_ISMARKED), fWidgetId, kFALSE);
618  UnMark();
619 
620  // only to make sure that IsSaved() returns true in case everything has
621  // been deleted
622  if (fText->RowCount() == 1 && fText->GetLineLength(0) == 0) {
623  delete fText;
624  fText = new TGText();
625  fText->Clear();
626  }
627 }
628 
629 ////////////////////////////////////////////////////////////////////////////////
630 /// Search for string in the specified direction. If direction is true
631 /// the search will be in forward direction.
632 
633 Bool_t TGTextEdit::Search(const char *string, Bool_t direction,
634  Bool_t caseSensitive)
635 {
636  if (!IsMapped()) return kFALSE;
637 
638  if (gTQSender && (gTQSender == TGSearchDialog::SearchDialog())) {
639  caseSensitive = TGSearchDialog::SearchDialog()->GetType()->fCaseSensitive;
640  direction = TGSearchDialog::SearchDialog()->GetType()->fDirection;
641  fSearch = TGSearchDialog::SearchDialog()->GetType();
642  }
643 
644  TGLongPosition pos;
645  if (!fText->Search(&pos, fCurrent, string, direction, caseSensitive)) {
646  fCurrent.fX = 1;
647  fCurrent.fY = 1;
648 
649  if (!fText->Search(&pos, fCurrent, string, direction, caseSensitive)) { //try again
650  TString msg;
651  msg.Form("Couldn't find \"%s\"", string);
652  gVirtualX->Bell(20);
653  new TGMsgBox(fClient->GetDefaultRoot(), fCanvas, "TextEdit",
654  msg.Data(), kMBIconExclamation, kMBOk, 0);
655  return kFALSE;
656  }
657  return kTRUE;
658  }
659  UnMark();
660  fIsMarked = kTRUE;
661  fMarkedStart.fY = fMarkedEnd.fY = pos.fY;
662  fMarkedStart.fX = pos.fX;
663  fMarkedEnd.fX = fMarkedStart.fX + strlen(string);
664 
665  if (direction) {
666  SetCurrent(fMarkedEnd);
667  } else {
668  SetCurrent(fMarkedStart);
669  }
670 
671  pos.fY = ToObjYCoord(fVisible.fY);
672  if (fCurrent.fY < pos.fY ||
673  ToScrYCoord(fCurrent.fY) >= (Int_t)fCanvas->GetHeight()) {
674  pos.fY = fMarkedStart.fY;
675  }
676  pos.fX = ToObjXCoord(fVisible.fX, pos.fY);
677 
678  if (fCurrent.fX < pos.fX ||
679  ToScrXCoord(fCurrent.fX, pos.fY) >= (Int_t)fCanvas->GetWidth()) {
680  pos.fX = fMarkedStart.fX;
681  }
682 
683  SetVsbPosition((ToScrYCoord(pos.fY)+fVisible.fY)/fScrollVal.fY);
684  SetHsbPosition((ToScrXCoord(pos.fX, pos.fY)+fVisible.fX)/fScrollVal.fX);
685 
686  UpdateRegion(0, (Int_t)ToScrYCoord(fMarkedStart.fY), fCanvas->GetWidth(),
687  UInt_t(ToScrYCoord(fMarkedEnd.fY+1)-ToScrYCoord(fMarkedEnd.fY)));
688 
689  return kTRUE;
690 }
691 
692 ////////////////////////////////////////////////////////////////////////////////
693 /// Replace text starting at textPos.
694 
695 Bool_t TGTextEdit::Replace(TGLongPosition textPos, const char *oldText,
696  const char *newText, Bool_t direction, Bool_t caseSensitive)
697 {
698  TGLongPosition pos;
699  if (!fText->Replace(textPos, oldText, newText, direction, caseSensitive)) {
700  return kFALSE;
701  }
702  UnMark();
703  fIsMarked = kTRUE;
704  fMarkedStart.fY = fMarkedEnd.fY = textPos.fY;
705  fMarkedStart.fX = textPos.fX;
706  fMarkedEnd.fX = fMarkedStart.fX + strlen(newText);
707 
708  if (direction) {
709  SetCurrent(fMarkedEnd);
710  } else {
711  SetCurrent(fMarkedStart);
712  }
713 
714  pos.fY = ToObjYCoord(fVisible.fY);
715  if (fCurrent.fY < pos.fY ||
716  ToScrYCoord(fCurrent.fY) >= (Int_t)fCanvas->GetHeight()) {
717  pos.fY = fMarkedStart.fY;
718  }
719  pos.fX = ToObjXCoord(fVisible.fX, pos.fY);
720  if (fCurrent.fX < pos.fX ||
721  ToScrXCoord(fCurrent.fX, pos.fY) >= (Int_t)fCanvas->GetWidth()) {
722  pos.fX = fMarkedStart.fX;
723  }
724 
725  SetVsbPosition((ToScrYCoord(pos.fY)+fVisible.fY)/fScrollVal.fY);
726  SetHsbPosition((ToScrXCoord(pos.fX, pos.fY)+fVisible.fX)/fScrollVal.fX);
727 
728  UpdateRegion(0, (Int_t)ToScrYCoord(fMarkedStart.fY), fCanvas->GetWidth(),
729  UInt_t(ToScrYCoord(fMarkedEnd.fY+1)-ToScrYCoord(fMarkedEnd.fY)));
730 
731  return kTRUE;
732 }
733 
734 ////////////////////////////////////////////////////////////////////////////////
735 /// Goto the specified line.
736 
737 Bool_t TGTextEdit::Goto(Long_t line, Long_t column)
738 {
739  if (line < 0)
740  line = 0;
741  if (line >= fText->RowCount())
742  line = fText->RowCount() - 1;
743  if (column < 0)
744  column = 0;
745  if (column > fText->GetLineLength(line))
746  column = fText->GetLineLength(line);
747 
748  TGLongPosition gotopos, pos;
749  gotopos.fY = line;
750  gotopos.fX = column;
751  SetCurrent(gotopos);
752 
753  pos.fY = ToObjYCoord(fVisible.fY);
754  if (fCurrent.fY < pos.fY ||
755  ToScrYCoord(fCurrent.fY) >= (Int_t)fCanvas->GetHeight())
756  pos.fY = gotopos.fY;
757 
758  SetVsbPosition((ToScrYCoord(pos.fY)+fVisible.fY)/fScrollVal.fY);
759  SetHsbPosition(0);
760 
761  UnMark();
762  fIsMarked = kTRUE;
763  fMarkedStart.fY = fMarkedEnd.fY = line;
764  fMarkedStart.fX = 0;
765  fMarkedEnd.fX = fCanvas->GetWidth();
766 
767  return kTRUE;
768 }
769 
770 ////////////////////////////////////////////////////////////////////////////////
771 /// Sets the mode how characters are entered.
772 
773 void TGTextEdit::SetInsertMode(EInsertMode mode)
774 {
775  if (fInsertMode == mode) return;
776 
777  fInsertMode = mode;
778 }
779 
780 ////////////////////////////////////////////////////////////////////////////////
781 /// If cursor if on, turn it off.
782 
783 void TGTextEdit::CursorOff()
784 {
785  if (fCursorState == 1) {
786  DrawCursor(2);
787  }
788  fCursorState = 2;
789 }
790 
791 ////////////////////////////////////////////////////////////////////////////////
792 /// Turn cursor on.
793 
794 void TGTextEdit::CursorOn()
795 {
796  DrawCursor(1);
797  fCursorState = 1;
798 
799  if (fCurBlink) {
800  fCurBlink->Reset();
801  }
802 }
803 
804 ////////////////////////////////////////////////////////////////////////////////
805 /// Make the specified position the current position.
806 
807 void TGTextEdit::SetCurrent(TGLongPosition new_coord)
808 {
809  CursorOff();
810 
811  fCurrent.fY = new_coord.fY;
812  fCurrent.fX = new_coord.fX;
813 
814  CursorOn();
815 
816  SendMessage(fMsgWindow, MK_MSG(kC_TEXTVIEW, kTXT_DATACHANGE), fWidgetId, 0);
817  DataChanged();
818 }
819 
820 ////////////////////////////////////////////////////////////////////////////////
821 /// Draw cursor. If mode = 1 draw cursor, if mode = 2 erase cursor.
822 
823 void TGTextEdit::DrawCursor(Int_t mode)
824 {
825  char count = -1;
826  char cursor = ' ';
827  if (fCurrent.fY >= fText->RowCount() || fCurrent.fX > fText->GetLineLength(fCurrent.fY) || fReadOnly) {
828  return;
829  }
830 
831  if (fCurrent.fY >= ToObjYCoord(fVisible.fY) &&
832  fCurrent.fY <= ToObjYCoord(fVisible.fY+fCanvas->GetHeight()) &&
833  fCurrent.fX >= ToObjXCoord(fVisible.fX, fCurrent.fY) &&
834  fCurrent.fX <= ToObjXCoord(fVisible.fX+fCanvas->GetWidth(),fCurrent.fY)) {
835  if (fCurrent.fY < fText->RowCount()) {
836  count = fText->GetChar(fCurrent);
837  }
838  if (count == -1 || count == '\t') {
839  cursor = ' ';
840  } else {
841  cursor = count;
842  }
843 
844  if (mode == 2) {
845  if (fIsMarked && count != -1) {
846  if ((fCurrent.fY > fMarkedStart.fY && fCurrent.fY < fMarkedEnd.fY) ||
847  (fCurrent.fY == fMarkedStart.fY && fCurrent.fX >= fMarkedStart.fX &&
848  fCurrent.fY < fMarkedEnd.fY) ||
849  (fCurrent.fY == fMarkedEnd.fY && fCurrent.fX < fMarkedEnd.fX &&
850  fCurrent.fY > fMarkedStart.fY) ||
851  (fCurrent.fY == fMarkedStart.fY && fCurrent.fY == fMarkedEnd.fY &&
852  fCurrent.fX >= fMarkedStart.fX && fCurrent.fX < fMarkedEnd.fX &&
853  fMarkedStart.fX != fMarkedEnd.fX)) {
854  // back ground fillrectangle
855  gVirtualX->FillRectangle(fCanvas->GetId(), fSelbackGC(),
856  Int_t(ToScrXCoord(fCurrent.fX, fCurrent.fY)),
857  Int_t(ToScrYCoord(fCurrent.fY)),
858  UInt_t(ToScrXCoord(fCurrent.fX+1, fCurrent.fY) -
859  ToScrXCoord(fCurrent.fX, fCurrent.fY)),
860  UInt_t(ToScrYCoord(fCurrent.fY+1)-ToScrYCoord(fCurrent.fY)));
861  if (count != -1)
862  gVirtualX->DrawString(fCanvas->GetId(), fSelGC(), (Int_t)ToScrXCoord(fCurrent.fX,fCurrent.fY),
863  Int_t(ToScrYCoord(fCurrent.fY+1) - fMaxDescent), &cursor, 1);
864  } else {
865  gVirtualX->ClearArea(fCanvas->GetId(),
866  Int_t(ToScrXCoord(fCurrent.fX, fCurrent.fY)),
867  Int_t(ToScrYCoord(fCurrent.fY)),
868  UInt_t(ToScrXCoord(fCurrent.fX+1, fCurrent.fY) -
869  ToScrXCoord(fCurrent.fX, fCurrent.fY)),
870  UInt_t(ToScrYCoord(fCurrent.fY+1)-ToScrYCoord(fCurrent.fY)));
871  if (count != -1)
872  gVirtualX->DrawString(fCanvas->GetId(), fNormGC(), (Int_t)ToScrXCoord(fCurrent.fX,fCurrent.fY),
873  Int_t(ToScrYCoord(fCurrent.fY+1) - fMaxDescent), &cursor, 1);
874  }
875  } else {
876  gVirtualX->ClearArea(fCanvas->GetId(),
877  Int_t(ToScrXCoord(fCurrent.fX, fCurrent.fY)),
878  Int_t(ToScrYCoord(fCurrent.fY)),
879  UInt_t(ToScrXCoord(fCurrent.fX+1, fCurrent.fY) -
880  ToScrXCoord(fCurrent.fX, fCurrent.fY)),
881  UInt_t(ToScrYCoord(fCurrent.fY+1)-ToScrYCoord(fCurrent.fY)));
882  gVirtualX->DrawString(fCanvas->GetId(), fNormGC(), (Int_t)ToScrXCoord(fCurrent.fX,fCurrent.fY),
883  Int_t(ToScrYCoord(fCurrent.fY+1) - fMaxDescent), &cursor, 1);
884  }
885  } else {
886  if (mode == 1) {
887  gVirtualX->FillRectangle(fCanvas->GetId(), fCursor1GC,
888  Int_t(ToScrXCoord(fCurrent.fX, fCurrent.fY)),
889  Int_t(ToScrYCoord(fCurrent.fY)),
890  2,
891  UInt_t(ToScrYCoord(fCurrent.fY+1)-ToScrYCoord(fCurrent.fY)));
892  }
893  }
894  }
895 }
896 
897 ////////////////////////////////////////////////////////////////////////////////
898 /// Adjust current position.
899 
900 void TGTextEdit::AdjustPos()
901 {
902  TGLongPosition pos;
903  pos.fY = fCurrent.fY;
904  pos.fX = fCurrent.fX;
905 
906  if (pos.fY < ToObjYCoord(fVisible.fY)) {
907  pos.fY = ToObjYCoord(fVisible.fY);
908  } else if (ToScrYCoord(pos.fY+1) >= (Int_t) fCanvas->GetHeight()) {
909  pos.fY = ToObjYCoord(fVisible.fY + fCanvas->GetHeight())-1;
910  }
911  if (pos.fX < ToObjXCoord(fVisible.fX, pos.fY)) {
912  pos.fX = ToObjXCoord(fVisible.fX, pos.fY);
913  } else if (ToScrXCoord(pos.fX, pos.fY) >= (Int_t) fCanvas->GetWidth()) {
914  pos.fX = ToObjXCoord(fVisible.fX + fCanvas->GetWidth(), pos.fY)-1;
915  }
916  if (pos.fY != fCurrent.fY || pos.fX != fCurrent.fX) {
917  SetCurrent(pos);
918  }
919 }
920 
921 ////////////////////////////////////////////////////////////////////////////////
922 /// Handle timer cursor blink timer.
923 
924 Bool_t TGTextEdit::HandleTimer(TTimer *t)
925 {
926  if (t != fCurBlink) {
927  TGTextView::HandleTimer(t);
928  return kTRUE;
929  }
930 
931  if (fCursorState == 1) {
932  fCursorState = 2;
933  } else {
934  fCursorState = 1;
935  }
936 
937  DrawCursor(fCursorState);
938 
939  return kTRUE;
940 }
941 
942 ////////////////////////////////////////////////////////////////////////////////
943 /// Handle selection notify event.
944 
945 Bool_t TGTextEdit::HandleSelection(Event_t *event)
946 {
947  TString data;
948  Int_t nchar;
949 
950  gVirtualX->GetPasteBuffer((Window_t)event->fUser[0], (Atom_t)event->fUser[3],
951  data, nchar, kFALSE);
952 
953  if (!nchar) return kTRUE;
954 
955  delete fClipText;
956 
957  fClipText = new TGText;
958  fClipText->LoadBuffer(data.Data());
959 
960  TGLongPosition start_src, end_src, pos;
961 
962  pos.fX = pos.fY = 0;
963  start_src.fY = start_src.fX = 0;
964  end_src.fY = fClipText->RowCount()-1;
965  end_src.fX = fClipText->GetLineLength(end_src.fY)-1;
966 
967  if (end_src.fX < 0) {
968  end_src.fX = 0;
969  }
970 
971  // undo command
972  TInsTextCom *icom = new TInsTextCom(this);
973  icom->fChar = fText->GetChar(fCurrent);
974  fText->InsText(fCurrent, fClipText, start_src, end_src);
975 
976  fIsMarked = kFALSE;
977 
978  fExposedRegion.fX = 0;
979  fExposedRegion.fY = ToScrYCoord(fCurrent.fY);
980 
981  pos.fY = fCurrent.fY + fClipText->RowCount()-1;
982  pos.fX = fClipText->GetLineLength(fClipText->RowCount()-1);
983 
984  if (start_src.fY == end_src.fY) {
985  pos.fX = pos.fX + fCurrent.fX;
986  }
987 
988  icom->SetEndPos(pos);
989 
990  // calculate exposed region
991  fExposedRegion.fW = fCanvas->GetWidth();
992  fExposedRegion.fH = fCanvas->GetHeight() - fExposedRegion.fY;
993 
994  SetCurrent(pos);
995 
996  if (ToScrYCoord(pos.fY) >= (Int_t)fCanvas->GetHeight()) {
997  pos.fY = ToScrYCoord(pos.fY) + fVisible.fY - fCanvas->GetHeight()/2;
998  fExposedRegion.fX = fExposedRegion.fY = 0;
999  fExposedRegion.fH = fCanvas->GetHeight();
1000  } else {
1001  pos.fY = fVisible.fY;
1002  }
1003  if (ToScrXCoord(pos.fX, fCurrent.fY) >= (Int_t) fCanvas->GetWidth()) {
1004  pos.fX = ToScrXCoord(pos.fX, fCurrent.fY) + fVisible.fX + fCanvas->GetWidth()/2;
1005  } else if (ToScrXCoord(pos.fX, fCurrent.fY < 0) && pos.fX != 0) {
1006  if (fVisible.fX - (Int_t)fCanvas->GetWidth()/2 > 0) {
1007  pos.fX = fVisible.fX - fCanvas->GetWidth()/2;
1008  } else {
1009  pos.fX = 0;
1010  }
1011  } else {
1012  pos.fX = fVisible.fX;
1013  }
1014 
1015  SetSBRange(kHorizontal);
1016  SetSBRange(kVertical);
1017  SetVsbPosition(pos.fY/fScrollVal.fY);
1018  SetHsbPosition(pos.fX/fScrollVal.fX);
1019 
1020  fClient->NeedRedraw(this);
1021 
1022  return kTRUE;
1023 }
1024 
1025 static Bool_t gDbl_clk = kFALSE;
1026 static Bool_t gTrpl_clk = kFALSE;
1027 
1028 ////////////////////////////////////////////////////////////////////////////////
1029 /// Handle mouse button event in text edit widget.
1030 
1031 Bool_t TGTextEdit::HandleButton(Event_t *event)
1032 {
1033  if (event->fWindow != fCanvas->GetId()) {
1034  return kFALSE;
1035  }
1036 
1037  TGLongPosition pos;
1038 
1039  TGTextView::HandleButton(event);
1040 
1041  if (event->fType == kButtonPress) {
1042  SetFocus();
1043  //Update();
1044 
1045  if (event->fCode == kButton1 || event->fCode == kButton2) {
1046  pos.fY = ToObjYCoord(fVisible.fY + event->fY);
1047  if (pos.fY >= fText->RowCount()) {
1048  pos.fY = fText->RowCount()-1;
1049  }
1050  pos.fX = ToObjXCoord(fVisible.fX+event->fX, pos.fY);
1051  if (pos.fX >= fText->GetLineLength(pos.fY)) {
1052  pos.fX = fText->GetLineLength(pos.fY);
1053  }
1054  while (fText->GetChar(pos) == 16) {
1055  pos.fX++;
1056  }
1057 
1058  SetCurrent(pos);
1059 
1060  TGTextLine *line = fText->GetCurrentLine();
1061  char *word = line->GetWord(pos.fX);
1062  Clicked((const char*)word); // emit signal
1063  delete [] word;
1064  }
1065  if (event->fCode == kButton2) {
1066  if (gVirtualX->GetPrimarySelectionOwner() != kNone) {
1067  gVirtualX->ConvertPrimarySelection(fId, fClipboard, event->fTime);
1068  Update();
1069  return kTRUE;
1070  }
1071  }
1072  if (event->fCode == kButton3) {
1073  // do not handle during guibuilding
1074  if (fClient->IsEditable() || !fEnableMenu) {
1075  return kTRUE;
1076  }
1077  SetMenuState();
1078  fMenu->PlaceMenu(event->fXRoot, event->fYRoot, kTRUE, kTRUE);
1079  }
1080  gDbl_clk = kFALSE;
1081  gTrpl_clk = kFALSE;
1082  }
1083 
1084  return kTRUE;
1085 }
1086 
1087 ////////////////////////////////////////////////////////////////////////////////
1088 /// Handle double click event.
1089 
1090 Bool_t TGTextEdit::HandleDoubleClick(Event_t *event)
1091 {
1092  if (event->fWindow != fCanvas->GetId()) {
1093  return kFALSE;
1094  }
1095 
1096  if (event->fCode != kButton1) {
1097  return kFALSE;
1098  }
1099  if (!fText->GetCurrentLine()->GetText()) {// empty line
1100  return kFALSE;
1101  }
1102 
1103  SetFocus();
1104  TGLongPosition pos;
1105  pos.fY = ToObjYCoord(fVisible.fY + event->fY);
1106 
1107  if (gDbl_clk && (event->fTime - fgLastClick < 350)) { // triple click
1108  fgLastClick = event->fTime;
1109  gDbl_clk = kFALSE;
1110  gTrpl_clk = kTRUE;
1111  fMarkedStart.fY = fMarkedEnd.fY = pos.fY;
1112  fIsMarked = kTRUE;
1113  fMarkedStart.fX = 0;
1114  fMarkedEnd.fX = strlen(fText->GetCurrentLine()->GetText());
1115  Marked(kTRUE);
1116  UpdateRegion(0, (Int_t)ToScrYCoord(fMarkedStart.fY), fCanvas->GetWidth(),
1117  UInt_t(ToScrYCoord(fMarkedEnd.fY + 1) - ToScrYCoord(fMarkedStart.fY)));
1118  return kTRUE;
1119  }
1120 
1121  if (gTrpl_clk && (event->fTime - fgLastClick < 350)) { // 4 click
1122  fgLastClick = event->fTime;
1123  gTrpl_clk = kFALSE;
1124  fIsMarked = kTRUE;
1125  fMarkedStart.fY = 0;
1126  fMarkedStart.fX = 0;
1127  fMarkedEnd.fY = fText->RowCount()-1;
1128  fMarkedEnd.fX = fText->GetLineLength(fMarkedEnd.fY);
1129  if (fMarkedEnd.fX < 0) {
1130  fMarkedEnd.fX = 0;
1131  }
1132  UpdateRegion(0, 0, fCanvas->GetWidth(), fCanvas->GetHeight());
1133  return kTRUE;
1134  }
1135 
1136  gDbl_clk = kTRUE;
1137  gTrpl_clk = kFALSE;
1138 
1139  if (pos.fY >= fText->RowCount()) {
1140  pos.fY = fText->RowCount() - 1;
1141  }
1142  pos.fX = ToObjXCoord(fVisible.fX + event->fX, pos.fY);
1143 
1144  if (pos.fX >= fText->GetLineLength(pos.fY)) {
1145  pos.fX = fText->GetLineLength(pos.fY);
1146  }
1147  while (fText->GetChar(pos) == 16) {
1148  pos.fX++;
1149  }
1150 
1151  SetCurrent(pos);
1152 
1153  fMarkedStart.fY = fMarkedEnd.fY = pos.fY;
1154  char *line = fText->GetCurrentLine()->GetText();
1155  UInt_t len = (UInt_t)fText->GetCurrentLine()->GetLineLength();
1156  Int_t start = pos.fX;
1157  Int_t end = pos.fX;
1158  Int_t i = pos.fX;
1159 
1160  if (line[i] == ' ' || line[i] == '\t') {
1161  while (start >= 0) {
1162  if (line[start] == ' ' || line[start] == '\t') --start;
1163  else break;
1164  }
1165  ++start;
1166  while (end < (Int_t)len) {
1167  if (line[end] == ' ' || line[end] == '\t') ++end;
1168  else break;
1169  }
1170  } else if (isalnum(line[i])) {
1171  while (start >= 0) {
1172  if (isalnum(line[start])) --start;
1173  else break;
1174  }
1175  ++start;
1176  while (end < (Int_t)len) {
1177  if (isalnum(line[end])) ++end;
1178  else break;
1179  }
1180  } else {
1181  while (start >= 0) {
1182  if (isalnum(line[start]) || line[start] == ' ' || line[start] == '\t') {
1183  break;
1184  } else {
1185  --start;
1186  }
1187  }
1188  ++start;
1189  while (end < (Int_t)len) {
1190  if (isalnum(line[end]) || line[end] == ' ' || line[end] == '\t') {
1191  break;
1192  } else {
1193  ++end;
1194  }
1195  }
1196  }
1197 
1198  fMarkedStart.fX = start;
1199  fIsMarked = kTRUE;
1200  fMarkedEnd.fX = end;
1201  Marked(kTRUE);
1202 
1203  len = end - start; //length
1204  char *word = new char[len + 1];
1205  word[len] = '\0';
1206  strncpy(word, line+start, (UInt_t)len);
1207  DoubleClicked((const char *)word); // emit signal
1208 
1209  delete [] word;
1210 // delete [] line;
1211 
1212  UpdateRegion(0, (Int_t)ToScrYCoord(fMarkedStart.fY), fCanvas->GetWidth(),
1213  UInt_t(ToScrYCoord(fMarkedEnd.fY + 1) - ToScrYCoord(fMarkedStart.fY)));
1214 
1215  return kTRUE;
1216 }
1217 
1218 ////////////////////////////////////////////////////////////////////////////////
1219 /// Handle mouse motion event in text edit widget.
1220 
1221 Bool_t TGTextEdit::HandleMotion(Event_t *event)
1222 {
1223  TGLongPosition pos;
1224  if (event->fWindow != fCanvas->GetId()) {
1225  return kTRUE;
1226  }
1227 
1228  if (fScrolling == -1) {
1229  pos.fY = ToObjYCoord(fVisible.fY+event->fY);
1230  if (pos.fY >= fText->RowCount()) {
1231  pos.fY = fText->RowCount()-1;
1232  }
1233  pos.fX = ToObjXCoord(fVisible.fX+event->fX, pos.fY);
1234  if (pos.fX > fText->GetLineLength(pos.fY)) {
1235  pos.fX = fText->GetLineLength(pos.fY);
1236  }
1237  if (fText->GetChar(pos) == 16) {
1238  if (pos.fX < fCurrent.fX) {
1239  pos.fX = fCurrent.fX;
1240  }
1241  if (pos.fX > fCurrent.fX) {
1242  do {
1243  pos.fX++;
1244  } while (fText->GetChar(pos) == 16);
1245  }
1246  }
1247  event->fY = (Int_t)ToScrYCoord(pos.fY);
1248  event->fX = (Int_t)ToScrXCoord(pos.fX, pos.fY);
1249  if (pos.fY != fCurrent.fY || pos.fX != fCurrent.fX) {
1250  TGTextView::HandleMotion(event);
1251  SetCurrent(pos);
1252  }
1253  }
1254  return kTRUE;
1255 }
1256 
1257 ////////////////////////////////////////////////////////////////////////////////
1258 /// The key press event handler converts a key press to some line editor
1259 /// action.
1260 
1261 Bool_t TGTextEdit::HandleKey(Event_t *event)
1262 {
1263  Bool_t mark_ok = kFALSE;
1264  char input[10];
1265  Int_t n;
1266  UInt_t keysym;
1267 
1268  if (event->fType == kGKeyPress) {
1269  gVirtualX->LookupString(event, input, sizeof(input), keysym);
1270  n = strlen(input);
1271 
1272  AdjustPos();
1273 
1274  switch ((EKeySym)keysym) { // ignore these keys
1275  case kKey_Shift:
1276  case kKey_Control:
1277  case kKey_Meta:
1278  case kKey_Alt:
1279  case kKey_CapsLock:
1280  case kKey_NumLock:
1281  case kKey_ScrollLock:
1282  return kTRUE;
1283  default:
1284  break;
1285  }
1286  if (event->fState & kKeyControlMask) { // Cntrl key modifier pressed
1287  switch((EKeySym)keysym & ~0x20) { // treat upper and lower the same
1288  case kKey_A:
1289  SelectAll();
1290  return kTRUE;
1291  case kKey_B:
1292  mark_ok = kTRUE;
1293  PrevChar();
1294  break;
1295  case kKey_C:
1296  Copy();
1297  return kTRUE;
1298  case kKey_D:
1299  if (fIsMarked) {
1300  Cut();
1301  } else {
1302  Long_t len = fText->GetLineLength(fCurrent.fY);
1303  if (fCurrent.fY == fText->RowCount()-1 && fCurrent.fX == len) {
1304  gVirtualX->Bell(0);
1305  return kTRUE;
1306  }
1307  NextChar();
1308  new TDelCharCom(this);
1309  }
1310  break;
1311  case kKey_E:
1312  mark_ok = kTRUE;
1313  End();
1314  break;
1315  case kKey_H:
1316  if (fCurrent.fX || fCurrent.fY) new TDelCharCom(this);
1317  else gVirtualX->Bell(0);
1318  break;
1319  case kKey_K:
1320  End();
1321  fIsMarked = kTRUE;
1322  Mark(fCurrent.fX, fCurrent.fY);
1323  Cut();
1324  break;
1325  case kKey_U:
1326  Home();
1327  UnMark();
1328  fMarkedStart.fY = fMarkedEnd.fY = fCurrent.fY;
1329  fMarkedStart.fX = fMarkedEnd.fX = fCurrent.fX;
1330  End();
1331  fIsMarked = kTRUE;
1332  Mark(fCurrent.fX, fCurrent.fY);
1333  Cut();
1334  break;
1335  case kKey_V:
1336  case kKey_Y:
1337  Paste();
1338  return kTRUE;
1339  case kKey_X:
1340  Cut();
1341  return kTRUE;
1342  case kKey_Z:
1343  fHistory->Notify(); // undo action
1344  return kTRUE;
1345  case kKey_F:
1346  Search(kFALSE);
1347  return kTRUE;
1348  case kKey_L:
1349  {
1350  Long_t ret = fCurrent.fY+1;
1351  new TGGotoDialog(fClient->GetDefaultRoot(), this, 400, 150, &ret);
1352  if (ret > -1) {
1353  ret--; // user specifies lines starting at 1
1354  Goto(ret);
1355  }
1356  return kTRUE;
1357  }
1358  case kKey_Home:
1359  {
1360  TGLongPosition pos;
1361  pos.fY = 0;
1362  pos.fX = 0;
1363  SetHsbPosition(0);
1364  SetVsbPosition(0);
1365  SetCurrent(pos);
1366  }
1367  break;
1368  case kKey_End:
1369  {
1370  TGLongPosition pos;
1371  pos.fY = fText->RowCount()-1;
1372  pos.fX = fText->GetLineLength(pos.fY);
1373  if (fVsb && fVsb->IsMapped())
1374  SetVsbPosition((ToScrYCoord(pos.fY)+fVisible.fY)/fScrollVal.fY);
1375  SetCurrent(pos);
1376  }
1377  break;
1378  default:
1379  return kTRUE;
1380  }
1381  }
1382  if (n && keysym >= 32 && keysym < 127 && // printable keys
1383  !(event->fState & kKeyControlMask) &&
1384  (EKeySym)keysym != kKey_Delete &&
1385  (EKeySym)keysym != kKey_Backspace) {
1386 
1387  if (fIsMarked) {
1388  Cut();
1389  }
1390  new TInsCharCom(this, input[0]);
1391 
1392  } else {
1393 
1394  switch ((EKeySym)keysym) {
1395  case kKey_F3:
1396  // typically FindAgain action
1397  SendMessage(fMsgWindow, MK_MSG(kC_TEXTVIEW, kTXT_F3), fWidgetId,
1398  kTRUE);
1399  SetMenuState();
1400  if (fMenu->IsEntryEnabled(kM_SEARCH_FINDAGAIN)) {
1401  SendMessage(this, MK_MSG(kC_COMMAND, kCM_MENU),
1402  kM_SEARCH_FINDAGAIN, 0);
1403  FindAgain();
1404  }
1405  break;
1406  case kKey_Delete:
1407  if (fIsMarked) {
1408  Cut();
1409  } else {
1410  Long_t len = fText->GetLineLength(fCurrent.fY);
1411  if (fCurrent.fY == fText->RowCount()-1 && fCurrent.fX == len) {
1412  gVirtualX->Bell(0);
1413  return kTRUE;
1414  }
1415  NextChar();
1416  new TDelCharCom(this);
1417  }
1418  break;
1419  case kKey_Return:
1420  case kKey_Enter:
1421  new TBreakLineCom(this);
1422  break;
1423  case kKey_Tab:
1424  new TInsCharCom(this, '\t');
1425  break;
1426  case kKey_Backspace:
1427  if (fIsMarked) {
1428  Cut();
1429  } else {
1430  if (fCurrent.fX || fCurrent.fY) {
1431  new TDelCharCom(this);
1432  } else {
1433  gVirtualX->Bell(0);
1434  }
1435  }
1436  break;
1437  case kKey_Left:
1438  mark_ok = kTRUE;
1439  PrevChar();
1440  break;
1441  case kKey_Right:
1442  mark_ok = kTRUE;
1443  NextChar();
1444  break;
1445  case kKey_Up:
1446  mark_ok = kTRUE;
1447  LineUp();
1448  break;
1449  case kKey_Down:
1450  mark_ok = kTRUE;
1451  LineDown();
1452  break;
1453  case kKey_PageUp:
1454  mark_ok = kTRUE;
1455  ScreenUp();
1456  break;
1457  case kKey_PageDown:
1458  mark_ok = kTRUE;
1459  ScreenDown();
1460  break;
1461  case kKey_Home:
1462  mark_ok = kTRUE;
1463  Home();
1464  break;
1465  case kKey_End:
1466  mark_ok = kTRUE;
1467  End();
1468  break;
1469  case kKey_Insert: // switch on/off insert mode
1470  SetInsertMode(GetInsertMode() == kInsert ? kReplace : kInsert);
1471  break;
1472  default:
1473  break;
1474  }
1475  }
1476  if ((event->fState & kKeyShiftMask) && mark_ok) {
1477  fIsMarked = kTRUE;
1478  Mark(fCurrent.fX, fCurrent.fY);
1479  Copy();
1480  SendMessage(fMsgWindow, MK_MSG(kC_TEXTVIEW, kTXT_ISMARKED), fWidgetId,
1481  kTRUE);
1482  Marked(kTRUE);
1483  } else {
1484  UnMark();
1485  SendMessage(fMsgWindow, MK_MSG(kC_TEXTVIEW, kTXT_ISMARKED),
1486  fWidgetId, kFALSE);
1487  fMarkedStart.fY = fMarkedEnd.fY = fCurrent.fY;
1488  fMarkedStart.fX = fMarkedEnd.fX = fCurrent.fX;
1489  }
1490  }
1491  return kTRUE;
1492 }
1493 
1494 ////////////////////////////////////////////////////////////////////////////////
1495 /// Handle mouse crossing event.
1496 
1497 Bool_t TGTextEdit::HandleCrossing(Event_t *event)
1498 {
1499  if (event->fWindow != fCanvas->GetId()) {
1500  return kTRUE;
1501  }
1502  if (gVirtualX->GetInputFocus() != fCanvas->GetId()) {
1503  if (event->fType == kEnterNotify) {
1504  if (!fCurBlink) {
1505  fCurBlink = new TViewTimer(this, 500);
1506  }
1507  fCurBlink->Reset();
1508  gSystem->AddTimer(fCurBlink);
1509  } else {
1510  if (fCurBlink) fCurBlink->Remove();
1511  if (!fEnableCursorWithoutFocus && (fCursorState == 1)) {
1512  DrawCursor(2);
1513  fCursorState = 2;
1514  } else if (fCursorState == 2) {
1515  DrawCursor(1);
1516  fCursorState = 1;
1517  }
1518  }
1519  }
1520 
1521  TGTextView::HandleCrossing(event);
1522 
1523  return kTRUE;
1524 }
1525 
1526 ////////////////////////////////////////////////////////////////////////////////
1527 /// Handle focus change event in text edit widget.
1528 
1529 Bool_t TGTextEdit::HandleFocusChange(Event_t *event)
1530 {
1531  if (event->fWindow != fCanvas->GetId()) {
1532  return kTRUE;
1533  }
1534 
1535  // check this when porting to Win32
1536  if ((event->fCode == kNotifyNormal) && (event->fState != kNotifyPointer)) {
1537  if (event->fType == kFocusIn) {
1538  if (!fCurBlink) {
1539  fCurBlink = new TViewTimer(this, 500);
1540  }
1541  fCurBlink->Reset();
1542  gSystem->AddTimer(fCurBlink);
1543  } else {
1544  if (fCurBlink) fCurBlink->Remove();
1545  if (fCursorState == 2) {
1546  DrawCursor(1);
1547  fCursorState = 1;
1548  }
1549  }
1550  fClient->NeedRedraw(this);
1551  }
1552  return kTRUE;
1553 }
1554 
1555 ////////////////////////////////////////////////////////////////////////////////
1556 /// Invokes search dialog.
1557 
1558 void TGTextEdit::Search(Bool_t close)
1559 {
1560  static TGSearchType *srch = 0;
1561  Int_t ret = 0;
1562 
1563  if (!srch) srch = new TGSearchType;
1564  srch->fClose = close;
1565 
1566  if (!close) {
1567  if (!TGSearchDialog::SearchDialog()) {
1568  TGSearchDialog::SearchDialog() = new TGSearchDialog(fClient->GetDefaultRoot(),
1569  fCanvas, 400, 150, srch, &ret);
1570  }
1571  TGSearchDialog::SearchDialog()->Connect("TextEntered(char *)", "TGTextEdit",
1572  this, "Search(char *,Bool_t,Bool_t)");
1573  TGSearchDialog::SearchDialog()->MapRaised();
1574  } else {
1575  new TGSearchDialog(fClient->GetDefaultRoot(), fCanvas, 400, 150, srch, &ret);
1576  if (ret) {
1577  Search(srch->fBuffer);
1578  }
1579  }
1580 }
1581 
1582 ////////////////////////////////////////////////////////////////////////////////
1583 /// Process context menu messages.
1584 
1585 Bool_t TGTextEdit::ProcessMessage(Long_t msg, Long_t parm1, Long_t parm2)
1586 {
1587  TString msg2;
1588  TGTextView::ProcessMessage(msg, parm1, parm2);
1589 
1590  switch(GET_MSG(msg)) {
1591  case kC_COMMAND:
1592  switch(GET_SUBMSG(msg)) {
1593  case kCM_MENU:
1594  switch (parm1) {
1595  case kM_FILE_NEW:
1596  case kM_FILE_CLOSE:
1597  case kM_FILE_OPEN:
1598  if (!IsSaved()) {
1599  Int_t retval;
1600  Bool_t untitled = !strlen(fText->GetFileName()) ? kTRUE : kFALSE;
1601 
1602  msg2.Form("Save \"%s\"?",
1603  untitled ? "Untitled" : fText->GetFileName());
1604  new TGMsgBox(fClient->GetDefaultRoot(), this, "Editor",
1605  msg2.Data(), kMBIconExclamation,
1606  kMBYes | kMBNo | kMBCancel, &retval);
1607 
1608  if (retval == kMBCancel)
1609  return kTRUE;
1610  if (retval == kMBYes)
1611  if (!SaveFile(0))
1612  return kTRUE;
1613  }
1614  Clear();
1615  if (parm1 == kM_FILE_CLOSE) {
1616  SendMessage(fMsgWindow, MK_MSG(kC_TEXTVIEW, kTXT_CLOSE),
1617  fWidgetId, 0);
1618  Closed();
1619  }
1620  if (parm1 == kM_FILE_OPEN) {
1621  TGFileInfo fi;
1622  fi.fFileTypes = gFiletypes;
1623  new TGFileDialog(fClient->GetDefaultRoot(), this, kFDOpen, &fi);
1624  if (fi.fFilename && strlen(fi.fFilename)) {
1625  LoadFile(fi.fFilename);
1626  SendMessage(fMsgWindow, MK_MSG(kC_TEXTVIEW, kTXT_OPEN),
1627  fWidgetId, 0);
1628  Opened();
1629  }
1630  }
1631  break;
1632  case kM_FILE_SAVE:
1633  if (SaveFile(0)) {
1634  SendMessage(fMsgWindow, MK_MSG(kC_TEXTVIEW, kTXT_SAVE),
1635  fWidgetId, 0);
1636  Saved();
1637  }
1638  break;
1639  case kM_FILE_SAVEAS:
1640  if (SaveFile(0, kTRUE)) {
1641  SendMessage(fMsgWindow, MK_MSG(kC_TEXTVIEW, kTXT_SAVE),
1642  fWidgetId, 0);
1643  SavedAs();
1644  }
1645  break;
1646  case kM_FILE_PRINT:
1647  {
1648  Int_t ret = 0;
1649  if (!gPrinter) {
1650  gPrinter = StrDup("892_2_cor"); // use gEnv
1651  gPrintCommand = StrDup("xprint");
1652  }
1653  new TGPrintDialog(fClient->GetDefaultRoot(), this, 400, 150,
1654  &gPrinter, &gPrintCommand, &ret);
1655  if (ret)
1656  Print();
1657  }
1658  break;
1659  case kM_EDIT_CUT:
1660  Cut();
1661  break;
1662  case kM_EDIT_COPY:
1663  Copy();
1664  break;
1665  case kM_EDIT_PASTE:
1666  Paste();
1667  break;
1668  case kM_EDIT_SELECTALL:
1669  SelectAll();
1670  break;
1671  case kM_SEARCH_FIND:
1672  {
1673  Search(kFALSE);
1674  }
1675  break;
1676  case kM_SEARCH_FINDAGAIN:
1677  if (!fSearch) {
1678  SendMessage(this, MK_MSG(kC_COMMAND, kCM_MENU),
1679  kM_SEARCH_FIND, 0);
1680  return kTRUE;
1681  }
1682  if (!Search(fSearch->fBuffer, fSearch->fDirection,
1683  fSearch->fCaseSensitive)) {
1684  msg2.Form("Couldn't find \"%s\"", fSearch->fBuffer);
1685  new TGMsgBox(fClient->GetDefaultRoot(), this, "Editor",
1686  msg2.Data(), kMBIconExclamation, kMBOk, 0);
1687  }
1688  break;
1689  case kM_SEARCH_GOTO:
1690  {
1691  Long_t ret = fCurrent.fY+1;
1692  new TGGotoDialog(fClient->GetDefaultRoot(), this, 400, 150, &ret);
1693  if (ret > -1) {
1694  ret--; // user specifies lines starting at 1
1695  Goto(ret);
1696  }
1697  }
1698  break;
1699  default:
1700  printf("No action implemented for menu id %ld\n", parm1);
1701  break;
1702  }
1703  default:
1704  break;
1705  }
1706  break;
1707 
1708  default:
1709  break;
1710  }
1711  return kTRUE;
1712 }
1713 
1714 ////////////////////////////////////////////////////////////////////////////////
1715 /// Insert a character in the text edit widget.
1716 
1717 void TGTextEdit::InsChar(char character)
1718 {
1719  if (fReadOnly) return;
1720 
1721  char *charstring = 0;
1722  TGLongPosition pos;
1723 
1724  if (character == '\t') {
1725  pos.fX = fCurrent.fX;
1726  pos.fY = fCurrent.fY;
1727  fText->InsChar(pos, '\t');
1728  pos.fX++;
1729  while (pos.fX & 0x7) {
1730  pos.fX++;
1731  }
1732  fText->ReTab(pos.fY);
1733  UpdateRegion(0, (Int_t)ToScrYCoord(pos.fY), fCanvas->GetWidth(),
1734  UInt_t(ToScrYCoord(pos.fY+1) - ToScrYCoord(pos.fY)));
1735  SetSBRange(kHorizontal);
1736  if (ToScrXCoord(pos.fX, pos.fY) >= (Int_t)fCanvas->GetWidth()) {
1737  if (pos.fX != fText->GetLineLength(fCurrent.fY)) {
1738  SetHsbPosition((fVisible.fX+fCanvas->GetWidth()/2)/fScrollVal.fX);
1739  } else {
1740  SetHsbPosition(fVisible.fX/fScrollVal.fX);
1741  }
1742  }
1743  SetCurrent(pos);
1744  return;
1745  } else {
1746  if (fInsertMode == kReplace) {
1747  fCurrent.fX++;
1748  new TDelCharCom(this);
1749  }
1750  fText->InsChar(fCurrent, character);
1751  pos.fX = fCurrent.fX + 1;
1752  pos.fY = fCurrent.fY;
1753  charstring = new char[2];
1754  charstring[1] = '\0';
1755  charstring[0] = character;
1756  }
1757  SetSBRange(kHorizontal);
1758  if (ToScrXCoord(pos.fX, pos.fY) >= (Int_t)fCanvas->GetWidth()) {
1759  if (pos.fX != fText->GetLineLength(fCurrent.fY)) {
1760  SetHsbPosition((fVisible.fX+fCanvas->GetWidth()/2)/fScrollVal.fX);
1761  } else {
1762  SetHsbPosition(fVisible.fX/fScrollVal.fX+strlen(charstring));
1763  }
1764  if (!fHsb)
1765  gVirtualX->DrawString(fCanvas->GetId(), fNormGC(),
1766  (Int_t)ToScrXCoord(fCurrent.fX, fCurrent.fY),
1767  Int_t(ToScrYCoord(fCurrent.fY+1) - fMaxDescent),
1768  charstring, strlen(charstring));
1769  } else {
1770 #ifdef R__HAS_COCOA
1771  //I would use const, but some members of TGTextLine are non-const.
1772  if (TGTextLine *currentLine = fText->GetCurrentLine()) {
1773  const ULong_t lineStart = ToObjXCoord(fVisible.fX, fCurrent.fY);
1774  if (lineStart < currentLine->GetLineLength()) {
1775  const char *textToRender = currentLine->GetText(lineStart, currentLine->GetLineLength() - lineStart);
1776  //The next two lines can throw and textToRender will leak, but ROOT does not care about such things. :(
1777  gVirtualX->ClearArea(fCanvas->GetId(), Int_t(ToScrXCoord(0, fCurrent.fY)),
1778  Int_t(ToScrYCoord(fCurrent.fY)), UInt_t(ToScrXCoord(currentLine->GetLineLength(), fCurrent.fY)),
1779  UInt_t(ToScrYCoord(fCurrent.fY+1)-ToScrYCoord(fCurrent.fY)));
1780  gVirtualX->DrawString(fCanvas->GetId(), fNormGC(), Int_t(ToScrXCoord(0, fCurrent.fY)),
1781  Int_t(ToScrYCoord(fCurrent.fY + 1) - fMaxDescent),
1782  textToRender, -1);
1783  delete [] textToRender;
1784  }
1785  }
1786 #else
1787  gVirtualX->CopyArea(fCanvas->GetId(), fCanvas->GetId(), fNormGC(),
1788  (Int_t)ToScrXCoord(fCurrent.fX, fCurrent.fY),
1789  (Int_t)ToScrYCoord(fCurrent.fY), fCanvas->GetWidth(),
1790  UInt_t(ToScrYCoord(fCurrent.fY+1)-ToScrYCoord(fCurrent.fY)),
1791  (Int_t)ToScrXCoord(pos.fX, fCurrent.fY),
1792  (Int_t)ToScrYCoord(fCurrent.fY));
1793  gVirtualX->ClearArea(fCanvas->GetId(),
1794  Int_t(ToScrXCoord(fCurrent.fX, fCurrent.fY)),
1795  Int_t(ToScrYCoord(fCurrent.fY)),
1796  UInt_t(ToScrXCoord(fCurrent.fX+strlen(charstring), fCurrent.fY) -
1797  ToScrXCoord(fCurrent.fX, fCurrent.fY)),
1798  UInt_t(ToScrYCoord(fCurrent.fY+1)-ToScrYCoord(fCurrent.fY)));
1799  gVirtualX->DrawString(fCanvas->GetId(), fNormGC(),
1800  Int_t(ToScrXCoord(fCurrent.fX, fCurrent.fY)),
1801  Int_t(ToScrYCoord(fCurrent.fY+1) - fMaxDescent),
1802  charstring, strlen(charstring));
1803  fCursorState = 2; // the ClearArea effectively turned off the cursor
1804 #endif
1805  }
1806  delete [] charstring;
1807  SetCurrent(pos);
1808 }
1809 
1810 ////////////////////////////////////////////////////////////////////////////////
1811 /// Delete a character from the text edit widget.
1812 
1813 void TGTextEdit::DelChar()
1814 {
1815  if (fReadOnly) {
1816  return;
1817  }
1818 
1819  char *buffer;
1820  TGLongPosition pos, pos2;
1821  Long_t len;
1822 
1823  pos.fY = fCurrent.fY;
1824  pos.fX = fCurrent.fX;
1825  UInt_t h = 0;
1826 
1827  if (fCurrent.fX > 0) {
1828  Int_t y = (Int_t)ToScrYCoord(pos.fY);
1829  h = UInt_t(ToScrYCoord(pos.fY+2) - y);
1830  if (!y) h = h << 1;
1831 
1832  pos.fX--;
1833  if (fText->GetChar(pos) == 16) {
1834  do {
1835  pos.fX++;
1836  fText->DelChar(pos);
1837  pos.fX -= 2;
1838  } while (fText->GetChar(pos) != '\t');
1839 
1840  pos.fX++;
1841  fText->DelChar(pos);
1842  pos.fX--;
1843  fText->ReTab(pos.fY);
1844  UpdateRegion(0, y, fCanvas->GetWidth(), h);
1845  } else {
1846  pos.fX = fCurrent.fX;
1847  fText->DelChar(pos);
1848  pos.fX = fCurrent.fX - 1;
1849  }
1850  if (ToScrXCoord(fCurrent.fX-1, fCurrent.fY) < 0) {
1851  SetHsbPosition((fVisible.fX-fCanvas->GetWidth()/2)/fScrollVal.fX);
1852  }
1853  SetSBRange(kHorizontal);
1854  UpdateRegion(0, y, fCanvas->GetWidth(), h);
1855  } else {
1856  if (fCurrent.fY > 0) {
1857  len = fText->GetLineLength(fCurrent.fY);
1858  if (len > 0) {
1859  buffer = fText->GetLine(fCurrent, len);
1860  pos.fY--;
1861  pos.fX = fText->GetLineLength(fCurrent.fY-1);
1862  fText->InsText(pos, buffer);
1863  pos.fY++;
1864  delete [] buffer;
1865  } else {
1866  pos.fX = fText->GetLineLength(fCurrent.fY-1);
1867  }
1868 
1869  pos2.fY = ToScrYCoord(fCurrent.fY+1);
1870  pos.fY = fCurrent.fY - 1;
1871  fText->DelLine(fCurrent.fY);
1872  len = fText->GetLineLength(fCurrent.fY-1);
1873 
1874  if (ToScrXCoord(pos.fX, fCurrent.fY-1) >= (Int_t)fCanvas->GetWidth()) {
1875  SetHsbPosition((ToScrXCoord(pos.fX, pos.fY)+fVisible.fX-fCanvas->GetWidth()/2)/fScrollVal.fX);
1876  }
1877 
1878 #ifdef R__HAS_COCOA
1879  UpdateRegion(0, 0, fCanvas->GetWidth(), fCanvas->GetHeight());
1880 #else
1881  h = UInt_t(fCanvas->GetHeight() - ToScrYCoord(fCurrent.fY));
1882  gVirtualX->CopyArea(fCanvas->GetId(), fCanvas->GetId(), fNormGC(), 0,
1883  Int_t(pos2.fY), fWidth, h, 0, (Int_t)ToScrYCoord(fCurrent.fY));
1884  if (ToScrYCoord(pos.fY) < 0) {
1885  SetVsbPosition(fVisible.fY/fScrollVal.fY-1);
1886  }
1887  UpdateRegion(0, (Int_t)ToScrYCoord(pos.fY), fCanvas->GetWidth(), h);
1888 #endif
1889  SetSBRange(kVertical);
1890  SetSBRange(kHorizontal);
1891  }
1892  }
1893 
1894  SetCurrent(pos);
1895 }
1896 
1897 ////////////////////////////////////////////////////////////////////////////////
1898 /// Break a line.
1899 
1900 void TGTextEdit::BreakLine()
1901 {
1902  if (fReadOnly) return;
1903 
1904  TGLongPosition pos;
1905  fText->BreakLine(fCurrent);
1906  if (ToScrYCoord(fCurrent.fY+2) <= (Int_t)fCanvas->GetHeight()) {
1907 #ifdef R__HAS_COCOA
1908  UpdateRegion(0, (Int_t)ToScrYCoord(fCurrent.fY + 1), fCanvas->GetWidth(), fCanvas->GetHeight());
1909 #else
1910  gVirtualX->CopyArea(fCanvas->GetId(), fCanvas->GetId(), fNormGC(), 0,
1911  (Int_t)ToScrYCoord(fCurrent.fY+1), fCanvas->GetWidth(),
1912  UInt_t(fCanvas->GetHeight()-(ToScrYCoord(fCurrent.fY+2)-
1913  ToScrYCoord(fCurrent.fY))),
1914  0, (Int_t)ToScrYCoord(fCurrent.fY+2));
1915  UpdateRegion(0, (Int_t)ToScrYCoord(fCurrent.fY), fCanvas->GetWidth(),
1916  UInt_t(ToScrYCoord(fCurrent.fY+2) - ToScrYCoord(fCurrent.fY)));
1917 #endif
1918  if (fVisible.fX != 0) {
1919  SetHsbPosition(0);
1920  }
1921  SetSBRange(kHorizontal);
1922  SetSBRange(kVertical);
1923  } else {
1924  SetSBRange(kHorizontal);
1925  SetSBRange(kVertical);
1926  SetVsbPosition(fVisible.fY/fScrollVal.fY + 1);
1927  UpdateRegion(0, (Int_t)ToScrYCoord(fCurrent.fY), fCanvas->GetWidth(),
1928  UInt_t(ToScrYCoord(fCurrent.fY+1) - ToScrYCoord(fCurrent.fY)));
1929  }
1930  pos.fY = fCurrent.fY+1;
1931  pos.fX = 0;
1932  SetCurrent(pos);
1933 }
1934 
1935 ////////////////////////////////////////////////////////////////////////////////
1936 /// Scroll the canvas to new_top in the kVertical or kHorizontal direction.
1937 
1938 void TGTextEdit::ScrollCanvas(Int_t new_top, Int_t direction)
1939 {
1940  CursorOff();
1941 
1942  TGTextView::ScrollCanvas(new_top, direction);
1943 
1944  CursorOn();
1945 }
1946 
1947 ////////////////////////////////////////////////////////////////////////////////
1948 /// Redraw the text edit widget.
1949 
1950 void TGTextEdit::DrawRegion(Int_t x, Int_t y, UInt_t width, UInt_t height)
1951 {
1952  CursorOff();
1953 
1954  TGTextView::DrawRegion(x, y, width, height);
1955 
1956  CursorOn();
1957 }
1958 
1959 ////////////////////////////////////////////////////////////////////////////////
1960 /// Go to the previous character.
1961 
1962 void TGTextEdit::PrevChar()
1963 {
1964  if (fCurrent.fY == 0 && fCurrent.fX == 0) {
1965  gVirtualX->Bell(0);
1966  return;
1967  }
1968 
1969  TGLongPosition pos;
1970  Long_t len;
1971 
1972  pos.fY = fCurrent.fY;
1973  pos.fX = fCurrent.fX;
1974  if (fCurrent.fX > 0) {
1975  pos.fX--;
1976  while (fText->GetChar(pos) == 16) {
1977  pos.fX--;
1978  }
1979 
1980  if (ToScrXCoord(pos.fX, pos.fY) < 0) {
1981  if (fVisible.fX-(Int_t)fCanvas->GetWidth()/2 >= 0) {
1982  SetHsbPosition((fVisible.fX-fCanvas->GetWidth()/2)/fScrollVal.fX);
1983  } else {
1984  SetHsbPosition(0);
1985  }
1986  }
1987  } else {
1988  if (fCurrent.fY > 0) {
1989  pos.fY = fCurrent.fY - 1;
1990  len = fText->GetLineLength(pos.fY);
1991  if (ToScrYCoord(fCurrent.fY) <= 0) {
1992  SetVsbPosition(fVisible.fY/fScrollVal.fY-1);
1993  }
1994  if (ToScrXCoord(len, pos.fY) >= (Int_t)fCanvas->GetWidth()) {
1995  SetHsbPosition((ToScrXCoord(len, pos.fY)+fVisible.fX -
1996  fCanvas->GetWidth()/2)/fScrollVal.fX);
1997  }
1998  pos.fX = len;
1999  }
2000  }
2001  SetCurrent(pos);
2002 }
2003 
2004 ////////////////////////////////////////////////////////////////////////////////
2005 /// Go to next character.
2006 
2007 void TGTextEdit::NextChar()
2008 {
2009  Long_t len = fText->GetLineLength(fCurrent.fY);
2010 
2011  if (fCurrent.fY == fText->RowCount()-1 && fCurrent.fX == len) {
2012  gVirtualX->Bell(0);
2013  return;
2014  }
2015 
2016  TGLongPosition pos;
2017  pos.fY = fCurrent.fY;
2018  if (fCurrent.fX < len) {
2019  if (fText->GetChar(fCurrent) == '\t') {
2020  pos.fX = fCurrent.fX + 8 - (fCurrent.fX & 0x7);
2021  } else {
2022  pos.fX = fCurrent.fX + 1;
2023  }
2024 
2025  if (ToScrXCoord(pos.fX, pos.fY) >= (Int_t)fCanvas->GetWidth()) {
2026  SetHsbPosition(fVisible.fX/fScrollVal.fX+(fCanvas->GetWidth()/2)/fScrollVal.fX);
2027  }
2028  } else {
2029  if (fCurrent.fY < fText->RowCount()-1) {
2030  pos.fY = fCurrent.fY + 1;
2031  if (ToScrYCoord(pos.fY+1) >= (Int_t)fCanvas->GetHeight()) {
2032  SetVsbPosition(fVisible.fY/fScrollVal.fY+1);
2033  }
2034  SetHsbPosition(0);
2035  pos.fX = 0;
2036  }
2037  }
2038  SetCurrent(pos);
2039 }
2040 
2041 ////////////////////////////////////////////////////////////////////////////////
2042 /// Make current position first line in window by scrolling up.
2043 
2044 void TGTextEdit::LineUp()
2045 {
2046  TGLongPosition pos;
2047  Long_t len;
2048  if (fCurrent.fY > 0) {
2049  pos.fY = fCurrent.fY - 1;
2050  if (ToScrYCoord(fCurrent.fY) <= 0) {
2051  SetVsbPosition(fVisible.fY/fScrollVal.fY-1);
2052  }
2053  len = fText->GetLineLength(fCurrent.fY-1);
2054  if (fCurrent.fX > len) {
2055  if (ToScrXCoord(len, pos.fY) <= 0) {
2056  if (ToScrXCoord(len, pos.fY) < 0) {
2057  SetHsbPosition(ToScrXCoord(len, pos.fY)+
2058  (fVisible.fX-fCanvas->GetWidth()/2)/fScrollVal.fX);
2059  } else {
2060  SetHsbPosition(0);
2061  }
2062  }
2063  pos.fX = len;
2064  } else {
2065  pos.fX = ToObjXCoord(ToScrXCoord(fCurrent.fX, fCurrent.fY)+fVisible.fX, pos.fY);
2066  }
2067 
2068  while (fText->GetChar(pos) == 16) {
2069  pos.fX++;
2070  }
2071  SetCurrent(pos);
2072  }
2073 }
2074 
2075 ////////////////////////////////////////////////////////////////////////////////
2076 /// Move one line down.
2077 
2078 void TGTextEdit::LineDown()
2079 {
2080  TGLongPosition pos;
2081  Long_t len;
2082  if (fCurrent.fY < fText->RowCount()-1) {
2083  len = fText->GetLineLength(fCurrent.fY+1);
2084  pos.fY = fCurrent.fY + 1;
2085  if (ToScrYCoord(pos.fY+1) > (Int_t)fCanvas->GetHeight()) {
2086  SetVsbPosition(fVisible.fY/fScrollVal.fY+1);
2087  }
2088  if (fCurrent.fX > len) {
2089  if (ToScrXCoord(len, pos.fY) <= 0) {
2090  if (ToScrXCoord(len, pos.fY) < 0) {
2091  SetHsbPosition((ToScrXCoord(len, pos.fY)+fVisible.fX-fCanvas->GetWidth()/2)/fScrollVal.fX);
2092  } else {
2093  SetHsbPosition(0);
2094  }
2095  }
2096  pos.fX = len;
2097  } else {
2098  pos.fX = ToObjXCoord(ToScrXCoord(fCurrent.fX, fCurrent.fY)+fVisible.fX, pos.fY);
2099  }
2100 
2101  while (fText->GetChar(pos) == 16) {
2102  pos.fX++;
2103  }
2104  SetCurrent(pos);
2105  }
2106 }
2107 
2108 ////////////////////////////////////////////////////////////////////////////////
2109 /// Move one screen up.
2110 
2111 void TGTextEdit::ScreenUp()
2112 {
2113  TGLongPosition pos;
2114  pos.fX = fCurrent.fX;
2115  pos.fY = fCurrent.fY - (ToObjYCoord(fCanvas->GetHeight())-ToObjYCoord(0))-1;
2116  if (fVisible.fY - (Int_t)fCanvas->GetHeight() >= 0) { // +1
2117  SetVsbPosition((fVisible.fY - fCanvas->GetHeight())/fScrollVal.fY);
2118  } else {
2119  pos.fY = 0;
2120  SetVsbPosition(0);
2121  }
2122  while (fText->GetChar(pos) == 16) {
2123  pos.fX++;
2124  }
2125  SetCurrent(pos);
2126 }
2127 
2128 ////////////////////////////////////////////////////////////////////////////////
2129 /// Move one screen down.
2130 
2131 void TGTextEdit::ScreenDown()
2132 {
2133  TGLongPosition pos;
2134  pos.fX = fCurrent.fX;
2135  pos.fY = fCurrent.fY + (ToObjYCoord(fCanvas->GetHeight()) - ToObjYCoord(0));
2136  Long_t count = fText->RowCount()-1;
2137  if ((Int_t)fCanvas->GetHeight() < ToScrYCoord(count)) {
2138  SetVsbPosition((fVisible.fY+fCanvas->GetHeight())/fScrollVal.fY);
2139  } else {
2140  pos.fY = count;
2141  }
2142  while (fText->GetChar(pos) == 16) {
2143  pos.fX++;
2144  }
2145  SetCurrent(pos);
2146 }
2147 
2148 ////////////////////////////////////////////////////////////////////////////////
2149 /// Move to beginning of line.
2150 
2151 void TGTextEdit::Home()
2152 {
2153  TGLongPosition pos;
2154  pos.fY = fCurrent.fY;
2155  pos.fX = 0;
2156  SetHsbPosition(0);
2157  SetCurrent(pos);
2158 }
2159 
2160 ////////////////////////////////////////////////////////////////////////////////
2161 /// Move to end of line.
2162 
2163 void TGTextEdit::End()
2164 {
2165  TGLongPosition pos;
2166  pos.fY = fCurrent.fY;
2167  pos.fX = fText->GetLineLength(pos.fY);
2168  if (ToScrXCoord(pos.fX, pos.fY) >= (Int_t)fCanvas->GetWidth()) {
2169  SetHsbPosition((ToScrXCoord(pos.fX, pos.fY) + fVisible.fX - fCanvas->GetWidth()/2)/fScrollVal.fX);
2170  }
2171  SetCurrent(pos);
2172 }
2173 
2174 ////////////////////////////////////////////////////////////////////////////////
2175 /// Return selection graphics context for text cursor.
2176 
2177 const TGGC &TGTextEdit::GetCursor0GC()
2178 {
2179  if (!fgCursor0GC) {
2180  fgCursor0GC = new TGGC(GetDefaultSelectedGC());
2181  fgCursor0GC->SetFunction(kGXxor);
2182  }
2183  return *fgCursor0GC;
2184 }
2185 
2186 ////////////////////////////////////////////////////////////////////////////////
2187 /// Return default graphics context for text cursor.
2188 
2189 const TGGC &TGTextEdit::GetCursor1GC()
2190 {
2191  if (!fgCursor1GC) {
2192  fgCursor1GC = new TGGC(GetDefaultGC());
2193  fgCursor1GC->SetFunction(kGXand);
2194  }
2195  return *fgCursor1GC;
2196 }
2197 
2198 ////////////////////////////////////////////////////////////////////////////////
2199 /// Save a text edit widget as a C++ statement(s) on output stream out
2200 
2201 void TGTextEdit::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/)
2202 {
2203  char quote = '"';
2204  out << " TGTextEdit *";
2205  out << GetName() << " = new TGTextEdit(" << fParent->GetName()
2206  << "," << GetWidth() << "," << GetHeight()
2207  << ");"<< std::endl;
2208  if (option && strstr(option, "keep_names"))
2209  out << " " << GetName() << "->SetName(\"" << GetName() << "\");" << std::endl;
2210 
2211  if (IsReadOnly()) {
2212  out << " " << GetName() << "->SetReadOnly(kTRUE);" << std::endl;
2213  }
2214 
2215  if (!IsMenuEnabled()) {
2216  out << " " << GetName() << "->EnableMenu(kFALSE);" << std::endl;
2217  }
2218 
2219  if (fCanvas->GetBackground() != TGFrame::fgWhitePixel) {
2220  out << " " << GetName() << "->ChangeBackground(" << fCanvas->GetBackground() << ");" << std::endl;
2221  }
2222 
2223  TGText *txt = GetText();
2224  Bool_t fromfile = strlen(txt->GetFileName()) ? kTRUE : kFALSE;
2225  TString fn;
2226 
2227  if (fromfile) {
2228  const char *filename = txt->GetFileName();
2229  fn = gSystem->ExpandPathName(gSystem->UnixPathName(filename));
2230  } else {
2231  fn = TString::Format("Txt%s", GetName()+5);
2232  txt->Save(fn.Data());
2233  }
2234  out << " " << GetName() << "->LoadFile(" << quote << fn.Data() << quote << ");" << std::endl;
2235 }