Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TText.cxx
Go to the documentation of this file.
1 // @(#)root/graf:$Id$
2 // Author: Nicolas Brun 12/12/94
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 #include "TText.h"
13 
14 #include "Riostream.h"
15 #include "TROOT.h"
16 #include "TVirtualPad.h"
17 # include <ft2build.h>
18 # include FT_FREETYPE_H
19 # include FT_GLYPH_H
20 #include "TTF.h"
21 #include "TVirtualX.h"
22 #include "TMath.h"
23 #include "TPoint.h"
24 #include "TClass.h"
25 #include <wchar.h>
26 #include <cstdlib>
27 
28 ClassImp(TText);
29 
30 
31 /** \class TText
32 \ingroup BasicGraphics
33 
34 Base class for several text objects.
35 
36 See TAttText for a list of text attributes or fonts,
37 and also for a discussion on text speed and font quality.
38 
39 By default, the text is drawn in the pad coordinates system.
40 One can draw in NDC coordinates [0,1] if the function SetNDC
41 is called for a TText object.
42 
43 Example:
44 Begin_Macro(source)
45 {
46  TText *t = new TText(.5,.5,"Hello World !");
47  t->SetTextAlign(22);
48  t->SetTextColor(kRed+2);
49  t->SetTextFont(43);
50  t->SetTextSize(40);
51  t->SetTextAngle(45);
52  t->Draw();
53 }
54 End_Macro
55 */
56 
57 ////////////////////////////////////////////////////////////////////////////////
58 /// Text normal constructor.
59 
60 TText::TText(Double_t x, Double_t y, const char *text) : TNamed("",text), TAttText(), fWcsTitle(nullptr)
61 {
62  fX = x;
63  fY = y;
64 }
65 
66 ////////////////////////////////////////////////////////////////////////////////
67 /// Text normal constructor.
68 
69 TText::TText(Double_t x, Double_t y, const wchar_t *text) : TNamed(), TAttText()
70 {
71  fX = x;
72  fY = y;
73  fWcsTitle = new std::wstring(text);
74  SetName("");
75  SetMbTitle(text);
76 }
77 
78 ////////////////////////////////////////////////////////////////////////////////
79 /// Text default destructor.
80 
81 TText::~TText()
82 {
83  if (fWcsTitle) delete reinterpret_cast<std::wstring *>(fWcsTitle);
84 }
85 
86 ////////////////////////////////////////////////////////////////////////////////
87 /// Copy constructor.
88 
89 TText::TText(const TText &text) : TNamed(text), TAttText(text), TAttBBox2D(text), fWcsTitle(nullptr)
90 {
91  text.TText::Copy(*this);
92 }
93 
94 ////////////////////////////////////////////////////////////////////////////////
95 /// Assignment operator.
96 
97 TText &TText::operator=(const TText &src)
98 {
99  src.TText::Copy(*this);
100  return *this;
101 }
102 
103 ////////////////////////////////////////////////////////////////////////////////
104 /// Copy this text to text.
105 
106 void TText::Copy(TObject &obj) const
107 {
108  ((TText&)obj).fX = fX;
109  ((TText&)obj).fY = fY;
110  TNamed::Copy(obj);
111  TAttText::Copy(((TText&)obj));
112  if (((TText&)obj).fWcsTitle != NULL) {
113  if (fWcsTitle != NULL) {
114  *reinterpret_cast<std::wstring*>(&((TText&)obj).fWcsTitle) = *reinterpret_cast<const std::wstring*>(&fWcsTitle);
115  } else {
116  delete reinterpret_cast<std::wstring*>(&((TText&)obj).fWcsTitle);
117  ((TText&)obj).fWcsTitle = NULL;
118  }
119  } else {
120  if (fWcsTitle != NULL) {
121  ((TText&)(obj)).fWcsTitle = new std::wstring(*reinterpret_cast<const std::wstring*>(fWcsTitle));
122  }
123  }
124 }
125 
126 ////////////////////////////////////////////////////////////////////////////////
127 /// Returns the text as UNICODE.
128 
129 const void *TText::GetWcsTitle(void) const
130 {
131  if (fWcsTitle != NULL) {
132  return reinterpret_cast<std::wstring *>(fWcsTitle)->c_str();
133  } else {
134  return NULL;
135  }
136 }
137 
138 ////////////////////////////////////////////////////////////////////////////////
139 /// Compute distance from point px,py to a string.
140 /// The rectangle surrounding this string is evaluated.
141 /// If the point (px,py) is in the rectangle, the distance is set to zero.
142 
143 Int_t TText::DistancetoPrimitive(Int_t px, Int_t py)
144 {
145  Int_t ptx, pty;
146 
147  TAttText::Modify(); // change text attributes only if necessary
148 
149  if (TestBit(kTextNDC)) {
150  ptx = gPad->UtoPixel(fX);
151  pty = gPad->VtoPixel(fY);
152  } else {
153  ptx = gPad->XtoAbsPixel(gPad->XtoPad(fX));
154  pty = gPad->YtoAbsPixel(gPad->YtoPad(fY));
155  }
156 
157  // Get the text control box
158  Int_t cBoxX[5], cBoxY[5];
159  GetControlBox(ptx, pty, -fTextAngle, cBoxX, cBoxY);
160  cBoxY[4] = cBoxY[0];
161  cBoxX[4] = cBoxX[0];
162 
163  // Check if the point (px,py) is inside the text control box
164  if (TMath::IsInside(px, py, 5, cBoxX, cBoxY)){
165  return 0;
166  } else {
167  return 9999;
168  }
169 }
170 
171 ////////////////////////////////////////////////////////////////////////////////
172 /// Draw this text with new coordinates.
173 
174 TText *TText::DrawText(Double_t x, Double_t y, const char *text)
175 {
176  TText *newtext = new TText(x, y, text);
177  TAttText::Copy(*newtext);
178  newtext->SetBit(kCanDelete);
179  if (TestBit(kTextNDC)) newtext->SetNDC();
180  newtext->AppendPad();
181  return newtext;
182 }
183 
184 ////////////////////////////////////////////////////////////////////////////////
185 /// Draw this text with new coordinates.
186 
187 TText *TText::DrawText(Double_t x, Double_t y, const wchar_t *text)
188 {
189  TText *newtext = new TText(x, y, text);
190  TAttText::Copy(*newtext);
191  newtext->SetBit(kCanDelete);
192  if (TestBit(kTextNDC)) newtext->SetNDC();
193  newtext->AppendPad();
194  return newtext;
195 }
196 
197 ////////////////////////////////////////////////////////////////////////////////
198 /// Draw this text with new coordinates in NDC.
199 
200 TText *TText::DrawTextNDC(Double_t x, Double_t y, const char *text)
201 {
202  TText *newtext = DrawText(x, y, text);
203  newtext->SetNDC();
204  return newtext;
205 }
206 
207 ////////////////////////////////////////////////////////////////////////////////
208 /// Draw this text with new coordinates in NDC.
209 
210 TText *TText::DrawTextNDC(Double_t x, Double_t y, const wchar_t *text)
211 {
212  TText *newtext = DrawText(x, y, text);
213  newtext->SetNDC();
214  return newtext;
215 }
216 
217 ////////////////////////////////////////////////////////////////////////////////
218 /// Execute action corresponding to one event.
219 ///
220 /// This member function must be implemented to realize the action
221 /// corresponding to the mouse click on the object in the window
222 
223 void TText::ExecuteEvent(Int_t event, Int_t px, Int_t py)
224 {
225  if (!gPad) return;
226 
227  static Int_t px1, py1, pxold, pyold, Size, height, width;
228  static Bool_t resize,turn;
229  Int_t dx, dy;
230  const char *text = GetTitle();
231  Int_t len = strlen(text);
232  Double_t sizetowin = gPad->GetAbsHNDC()*Double_t(gPad->GetWh());
233  Double_t fh = (fTextSize*sizetowin);
234  Int_t h = Int_t(fh/2);
235  Int_t w = h*len;
236  Short_t halign = fTextAlign/10;
237  Short_t valign = fTextAlign - 10*halign;
238  Double_t co, si, dtheta, norm;
239  static Bool_t right, ndcsav;
240  static Double_t theta;
241  Int_t ax, ay, bx, by, cx, cy;
242  ax = ay = 0;
243  Double_t lambda, x2,y2;
244  Double_t dpx,dpy,xp1,yp1;
245  Int_t cBoxX[4], cBoxY[4], part;
246  Double_t div = 0;
247  Bool_t opaque = gPad->OpaqueMoving();
248 
249  if (!gPad->IsEditable()) return;
250  switch (event) {
251 
252  case kArrowKeyPress:
253  case kButton1Down:
254  ndcsav = TestBit(kTextNDC);
255  // No break !!!
256 
257  case kMouseMotion:
258  if (TestBit(kTextNDC)) {
259  px1 = gPad->UtoPixel(fX);
260  py1 = gPad->VtoPixel(fY);
261  } else {
262  px1 = gPad->XtoAbsPixel(gPad->XtoPad(fX));
263  py1 = gPad->YtoAbsPixel(gPad->YtoPad(fY));
264  }
265  theta = fTextAngle;
266  Size = 0;
267  pxold = px;
268  pyold = py;
269  co = TMath::Cos(fTextAngle*0.017453293);
270  si = TMath::Sin(fTextAngle*0.017453293);
271  resize = kFALSE;
272  turn = kFALSE;
273  GetControlBox(px1, py1, -theta, cBoxX, cBoxY);
274  div = ((cBoxX[3]-cBoxX[0])*co-(cBoxY[3]-cBoxY[0])*si);
275  if (TMath::Abs(div) > 1e-8) part = (Int_t)(3*((px-cBoxX[0])*co-(py-cBoxY[0])*si)/ div);
276  else part = 0;
277  switch (part) {
278  case 0:
279  if (halign == 3) {
280  turn = kTRUE;
281  right = kTRUE;
282  gPad->SetCursor(kRotate);
283  } else {
284  resize = kTRUE;
285  height = valign;
286  width = halign;
287  gPad->SetCursor(kArrowVer);
288  }
289  break;
290  case 1:
291  gPad->SetCursor(kMove);
292  break;
293  case 2:
294  if (halign == 3) {
295  resize = kTRUE;
296  height = valign;
297  width = halign;
298  gPad->SetCursor(kArrowVer);
299  } else {
300  turn = kTRUE;
301  right = kFALSE;
302  gPad->SetCursor(kRotate);
303  }
304  }
305  break;
306 
307  case kArrowKeyRelease:
308  case kButton1Motion:
309  if (!opaque) PaintControlBox(px1, py1, -theta);
310  if (turn) {
311  norm = TMath::Sqrt(Double_t((py-py1)*(py-py1)+(px-px1)*(px-px1)));
312  if (norm>0) {
313  theta = TMath::ACos((px-px1)/norm);
314  dtheta= TMath::ASin((py1-py)/norm);
315  if (dtheta<0) theta = -theta;
316  theta = theta/TMath::ACos(-1)*180;
317  if (theta<0) theta += 360;
318  if (right) {theta = theta+180; if (theta>=360) theta -= 360;}
319  }
320  } else if (resize) {
321 
322  co = TMath::Cos(fTextAngle*0.017453293);
323  si = TMath::Sin(fTextAngle*0.017453293);
324  if (width == 1) {
325  switch (valign) {
326  case 1 : ax = px1; ay = py1; break;
327  case 2 : ax = px1+Int_t(si*h/2); ay = py1+Int_t(co*h/2); break;
328  case 3 : ax = px1+Int_t(si*h*3/2); ay = py1+Int_t(co*h*3/2); break;
329  }
330  }
331  if (width == 2) {
332  switch (valign) {
333  case 1 : ax = px1-Int_t(co*w/2); ay = py1+Int_t(si*w/2); break;
334  case 2 : ax = px1-Int_t(co*w/2+si*h/2); ay = py1+Int_t(si*w/2+co*h/2); break;
335  case 3 : ax = px1-Int_t(co*w/2+si*h*3/2); ay = py1+Int_t(si*w/2+co*h*3/2); break;
336  }
337  }
338  if (width == 3) {
339  switch (valign) {
340  case 1 : ax = px1-Int_t(co*w); ay = py1+Int_t(si*w); break;
341  case 2 : ax = px1-Int_t(co*w+si*h/2); ay = py1+Int_t(si*w+co*h/2); break;
342  case 3 : ax = px1-Int_t(co*w+si*h*3/2); ay = py1+Int_t(si*w+co*h*3/2); break;
343  }
344  }
345  if (height == 3) {bx = ax-Int_t(si*h); by = ay-Int_t(co*h);}
346  else {bx = ax; by = ay;}
347  cx = bx+Int_t(co*w); cy = by-Int_t(si*w);
348  lambda = Double_t(((px-bx)*(cx-bx)+(py-by)*(cy-by)))/Double_t(((cx-bx)*(cx-bx)+(cy-by)*(cy-by)));
349  x2 = Double_t(px) - lambda*Double_t(cx-bx)-Double_t(bx);
350  y2 = Double_t(py) - lambda*Double_t(cy-by)-Double_t(by);
351  Size = Int_t(TMath::Sqrt(x2*x2+y2*y2)*2);
352  if (Size<4) Size = 4;
353 
354  SetTextSize(Size/sizetowin);
355  TAttText::Modify();
356  } else {
357  dx = px - pxold; px1 += dx;
358  dy = py - pyold; py1 += dy;
359  }
360  if (opaque) {
361  if (ndcsav) this->SetNDC(kFALSE);
362  this->SetX(gPad->PadtoX(gPad->AbsPixeltoX(px1)));
363  this->SetY(gPad->PadtoY(gPad->AbsPixeltoY(py1)));
364  if (resize) gPad->ShowGuidelines(this, event, 't', false);
365  if ((!resize)&&(!turn)) gPad->ShowGuidelines(this, event, 'i', true);
366  gPad->ShowGuidelines(this, event, !resize&!turn);
367  this->SetTextAngle(theta);
368  gPad->Modified(kTRUE);
369  gPad->Update();
370  }
371  if (!opaque) PaintControlBox(px1, py1, -theta);
372  pxold = px; pyold = py;
373  break;
374 
375  case kButton1Up:
376  if (opaque) {
377  if (ndcsav && !this->TestBit(kTextNDC)) {
378  this->SetX((fX - gPad->GetX1())/(gPad->GetX2()-gPad->GetX1()));
379  this->SetY((fY - gPad->GetY1())/(gPad->GetY2()-gPad->GetY1()));
380  this->SetNDC();
381  }
382  gPad->ShowGuidelines(this, event, !resize&!turn);
383  } else {
384  if (TestBit(kTextNDC)) {
385  dpx = gPad->GetX2() - gPad->GetX1();
386  dpy = gPad->GetY2() - gPad->GetY1();
387  xp1 = gPad->GetX1();
388  yp1 = gPad->GetY1();
389  fX = (gPad->AbsPixeltoX(px1)-xp1)/dpx;
390  fY = (gPad->AbsPixeltoY(py1)-yp1)/dpy;
391  } else {
392  fX = gPad->PadtoX(gPad->AbsPixeltoX(px1));
393  fY = gPad->PadtoY(gPad->AbsPixeltoY(py1));
394  }
395  fTextAngle = theta;
396  }
397  gPad->Modified(kTRUE);
398  break;
399 
400  case kButton1Locate:
401  ExecuteEvent(kButton1Down, px, py);
402 
403  while (1) {
404  px = py = 0;
405  event = gVirtualX->RequestLocator(1, 1, px, py);
406 
407  ExecuteEvent(kButton1Motion, px, py);
408 
409  if (event != -1) { // button is released
410  ExecuteEvent(kButton1Up, px, py);
411  return;
412  }
413  }
414  }
415 }
416 
417 ////////////////////////////////////////////////////////////////////////////////
418 /// Return the text control box. The text position coordinates is (x,y) and
419 /// the text angle is theta. The control box coordinates are returned in cBoxX
420 /// and cBoxY.
421 
422 void TText::GetControlBox(Int_t x, Int_t y, Double_t theta,
423  Int_t cBoxX[4], Int_t cBoxY[4])
424 {
425  Short_t halign = fTextAlign/10; // horizontal alignment
426  Short_t valign = fTextAlign - 10*halign; // vertical alignment
427  UInt_t cBoxW, cBoxH; // control box width and heigh
428  UInt_t Dx = 0, Dy = 0; // delta along x and y to align the box
429 
430  GetBoundingBox(cBoxW, cBoxH);
431 
432  // compute the translations (Dx, Dy) required by the alignments
433  switch (halign) {
434  case 1 : Dx = 0 ; break;
435  case 2 : Dx = cBoxW/2; break;
436  case 3 : Dx = cBoxW ; break;
437  }
438  switch (valign) {
439  case 1 : Dy = 0 ; break;
440  case 2 : Dy = cBoxH/2; break;
441  case 3 : Dy = cBoxH ; break;
442  }
443 
444  // compute the control box coordinates before rotation
445  cBoxX[0] = x-Dx;
446  cBoxY[0] = y+Dy;
447  cBoxX[1] = x-Dx;
448  cBoxY[1] = y-cBoxH+Dy;
449  cBoxX[2] = x+cBoxW-Dx;
450  cBoxY[2] = y-cBoxH+Dy;
451  cBoxX[3] = x+cBoxW-Dx;
452  cBoxY[3] = y+Dy;
453 
454  // rotate the control box if needed
455  if (theta) {
456  Double_t cosTheta = TMath::Cos(theta*0.017453293);
457  Double_t sinTheta = TMath::Sin(theta*0.017453293);
458  for (int i=0; i<4 ; i++) {
459  Int_t hcBoxX = cBoxX[i];
460  Int_t hcBoxY = cBoxY[i];
461  cBoxX[i] = (Int_t)((hcBoxX-x)*cosTheta-(hcBoxY-y)*sinTheta+x);
462  cBoxY[i] = (Int_t)((hcBoxX-x)*sinTheta+(hcBoxY-y)*cosTheta+y);
463  }
464  }
465 }
466 
467 ////////////////////////////////////////////////////////////////////////////////
468 /// Return text size in pixels. By default the size returned does not take
469 /// into account the text angle (angle = kFALSE). If angle is set to kTRUE
470 /// w and h take the angle into account.
471 
472 void TText::GetBoundingBox(UInt_t &w, UInt_t &h, Bool_t angle)
473 {
474  const char *text = GetTitle();
475  if (!text[0]) {
476  w = h = 0;
477  return;
478  }
479 
480  if (angle) {
481  Int_t cBoxX[4], cBoxY[4];
482  Int_t ptx, pty;
483  if (TestBit(kTextNDC)) {
484  ptx = gPad->UtoPixel(fX);
485  pty = gPad->VtoPixel(fY);
486  } else {
487  ptx = gPad->XtoAbsPixel(gPad->XtoPad(fX));
488  pty = gPad->YtoAbsPixel(gPad->YtoPad(fY));
489  }
490  GetControlBox(ptx, pty, fTextAngle, cBoxX, cBoxY);
491  Int_t x1 = cBoxX[0];
492  Int_t x2 = cBoxX[0];
493  Int_t y1 = cBoxY[0];
494  Int_t y2 = cBoxY[0];
495  for (Int_t i=1; i<4; i++) {
496  if (cBoxX[i] < x1) x1 = cBoxX[i];
497  if (cBoxX[i] > x2) x2 = cBoxX[i];
498  if (cBoxY[i] < y1) y1 = cBoxY[i];
499  if (cBoxY[i] > y2) y2 = cBoxY[i];
500  }
501  w = x2-x1;
502  h = y2-y1;
503  } else {
504  if ((gVirtualX->HasTTFonts() && TTF::IsInitialized()) || gPad->IsBatch()) {
505  TTF::GetTextExtent(w, h, (char*)GetTitle());
506  } else {
507  const Font_t oldFont = gVirtualX->GetTextFont();
508  if (gVirtualX->InheritsFrom("TGCocoa"))
509  gVirtualX->SetTextFont(fTextFont);
510  gVirtualX->GetTextExtent(w, h, (char*)GetTitle());
511  if (gVirtualX->InheritsFrom("TGCocoa"))
512  gVirtualX->SetTextFont(oldFont);
513  }
514  }
515 }
516 
517 ////////////////////////////////////////////////////////////////////////////////
518 /// Return text ascent and descent for string text
519 /// - in a return total text ascent
520 /// - in d return text descent
521 
522 void TText::GetTextAscentDescent(UInt_t &a, UInt_t &d, const char *text) const
523 {
524  Double_t wh = (Double_t)gPad->XtoPixel(gPad->GetX2());
525  Double_t hh = (Double_t)gPad->YtoPixel(gPad->GetY1());
526  Double_t tsize;
527  if (wh < hh) tsize = fTextSize*wh;
528  else tsize = fTextSize*hh;
529 
530  if (gVirtualX->HasTTFonts() || gPad->IsBatch()) {
531  TTF::SetTextFont(fTextFont);
532  TTF::SetTextSize(tsize);
533  a = TTF::GetBox().yMax;
534  d = TMath::Abs(TTF::GetBox().yMin);
535  } else {
536  const Font_t oldFont = gVirtualX->GetTextFont();
537  if (gVirtualX->InheritsFrom("TGCocoa"))
538  gVirtualX->SetTextFont(fTextFont);
539  gVirtualX->SetTextSize(tsize);
540  a = gVirtualX->GetFontAscent(text);
541  if (!a) {
542  UInt_t w;
543  gVirtualX->GetTextExtent(w, a, (char*)text);
544  }
545  d = gVirtualX->GetFontDescent(text);
546  if (gVirtualX->InheritsFrom("TGCocoa"))
547  gVirtualX->SetTextFont(oldFont);
548  }
549 }
550 
551 
552 ////////////////////////////////////////////////////////////////////////////////
553 /// Return text ascent and descent for string text
554 /// - in a return total text ascent
555 /// - in d return text descent
556 
557 void TText::GetTextAscentDescent(UInt_t &a, UInt_t &d, const wchar_t *text) const
558 {
559  Double_t wh = (Double_t)gPad->XtoPixel(gPad->GetX2());
560  Double_t hh = (Double_t)gPad->YtoPixel(gPad->GetY1());
561  Double_t tsize;
562  if (wh < hh) tsize = fTextSize*wh;
563  else tsize = fTextSize*hh;
564 
565  if (gVirtualX->HasTTFonts() || gPad->IsBatch() || gVirtualX->InheritsFrom("TGCocoa")) {
566  TTF::SetTextFont(fTextFont);
567  TTF::SetTextSize(tsize);
568  a = TTF::GetBox().yMax;
569  d = TMath::Abs(TTF::GetBox().yMin);
570  } else {
571  gVirtualX->SetTextSize(tsize);
572  a = gVirtualX->GetFontAscent();
573  if (!a) {
574  UInt_t w;
575  gVirtualX->GetTextExtent(w, a, (wchar_t*)text);
576  }
577  d = gVirtualX->GetFontDescent();
578  }
579 }
580 
581 ////////////////////////////////////////////////////////////////////////////////
582 /// Return text extent for string text
583 /// - in w return total text width
584 /// - in h return text height
585 
586 void TText::GetTextExtent(UInt_t &w, UInt_t &h, const char *text) const
587 {
588  Double_t wh = (Double_t)gPad->XtoPixel(gPad->GetX2());
589  Double_t hh = (Double_t)gPad->YtoPixel(gPad->GetY1());
590  Double_t tsize;
591  if (wh < hh) tsize = fTextSize*wh;
592  else tsize = fTextSize*hh;
593 
594  if (gVirtualX->HasTTFonts() || gPad->IsBatch()) {
595  TTF::SetTextFont(fTextFont);
596  TTF::SetTextSize(tsize);
597  TTF::GetTextExtent(w, h, (char*)text);
598  } else {
599  const Font_t oldFont = gVirtualX->GetTextFont();
600  if (gVirtualX->InheritsFrom("TGCocoa"))
601  gVirtualX->SetTextFont(fTextFont);
602  gVirtualX->SetTextSize(tsize);
603  gVirtualX->GetTextExtent(w, h, (char*)text);
604  if (gVirtualX->InheritsFrom("TGCocoa"))
605  gVirtualX->SetTextFont(oldFont);
606  }
607 }
608 
609 ////////////////////////////////////////////////////////////////////////////////
610 /// Return text advance for string text
611 /// if kern is true (default) kerning is taken into account. If it is false
612 /// the kerning is not taken into account.
613 
614 void TText::GetTextAdvance(UInt_t &a, const char *text, const Bool_t kern) const
615 {
616  Double_t wh = (Double_t)gPad->XtoPixel(gPad->GetX2());
617  Double_t hh = (Double_t)gPad->YtoPixel(gPad->GetY1());
618  Double_t tsize;
619  if (wh < hh) tsize = fTextSize*wh;
620  else tsize = fTextSize*hh;
621 
622  if (gVirtualX->HasTTFonts() || gPad->IsBatch()) {
623  Bool_t kernsave = TTF::GetKerning();
624  TTF::SetKerning(kern);
625  TTF::SetTextFont(fTextFont);
626  TTF::SetTextSize(tsize);
627  TTF::GetTextAdvance(a, (char*)text);
628  TTF::SetKerning(kernsave);
629  } else {
630  UInt_t h;
631  const Font_t oldFont = gVirtualX->GetTextFont();
632  //how do I know what to calculate without a font???
633  if (gVirtualX->InheritsFrom("TGCocoa"))
634  gVirtualX->SetTextFont(fTextFont);
635 
636  gVirtualX->SetTextSize(tsize);
637  gVirtualX->GetTextExtent(a, h, (char*)text);
638 
639  if (gVirtualX->InheritsFrom("TGCocoa"))
640  gVirtualX->SetTextFont(oldFont);
641  }
642 }
643 
644 ////////////////////////////////////////////////////////////////////////////////
645 /// Return text extent for string text
646 /// - in w return total text width
647 /// - in h return text height
648 
649 void TText::GetTextExtent(UInt_t &w, UInt_t &h, const wchar_t *text) const
650 {
651  Double_t wh = (Double_t)gPad->XtoPixel(gPad->GetX2());
652  Double_t hh = (Double_t)gPad->YtoPixel(gPad->GetY1());
653  Double_t tsize;
654  if (wh < hh) tsize = fTextSize*wh;
655  else tsize = fTextSize*hh;
656 
657  if (gVirtualX->HasTTFonts() || gPad->IsBatch() || gVirtualX->InheritsFrom("TGCocoa")) {
658  TTF::SetTextFont(fTextFont);
659  TTF::SetTextSize(tsize);
660  TTF::GetTextExtent(w, h, (wchar_t*)text);
661  } else {
662  gVirtualX->SetTextSize(tsize);
663  gVirtualX->GetTextExtent(w, h, (wchar_t*)text);
664  }
665 }
666 
667 ////////////////////////////////////////////////////////////////////////////////
668 /// List this text with its attributes.
669 
670 void TText::ls(Option_t *) const
671 {
672  TROOT::IndentLevel();
673  printf("Text X=%f Y=%f Text=%s\n",fX,fY,GetTitle());
674 }
675 
676 ////////////////////////////////////////////////////////////////////////////////
677 /// Paint this text with its current attributes.
678 
679 void TText::Paint(Option_t *)
680 {
681  TAttText::Modify(); //Change text attributes only if necessary
682  if (TestBit(kTextNDC)) gPad->PaintTextNDC(fX,fY,GetTitle());
683  else gPad->PaintText(gPad->XtoPad(fX),gPad->YtoPad(fY),GetTitle());
684 }
685 
686 ////////////////////////////////////////////////////////////////////////////////
687 /// Paint the text control box. (x,y) are the coordinates where the control
688 /// box should be painted and theta is the angle of the box.
689 
690 void TText::PaintControlBox(Int_t x, Int_t y, Double_t theta)
691 {
692  Int_t cBoxX[4], cBoxY[4];
693  Short_t halign = fTextAlign/10; // horizontal alignment
694  Short_t valign = fTextAlign - 10*halign; // vertical alignment
695 
696  GetControlBox(x, y, theta, cBoxX, cBoxY);
697  // Draw the text control box outline
698  gVirtualX->SetLineStyle((Style_t)1);
699  gVirtualX->SetLineWidth(1);
700  gVirtualX->SetLineColor(1);
701  gVirtualX->DrawLine(cBoxX[0], cBoxY[0], cBoxX[1], cBoxY[1]);
702  gVirtualX->DrawLine(cBoxX[1], cBoxY[1], cBoxX[2], cBoxY[2]);
703  gVirtualX->DrawLine(cBoxX[2], cBoxY[2], cBoxX[3], cBoxY[3]);
704  gVirtualX->DrawLine(cBoxX[3], cBoxY[3], cBoxX[0], cBoxY[0]);
705 
706  // Draw a symbol at the text starting point
707  TPoint p;
708  Int_t ix = 0, iy = 0;
709  switch (halign) {
710  case 1 :
711  switch (valign) {
712  case 1 : ix = 0 ; iy = 0 ; break;
713  case 2 : ix = 0 ; iy = 1 ; break;
714  case 3 : ix = 1 ; iy = 1 ; break;
715  }
716  break;
717  case 2 :
718  switch (valign) {
719  case 1 : ix = 0 ; iy = 3 ; break;
720  case 2 : ix = 0 ; iy = 2 ; break;
721  case 3 : ix = 1 ; iy = 2 ; break;
722  }
723  break;
724  case 3 :
725  switch (valign) {
726  case 1 : ix = 3 ; iy = 3 ; break;
727  case 2 : ix = 2 ; iy = 3 ; break;
728  case 3 : ix = 2 ; iy = 2 ; break;
729  }
730  break;
731  }
732  p.fX = (cBoxX[ix]+cBoxX[iy])/2;
733  p.fY = (cBoxY[ix]+cBoxY[iy])/2;
734  gVirtualX->SetMarkerColor(1);
735  gVirtualX->SetMarkerStyle(24);
736  gVirtualX->SetMarkerSize(0.7);
737  gVirtualX->DrawPolyMarker(1, &p);
738 }
739 
740 ////////////////////////////////////////////////////////////////////////////////
741 /// Draw this text with new coordinates.
742 
743 void TText::PaintText(Double_t x, Double_t y, const char *text)
744 {
745  TAttText::Modify(); //Change text attributes only if necessary
746  gPad->PaintText(x,y,text);
747 }
748 
749 ////////////////////////////////////////////////////////////////////////////////
750 /// Draw this text with new coordinates.
751 
752 void TText::PaintText(Double_t x, Double_t y, const wchar_t *text)
753 {
754  TAttText::Modify(); //Change text attributes only if necessary
755  gPad->PaintText(x,y,text);
756 }
757 
758 ////////////////////////////////////////////////////////////////////////////////
759 /// Draw this text with new coordinates in NDC.
760 
761 void TText::PaintTextNDC(Double_t u, Double_t v, const char *text)
762 {
763  TAttText::Modify(); //Change text attributes only if necessary
764  gPad->PaintTextNDC(u,v,text);
765 }
766 
767 ////////////////////////////////////////////////////////////////////////////////
768 /// Draw this text with new coordinates in NDC.
769 
770 void TText::PaintTextNDC(Double_t u, Double_t v, const wchar_t *text)
771 {
772  TAttText::Modify(); //Change text attributes only if necessary
773  gPad->PaintTextNDC(u,v,text);
774 }
775 
776 ////////////////////////////////////////////////////////////////////////////////
777 /// Dump this text with its attributes.
778 
779 void TText::Print(Option_t *) const
780 {
781  printf("Text X=%f Y=%f Text=%s Font=%d Size=%f",fX,fY,GetTitle(),GetTextFont(),GetTextSize());
782  if (GetTextColor() != 1 ) printf(" Color=%d",GetTextColor());
783  if (GetTextAlign() != 10) printf(" Align=%d",GetTextAlign());
784  if (GetTextAngle() != 0 ) printf(" Angle=%f",GetTextAngle());
785  printf("\n");
786 }
787 
788 ////////////////////////////////////////////////////////////////////////////////
789 /// Save primitive as a C++ statement(s) on output stream out
790 
791 void TText::SavePrimitive(std::ostream &out, Option_t * /*= ""*/)
792 {
793  char quote = '"';
794  if (gROOT->ClassSaved(TText::Class())) {
795  out<<" ";
796  } else {
797  out<<" TText *";
798  }
799  TString s = GetTitle();
800  s.ReplaceAll("\"","\\\"");
801  out<<"text = new TText("<<fX<<","<<fY<<","<<quote<<s.Data()<<quote<<");"<<std::endl;
802  if (TestBit(kTextNDC)) out<<" text->SetNDC();"<<std::endl;
803 
804  SaveTextAttributes(out,"text",11,0,1,62,0.05);
805 
806  out<<" text->Draw();"<<std::endl;
807 }
808 
809 ////////////////////////////////////////////////////////////////////////////////
810 /// Set NDC mode on if isNDC = kTRUE, off otherwise
811 
812 void TText::SetNDC(Bool_t isNDC)
813 {
814  ResetBit(kTextNDC);
815  if (isNDC) SetBit(kTextNDC);
816 }
817 
818 ////////////////////////////////////////////////////////////////////////////////
819 /// Change (i.e. set) the title of the TNamed.
820 
821 void TText::SetMbTitle(const wchar_t *title)
822 {
823  char *mb_title = new char[MB_CUR_MAX * wcslen(title) + 1]();
824  char *p = mb_title;
825  size_t length = wcslen(title);
826  for (size_t i = 0; i < length; i++) {
827  const int n = wctomb(p, title[i]);
828  if (n >= 0) p += n;
829  }
830  fTitle = mb_title;
831  delete [] mb_title;
832  if (gPad && TestBit(kMustCleanup)) gPad->Modified();
833 }
834 
835 ////////////////////////////////////////////////////////////////////////////////
836 /// Stream an object of class TText.
837 
838 void TText::Streamer(TBuffer &R__b)
839 {
840  if (R__b.IsReading()) {
841  UInt_t R__s, R__c;
842  Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
843  if (R__v > 1) {
844  R__b.ReadClassBuffer(TText::Class(), this, R__v, R__s, R__c);
845  return;
846  }
847  //====process old versions before automatic schema evolution
848  TNamed::Streamer(R__b);
849  TAttText::Streamer(R__b);
850  Float_t x,y;
851  R__b >> x; fX = x;
852  R__b >> y; fY = y;
853  //====end of old versions
854 
855  } else {
856  R__b.WriteClassBuffer(TText::Class(),this);
857  }
858 }
859 ////////////////////////////////////////////////////////////////////////////////
860 /// Return the "bounding Box" of the Box
861 
862 Rectangle_t TText::GetBBox()
863 {
864  UInt_t w, h;
865  Int_t Dx, Dy;
866  Dx = Dy = 0;
867  GetBoundingBox(w, h, false);
868 
869  Short_t halign = fTextAlign/10;
870  Short_t valign = fTextAlign - 10*halign;
871 
872  switch (halign) {
873  case 1 : Dx = 0 ; break;
874  case 2 : Dx = w/2 ; break;
875  case 3 : Dx = w ; break;
876  }
877  switch (valign) {
878  case 1 : Dy = h ; break;
879  case 2 : Dy = h/2 ; break;
880  case 3 : Dy = 0 ; break;
881  }
882 
883  Rectangle_t BBox;
884  BBox.fX = gPad->XtoPixel(fX)-Dx;
885  BBox.fY = gPad->YtoPixel(fY)-Dy;
886  BBox.fWidth = w;
887  BBox.fHeight = h;
888  return (BBox);
889 }
890 
891 ////////////////////////////////////////////////////////////////////////////////
892 /// Return the point given by Alignment as 'center'
893 
894 TPoint TText::GetBBoxCenter()
895 {
896  TPoint p;
897  p.SetX(gPad->XtoPixel(fX));
898  p.SetY(gPad->YtoPixel(fY));
899  return(p);
900 }
901 
902 ////////////////////////////////////////////////////////////////////////////////
903 /// Set the point given by Alignment as 'center'
904 
905 void TText::SetBBoxCenter(const TPoint &p)
906 {
907  this->SetX(gPad->PixeltoX(p.GetX()));
908  this->SetY(gPad->PixeltoY(p.GetY()-gPad->VtoPixel(0)));
909 }
910 
911 ////////////////////////////////////////////////////////////////////////////////
912 /// Set X coordinate of the point given by Alignment as 'center'
913 
914 void TText::SetBBoxCenterX(const Int_t x)
915 {
916  this->SetX(gPad->PixeltoX(x));
917 }
918 
919 ////////////////////////////////////////////////////////////////////////////////
920 /// Set Y coordinate of the point given by Alignment as 'center'
921 
922 void TText::SetBBoxCenterY(const Int_t y)
923 {
924  this->SetY(gPad->PixeltoY(y - gPad->VtoPixel(0)));
925 }
926 
927 ////////////////////////////////////////////////////////////////////////////////
928 /// Set left hand side of BoundingBox to a value
929 /// (resize in x direction on left)
930 
931 void TText::SetBBoxX1(const Int_t /*x*/)
932 {
933  //NOT IMPLEMENTED
934 }
935 
936 ////////////////////////////////////////////////////////////////////////////////
937 /// Set right hand side of BoundingBox to a value
938 /// (resize in x direction on right)
939 
940 void TText::SetBBoxX2(const Int_t /*x*/)
941 {
942  //NOT IMPLEMENTED
943 }
944 
945 ////////////////////////////////////////////////////////////////////////////////
946 /// Set top of BoundingBox to a value (resize in y direction on top)
947 
948 void TText::SetBBoxY1(const Int_t /*y*/)
949 {
950  //NOT IMPLEMENTED
951 }
952 
953 ////////////////////////////////////////////////////////////////////////////////
954 /// Set bottom of BoundingBox to a value
955 /// (resize in y direction on bottom)
956 
957 void TText::SetBBoxY2(const Int_t /*y*/)
958 {
959  //NOT IMPLEMENTED
960 }