Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGButton.cxx
Go to the documentation of this file.
1 // @(#)root/gui:$Id: ee86415852b0e43b57190b9645717cf508b7920e $
2 // Author: Fons Rademakers 06/01/98
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 // TGButton, TGTextButton, TGPictureButton, TGCheckButton, //
26 // TGRadioButton and TGSplitButton //
27 // //
28 // This header defines all GUI button widgets. //
29 // //
30 // TGButton is a button abstract base class. It defines general button //
31 // behaviour. //
32 // //
33 // TGTextButton and TGPictureButton yield an action as soon as they are //
34 // clicked. These buttons usually provide fast access to frequently //
35 // used or critical commands. They may appear alone or placed in a //
36 // group. //
37 // //
38 // The action they perform can be inscribed with a meaningful tooltip //
39 // set by SetToolTipText(const char* text, Long_t delayms=400). //
40 // //
41 // The text button has a label indicating the action to be taken when //
42 // the button is pressed. The text can be a hot string ("&Exit") that //
43 // defines the label "Exit" and keyboard mnemonics Alt+E for button //
44 // selection. A button label can be changed by SetText(new_label). //
45 // //
46 // Selecting a text or picture button will generate the event: //
47 // kC_COMMAND, kCM_BUTTON, button id, user data. //
48 // //
49 // The purpose of TGCheckButton and TGRadioButton is for selecting //
50 // different options. Like text buttons, they have text or hot string //
51 // as a label. //
52 // //
53 // Radio buttons are grouped usually in logical sets of two or more //
54 // buttons to present mutually exclusive choices. //
55 // //
56 // Selecting a check button will generate the event: //
57 // kC_COMMAND, kCM_CHECKBUTTON, button id, user data. //
58 // //
59 // Selecting a radio button will generate the event: //
60 // kC_COMMAND, kCM_RADIOBUTTON, button id, user data. //
61 // //
62 // If a command string has been specified (via SetCommand()) then this //
63 // command string will be executed via the interpreter whenever a //
64 // button is selected. A command string can contain the macros: //
65 // $MSG -- kC_COMMAND, kCM[CHECK|RADIO]BUTTON packed message //
66 // (use GET_MSG() and GET_SUBMSG() to unpack) //
67 // $PARM1 -- button id //
68 // $PARM2 -- user data pointer //
69 // Before executing these macros are expanded into the respective //
70 // Long_t's //
71 // //
72 // TGSplitButton implements a button with added menu functionality. //
73 // There are 2 modes of operation available. //
74 // //
75 // If the button is split, a menu will popup when the menu area of the //
76 // button is clicked. Activating a menu item changes the functionality //
77 // of the button by having it emit a additional signal when it is //
78 // clicked. The signal emitted when the button is clicked, is the //
79 // ItemClicked(Int_t) signal with a different fixed value for the //
80 // Int_t that corresponds to the id of the activated menu entry. //
81 // //
82 // If the button is not split, clicking it will popup the menu and the //
83 // ItemClicked(Int_t) signal will be emitted when a menu entry is //
84 // acitvated. The value of the Int_t is again equal to the value of //
85 // the id of the activated menu entry. //
86 // //
87 // The mode of operation of a SplitButton can be changed on the fly //
88 // by calling the SetSplit(Bool_t) method. //
89 //////////////////////////////////////////////////////////////////////////
90 
91 #include "TGButton.h"
92 #include "TGWidget.h"
93 #include "TGPicture.h"
94 #include "TGToolTip.h"
95 #include "TGButtonGroup.h"
96 #include "TGResourcePool.h"
97 #include "Riostream.h"
98 #include "TSystem.h"
99 #include "TImage.h"
100 #include "TEnv.h"
101 #include "TClass.h"
102 #include "TGMenu.h"
103 #include "KeySymbols.h"
104 
105 const TGGC *TGButton::fgHibckgndGC = 0;
106 const TGGC *TGButton::fgDefaultGC = 0;
107 
108 const TGFont *TGTextButton::fgDefaultFont = 0;
109 
110 const TGFont *TGCheckButton::fgDefaultFont = 0;
111 const TGGC *TGCheckButton::fgDefaultGC = 0;
112 
113 const TGFont *TGRadioButton::fgDefaultFont = 0;
114 const TGGC *TGRadioButton::fgDefaultGC = 0;
115 
116 Window_t TGButton::fgReleaseBtn = 0;
117 
118 ClassImp(TGButton);
119 ClassImp(TGTextButton);
120 ClassImp(TGPictureButton);
121 ClassImp(TGCheckButton);
122 ClassImp(TGRadioButton);
123 ClassImp(TGSplitButton);
124 
125 ////////////////////////////////////////////////////////////////////////////////
126 /// Create button base class part.
127 
128 TGButton::TGButton(const TGWindow *p, Int_t id, GContext_t norm, UInt_t options)
129  : TGFrame(p, 1, 1, options)
130 {
131  fWidgetId = id;
132  fWidgetFlags = kWidgetWantFocus;
133  fMsgWindow = p;
134  fUserData = 0;
135  fTip = 0;
136  fGroup = 0;
137  fStyle = 0;
138  fTWidth = fTHeight = 0;
139 
140  fNormGC = norm;
141  fState = kButtonUp;
142  fStayDown = kFALSE;
143  fWidgetFlags = kWidgetIsEnabled;
144 
145 // fStyle = gClient->GetStyle();
146 // if (fStyle > 0) {
147 // fOptions &= ~(kRaisedFrame | kDoubleBorder);
148 // }
149 
150  // coverity[returned_null]
151  // coverity[dereference]
152  if (p && p->IsA()->InheritsFrom(TGButtonGroup::Class())) {
153  TGButtonGroup *bg = (TGButtonGroup*) p;
154  bg->Insert(this, id);
155  }
156 
157  fBgndColor = fBackground;
158  fHighColor = gClient->GetResourcePool()->GetHighLightColor();
159 
160  gVirtualX->GrabButton(fId, kButton1, kAnyModifier,
161  kButtonPressMask | kButtonReleaseMask,
162  kNone, kNone);
163 
164  AddInput(kEnterWindowMask | kLeaveWindowMask);
165  SetWindowName();
166 }
167 
168 ////////////////////////////////////////////////////////////////////////////////
169 /// Delete button.
170 
171 TGButton::~TGButton()
172 {
173  // remove from button group
174  if (fGroup) {
175  fGroup->Remove(this);
176  fGroup = 0;
177  }
178 
179  if (fTip) delete fTip;
180 }
181 
182 ////////////////////////////////////////////////////////////////////////////////
183 /// Set button state.
184 
185 void TGButton::SetState(EButtonState state, Bool_t emit)
186 {
187  Bool_t was = !IsDown(); // kTRUE if button was off
188 
189  if (state == kButtonDisabled)
190  fWidgetFlags &= ~kWidgetIsEnabled;
191  else
192  fWidgetFlags |= kWidgetIsEnabled;
193  if (state != fState) {
194  switch (state) {
195  case kButtonEngaged:
196  case kButtonDown:
197  fOptions &= ~kRaisedFrame;
198  fOptions |= kSunkenFrame;
199  break;
200  case kButtonDisabled:
201  case kButtonUp:
202  if (fStyle > 0) {
203  fOptions &= ~kRaisedFrame;
204  fOptions &= ~kSunkenFrame;
205  }
206  else {
207  fOptions &= ~kSunkenFrame;
208  fOptions |= kRaisedFrame;
209  }
210  break;
211  }
212  fState = state;
213  DoRedraw();
214  if (emit || fGroup) EmitSignals(was);
215  }
216 }
217 
218 ////////////////////////////////////////////////////////////////////////////////
219 /// Set the button style (modern or classic).
220 
221 void TGButton::SetStyle(UInt_t newstyle)
222 {
223  fStyle = newstyle;
224  fBgndColor = fBackground;
225  if (fStyle > 0) {
226  ChangeOptions(GetOptions() & ~kRaisedFrame);
227  }
228  else {
229  ChangeOptions(GetOptions() | kRaisedFrame);
230  }
231 }
232 
233 ////////////////////////////////////////////////////////////////////////////////
234 /// Set the button style (modern or classic).
235 
236 void TGButton::SetStyle(const char *style)
237 {
238  fBgndColor = fBackground;
239  if (style && strstr(style, "modern")) {
240  fStyle = 1;
241  ChangeOptions(GetOptions() & ~kRaisedFrame);
242  }
243  else {
244  fStyle = 0;
245  ChangeOptions(GetOptions() | kRaisedFrame);
246  }
247 }
248 
249 ////////////////////////////////////////////////////////////////////////////////
250 
251 Bool_t TGButton::IsDown() const
252 {
253  if (fStyle > 0)
254  return (fOptions & kSunkenFrame);
255  return !(fOptions & kRaisedFrame);
256 }
257 
258 ////////////////////////////////////////////////////////////////////////////////
259 
260 void TGButton::SetDown(Bool_t on, Bool_t emit)
261 {
262  // Set button state down according to the parameter 'on'.
263 
264  if (GetState() == kButtonDisabled) return;
265 
266  SetState(on ? kButtonDown : kButtonUp, emit);
267 }
268 
269 ////////////////////////////////////////////////////////////////////////////////
270 /// Sets new button-group for this button.
271 
272 void TGButton::SetGroup(TGButtonGroup *group)
273 {
274  fGroup = group;
275 }
276 
277 ////////////////////////////////////////////////////////////////////////////////
278 /// Handle mouse button event.
279 
280 Bool_t TGButton::HandleButton(Event_t *event)
281 {
282  Bool_t click = kFALSE;
283 
284  if (fTip) fTip->Hide();
285 
286  if (fState == kButtonDisabled) return kTRUE;
287 
288  Bool_t in = (event->fX >= 0) && (event->fY >= 0) &&
289  (event->fX <= (Int_t)fWidth) && (event->fY <= (Int_t)fHeight);
290 
291  // We don't need to check the button number as GrabButton will
292  // only allow button1 events
293  if (event->fType == kButtonPress) {
294  fgReleaseBtn = 0;
295 
296  if (fState == kButtonEngaged) {
297  return kTRUE;
298  }
299  if (in) SetState(kButtonDown, kTRUE);
300  } else { // ButtonRelease
301  if (fState == kButtonEngaged) {
302  if (in) SetState(kButtonUp, kTRUE);
303  click = kTRUE;
304  } else {
305  click = (fState == kButtonDown) && in;
306  if (click && fStayDown) {
307  if (in) {
308  SetState(kButtonEngaged, kTRUE);
309  fgReleaseBtn = 0;
310  }
311  } else {
312  if (in) {
313  SetState(kButtonUp, kTRUE);
314  fgReleaseBtn = fId;
315  }
316  }
317  }
318  }
319  if (click) {
320  SendMessage(fMsgWindow, MK_MSG(kC_COMMAND, kCM_BUTTON), fWidgetId,
321  (Long_t) fUserData);
322  fClient->ProcessLine(fCommand, MK_MSG(kC_COMMAND, kCM_BUTTON), fWidgetId,
323  (Long_t) fUserData);
324  }
325  if ((fStyle > 0) && (event->fType == kButtonRelease)) {
326  fBgndColor = fBackground;
327  }
328  DoRedraw();
329  return kTRUE;
330 }
331 
332 ////////////////////////////////////////////////////////////////////////////////
333 /// Emit button signals.
334 
335 void TGButton::EmitSignals(Bool_t was)
336 {
337  Bool_t now = !IsDown(); // kTRUE if button now is off
338 
339  // emit signals
340  if (was && !now) {
341  Pressed(); // emit Pressed = was off , now on
342  if (fStayDown) Clicked(); // emit Clicked
343  }
344  if (!was && now) {
345  Released(); // emit Released = was on , now off
346  Clicked(); // emit Clicked
347  }
348  if ((was != now) && IsToggleButton()) Toggled(!now); // emit Toggled = was != now
349 }
350 
351 ////////////////////////////////////////////////////////////////////////////////
352 /// Handle mouse crossing event.
353 
354 Bool_t TGButton::HandleCrossing(Event_t *event)
355 {
356  if (fTip) {
357  if (event->fType == kEnterNotify)
358  fTip->Reset();
359  else
360  fTip->Hide();
361  }
362 
363  if (fStyle > 0) {
364  if ((event->fType == kEnterNotify) && (fState != kButtonDisabled)) {
365  fBgndColor = fHighColor;
366  } else {
367  fBgndColor = fBackground;
368  }
369  if (event->fType == kLeaveNotify) {
370  fBgndColor = fBackground;
371  }
372  DoRedraw();
373  }
374 
375  if ((fgDbw != event->fWindow) || (fgReleaseBtn == event->fWindow)) return kTRUE;
376 
377  if (!(event->fState & (kButton1Mask | kButton2Mask | kButton3Mask)))
378  return kTRUE;
379 
380  if (fState == kButtonEngaged || fState == kButtonDisabled) return kTRUE;
381 
382  if (event->fType == kLeaveNotify) {
383  fgReleaseBtn = fId;
384  SetState(kButtonUp, kFALSE);
385  }
386  DoRedraw();
387  return kTRUE;
388 }
389 
390 ////////////////////////////////////////////////////////////////////////////////
391 /// Set tool tip text associated with this button. The delay is in
392 /// milliseconds (minimum 250). To remove tool tip call method with
393 /// text = 0.
394 
395 void TGButton::SetToolTipText(const char *text, Long_t delayms)
396 {
397  if (fTip) {
398  delete fTip;
399  fTip = 0;
400  }
401 
402  if (text && strlen(text))
403  fTip = new TGToolTip(fClient->GetDefaultRoot(), this, text, delayms);
404 }
405 
406 ////////////////////////////////////////////////////////////////////////////////
407 /// Set enabled or disabled state of button
408 
409 void TGButton::SetEnabled(Bool_t e)
410 {
411  SetState(e ? kButtonUp : kButtonDisabled);
412 
413  if (e) fWidgetFlags |= kWidgetIsEnabled;
414  else fWidgetFlags &= ~kWidgetIsEnabled;
415 }
416 
417 ////////////////////////////////////////////////////////////////////////////////
418 /// Return default graphics context.
419 
420 const TGGC &TGButton::GetDefaultGC()
421 {
422  if (!fgDefaultGC)
423  fgDefaultGC = gClient->GetResourcePool()->GetFrameGC();
424  return *fgDefaultGC;
425 }
426 
427 ////////////////////////////////////////////////////////////////////////////////
428 /// Return graphics context for highlighted frame background.
429 
430 const TGGC &TGButton::GetHibckgndGC()
431 {
432  if (!fgHibckgndGC) {
433  GCValues_t gval;
434  gval.fMask = kGCForeground | kGCBackground | kGCTile |
435  kGCFillStyle | kGCGraphicsExposures;
436  gval.fForeground = gClient->GetResourcePool()->GetFrameHiliteColor();
437  gval.fBackground = gClient->GetResourcePool()->GetFrameBgndColor();
438  gval.fFillStyle = kFillTiled;
439  gval.fTile = gClient->GetResourcePool()->GetCheckeredPixmap();
440  gval.fGraphicsExposures = kFALSE;
441  fgHibckgndGC = gClient->GetGC(&gval, kTRUE);
442  }
443  return *fgHibckgndGC;
444 }
445 
446 
447 ////////////////////////////////////////////////////////////////////////////////
448 /// Create a text button widget. The hotstring will be adopted and deleted
449 /// by the text button.
450 
451 TGTextButton::TGTextButton(const TGWindow *p, TGHotString *s, Int_t id,
452  GContext_t norm, FontStruct_t font,
453  UInt_t options) : TGButton(p, id, norm, options)
454 {
455  fLabel = s;
456  fFontStruct = font;
457 
458  Init();
459 }
460 
461 ////////////////////////////////////////////////////////////////////////////////
462 /// Create a text button widget.
463 
464 TGTextButton::TGTextButton(const TGWindow *p, const char *s, Int_t id,
465  GContext_t norm, FontStruct_t font,
466  UInt_t options) : TGButton(p, id, norm, options)
467 {
468  fLabel = new TGHotString(!p && !s ? GetName() : s);
469  fFontStruct = font;
470 
471  Init();
472 }
473 
474 ////////////////////////////////////////////////////////////////////////////////
475 /// Create a text button widget and set cmd string at same time.
476 
477 TGTextButton::TGTextButton(const TGWindow *p, const char *s, const char *cmd,
478  Int_t id, GContext_t norm, FontStruct_t font,
479  UInt_t options) : TGButton(p, id, norm, options)
480 {
481  fLabel = new TGHotString(s);
482  fFontStruct = font;
483  fCommand = cmd;
484 
485  Init();
486 }
487 
488 ////////////////////////////////////////////////////////////////////////////////
489 /// Common initialization used by the different ctors.
490 
491 void TGTextButton::Init()
492 {
493  int hotchar;
494 
495  fTMode = kTextCenterX | kTextCenterY;
496  fHKeycode = 0;
497  fHasOwnFont = kFALSE;
498  fPrevStateOn =
499  fStateOn = kFALSE;
500  fWrapLength = -1;
501  fMLeft = fMRight = fMTop = fMBottom = 0;
502 
503  TGFont *font = fClient->GetFontPool()->FindFont(fFontStruct);
504  if (!font) {
505  font = fClient->GetFontPool()->GetFont(fgDefaultFont);
506  if (font) fFontStruct = font->GetFontStruct();
507  }
508  if (font) {
509  fTLayout = font->ComputeTextLayout(fLabel->GetString(), fLabel->GetLength(),
510  fWrapLength, kTextLeft, 0,
511  &fTWidth, &fTHeight);
512  }
513  Resize();
514  fWidth = fTWidth;
515  fHeight = fTHeight;
516 
517  if ((hotchar = fLabel->GetHotChar()) != 0) {
518  if ((fHKeycode = gVirtualX->KeysymToKeycode(hotchar)) != 0) {
519  const TGMainFrame *main = (TGMainFrame *) GetMainFrame();
520  if (main) {
521  main->BindKey(this, fHKeycode, kKeyMod1Mask);
522  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask);
523  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyLockMask);
524  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyLockMask);
525 
526  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyMod2Mask);
527  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask);
528  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyMod2Mask | kKeyLockMask);
529  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask | kKeyLockMask);
530  }
531  }
532  }
533  SetWindowAttributes_t wattr;
534  wattr.fMask = kWAWinGravity | kWABitGravity;
535  wattr.fBitGravity = 5; // center
536  wattr.fWinGravity = 1;
537  gVirtualX->ChangeWindowAttributes(fId, &wattr);
538 
539  SetWindowName();
540 }
541 
542 ////////////////////////////////////////////////////////////////////////////////
543 /// Delete a text button widget.
544 
545 TGTextButton::~TGTextButton()
546 {
547  if (fHKeycode && (fParent->MustCleanup() != kDeepCleanup)) {
548  const TGMainFrame *main = (TGMainFrame *) GetMainFrame();
549  if (main) {
550  main->RemoveBind(this, fHKeycode, kKeyMod1Mask);
551  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask);
552  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyLockMask);
553  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyLockMask);
554 
555  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyMod2Mask);
556  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask);
557  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyMod2Mask | kKeyLockMask);
558  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask | kKeyLockMask);
559  }
560  }
561  if (fLabel) delete fLabel;
562  if (fHasOwnFont) {
563  TGGCPool *pool = fClient->GetGCPool();
564  TGGC *gc = pool->FindGC(fNormGC);
565  pool->FreeGC(gc);
566  }
567 
568  delete fTLayout;
569 }
570 
571 ////////////////////////////////////////////////////////////////////////////////
572 /// layout text button
573 
574 void TGTextButton::Layout()
575 {
576  delete fTLayout;
577 
578  TGFont *font = fClient->GetFontPool()->FindFont(fFontStruct);
579  if (!font) {
580  font = fClient->GetFontPool()->GetFont(fgDefaultFont);
581  if (font) fFontStruct = font->GetFontStruct();
582  }
583  if (font) {
584  fTLayout = font->ComputeTextLayout(fLabel->GetString(), fLabel->GetLength(),
585  fWrapLength, kTextLeft, 0,
586  &fTWidth, &fTHeight);
587  }
588  fClient->NeedRedraw(this);
589 }
590 
591 ////////////////////////////////////////////////////////////////////////////////
592 /// Set new button text.
593 
594 void TGTextButton::SetText(TGHotString *new_label)
595 {
596  int hotchar;
597  const TGMainFrame *main = (TGMainFrame *) GetMainFrame();
598 
599  if (fLabel) {
600  if (main && fHKeycode) {
601  main->RemoveBind(this, fHKeycode, kKeyMod1Mask);
602  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask);
603  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyLockMask);
604  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyLockMask);
605 
606  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyMod2Mask);
607  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask);
608  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyMod2Mask | kKeyLockMask);
609  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask | kKeyLockMask);
610  }
611  delete fLabel;
612  }
613 
614  fLabel = new_label;
615  if ((hotchar = fLabel->GetHotChar()) != 0) {
616  if (main && ((fHKeycode = gVirtualX->KeysymToKeycode(hotchar)) != 0)) {
617  main->BindKey(this, fHKeycode, kKeyMod1Mask);
618  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask);
619  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyLockMask);
620  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyLockMask);
621 
622  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyMod2Mask);
623  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask);
624  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyMod2Mask | kKeyLockMask);
625  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask | kKeyLockMask);
626  }
627  }
628 
629  Layout();
630 }
631 
632 ////////////////////////////////////////////////////////////////////////////////
633 /// Set new button text.
634 
635 void TGTextButton::SetText(const TString &new_label)
636 {
637  SetText(new TGHotString(new_label));
638 }
639 
640 ////////////////////////////////////////////////////////////////////////////////
641 /// Set text justification. Mode is an OR of the bits:
642 /// kTextTop, kTextBottom, kTextLeft, kTextRight, kTextCenterX and
643 /// kTextCenterY.
644 
645 void TGTextButton::SetTextJustify(Int_t mode)
646 {
647  fTMode = mode;
648 
649  SetWindowAttributes_t wattr;
650  wattr.fMask = kWAWinGravity | kWABitGravity;
651  wattr.fWinGravity = 1;
652 
653  switch (mode) {
654  case kTextTop | kTextLeft:
655  wattr.fBitGravity = 1; //NorthWestGravity
656  break;
657  case kTextTop | kTextCenterX:
658  case kTextTop:
659  wattr.fBitGravity = 2; //NorthGravity
660  break;
661  case kTextTop | kTextRight:
662  wattr.fBitGravity = 3; //NorthEastGravity
663  break;
664  case kTextLeft | kTextCenterY:
665  case kTextLeft:
666  wattr.fBitGravity = 4; //WestGravity
667  break;
668  case kTextCenterY | kTextCenterX:
669  wattr.fBitGravity = 5; //CenterGravity
670  break;
671  case kTextRight | kTextCenterY:
672  case kTextRight:
673  wattr.fBitGravity = 6; //EastGravity
674  break;
675  case kTextBottom | kTextLeft:
676  wattr.fBitGravity = 7; //SouthWestGravity
677  break;
678  case kTextBottom | kTextCenterX:
679  case kTextBottom:
680  wattr.fBitGravity = 8; //SouthGravity
681  break;
682  case kTextBottom | kTextRight:
683  wattr.fBitGravity = 9; //SouthEastGravity
684  break;
685  default:
686  wattr.fBitGravity = 5; //CenterGravity
687  break;
688  }
689 
690  gVirtualX->ChangeWindowAttributes(fId, &wattr);
691  Layout();
692 }
693 
694 ////////////////////////////////////////////////////////////////////////////////
695 /// Draw the text button.
696 
697 void TGTextButton::DoRedraw()
698 {
699  int x, y;
700  UInt_t w = GetWidth() - 1;
701  UInt_t h = GetHeight()- 1;
702 
703  if ((fStyle > 0) && !(fOptions & kOwnBackground))
704  gVirtualX->SetWindowBackground(fId, fBgndColor);
705  TGFrame::DoRedraw();
706 
707  if (fTMode & kTextLeft) {
708  x = fMLeft + 4;
709  } else if (fTMode & kTextRight) {
710  x = fWidth - fTWidth - fMRight - 4;
711  } else {
712  x = (fWidth - fTWidth + fMLeft - fMRight) >> 1;
713  }
714 
715  if (fTMode & kTextTop) {
716  y = fMTop + 3;
717  } else if (fTMode & kTextBottom) {
718  y = fHeight - fTHeight - fMBottom - 3;
719  } else {
720  y = (fHeight - fTHeight + fMTop - fMBottom) >> 1;
721  }
722 
723  if (fState == kButtonDown || fState == kButtonEngaged) {
724  ++x; ++y;
725  w--; h--;
726  }
727  if (fStyle == 0) {
728  if (fState == kButtonEngaged) {
729  gVirtualX->FillRectangle(fId, GetHibckgndGC()(), 2, 2, fWidth-4, fHeight-4);
730  gVirtualX->DrawLine(fId, GetHilightGC()(), 2, 2, fWidth-3, 2);
731  }
732  }
733 
734  Int_t hotpos = fLabel->GetHotPos();
735 
736  if (fStyle > 0) {
737  gVirtualX->DrawRectangle(fId, TGFrame::GetShadowGC()(), 0, 0, w, h);
738  }
739  if (fState == kButtonDisabled) {
740  TGGCPool *pool = fClient->GetResourcePool()->GetGCPool();
741  TGGC *gc = pool->FindGC(fNormGC);
742  if (gc) {
743  Pixel_t fore = gc->GetForeground();
744  Pixel_t hi = GetHilightGC().GetForeground();
745  Pixel_t sh = GetShadowGC().GetForeground();
746 
747  gc->SetForeground(hi);
748  fTLayout->DrawText(fId, gc->GetGC(), x + 1, y + 1, 0, -1);
749  if (hotpos) fTLayout->UnderlineChar(fId, gc->GetGC(), x + 1, y + 1, hotpos - 1);
750 
751  gc->SetForeground(sh);
752  fTLayout->DrawText(fId, gc->GetGC(), x, y, 0, -1);
753  if (hotpos) fTLayout->UnderlineChar(fId, gc->GetGC(), x, y, hotpos - 1);
754  gc->SetForeground(fore);
755  }
756  } else {
757  fTLayout->DrawText(fId, fNormGC, x, y, 0, -1);
758  if (hotpos) fTLayout->UnderlineChar(fId, fNormGC, x, y, hotpos - 1);
759  }
760 }
761 
762 ////////////////////////////////////////////////////////////////////////////////
763 /// Handle key event. This function will be called when the hotkey is hit.
764 
765 Bool_t TGTextButton::HandleKey(Event_t *event)
766 {
767  Bool_t click = kFALSE;
768  Bool_t was = !IsDown(); // kTRUE if button was off
769 
770  if (event->fType == kGKeyPress) {
771  gVirtualX->SetKeyAutoRepeat(kFALSE);
772  } else {
773  gVirtualX->SetKeyAutoRepeat(kTRUE);
774  }
775 
776  if (fTip && event->fType == kGKeyPress) fTip->Hide();
777 
778  if (fState == kButtonDisabled) return kTRUE;
779 
780  // We don't need to check the key number as GrabKey will only
781  // allow fHotchar events if Alt button is pressed (kKeyMod1Mask)
782 
783  if ((event->fType == kGKeyPress) && (event->fState & kKeyMod1Mask)) {
784  if (fState == kButtonEngaged) return kTRUE;
785  SetState(kButtonDown);
786  } else if ((event->fType == kKeyRelease) && (event->fState & kKeyMod1Mask)) {
787  if (fState == kButtonEngaged /*&& !allowRelease*/) return kTRUE;
788  click = (fState == kButtonDown);
789  if (click && fStayDown) {
790  SetState(kButtonEngaged);
791  } else {
792  SetState(kButtonUp);
793  }
794  }
795  if (click) {
796  SendMessage(fMsgWindow, MK_MSG(kC_COMMAND, kCM_BUTTON), fWidgetId,
797  (Long_t) fUserData);
798  fClient->ProcessLine(fCommand, MK_MSG(kC_COMMAND, kCM_BUTTON), fWidgetId,
799  (Long_t) fUserData);
800  }
801  EmitSignals(was);
802 
803  return kTRUE;
804 }
805 
806 ////////////////////////////////////////////////////////////////////////////////
807 /// returns default size
808 
809 TGDimension TGTextButton::GetDefaultSize() const
810 {
811  UInt_t w = GetOptions() & kFixedWidth ? fWidth : fTWidth + fMLeft + fMRight + 8;
812  UInt_t h = GetOptions() & kFixedHeight ? fHeight : fTHeight + fMTop + fMBottom + 7;
813  return TGDimension(w, h);
814 }
815 
816 ////////////////////////////////////////////////////////////////////////////////
817 /// Return default font structure.
818 
819 FontStruct_t TGTextButton::GetDefaultFontStruct()
820 {
821  if (!fgDefaultFont)
822  fgDefaultFont = gClient->GetResourcePool()->GetDefaultFont();
823  return fgDefaultFont->GetFontStruct();
824 }
825 
826 ////////////////////////////////////////////////////////////////////////////////
827 /// Changes text font.
828 /// If global is kTRUE font is changed globally, otherwise - locally.
829 
830 void TGTextButton::SetFont(FontStruct_t font, Bool_t global)
831 {
832  if (font != fFontStruct) {
833  FontH_t v = gVirtualX->GetFontHandle(font);
834  if (!v) return;
835 
836  fFontStruct = font;
837  TGGCPool *pool = fClient->GetResourcePool()->GetGCPool();
838  TGGC *gc = pool->FindGC(fNormGC);
839 
840  if (gc && !global) {
841  gc = pool->GetGC((GCValues_t*)gc->GetAttributes(), kTRUE); // copy
842  fHasOwnFont = kTRUE;
843  }
844  if (gc) {
845  gc->SetFont(v);
846  fNormGC = gc->GetGC();
847  }
848  Layout();
849  }
850 }
851 
852 ////////////////////////////////////////////////////////////////////////////////
853 /// Changes text font specified by name.
854 /// If global is true color is changed globally, otherwise - locally.
855 
856 void TGTextButton::SetFont(const char *fontName, Bool_t global)
857 {
858  TGFont *font = fClient->GetFont(fontName);
859  if (font) {
860  SetFont(font->GetFontStruct(), global);
861  }
862 }
863 
864 ////////////////////////////////////////////////////////////////////////////////
865 /// Changes text color.
866 /// If global is true color is changed globally, otherwise - locally.
867 
868 void TGTextButton::SetTextColor(Pixel_t color, Bool_t global)
869 {
870  TGGCPool *pool = fClient->GetResourcePool()->GetGCPool();
871  TGGC *gc = pool->FindGC(fNormGC);
872 
873  if (gc && !global) {
874  gc = pool->GetGC((GCValues_t*)gc->GetAttributes(), kTRUE); // copy
875  fHasOwnFont = kTRUE;
876  }
877  if (gc) {
878  gc->SetForeground(color);
879  fNormGC = gc->GetGC();
880  }
881  fClient->NeedRedraw(this);
882 }
883 
884 ////////////////////////////////////////////////////////////////////////////////
885 /// Returns kTRUE if text attributes are unique,
886 /// returns kFALSE if text attributes are shared (global).
887 
888 Bool_t TGTextButton::HasOwnFont() const
889 {
890  return fHasOwnFont;
891 }
892 
893 ////////////////////////////////////////////////////////////////////////////////
894 /// Create a picture button widget. The picture is not adopted and must
895 /// later be freed by the user once the picture button is deleted (a single
896 /// picture reference might be used by other buttons).
897 
898 TGPictureButton::TGPictureButton(const TGWindow *p, const TGPicture *pic,
899  Int_t id, GContext_t norm, UInt_t option) : TGButton(p, id, norm, option)
900 {
901  if (!pic) {
902  Error("TGPictureButton", "pixmap not found for button %d", id);
903  fPic = fClient->GetPicture("mb_question_s.xpm");
904  } else {
905  fPic = pic;
906  }
907 
908  if (fPic) {
909  fTWidth = fPic->GetWidth();
910  fTHeight = fPic->GetHeight();
911 
912  Resize(fTWidth + (fBorderWidth << 1) + fBorderWidth + 1,
913  fTHeight + (fBorderWidth << 1) + fBorderWidth); // *3
914  }
915  fPicD = 0;
916  fOwnDisabledPic = kFALSE;
917  SetWindowName();
918 }
919 
920 ////////////////////////////////////////////////////////////////////////////////
921 /// Create a picture button widget and set action command. The picture is
922 /// not adopted and must later be freed by the user once the picture button
923 /// is deleted (a single picture reference might be used by other
924 /// buttons).
925 
926 TGPictureButton::TGPictureButton(const TGWindow *p, const TGPicture *pic,
927  const char *cmd, Int_t id, GContext_t norm, UInt_t option)
928  : TGButton(p, id, norm, option)
929 {
930  if (!pic) {
931  Error("TGPictureButton", "pixmap not found for button\n%s",
932  cmd ? cmd : "");
933  fPic = fClient->GetPicture("mb_question_s.xpm");
934  } else {
935  fPic = pic;
936  }
937 
938  fCommand = cmd;
939 
940  if (fPic) {
941  fTWidth = fPic->GetWidth();
942  fTHeight = fPic->GetHeight();
943 
944  Resize(fTWidth + (fBorderWidth << 1) + fBorderWidth + 1,
945  fTHeight + (fBorderWidth << 1) + fBorderWidth); // *3
946  }
947  fPicD = 0;
948  fOwnDisabledPic = kFALSE;
949  SetWindowName();
950 }
951 
952 ////////////////////////////////////////////////////////////////////////////////
953 /// Create a picture button. Where pic is the file name of the picture.
954 
955 TGPictureButton::TGPictureButton(const TGWindow *p, const char *pic,
956  Int_t id, GContext_t norm, UInt_t option) : TGButton(p, id, norm, option)
957 {
958  if (!pic || !pic[0]) {
959  if (p) Error("TGPictureButton", "pixmap not found for button");
960  fPic = fClient->GetPicture("mb_question_s.xpm");
961  } else {
962  fPic = fClient->GetPicture(pic);
963  }
964 
965  if (fPic) {
966  fTWidth = fPic->GetWidth();
967  fTHeight = fPic->GetHeight();
968 
969  Resize(fTWidth + (fBorderWidth << 1) + fBorderWidth + 1,
970  fTHeight + (fBorderWidth << 1) + fBorderWidth); // *3
971  }
972  fPicD = 0;
973  fOwnDisabledPic = kFALSE;
974  SetWindowName();
975 }
976 
977 ////////////////////////////////////////////////////////////////////////////////
978 /// Destructor.
979 
980 TGPictureButton::~TGPictureButton()
981 {
982  if (fOwnDisabledPic) fClient->FreePicture(fPicD);
983 }
984 
985 ////////////////////////////////////////////////////////////////////////////////
986 /// Change a picture in a picture button. The picture is not adopted and
987 /// must later be freed by the user once the picture button is deleted
988 /// (a single picture reference might be used by other buttons).
989 
990 void TGPictureButton::SetPicture(const TGPicture *new_pic)
991 {
992  if (!new_pic) {
993  Error("SetPicture", "pixmap not found for button %d\n%s",
994  fWidgetId, fCommand.Data());
995  return;
996  }
997 
998  fPic = new_pic;
999 
1000  if (fState == kButtonDisabled) {
1001  fClient->FreePicture(fPicD);
1002  fPicD = 0;
1003  }
1004 
1005  fTWidth = fPic->GetWidth();
1006  fTHeight = fPic->GetHeight();
1007 
1008  fClient->NeedRedraw(this);
1009 }
1010 
1011 ////////////////////////////////////////////////////////////////////////////////
1012 /// Redraw picture button.
1013 
1014 void TGPictureButton::DoRedraw()
1015 {
1016  if (!fPic) {
1017  TGFrame::DoRedraw();
1018  return;
1019  }
1020 
1021  int x = (fWidth - fTWidth) >> 1;
1022  int y = (fHeight - fTHeight) >> 1;
1023  UInt_t w = GetWidth() - 1;
1024  UInt_t h = GetHeight()- 1;
1025 
1026  if ((fStyle > 0) && !(fOptions & kOwnBackground))
1027  gVirtualX->SetWindowBackground(fId, fBgndColor);
1028  TGFrame::DoRedraw();
1029 
1030  if (fState == kButtonDown || fState == kButtonEngaged) {
1031  ++x; ++y;
1032  w--; h--;
1033  }
1034  if (fStyle == 0) {
1035  if (fState == kButtonEngaged) {
1036  gVirtualX->FillRectangle(fId, GetHibckgndGC()(), 2, 2, fWidth-4, fHeight-4);
1037  gVirtualX->DrawLine(fId, GetHilightGC()(), 2, 2, fWidth-3, 2);
1038  }
1039  }
1040 
1041  const TGPicture *pic = fPic;
1042  if (fState == kButtonDisabled) {
1043  if (!fPicD) CreateDisabledPicture();
1044  pic = fPicD ? fPicD : fPic;
1045  }
1046  if (fStyle > 0) {
1047  if (fBgndColor == fHighColor) {
1048  gVirtualX->DrawRectangle(fId, TGFrame::GetShadowGC()(), 0, 0, w, h);
1049  }
1050  }
1051 
1052  pic->Draw(fId, fNormGC, x, y);
1053 }
1054 
1055 ////////////////////////////////////////////////////////////////////////////////
1056 /// Creates disabled picture.
1057 
1058 void TGPictureButton::CreateDisabledPicture()
1059 {
1060  TImage *img = TImage::Create();
1061  if (!img) return;
1062  TImage *img2 = TImage::Create();
1063  if (!img2) {
1064  if (img) delete img;
1065  return;
1066  }
1067  TString back = gEnv->GetValue("Gui.BackgroundColor", "#c0c0c0");
1068  img2->FillRectangle(back.Data(), 0, 0, fPic->GetWidth(), fPic->GetHeight());
1069  img->SetImage(fPic->GetPicture(), fPic->GetMask());
1070  Pixmap_t mask = img->GetMask();
1071  img2->Merge(img, "overlay");
1072 
1073  TString name = "disbl_";
1074  name += fPic->GetName();
1075  fPicD = fClient->GetPicturePool()->GetPicture(name.Data(), img2->GetPixmap(),
1076  mask);
1077  fOwnDisabledPic = kTRUE;
1078  delete img;
1079  delete img2;
1080 }
1081 
1082 ////////////////////////////////////////////////////////////////////////////////
1083 /// Changes disabled picture.
1084 
1085 void TGPictureButton::SetDisabledPicture(const TGPicture *pic)
1086 {
1087  if (!pic) return;
1088 
1089  if (fOwnDisabledPic && fPicD) fClient->FreePicture(fPicD);
1090  fPicD = pic;
1091  ((TGPicture*)pic)->AddReference();
1092  fOwnDisabledPic = kFALSE;
1093 }
1094 
1095 ////////////////////////////////////////////////////////////////////////////////
1096 /// Create a check button widget. The hotstring will be adopted and deleted
1097 /// by the check button.
1098 
1099 TGCheckButton::TGCheckButton(const TGWindow *p, TGHotString *s, Int_t id,
1100  GContext_t norm, FontStruct_t font, UInt_t option)
1101  : TGTextButton(p, s, id, norm, font, option)
1102 {
1103  Init();
1104 }
1105 
1106 ////////////////////////////////////////////////////////////////////////////////
1107 /// Create a check button widget.
1108 
1109 TGCheckButton::TGCheckButton(const TGWindow *p, const char *s, Int_t id,
1110  GContext_t norm, FontStruct_t font, UInt_t option)
1111  : TGTextButton(p, s, id, norm, font, option)
1112 {
1113  Init();
1114 }
1115 
1116 ////////////////////////////////////////////////////////////////////////////////
1117 /// Create a check button widget.
1118 
1119 TGCheckButton::TGCheckButton(const TGWindow *p, const char *s, const char *cmd,
1120  Int_t id, GContext_t norm, FontStruct_t font,
1121  UInt_t option) : TGTextButton(p, s, cmd, id, norm, font, option)
1122 {
1123  Init();
1124 }
1125 
1126 ////////////////////////////////////////////////////////////////////////////////
1127 /// Common check button initialization.
1128 
1129 void TGCheckButton::Init()
1130 {
1131  fPrevState =
1132  fState = kButtonUp;
1133  fHKeycode = 0;
1134 
1135  fOn = fClient->GetPicture("checked_t.xpm");
1136  fOff = fClient->GetPicture("unchecked_t.xpm");
1137  fDisOn = fClient->GetPicture("checked_dis_t.xpm");
1138  fDisOff = fClient->GetPicture("unchecked_dis_t.xpm");
1139 
1140  Resize();
1141 
1142  if (!fOn) {
1143  Error("TGCheckButton", "checked_t.xpm not found");
1144  } else if (!fOff) {
1145  Error("TGCheckButton", "unchecked_t.xpm not found");
1146  } else if (!fDisOn) {
1147  Error("TGCheckButton", "checked_dis_t.xpm not found");
1148  } else if (!fDisOff) {
1149  Error("TGCheckButton", "unchecked_dis_t.xpm not found");
1150  }
1151  int hotchar;
1152 
1153  if ((hotchar = fLabel->GetHotChar()) != 0) {
1154  if ((fHKeycode = gVirtualX->KeysymToKeycode(hotchar)) != 0) {
1155  const TGMainFrame *main = (TGMainFrame *) GetMainFrame();
1156  if (main) {
1157  main->BindKey(this, fHKeycode, kKeyMod1Mask);
1158  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask);
1159  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyLockMask);
1160  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyLockMask);
1161 
1162  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyMod2Mask);
1163  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask);
1164  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyMod2Mask | kKeyLockMask);
1165  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask | kKeyLockMask);
1166  }
1167  }
1168  }
1169  SetWindowName();
1170 }
1171 
1172 ////////////////////////////////////////////////////////////////////////////////
1173 /// Delete a check button.
1174 
1175 TGCheckButton::~TGCheckButton()
1176 {
1177  if (fOn) fClient->FreePicture(fOn);
1178  if (fOff) fClient->FreePicture(fOff);
1179  if (fDisOn) fClient->FreePicture(fDisOn);
1180  if (fDisOff) fClient->FreePicture(fDisOff);
1181 }
1182 
1183 ////////////////////////////////////////////////////////////////////////////////
1184 /// default size
1185 
1186 TGDimension TGCheckButton::GetDefaultSize() const
1187 {
1188  UInt_t w = !fTWidth ? fOff->GetWidth() : fTWidth + fOff->GetWidth() + 9;
1189  UInt_t h = !fTHeight ? fOff->GetHeight() : fTHeight + 2;
1190 
1191  w = GetOptions() & kFixedWidth ? fWidth : w;
1192  h = GetOptions() & kFixedHeight ? fHeight : h;
1193 
1194  return TGDimension(w, h);
1195 }
1196 
1197 ////////////////////////////////////////////////////////////////////////////////
1198 /// Set check button state.
1199 
1200 void TGCheckButton::SetState(EButtonState state, Bool_t emit)
1201 {
1202  if (state == kButtonDisabled)
1203  fWidgetFlags &= ~kWidgetIsEnabled;
1204  else
1205  fWidgetFlags |= kWidgetIsEnabled;
1206  PSetState(state, emit);
1207 }
1208 
1209 ////////////////////////////////////////////////////////////////////////////////
1210 /// Emit signals.
1211 
1212 void TGCheckButton::EmitSignals(Bool_t /*wasUp*/)
1213 {
1214  if (fState == kButtonUp) Released(); // emit Released
1215  if (fState == kButtonDown) Pressed(); // emit Pressed
1216  Clicked(); // emit Clicked
1217  Toggled(fStateOn); // emit Toggled
1218 }
1219 
1220 ////////////////////////////////////////////////////////////////////////////////
1221 /// Set check button state.
1222 
1223 void TGCheckButton::PSetState(EButtonState state, Bool_t emit)
1224 {
1225  if (state != fState) {
1226  if (state == kButtonUp) {
1227  if (fPrevState == kButtonDisabled) {
1228  if (fStateOn) {
1229  fState = kButtonDown;
1230  fPrevState = kButtonDown;
1231  } else {
1232  fState = state;
1233  fPrevState = state;
1234  }
1235  } else if (fPrevState == kButtonDown) {
1236  fStateOn = kFALSE;
1237  fState = state;
1238  fPrevState = state;
1239  }
1240  } else if (state == kButtonDown) {
1241  fStateOn = kTRUE;
1242  fState = state;
1243  fPrevState = state;
1244  } else {
1245  fState = state;
1246  fPrevState = state;
1247  }
1248  if (emit) {
1249  // button signals
1250  EmitSignals();
1251  }
1252  DoRedraw();
1253  }
1254 }
1255 
1256 ////////////////////////////////////////////////////////////////////////////////
1257 /// Set the state of a check button to disabled and either on or
1258 /// off.
1259 
1260 void TGCheckButton::SetDisabledAndSelected(Bool_t enable)
1261 {
1262  if (!enable) {
1263  if (fState == kButtonDisabled && fStateOn) {
1264  PSetState(kButtonUp, kFALSE); // enable button
1265  PSetState(kButtonUp, kFALSE); // set button up
1266  PSetState(kButtonDisabled, kFALSE); // disable button
1267  } else {
1268  PSetState(kButtonUp, kFALSE);
1269  PSetState(kButtonDisabled, kFALSE);
1270  }
1271  } else {
1272  PSetState(kButtonDown, kFALSE); // set button down
1273  PSetState(kButtonDisabled, kFALSE); // disable button
1274  }
1275 }
1276 
1277 ////////////////////////////////////////////////////////////////////////////////
1278 /// Handle mouse button event.
1279 
1280 Bool_t TGCheckButton::HandleButton(Event_t *event)
1281 {
1282  Bool_t click = kFALSE;
1283 
1284  if (fTip) fTip->Hide();
1285 
1286  if (fState == kButtonDisabled) return kTRUE;
1287 
1288  Bool_t in = (event->fX >= 0) && (event->fY >= 0) &&
1289  (event->fX <= (Int_t)fWidth) && (event->fY <= (Int_t)fHeight);
1290 
1291  // We don't need to check the button number as GrabButton will
1292  // only allow button1 events
1293  if (event->fType == kButtonPress) {
1294  fgReleaseBtn = 0;
1295  if (in) {
1296  fOptions |= kSunkenFrame;
1297  Pressed();
1298  }
1299  } else { // ButtonRelease
1300  if (in) {
1301  PSetState((fPrevState == kButtonUp) ? kButtonDown : kButtonUp, kFALSE);
1302  click = kTRUE;
1303  fPrevStateOn = fStateOn;
1304  Released();
1305  }
1306  fgReleaseBtn = fId;
1307  fOptions &= ~kSunkenFrame;
1308  }
1309  if (click) {
1310  Clicked();
1311  Toggled(fStateOn);
1312  SendMessage(fMsgWindow, MK_MSG(kC_COMMAND, kCM_CHECKBUTTON),
1313  fWidgetId, (Long_t) fUserData);
1314  fClient->ProcessLine(fCommand, MK_MSG(kC_COMMAND, kCM_CHECKBUTTON),
1315  fWidgetId, (Long_t) fUserData);
1316  }
1317  DoRedraw();
1318  return kTRUE;
1319 }
1320 
1321 ////////////////////////////////////////////////////////////////////////////////
1322 /// Handle mouse crossing event.
1323 
1324 Bool_t TGCheckButton::HandleCrossing(Event_t *event)
1325 {
1326  if (fTip) {
1327  if (event->fType == kEnterNotify)
1328  fTip->Reset();
1329  else
1330  fTip->Hide();
1331  }
1332 
1333  if ((fgDbw != event->fWindow) || (fgReleaseBtn == event->fWindow)) return kTRUE;
1334 
1335  if (!(event->fState & (kButton1Mask | kButton2Mask | kButton3Mask)))
1336  return kTRUE;
1337 
1338  if (fState == kButtonDisabled) return kTRUE;
1339 
1340  if (event->fType == kEnterNotify) {
1341  fOptions |= kSunkenFrame;
1342  } else {
1343  fOptions &= ~kSunkenFrame;
1344  }
1345  DoRedraw();
1346 
1347  return kTRUE;
1348 }
1349 
1350 ////////////////////////////////////////////////////////////////////////////////
1351 /// Handle key event. This function will be called when the hotkey is hit.
1352 
1353 Bool_t TGCheckButton::HandleKey(Event_t *event)
1354 {
1355  Bool_t click = kFALSE;
1356 
1357  if (event->fType == kGKeyPress)
1358  gVirtualX->SetKeyAutoRepeat(kFALSE);
1359  else
1360  gVirtualX->SetKeyAutoRepeat(kTRUE);
1361 
1362  if (fTip && event->fType == kGKeyPress) fTip->Hide();
1363 
1364  if (fState == kButtonDisabled) return kTRUE;
1365 
1366  // We don't need to check the key number as GrabKey will only
1367  // allow fHotchar events if Alt button is pressed (kKeyMod1Mask)
1368 
1369  if ((event->fType == kGKeyPress) && (event->fState & kKeyMod1Mask)) {
1370  PSetState((fPrevState == kButtonUp) ? kButtonDown : kButtonUp, kTRUE);
1371  } else if ((event->fType == kKeyRelease) && (event->fState & kKeyMod1Mask)) {
1372  click = (fState != fPrevState);
1373  fPrevState = fState;
1374  }
1375  if (click) {
1376  SendMessage(fMsgWindow, MK_MSG(kC_COMMAND, kCM_CHECKBUTTON), fWidgetId,
1377  (Long_t) fUserData);
1378  fClient->ProcessLine(fCommand, MK_MSG(kC_COMMAND, kCM_CHECKBUTTON), fWidgetId,
1379  (Long_t) fUserData);
1380  }
1381  return kTRUE;
1382 }
1383 
1384 ////////////////////////////////////////////////////////////////////////////////
1385 /// Draw the check button widget.
1386 
1387 void TGCheckButton::DoRedraw()
1388 {
1389  int x, y, y0;
1390 
1391  TGFrame::DoRedraw();
1392 
1393  x = 20;
1394  y = (fHeight - fTHeight) >> 1;
1395 
1396  y0 = !fTHeight ? 0 : y + 1;
1397  if (fOn && fOff) {
1398  Int_t smax = TMath::Max(fOn->GetHeight(), fOff->GetHeight());
1399  y0 = ((Int_t)fHeight <= smax) ? 0 : 1 + (((Int_t)fHeight - smax) >> 1);
1400  }
1401 
1402  if (fStateOn) {
1403  if (fOn) fOn->Draw(fId, fNormGC, 0, y0);
1404  } else {
1405  if (fOff) fOff->Draw(fId, fNormGC, 0, y0);
1406  }
1407 
1408  Int_t hotpos = fLabel->GetHotPos();
1409 
1410  if (fState == kButtonDisabled) {
1411  if (fStateOn == kTRUE) {
1412  if (fDisOn) fDisOn->Draw(fId, fNormGC, 0, y0);
1413  } else {
1414  if (fDisOff) fDisOff->Draw(fId, fNormGC, 0, y0);
1415  }
1416 
1417  TGGCPool *pool = fClient->GetResourcePool()->GetGCPool();
1418  TGGC *gc = pool->FindGC(fNormGC);
1419  if (gc) {
1420  Pixel_t fore = gc->GetForeground();
1421  Pixel_t hi = GetHilightGC().GetForeground();
1422  Pixel_t sh = GetShadowGC().GetForeground();
1423 
1424  gc->SetForeground(hi);
1425  fTLayout->DrawText(fId, gc->GetGC(), x + 1, y + 1, 0, -1);
1426  if (hotpos) fTLayout->UnderlineChar(fId, gc->GetGC(), x, y, hotpos - 1);
1427 
1428  gc->SetForeground(sh);
1429  fTLayout->DrawText(fId, gc->GetGC(), x, y, 0, -1);
1430  if (hotpos) fTLayout->UnderlineChar(fId, gc->GetGC(), x, y, hotpos - 1);
1431 
1432  gc->SetForeground(fore);
1433  }
1434  } else {
1435  fTLayout->DrawText(fId, fNormGC, x, y, 0, -1);
1436  if (hotpos) fTLayout->UnderlineChar(fId, fNormGC, x, y, hotpos - 1);
1437  }
1438 }
1439 
1440 ////////////////////////////////////////////////////////////////////////////////
1441 /// Return default font structure.
1442 
1443 FontStruct_t TGCheckButton::GetDefaultFontStruct()
1444 {
1445  if (!fgDefaultFont)
1446  fgDefaultFont = gClient->GetResourcePool()->GetDefaultFont();
1447  return fgDefaultFont->GetFontStruct();
1448 }
1449 
1450 ////////////////////////////////////////////////////////////////////////////////
1451 /// Return default graphics context.
1452 
1453 const TGGC &TGCheckButton::GetDefaultGC()
1454 {
1455  if (!fgDefaultGC)
1456  fgDefaultGC = gClient->GetResourcePool()->GetFrameGC();
1457  return *fgDefaultGC;
1458 }
1459 
1460 
1461 ////////////////////////////////////////////////////////////////////////////////
1462 /// Create a radio button widget. The hotstring will be adopted and deleted
1463 /// by the radio button.
1464 
1465 TGRadioButton::TGRadioButton(const TGWindow *p, TGHotString *s, Int_t id,
1466  GContext_t norm, FontStruct_t font, UInt_t option)
1467  : TGTextButton(p, s, id, norm, font, option)
1468 {
1469  Init();
1470 }
1471 
1472 ////////////////////////////////////////////////////////////////////////////////
1473 /// Create a radio button widget.
1474 
1475 TGRadioButton::TGRadioButton(const TGWindow *p, const char *s, Int_t id,
1476  GContext_t norm, FontStruct_t font, UInt_t option)
1477  : TGTextButton(p, s, id, norm, font, option)
1478 {
1479  Init();
1480 }
1481 ////////////////////////////////////////////////////////////////////////////////
1482 /// Create a radio button widget.
1483 
1484 TGRadioButton::TGRadioButton(const TGWindow *p, const char *s, const char *cmd,
1485  Int_t id, GContext_t norm,
1486  FontStruct_t font, UInt_t option)
1487  : TGTextButton(p, s, cmd, id, norm, font, option)
1488 {
1489  Init();
1490 }
1491 
1492 ////////////////////////////////////////////////////////////////////////////////
1493 /// Common radio button initialization.
1494 
1495 void TGRadioButton::Init()
1496 {
1497  fPrevState =
1498  fState = kButtonUp;
1499  fHKeycode = 0;
1500 
1501  fOn = fClient->GetPicture("rbutton_on.xpm");
1502  fOff = fClient->GetPicture("rbutton_off.xpm");
1503  fDisOn = fClient->GetPicture("rbutton_dis_on.xpm");
1504  fDisOff = fClient->GetPicture("rbutton_dis_off.xpm");
1505 
1506  if (!fOn || !fOff || !fDisOn || !fDisOff)
1507  Error("TGRadioButton", "rbutton_*.xpm not found");
1508 
1509  Resize();
1510 
1511  int hotchar;
1512 
1513  if ((hotchar = fLabel->GetHotChar()) != 0) {
1514  if ((fHKeycode = gVirtualX->KeysymToKeycode(hotchar)) != 0) {
1515  const TGMainFrame *main = (TGMainFrame *) GetMainFrame();
1516  if (main) {
1517  main->BindKey(this, fHKeycode, kKeyMod1Mask);
1518  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask);
1519  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyLockMask);
1520  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyLockMask);
1521 
1522  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyMod2Mask);
1523  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask);
1524  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyMod2Mask | kKeyLockMask);
1525  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask | kKeyLockMask);
1526  }
1527  }
1528  }
1529 
1530  if (fParent->IsA()->InheritsFrom(TGButtonGroup::Class())) {
1531  ((TGButtonGroup*)fParent)->SetRadioButtonExclusive(kTRUE);
1532  }
1533  SetWindowName();
1534 }
1535 
1536 ////////////////////////////////////////////////////////////////////////////////
1537 /// Delete a radio button.
1538 
1539 TGRadioButton::~TGRadioButton()
1540 {
1541  if (fOn) fClient->FreePicture(fOn);
1542  if (fOff) fClient->FreePicture(fOff);
1543  if (fDisOn) fClient->FreePicture(fDisOn);
1544  if (fDisOff) fClient->FreePicture(fDisOff);
1545 }
1546 
1547 ////////////////////////////////////////////////////////////////////////////////
1548 /// default size
1549 
1550 TGDimension TGRadioButton::GetDefaultSize() const
1551 {
1552  UInt_t w = !fTWidth ? fOff->GetWidth() : fTWidth + fOff->GetWidth() + 10;
1553  UInt_t h = !fTHeight ? fOff->GetHeight() : fTHeight + 2;
1554 
1555  w = GetOptions() & kFixedWidth ? fWidth : w;
1556  h = GetOptions() & kFixedHeight ? fHeight : h;
1557 
1558  return TGDimension(w, h);
1559 }
1560 ////////////////////////////////////////////////////////////////////////////////
1561 /// Set radio button state.
1562 
1563 void TGRadioButton::SetState(EButtonState state, Bool_t emit)
1564 {
1565  if (state == kButtonDisabled)
1566  fWidgetFlags &= ~kWidgetIsEnabled;
1567  else
1568  fWidgetFlags |= kWidgetIsEnabled;
1569  PSetState(state, emit);
1570 }
1571 
1572 ////////////////////////////////////////////////////////////////////////////////
1573 /// Set the state of a radio button to disabled and either on or
1574 /// off.
1575 
1576 void TGRadioButton::SetDisabledAndSelected(Bool_t enable)
1577 {
1578  if (!enable) {
1579  if (fState == kButtonDisabled && fStateOn) {
1580  PSetState(kButtonUp, kFALSE); // enable button
1581  PSetState(kButtonUp, kFALSE); // set button up
1582  PSetState(kButtonDisabled, kFALSE); // disable button
1583  } else {
1584  PSetState(kButtonUp, kFALSE);
1585  PSetState(kButtonDisabled, kFALSE);
1586  }
1587  } else {
1588  PSetState(kButtonDown, kFALSE); // set button down
1589  PSetState(kButtonDisabled, kFALSE); // disable button
1590  }
1591 }
1592 
1593 ////////////////////////////////////////////////////////////////////////////////
1594 /// Emit signals.
1595 
1596 void TGRadioButton::EmitSignals(Bool_t /*wasUp*/)
1597 {
1598  if (fState == kButtonUp) Released(); // emit Released
1599  if (fState == kButtonDown) Pressed(); // emit Pressed
1600  Clicked(); // emit Clicked
1601  Toggled(fStateOn); // emit Toggled
1602 }
1603 
1604 ////////////////////////////////////////////////////////////////////////////////
1605 /// Set radio button state.
1606 
1607 void TGRadioButton::PSetState(EButtonState state, Bool_t emit)
1608 {
1609  if (state != fState) {
1610  // fPrevState = fState = state;
1611  if (state == kButtonUp) {
1612  if (fPrevState == kButtonDisabled) {
1613  if (fStateOn) {
1614  fState = kButtonDown;
1615  fPrevState = kButtonDown;
1616  } else {
1617  fState = state;
1618  fPrevState = state;
1619  }
1620  } else if (fPrevState == kButtonDown) {
1621  fStateOn = kFALSE;
1622  fState = state;
1623  fPrevState = state;
1624  }
1625  } else if (state == kButtonDown) {
1626  fStateOn = kTRUE;
1627  fState = state;
1628  fPrevState = state;
1629  } else {
1630  fState = state;
1631  fPrevState = state;
1632  }
1633  if (emit) {
1634  // button signals
1635  EmitSignals();
1636  }
1637  DoRedraw();
1638  }
1639 }
1640 
1641 ////////////////////////////////////////////////////////////////////////////////
1642 /// Handle mouse button event.
1643 
1644 Bool_t TGRadioButton::HandleButton(Event_t *event)
1645 {
1646  Bool_t click = kFALSE;
1647  Bool_t toggled = kFALSE;
1648 
1649  if (fTip) fTip->Hide();
1650 
1651  if (fState == kButtonDisabled) return kFALSE;
1652 
1653 
1654  Bool_t in = (event->fX >= 0) && (event->fY >= 0) &&
1655  (event->fX <= (Int_t)fWidth) && (event->fY <= (Int_t)fHeight);
1656 
1657  if (event->fType == kButtonPress) { // button pressed
1658  fgReleaseBtn = 0;
1659  if (in) {
1660  fOptions |= kSunkenFrame;
1661  Pressed();
1662  }
1663  } else { // ButtonRelease
1664  if (in) {
1665  if (!fStateOn) {
1666  PSetState(kButtonDown, kFALSE);
1667  toggled = kTRUE;
1668  }
1669  fPrevStateOn = fStateOn;
1670  Released();
1671  click = kTRUE;
1672  }
1673  fOptions &= ~kSunkenFrame;
1674  fgReleaseBtn = fId;
1675  }
1676  if (click) {
1677  Clicked();
1678  SendMessage(fMsgWindow, MK_MSG(kC_COMMAND, kCM_RADIOBUTTON),
1679  fWidgetId, (Long_t) fUserData);
1680  fClient->ProcessLine(fCommand, MK_MSG(kC_COMMAND, kCM_RADIOBUTTON),
1681  fWidgetId, (Long_t) fUserData);
1682  }
1683  if (toggled) {
1684  Toggled(fStateOn);
1685  }
1686  DoRedraw();
1687  return kTRUE;
1688 }
1689 
1690 ////////////////////////////////////////////////////////////////////////////////
1691 /// Handle mouse crossing event.
1692 
1693 Bool_t TGRadioButton::HandleCrossing(Event_t *event)
1694 {
1695  if (fTip) {
1696  if (event->fType == kEnterNotify)
1697  fTip->Reset();
1698  else
1699  fTip->Hide();
1700  }
1701 
1702  if ((fgDbw != event->fWindow) || (fgReleaseBtn == event->fWindow)) return kTRUE;
1703 
1704  if (!(event->fState & (kButton1Mask | kButton2Mask | kButton3Mask)))
1705  return kTRUE;
1706 
1707  if (fState == kButtonDisabled) return kTRUE;
1708 
1709  if (event->fType == kEnterNotify) {
1710  fOptions |= kSunkenFrame;
1711  } else {
1712  fOptions &= ~kSunkenFrame;
1713  }
1714  DoRedraw();
1715 
1716  return kTRUE;
1717 }
1718 
1719 ////////////////////////////////////////////////////////////////////////////////
1720 /// Handle key event. This function will be called when the hotkey is hit.
1721 
1722 Bool_t TGRadioButton::HandleKey(Event_t *event)
1723 {
1724  if (event->fType == kGKeyPress)
1725  gVirtualX->SetKeyAutoRepeat(kFALSE);
1726  else
1727  gVirtualX->SetKeyAutoRepeat(kTRUE);
1728 
1729  if (fTip && event->fType == kGKeyPress)
1730  fTip->Hide();
1731 
1732  if (fState == kButtonDisabled) return kTRUE;
1733 
1734  // We don't need to check the key number as GrabKey will only
1735  // allow fHotchar events if Alt button is pressed (kKeyMod1Mask)
1736 
1737  if ((event->fType == kGKeyPress) && (event->fState & kKeyMod1Mask)) {
1738  PSetState(kButtonDown, kTRUE);
1739  SendMessage(fMsgWindow, MK_MSG(kC_COMMAND, kCM_RADIOBUTTON),
1740  fWidgetId, (Long_t) fUserData);
1741  fClient->ProcessLine(fCommand, MK_MSG(kC_COMMAND, kCM_RADIOBUTTON),
1742  fWidgetId, (Long_t) fUserData);
1743  } else if ((event->fType == kKeyRelease) && (event->fState & kKeyMod1Mask)) {
1744  fPrevState = fState;
1745  }
1746  return kTRUE;
1747 }
1748 
1749 ////////////////////////////////////////////////////////////////////////////////
1750 /// Draw a radio button.
1751 
1752 void TGRadioButton::DoRedraw()
1753 {
1754  Int_t tx, ty, y0;
1755 
1756  TGFrame::DoRedraw();
1757 
1758  tx = 20;
1759  ty = (fHeight - fTHeight) >> 1;
1760 
1761 // pw = 12;
1762  y0 = !fTHeight ? 0 : ty + 1;
1763  if (fOn && fOff) {
1764  Int_t smax = TMath::Max(fOn->GetHeight(), fOff->GetHeight());
1765  y0 = ((Int_t)fHeight <= smax) ? 0 : 1 + (((Int_t)fHeight - smax) >> 1);
1766  }
1767 
1768  if (fStateOn) {
1769  if (fOn) fOn->Draw(fId, fNormGC, 0, y0);
1770  } else {
1771  if (fOff) fOff->Draw(fId, fNormGC, 0, y0);
1772  }
1773 
1774  Int_t hotpos = fLabel->GetHotPos();
1775 
1776  if (fState == kButtonDisabled) {
1777  if (fStateOn == kTRUE) {
1778  if (fDisOn) fDisOn->Draw(fId, fNormGC, 0, y0);
1779  } else {
1780  if (fDisOff) fDisOff->Draw(fId, fNormGC, 0, y0);
1781  }
1782 
1783  TGGCPool *pool = fClient->GetResourcePool()->GetGCPool();
1784  TGGC *gc = pool->FindGC(fNormGC);
1785  if (gc) {
1786  Pixel_t fore = gc->GetForeground();
1787  Pixel_t hi = GetHilightGC().GetForeground();
1788  Pixel_t sh = GetShadowGC().GetForeground();
1789 
1790  gc->SetForeground(hi);
1791  fTLayout->DrawText(fId, gc->GetGC(), tx + 1, ty + 1, 0, -1);
1792  if (hotpos) fTLayout->UnderlineChar(fId, gc->GetGC(), tx, ty, hotpos - 1);
1793 
1794  gc->SetForeground(sh);
1795  fTLayout->DrawText(fId, gc->GetGC(), tx, ty, 0, -1);
1796  if (hotpos) fTLayout->UnderlineChar(fId, gc->GetGC(), tx, ty, hotpos - 1);
1797 
1798  gc->SetForeground(fore);
1799  }
1800  } else {
1801  fTLayout->DrawText(fId, fNormGC, tx, ty, 0, -1);
1802  if (hotpos) fTLayout->UnderlineChar(fId, fNormGC, tx, ty, hotpos-1);
1803  }
1804 }
1805 
1806 ////////////////////////////////////////////////////////////////////////////////
1807 /// Return default font structure.
1808 
1809 FontStruct_t TGRadioButton::GetDefaultFontStruct()
1810 {
1811  if (!fgDefaultFont)
1812  fgDefaultFont = gClient->GetResourcePool()->GetDefaultFont();
1813  return fgDefaultFont->GetFontStruct();
1814 }
1815 
1816 ////////////////////////////////////////////////////////////////////////////////
1817 /// Return default graphics context.
1818 
1819 const TGGC &TGRadioButton::GetDefaultGC()
1820 {
1821  if (!fgDefaultGC)
1822  fgDefaultGC = gClient->GetResourcePool()->GetFrameGC();
1823  return *fgDefaultGC;
1824 }
1825 
1826 ////////////////////////////////////////////////////////////////////////////////
1827 /// Save a button widget as a C++ statement(s) on output stream out.
1828 
1829 void TGButton::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/)
1830 {
1831  char quote = '"';
1832 
1833  if (option && strstr(option, "keep_names"))
1834  out << " " << GetName() << "->SetName(\"" << GetName() << "\");" << std::endl;
1835 
1836  if (fState == kButtonDown) {
1837  out << " " << GetName() << "->SetState(kButtonDown);" << std::endl;
1838  }
1839  if (fState == kButtonDisabled) {
1840  out << " " << GetName() << "->SetState(kButtonDisabled);" << std::endl;
1841  }
1842  if (fState == kButtonEngaged) {
1843  out << " " << GetName() << "->SetState(kButtonEngaged);" << std::endl;
1844  }
1845  if (fBackground != fgDefaultFrameBackground) {
1846  SaveUserColor(out, option);
1847  out << " " << GetName() << "->ChangeBackground(ucolor);" << std::endl;
1848  }
1849 
1850  if (fTip) {
1851  TString tiptext = fTip->GetText()->GetString();
1852  tiptext.ReplaceAll("\n", "\\n");
1853  out << " ";
1854  out << GetName() << "->SetToolTipText(" << quote
1855  << tiptext << quote << ");" << std::endl;
1856  }
1857  if (strlen(fCommand)) {
1858  out << " " << GetName() << "->SetCommand(" << quote << fCommand
1859  << quote << ");" << std::endl;
1860  }
1861 }
1862 
1863 ////////////////////////////////////////////////////////////////////////////////
1864 /// Save a text button widget as a C++ statement(s) on output stream out.
1865 
1866 void TGTextButton::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/)
1867 {
1868  char quote = '"';
1869  TString outext(fLabel->GetString());
1870  if (fLabel->GetHotPos() > 0)
1871  outext.Insert(fLabel->GetHotPos()-1, "&");
1872  if (outext.First('\n') >= 0)
1873  outext.ReplaceAll("\n", "\\n");
1874 
1875  // font + GC
1876  option = GetName()+5; // unique digit id of the name
1877  TString parGC, parFont;
1878  parFont.Form("%s::GetDefaultFontStruct()",IsA()->GetName());
1879  parGC.Form("%s::GetDefaultGC()()",IsA()->GetName());
1880 
1881  if ((GetDefaultFontStruct() != fFontStruct) || (GetDefaultGC()() != fNormGC)) {
1882  TGFont *ufont = gClient->GetResourcePool()->GetFontPool()->FindFont(fFontStruct);
1883  if (ufont) {
1884  ufont->SavePrimitive(out, option);
1885  parFont.Form("ufont->GetFontStruct()");
1886  }
1887 
1888  TGGC *userGC = gClient->GetResourcePool()->GetGCPool()->FindGC(fNormGC);
1889  if (userGC) {
1890  userGC->SavePrimitive(out, option);
1891  parGC.Form("uGC->GetGC()");
1892  }
1893  }
1894 
1895  if (fBackground != GetDefaultFrameBackground()) SaveUserColor(out, option);
1896 
1897  out << " TGTextButton *";
1898  out << GetName() << " = new TGTextButton(" << fParent->GetName()
1899  << "," << quote << outext.Data() << quote;
1900 
1901  if (GetOptions() == (kRaisedFrame | kDoubleBorder)) {
1902  if (fFontStruct == GetDefaultFontStruct()) {
1903  if (fNormGC == GetDefaultGC()()) {
1904  if (fWidgetId == -1) {
1905  out << ");" << std::endl;
1906  } else {
1907  out << "," << fWidgetId <<");" << std::endl;
1908  }
1909  } else {
1910  out << "," << fWidgetId << "," << parGC << ");" << std::endl;
1911  }
1912  } else {
1913  out << "," << fWidgetId << "," << parGC << "," << parFont << ");" << std::endl;
1914  }
1915  } else {
1916  out << "," << fWidgetId << "," << parGC << "," << parFont << "," << GetOptionString() << ");" << std::endl;
1917  }
1918 
1919  out << " " << GetName() << "->SetTextJustify(" << fTMode << ");" << std::endl;
1920  out << " " << GetName() << "->SetMargins(" << fMLeft << "," << fMRight << ",";
1921  out << fMTop << "," << fMBottom << ");" << std::endl;
1922  out << " " << GetName() << "->SetWrapLength(" << fWrapLength << ");" << std::endl;
1923 
1924  out << " " << GetName() << "->Resize(" << GetWidth() << "," << GetHeight()
1925  << ");" << std::endl;
1926 
1927  TGButton::SavePrimitive(out,option);
1928 }
1929 
1930 ////////////////////////////////////////////////////////////////////////////////
1931 /// Save a picture button widget as a C++ statement(s) on output stream out.
1932 
1933 void TGPictureButton::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/)
1934 {
1935  if (!fPic) {
1936  Error("SavePrimitive()", "pixmap not found for picture button %d ", fWidgetId);
1937  return;
1938  }
1939 
1940  // GC
1941  option = GetName()+5; // unique digit id of the name
1942  TString parGC;
1943  parGC.Form("%s::GetDefaultGC()()",IsA()->GetName());
1944 
1945  if (GetDefaultGC()() != fNormGC) {
1946  TGGC *userGC = gClient->GetResourcePool()->GetGCPool()->FindGC(fNormGC);
1947  if (userGC) {
1948  userGC->SavePrimitive(out, option);
1949  parGC.Form("uGC->GetGC()");
1950  }
1951  }
1952 
1953  char quote = '"';
1954  const char *picname = fPic->GetName();
1955 
1956  out <<" TGPictureButton *";
1957 
1958  out << GetName() << " = new TGPictureButton(" << fParent->GetName()
1959  << ",gClient->GetPicture(" << quote
1960  << gSystem->ExpandPathName(gSystem->UnixPathName(picname)) << quote << ")";
1961 
1962  if (GetOptions() == (kRaisedFrame | kDoubleBorder)) {
1963  if (fNormGC == GetDefaultGC()()) {
1964  if (fWidgetId == -1) {
1965  out << ");" << std::endl;
1966  } else {
1967  out << "," << fWidgetId << ");" << std::endl;
1968  }
1969  } else {
1970  out << "," << fWidgetId << "," << parGC.Data() << ");" << std::endl;
1971  }
1972  } else {
1973  out << "," << fWidgetId << "," << parGC.Data() << "," << GetOptionString()
1974  << ");" << std::endl;
1975  }
1976 
1977  TGButton::SavePrimitive(out,option);
1978 }
1979 
1980 ////////////////////////////////////////////////////////////////////////////////
1981 /// Save a check button widget as a C++ statement(s) on output stream out.
1982 
1983 void TGCheckButton::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/)
1984 {
1985  char quote = '"';
1986 
1987  TString outext(fLabel->GetString());
1988  if (fLabel->GetHotPos() > 0)
1989  outext.Insert(fLabel->GetHotPos()-1, "&");
1990  if (outext.First('\n') >= 0)
1991  outext.ReplaceAll("\n", "\\n");
1992 
1993  out <<" TGCheckButton *";
1994  out << GetName() << " = new TGCheckButton(" << fParent->GetName()
1995  << "," << quote << outext.Data() << quote;
1996 
1997  // font + GC
1998  option = GetName()+5; // unique digit id of the name
1999  TString parGC, parFont;
2000  parFont.Form("%s::GetDefaultFontStruct()",IsA()->GetName());
2001  parGC.Form("%s::GetDefaultGC()()",IsA()->GetName());
2002 
2003  if ((GetDefaultFontStruct() != fFontStruct) || (GetDefaultGC()() != fNormGC)) {
2004  TGFont *ufont = gClient->GetResourcePool()->GetFontPool()->FindFont(fFontStruct);
2005  if (ufont) {
2006  ufont->SavePrimitive(out, option);
2007  parFont.Form("ufont->GetFontStruct()");
2008  }
2009 
2010  TGGC *userGC = gClient->GetResourcePool()->GetGCPool()->FindGC(fNormGC);
2011  if (userGC) {
2012  userGC->SavePrimitive(out, option);
2013  parGC.Form("uGC->GetGC()");
2014  }
2015  }
2016 
2017  if (GetOptions() == kChildFrame) {
2018  if (fFontStruct == GetDefaultFontStruct()) {
2019  if (fNormGC == GetDefaultGC()()) {
2020  if (fWidgetId == -1) {
2021  out << ");" << std::endl;
2022  } else {
2023  out << "," << fWidgetId << ");" << std::endl;
2024  }
2025  } else {
2026  out << "," << fWidgetId << "," << parGC << ");" << std::endl;
2027  }
2028  } else {
2029  out << "," << fWidgetId << "," << parGC << "," << parFont << ");" << std::endl;
2030  }
2031  } else {
2032  out << "," << fWidgetId << "," << parGC << "," << parFont << "," << GetOptionString() << ");" << std::endl;
2033  }
2034 
2035  TGButton::SavePrimitive(out,option);
2036  if (fState == kButtonDisabled) {
2037  if (IsDisabledAndSelected())
2038  out << " " << GetName() << "->SetDisabledAndSelected(kTRUE);" << std::endl;
2039  else
2040  out << " " << GetName() << "->SetDisabledAndSelected(kFALSE);" << std::endl;
2041  }
2042  out << " " << GetName() << "->SetTextJustify(" << fTMode << ");" << std::endl;
2043  out << " " << GetName() << "->SetMargins(" << fMLeft << "," << fMRight << ",";
2044  out << fMTop << "," << fMBottom << ");" << std::endl;
2045  out << " " << GetName() << "->SetWrapLength(" << fWrapLength << ");" << std::endl;
2046 }
2047 
2048 ////////////////////////////////////////////////////////////////////////////////
2049 /// Save a radio button widget as a C++ statement(s) on output stream out.
2050 
2051 void TGRadioButton::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/)
2052 {
2053  char quote = '"';
2054 
2055  TString outext(fLabel->GetString());
2056  if (fLabel->GetHotPos() > 0)
2057  outext.Insert(fLabel->GetHotPos()-1, "&");
2058  if (outext.First('\n') >= 0)
2059  outext.ReplaceAll("\n", "\\n");
2060 
2061  out << " TGRadioButton *";
2062  out << GetName() << " = new TGRadioButton(" << fParent->GetName()
2063  << "," << quote << outext.Data() << quote;
2064 
2065  // font + GC
2066  option = GetName()+5; // unique digit id of the name
2067  TString parGC, parFont;
2068  parFont.Form("%s::GetDefaultFontStruct()",IsA()->GetName());
2069  parGC.Form("%s::GetDefaultGC()()",IsA()->GetName());
2070 
2071  if ((GetDefaultFontStruct() != fFontStruct) || (GetDefaultGC()() != fNormGC)) {
2072  TGFont *ufont = gClient->GetResourcePool()->GetFontPool()->FindFont(fFontStruct);
2073  if (ufont) {
2074  ufont->SavePrimitive(out, option);
2075  parFont.Form("ufont->GetFontStruct()");
2076  }
2077 
2078  TGGC *userGC = gClient->GetResourcePool()->GetGCPool()->FindGC(fNormGC);
2079  if (userGC) {
2080  userGC->SavePrimitive(out, option);
2081  parGC.Form("uGC->GetGC()");
2082  }
2083  }
2084 
2085  if (GetOptions() == (kChildFrame)) {
2086  if (fFontStruct == GetDefaultFontStruct()) {
2087  if (fNormGC == GetDefaultGC()()) {
2088  if (fWidgetId == -1) {
2089  out <<");" << std::endl;
2090  } else {
2091  out << "," << fWidgetId << ");" << std::endl;
2092  }
2093  } else {
2094  out << "," << fWidgetId << "," << parGC << ");" << std::endl;
2095  }
2096  } else {
2097  out << "," << fWidgetId << "," << parGC << "," << parFont << ");" << std::endl;
2098  }
2099  } else {
2100  out << "," << fWidgetId << "," << parGC << "," << parFont << "," << GetOptionString() << ");" << std::endl;
2101  }
2102 
2103  TGButton::SavePrimitive(out,option);
2104  if (fState == kButtonDisabled) {
2105  if (IsDisabledAndSelected())
2106  out << " " << GetName() << "->SetDisabledAndSelected(kTRUE);" << std::endl;
2107  else
2108  out << " " << GetName() << "->SetDisabledAndSelected(kFALSE);" << std::endl;
2109  }
2110  out << " " << GetName() << "->SetTextJustify(" << fTMode << ");" << std::endl;
2111  out << " " << GetName() << "->SetMargins(" << fMLeft << "," << fMRight << ",";
2112  out << fMTop << "," << fMBottom << ");" << std::endl;
2113  out << " " << GetName() << "->SetWrapLength(" << fWrapLength << ");" << std::endl;
2114 }
2115 
2116 ////////////////////////////////////////////////////////////////////////////////
2117 /// Create a menu button widget. The hotstring will be adopted and
2118 /// deleted by the menu button. This constructior creates a
2119 /// menubutton with a popup menu attached that appears when the
2120 /// button for it is clicked. The popup menu is adopted.
2121 
2122 TGSplitButton::TGSplitButton(const TGWindow *p, TGHotString* menulabel,
2123  TGPopupMenu *popmenu, Bool_t split, Int_t id,
2124  GContext_t norm, FontStruct_t fontstruct, UInt_t options)
2125  : TGTextButton(p, menulabel, id, norm, fontstruct, options)
2126 {
2127  fFontStruct = fontstruct;
2128  fMBWidth = 16;
2129  fMenuLabel = new TGHotString(*menulabel);
2130  fPopMenu = popmenu;
2131  fPopMenu->fSplitButton = this;
2132  fSplit = split;
2133  fTMode = 0;
2134  fHKeycode = 0;
2135  fMBState = kButtonUp; fDefaultCursor = fClient->GetResourcePool()->GetGrabCursor();
2136  fKeyNavigate = kFALSE;
2137  fWidestLabel = "";
2138  fHeighestLabel = "";
2139 
2140  // Find and set the correct size for the menu and the button.
2141  TGMenuEntry *entry = 0;
2142  TGHotString lstring(*fMenuLabel);
2143  TGHotString hstring(*fMenuLabel);
2144  const TList *list = fPopMenu->GetListOfEntries();
2145  UInt_t lwidth = 0, lheight = 0;
2146  UInt_t twidth = 0, theight = 0;
2147 
2148  TGFont *font = fClient->GetFontPool()->FindFont(fFontStruct);
2149  if (!font) {
2150  font = fClient->GetFontPool()->GetFont(fgDefaultFont);
2151  if (font) fFontStruct = font->GetFontStruct();
2152  }
2153 
2154  if (font) font->ComputeTextLayout(lstring, lstring.GetLength(),
2155  fWrapLength, kTextLeft, 0,
2156  &lwidth, &lheight);
2157 
2158  TIter iter(list);
2159  entry = (TGMenuEntry *)iter.Next();
2160  while (entry != 0) {
2161  if (entry->GetType() == kMenuEntry) {
2162  const TGHotString string(*(entry->GetLabel()));
2163  if (font) font->ComputeTextLayout(string, string.GetLength(),
2164  fWrapLength, kTextLeft, 0,
2165  &twidth, &theight);
2166  if(twidth > lwidth) {
2167  lstring = string;
2168  }
2169  if(theight > lheight) {
2170  hstring = string;
2171  }
2172  }
2173  entry = (TGMenuEntry *)iter.Next();
2174  }
2175  fWidestLabel = lstring;
2176  fHeighestLabel = hstring;
2177 
2178  if (font) {
2179  UInt_t dummy = 0;
2180  font->ComputeTextLayout(lstring, lstring.GetLength(),
2181  fWrapLength, kTextLeft, 0,
2182  &fTWidth, &dummy);
2183  font->ComputeTextLayout(hstring, hstring.GetLength(),
2184  fWrapLength, kTextLeft, 0,
2185  &dummy, &fTHeight);
2186  }
2187  fTBWidth = fTWidth + 8;
2188  fHeight = fTHeight + 7;
2189  Resize(fTBWidth + fMBWidth, fHeight);
2190 
2191  ChangeOptions(GetOptions() | kFixedSize);
2192 
2193  // Save the id of the 1st item on the menu.
2194  TIter iter1(list);
2195  do {
2196  entry = (TGMenuEntry *)iter1.Next();
2197  if ((entry) && (entry->GetStatus() & kMenuEnableMask) &&
2198  !(entry->GetStatus() & kMenuHideMask) &&
2199  (entry->GetType() != kMenuSeparator) &&
2200  (entry->GetType() != kMenuLabel)) break;
2201  entry = (TGMenuEntry *)iter1.Next();
2202  } while (entry);
2203  if (entry) fEntryId = entry->GetEntryId();
2204 
2205  // An additional connection that is needed.
2206  fPopMenu->Connect("Activated(Int_t)", "TGSplitButton", this, "HandleMenu(Int_t)");
2207  SetSplit(fSplit);
2208 
2209  Init();
2210 }
2211 
2212 
2213 ////////////////////////////////////////////////////////////////////////////////
2214 /// Common initialization used by the different ctors.
2215 
2216 void TGSplitButton::Init()
2217 {
2218  Int_t hotchar;
2219 
2220  fTMode = kTextCenterX | kTextCenterY;
2221  fHKeycode = 0;
2222  fHasOwnFont = kFALSE;
2223  fPrevStateOn =
2224  fStateOn = kFALSE;
2225  fMBState = kButtonUp;
2226 
2227  SetSize(TGDimension(fWidth, fHeight));
2228 
2229  if ((hotchar = fLabel->GetHotChar()) != 0) {
2230  if ((fHKeycode = gVirtualX->KeysymToKeycode(hotchar)) != 0) {
2231  const TGMainFrame *main = (TGMainFrame *) GetMainFrame();
2232  if (main) {
2233  main->BindKey(this, fHKeycode, kKeyMod1Mask);
2234  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask);
2235  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyLockMask);
2236  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyLockMask);
2237 
2238  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyMod2Mask);
2239  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask);
2240  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyMod2Mask | kKeyLockMask);
2241  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask | kKeyLockMask);
2242  }
2243  }
2244  }
2245  SetWindowAttributes_t wattr;
2246  wattr.fMask = kWAWinGravity | kWABitGravity;
2247  wattr.fBitGravity = 5; // center
2248  wattr.fWinGravity = 1;
2249  gVirtualX->ChangeWindowAttributes(fId, &wattr);
2250 
2251  // Make sure motion is detected too.
2252  AddInput(kPointerMotionMask | kEnterWindowMask | kLeaveWindowMask);
2253 
2254  SetWindowName();
2255 }
2256 
2257 ////////////////////////////////////////////////////////////////////////////////
2258 /// Delete a split button widget.
2259 
2260 TGSplitButton::~TGSplitButton()
2261 {
2262  if (fPopMenu) delete fPopMenu;
2263  if (fMenuLabel) delete fMenuLabel;
2264 }
2265 
2266 ////////////////////////////////////////////////////////////////////////////////
2267 /// Draw triangle (arrow) on which user can click to open Popup.
2268 
2269 void TGSplitButton::DrawTriangle(const GContext_t gc, Int_t x, Int_t y)
2270 {
2271  Point_t points[3];
2272 
2273  points[0].fX = x;
2274  points[0].fY = y;
2275  points[1].fX = x + 5;
2276  points[1].fY = y;
2277  points[2].fX = x + 2;
2278  points[2].fY = y + 3;
2279 
2280  gVirtualX->FillPolygon(fId, gc, points, 3);
2281 }
2282 
2283 ////////////////////////////////////////////////////////////////////////////////
2284 /// Calculate the size of the button.
2285 
2286 void TGSplitButton::CalcSize()
2287 {
2288  Int_t max_ascent, max_descent;
2289  fTWidth = gVirtualX->TextWidth(fFontStruct, fLabel->GetString(), fLabel->GetLength());
2290  gVirtualX->GetFontProperties(fFontStruct, max_ascent, max_descent);
2291  fTHeight = max_ascent + max_descent;
2292 
2293  fTBWidth = fTWidth + 8;
2294  fHeight = fTHeight + 7;
2295  fWidth = fTBWidth;
2296 }
2297 
2298 ////////////////////////////////////////////////////////////////////////////////
2299 /// Handle mouse button event in case the button is split.
2300 
2301 Bool_t TGSplitButton::HandleSButton(Event_t *event)
2302 {
2303  if (fState == kButtonDisabled) return kFALSE;
2304 
2305  Bool_t activate = kFALSE;
2306  Bool_t bclick = kFALSE;
2307  static Bool_t mbpress = kFALSE;
2308  static Bool_t tbpress = kFALSE;
2309  static Bool_t outpress = kFALSE;
2310 
2311  Bool_t inTB = (event->fX >= 0) && (event->fY >= 0) &&
2312  (event->fX <= (Int_t)fTBWidth) && (event->fY <= (Int_t)fHeight);
2313 
2314  Bool_t inMB = (event->fX >= (Int_t)(fWidth -fMBWidth)) && (event->fY >= 0) &&
2315  (event->fX <= (Int_t)fWidth) && (event->fY <= (Int_t)fHeight);
2316 
2317  // We don't need to check the button number as GrabButton will
2318  // only allow button1 events
2319 
2320  if (inTB) {
2321  if (event->fType == kButtonPress) {
2322  mbpress = kFALSE;
2323  tbpress = kTRUE;
2324  fgReleaseBtn = 0;
2325  if (fState == kButtonEngaged) {
2326  return kTRUE;
2327  }
2328  SetState(kButtonDown);
2329  Pressed();
2330  } else { // ButtonRelease
2331  if (fMBState == kButtonDown) {
2332  SetMBState(kButtonUp);
2333  }
2334  if (fState == kButtonEngaged && tbpress) {
2335  SetState(kButtonUp);
2336  Released();
2337  bclick = kTRUE;
2338  } else if (fState == kButtonDown && tbpress) {
2339  tbpress = kFALSE;
2340  if (fStayDown) {
2341  bclick = kTRUE;
2342  SetState(kButtonEngaged);
2343  fgReleaseBtn = 0;
2344  } else {
2345  bclick = kTRUE;
2346  SetState(kButtonUp);
2347  Released();
2348  fgReleaseBtn = fId;
2349  }
2350  }else {
2351  SetState(kButtonUp);
2352  }
2353  }
2354  } else if (inMB) {
2355  if (event->fType == kButtonPress) {
2356  fgReleaseBtn = 0;
2357  mbpress = kTRUE;
2358  tbpress = kFALSE;
2359  if (fMBState == kButtonEngaged) {
2360  return kTRUE;
2361  }
2362  SetMBState(kButtonDown);
2363  MBPressed();
2364  gVirtualX->GrabPointer(fId, kButtonPressMask | kButtonReleaseMask |
2365  kPointerMotionMask, kNone, fDefaultCursor);
2366  } else { // ButtonRelease
2367  if (fState == kButtonDown) {
2368  SetState(kButtonUp);
2369  }
2370  if (fMBState == kButtonEngaged && mbpress) {
2371  mbpress = kFALSE;
2372  SetMBState(kButtonUp);
2373  SetMenuState(kFALSE);
2374  MBReleased();
2375  MBClicked();
2376  gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE); // ungrab pointer
2377  } else if (fMBState == kButtonDown && mbpress) {
2378  MBClicked();
2379  SetMBState(kButtonEngaged);
2380  SetMenuState(kTRUE);
2381  fgReleaseBtn = 0;
2382  } else {
2383  SetMBState(kButtonUp);
2384  }
2385  }
2386  } else {
2387  if (event->fType == kButtonPress) {
2388  fgReleaseBtn = 0;
2389  outpress = kTRUE;
2390  } else { // ButtonRelease
2391  if(outpress) {
2392  outpress = kFALSE;
2393  SetMBState(kButtonUp);
2394  SetMenuState(kFALSE);
2395  gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE); // ungrab pointer
2396  activate = kTRUE;
2397  }
2398  }
2399  }
2400  if (bclick) {
2401  Clicked();
2402  SendMessage(fMsgWindow, MK_MSG(kC_COMMAND, kCM_BUTTON), fWidgetId,
2403  (Long_t) fUserData);
2404  fClient->ProcessLine(fCommand, MK_MSG(kC_COMMAND, kCM_BUTTON), fWidgetId,
2405  (Long_t) fUserData);
2406  }
2407  if (activate) {
2408  TGMenuEntry *entry = fPopMenu->GetCurrent();
2409  if (entry) {
2410  if ((entry->GetStatus() & kMenuEnableMask) &&
2411  !(entry->GetStatus() & kMenuHideMask) &&
2412  (entry->GetType() != kMenuSeparator) &&
2413  (entry->GetType() != kMenuLabel)) {
2414  Int_t id = entry->GetEntryId();
2415  fPopMenu->Activated(id);
2416  }
2417  }
2418  }
2419  // if (mbclick) {
2420  // MBClicked();
2421  // SendMessage(fMsgWindow, MK_MSG(kC_COMMAND, kCM_BUTTON), fWidgetId,
2422  // (Long_t) fUserData);
2423  // fClient->ProcessLine(fCommand, MK_MSG(kC_COMMAND, kCM_BUTTON), fWidgetId,
2424  // (Long_t) fUserData);
2425  // }
2426  return kTRUE;
2427 }
2428 
2429 ////////////////////////////////////////////////////////////////////////////////
2430 /// Handle mouse crossing event in case of split menu.
2431 
2432 Bool_t TGSplitButton::HandleSCrossing(Event_t *event)
2433 {
2434  if (fTip) {
2435  if (event->fType == kEnterNotify)
2436  fTip->Reset();
2437  else
2438  fTip->Hide();
2439  }
2440 
2441  if ((fgDbw != event->fWindow) || (fgReleaseBtn == event->fWindow)) return kTRUE;
2442 
2443  if (!(event->fState & (kButton1Mask | kButton2Mask | kButton3Mask)))
2444  return kTRUE;
2445 
2446  if (fState == kButtonEngaged || fState == kButtonDisabled) return kTRUE;
2447 
2448  Bool_t inTB = (event->fX <= (Int_t)fTBWidth);
2449 
2450  // Bool_t inMB = (event->fX >= (Int_t)(fWidth -fMBWidth)) && (event->fY >= 0) &&
2451  // (event->fX <= (Int_t)fWidth) && (event->fY <= (Int_t)fHeight);
2452 
2453  if (event->fType == kEnterNotify) {
2454  if (inTB) {
2455  SetState(kButtonDown, kFALSE);
2456  } else {
2457  if(fMBState == kButtonEngaged) return kTRUE;
2458  SetMBState(kButtonDown);
2459  }
2460  } else {
2461  // kLeaveNotify
2462  if(fState == kButtonDown) {
2463  SetState(kButtonUp, kFALSE);
2464  }
2465  if (fMBState == kButtonEngaged) return kTRUE;
2466  SetMBState(kButtonUp);
2467  }
2468  return kTRUE;
2469 }
2470 
2471 ////////////////////////////////////////////////////////////////////////////////
2472 /// Handle key event. This function will be called when the hotkey is hit.
2473 
2474 Bool_t TGSplitButton::HandleSKey(Event_t *event)
2475 {
2476  if (fState == kButtonDisabled) return kFALSE;
2477 
2478  Bool_t click = kFALSE;
2479 
2480  if (event->fType == kGKeyPress) {
2481  gVirtualX->SetKeyAutoRepeat(kFALSE);
2482  } else {
2483  gVirtualX->SetKeyAutoRepeat(kTRUE);
2484  }
2485 
2486  if (fTip && event->fType == kGKeyPress) fTip->Hide();
2487 
2488  // We don't need to check the key number as GrabKey will only
2489  // allow fHotchar events if Alt button is pressed (kKeyMod1Mask)
2490 
2491  if ((event->fType == kGKeyPress) && (event->fState & kKeyMod1Mask)) {
2492  if (fState == kButtonEngaged) return kTRUE;
2493  SetState(kButtonDown);
2494  Pressed();
2495  } else if ((event->fType == kKeyRelease) && (event->fState & kKeyMod1Mask)) {
2496  if (fState == kButtonEngaged) {
2497  SetState(kButtonUp);
2498  Released();
2499  }
2500  if (fStayDown) {
2501  SetState(kButtonEngaged);
2502  } else {
2503  SetState(kButtonUp);
2504  Released();
2505  }
2506  click = kTRUE;
2507  }
2508  if (click) {
2509  Clicked();
2510  SendMessage(fMsgWindow, MK_MSG(kC_COMMAND, kCM_BUTTON), fWidgetId,
2511  (Long_t) fUserData);
2512  fClient->ProcessLine(fCommand, MK_MSG(kC_COMMAND, kCM_BUTTON), fWidgetId,
2513  (Long_t) fUserData);
2514  }
2515 
2516  return kTRUE;
2517 }
2518 
2519 ////////////////////////////////////////////////////////////////////////////////
2520 /// Popup the attached menu.
2521 
2522 void TGSplitButton::SetMenuState(Bool_t state)
2523 {
2524  if (state) {
2525  Int_t ax, ay;
2526  Window_t wdummy;
2527 
2528  if (fSplit) {
2529  Int_t n_entries = 0;
2530  TGMenuEntry *entry = 0;
2531  TIter next(fPopMenu->GetListOfEntries());
2532 
2533  while ((entry = (TGMenuEntry *) next())) {
2534  if ((entry->GetType() != kMenuSeparator) &&
2535  (entry->GetType() != kMenuLabel)) {
2536  n_entries++;
2537  }
2538  }
2539  if (n_entries <= 1) {
2540  Info("TGSplitButton", "Only one entry in the menu.");
2541  return;
2542  }
2543  }
2544 
2545  gVirtualX->TranslateCoordinates(fId, fPopMenu->GetParent()->GetId(),
2546  0, 0, ax, ay, wdummy);
2547 
2548  // place the menu just under the window:
2549  fPopMenu->PlaceMenu(ax-1, ay+fHeight, kTRUE, kFALSE); //kTRUE);
2550  BindKeys(kTRUE);
2551  BindMenuKeys(kTRUE);
2552  } else {
2553  fPopMenu->EndMenu(fUserData);
2554  BindKeys(kFALSE);
2555  BindMenuKeys(kFALSE);
2556  fPopMenu->EndMenu(fUserData);
2557  }
2558 }
2559 
2560 ////////////////////////////////////////////////////////////////////////////////
2561 /// Draw the text button.
2562 
2563 void TGSplitButton::DoRedraw()
2564 {
2565  int x, y;
2566  TGFrame::DoRedraw();
2567 
2568  if (fState == kButtonDisabled) fMBState = kButtonDisabled;
2569  else if (fMBState == kButtonDisabled) fMBState = kButtonUp;
2570 
2571  if (fTMode & kTextLeft) {
2572  x = fMLeft + 4;
2573  } else if (fTMode & kTextRight) {
2574  x = fWidth - fTWidth -fMBWidth - fMRight - 4;
2575  } else {
2576  x = (fWidth - fTWidth -fMBWidth + fMLeft - fMRight) >> 1;
2577  }
2578 
2579  if (fTMode & kTextTop) {
2580  y = fMTop + 3;
2581  } else if (fTMode & kTextBottom) {
2582  y = fHeight - fTHeight - fMBottom - 3;
2583  } else {
2584  y = (fHeight - fTHeight + fMTop - fMBottom) >> 1;
2585  }
2586 
2587  if (fState == kButtonDown || fState == kButtonEngaged) { ++x; ++y; }
2588  if (fState == kButtonEngaged) {
2589  gVirtualX->FillRectangle(fId, GetHibckgndGC()(), 2, 2, fWidth-4, fHeight-4);
2590  gVirtualX->DrawLine(fId, GetHilightGC()(), 2, 2, fWidth-3, 2);
2591  }
2592 
2593  Int_t hotpos = fLabel->GetHotPos();
2594 
2595  if (fState == kButtonDisabled) {
2596  TGGCPool *pool = fClient->GetResourcePool()->GetGCPool();
2597  TGGC *gc = pool->FindGC(fNormGC);
2598  if (gc) {
2599  Pixel_t fore = gc->GetForeground();
2600  Pixel_t hi = GetHilightGC().GetForeground();
2601  Pixel_t sh = GetShadowGC().GetForeground();
2602 
2603  gc->SetForeground(hi);
2604  fTLayout->DrawText(fId, gc->GetGC(), x + 1, y + 1, 0, -1);
2605  if (hotpos) fTLayout->UnderlineChar(fId, gc->GetGC(), x + 1, y + 1, hotpos - 1);
2606 
2607  gc->SetForeground(sh);
2608  fTLayout->DrawText(fId, gc->GetGC(), x, y, 0, -1);
2609  if (hotpos) fTLayout->UnderlineChar(fId, gc->GetGC(), x, y, hotpos - 1);
2610  gc->SetForeground(fore);
2611  }
2612  } else {
2613  fTLayout->DrawText(fId, fNormGC, x, y, 0, -1);
2614  if (hotpos) fTLayout->UnderlineChar(fId, fNormGC, x, y, hotpos - 1);
2615  }
2616 
2617  // Draw the parts of the button needed when a menu is attached.
2618 
2619  // triangle position
2620  x = fWidth - 11;
2621  y = fHeight - 10;
2622 
2623  if (fSplit) {
2624  // separator position
2625  Int_t lx = fWidth - fMBWidth;
2626  Int_t ly = 2;
2627  Int_t lh = fHeight - 2;
2628 
2629  if(fMBState == kButtonDown || fMBState == kButtonEngaged) {
2630  x++;
2631  y++;
2632  }
2633 
2634  gVirtualX->DrawLine(fId, GetShadowGC()(), lx, ly + 2, lx, lh - 4);
2635  gVirtualX->DrawLine(fId, GetHilightGC()(), lx + 1, ly + 2, lx + 1, lh - 3);
2636  gVirtualX->DrawLine(fId, GetHilightGC()(), lx, lh - 3, lx + 1, lh - 3);
2637 
2638  if (fMBState == kButtonEngaged) {
2639  gVirtualX->FillRectangle(fId, GetHibckgndGC()(), fTBWidth + 1, 1, fMBWidth - 3, fHeight - 3);
2640  }
2641 
2642  if (fMBState == kButtonDisabled) {
2643  DrawTriangle(GetHilightGC()(), x + 1, y + 1);
2644  DrawTriangle(GetShadowGC()(), x, y);
2645  } else {
2646  DrawTriangle(fNormGC, x, y);
2647  }
2648 
2649  } else {
2650  x -= 2;
2651  if(fState == kButtonDown || fState == kButtonEngaged) {
2652  x++;
2653  y++;
2654  }
2655  if (fState == kButtonDisabled) {
2656  DrawTriangle(GetHilightGC()(), x + 1, y + 1);
2657  DrawTriangle(GetShadowGC()(), x, y);
2658  } else {
2659  DrawTriangle(fNormGC, x, y);
2660  }
2661  }
2662 
2663 }
2664 
2665 ////////////////////////////////////////////////////////////////////////////////
2666 /// If on kTRUE bind arrow, popup menu hot keys, otherwise
2667 /// remove key bindings.
2668 
2669 void TGSplitButton::BindKeys(Bool_t on)
2670 {
2671  gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(kKey_Up), kAnyModifier, on);
2672  gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(kKey_Down), kAnyModifier, on);
2673  gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(kKey_Enter), kAnyModifier, on);
2674  gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(kKey_Return), kAnyModifier, on);
2675  gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(kKey_Escape), kAnyModifier, on);
2676 }
2677 
2678 ////////////////////////////////////////////////////////////////////////////////
2679 /// If on kTRUE bind Menu hot keys, otherwise remove key bindings.
2680 
2681 void TGSplitButton::BindMenuKeys(Bool_t on)
2682 {
2683  TGMenuEntry *e = 0;
2684  TIter next(fPopMenu->GetListOfEntries());
2685 
2686  while ((e = (TGMenuEntry*)next())) {
2687  Int_t hot = 0;
2688  if (e->GetLabel()) {
2689  hot = e->GetLabel()->GetHotChar();
2690  }
2691  if (!hot) continue;
2692  gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(hot), 0, on);
2693  gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(hot), kKeyShiftMask, on);
2694  gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(hot), kKeyLockMask, on);
2695  gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(hot), kKeyMod2Mask, on);
2696  gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(hot), kKeyShiftMask | kKeyLockMask, on);
2697  gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(hot), kKeyShiftMask | kKeyMod2Mask, on);
2698  gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(hot), kKeyLockMask | kKeyMod2Mask, on);
2699  gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(hot), kKeyShiftMask | kKeyLockMask | kKeyMod2Mask, on);
2700  }
2701 }
2702 
2703 ////////////////////////////////////////////////////////////////////////////////
2704 /// returns default size
2705 
2706 TGDimension TGSplitButton::GetDefaultSize() const
2707 {
2708  UInt_t w = GetOptions() & kFixedWidth ? fWidth + fMBWidth : fTWidth + fMLeft + fMRight + fMBWidth + 8;
2709  UInt_t h = GetOptions() & kFixedHeight ? fHeight : fTHeight + fMTop + fMBottom + 7;
2710  return TGDimension(w, h);
2711 }
2712 
2713 ////////////////////////////////////////////////////////////////////////////////
2714 /// Set new button text.
2715 
2716 void TGSplitButton::SetText(TGHotString *new_label)
2717 {
2718  Int_t hotchar;
2719  static Bool_t longlabeltip = kFALSE;
2720  const TGMainFrame *main = (TGMainFrame *) GetMainFrame();
2721 
2722  TGFont *font = fClient->GetFontPool()->FindFont(fFontStruct);
2723  if (!font) {
2724  font = fClient->GetFontPool()->GetFont(fgDefaultFont);
2725  if (font) fFontStruct = font->GetFontStruct();
2726  }
2727 
2728  UInt_t width = 0, bwidth = 0, dummy;
2729  if (font) {
2730  font->ComputeTextLayout(new_label->GetString(), new_label->GetLength(),
2731  fWrapLength, kTextLeft, 0,
2732  &width, &dummy);
2733  font->ComputeTextLayout(fWidestLabel.GetString(), fWidestLabel.GetLength(),
2734  fWrapLength, kTextLeft, 0,
2735  &bwidth, &dummy);
2736  }
2737  if (width > bwidth) {
2738  if (!fTip) {
2739  SetToolTipText(new_label->GetString());
2740  longlabeltip = kTRUE;
2741  }
2742  Info("TGSplitbutton", "Length of new label to long, label truncated.");
2743  new_label->Resize(fWidestLabel.GetLength());
2744  } else if (new_label->GetLength() <= fWidestLabel.GetLength() && longlabeltip) {
2745  if (fTip) delete fTip;
2746  fTip = 0;
2747  longlabeltip = kFALSE;
2748  }
2749 
2750  if (fLabel) {
2751  if (main && fHKeycode) {
2752  main->RemoveBind(this, fHKeycode, kKeyMod1Mask);
2753  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask);
2754  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyLockMask);
2755  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyLockMask);
2756 
2757  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyMod2Mask);
2758  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask);
2759  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyMod2Mask | kKeyLockMask);
2760  main->RemoveBind(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask | kKeyLockMask);
2761  }
2762  delete fLabel;
2763  }
2764 
2765  fLabel = new_label;
2766  if ((hotchar = fLabel->GetHotChar()) != 0) {
2767  if (main && ((fHKeycode = gVirtualX->KeysymToKeycode(hotchar)) != 0)) {
2768  main->BindKey(this, fHKeycode, kKeyMod1Mask);
2769  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask);
2770  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyLockMask);
2771  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyLockMask);
2772 
2773  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyMod2Mask);
2774  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask);
2775  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyMod2Mask | kKeyLockMask);
2776  main->BindKey(this, fHKeycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask | kKeyLockMask);
2777  }
2778  }
2779 
2780  Layout();
2781 }
2782 
2783 ////////////////////////////////////////////////////////////////////////////////
2784 /// Set new button text.
2785 
2786 void TGSplitButton::SetText(const TString &new_label)
2787 {
2788  SetText(new TGHotString(new_label));
2789 }
2790 
2791 ////////////////////////////////////////////////////////////////////////////////
2792 /// Changes text font.
2793 /// If global is kTRUE font is changed globally, otherwise - locally.
2794 
2795 void TGSplitButton::SetFont(FontStruct_t font, Bool_t global)
2796 {
2797  if (font != fFontStruct) {
2798  FontH_t v = gVirtualX->GetFontHandle(font);
2799  if (!v) return;
2800 
2801  fFontStruct = font;
2802  TGGCPool *pool = fClient->GetResourcePool()->GetGCPool();
2803  TGGC *gc = pool->FindGC(fNormGC);
2804 
2805  if ((gc) && !global) {
2806  gc = pool->GetGC((GCValues_t*)gc->GetAttributes(), kTRUE); // copy
2807  fHasOwnFont = kTRUE;
2808  }
2809  if (gc) {
2810  gc->SetFont(v);
2811  fNormGC = gc->GetGC();
2812  }
2813  fClient->NeedRedraw(this);
2814  }
2815 }
2816 
2817 ////////////////////////////////////////////////////////////////////////////////
2818 /// Changes text font specified by name.
2819 /// If global is true color is changed globally, otherwise - locally.
2820 
2821 void TGSplitButton::SetFont(const char *fontName, Bool_t global)
2822 {
2823  TGFont *font = fClient->GetFont(fontName);
2824  if (font) {
2825  SetFont(font->GetFontStruct(), global);
2826  }
2827 }
2828 
2829 ////////////////////////////////////////////////////////////////////////////////
2830 /// Set the state of the Menu Button part
2831 
2832 void TGSplitButton::SetMBState(EButtonState state)
2833 {
2834  if (state != fMBState) {
2835  fMBState = state;
2836  DoRedraw();
2837  }
2838 }
2839 
2840 ////////////////////////////////////////////////////////////////////////////////
2841 /// Set the split status of a button.
2842 
2843 void TGSplitButton::SetSplit(Bool_t split)
2844 {
2845  if(split) {
2846  fStayDown = kFALSE;
2847  Disconnect(fPopMenu, "PoppedDown()");
2848  fPopMenu->Connect("PoppedDown()", "TGSplitButton", this, "SetMBState(=kButtonUp)");
2849  fPopMenu->Connect("PoppedDown()", "TGSplitButton", this, "MBReleased()");
2850 
2851  TGMenuEntry *entry = fPopMenu->GetEntry(fEntryId);
2852  if (entry) {
2853  TGHotString *tmp = new TGHotString(*(entry->GetLabel()));
2854  SetText(tmp);
2855 
2856  TString str("ItemClicked(=");
2857  str += entry->GetEntryId();
2858  str += ")";
2859  Connect("Clicked()", "TGSplitButton", this, str);
2860  fEntryId = entry->GetEntryId();
2861  fPopMenu->HideEntry(fEntryId);
2862  }
2863  } else {
2864  fStayDown = kTRUE;
2865  Disconnect(fPopMenu, "PoppedDown()");
2866  Disconnect(this, "Clicked()", this);
2867  fPopMenu->Connect("PoppedDown()", "TGSplitButton", this, "SetState(=kButtonUp)");
2868  fPopMenu->Connect("PoppedDown()", "TGSplitButton", this, "Released()");
2869  fPopMenu->EnableEntry(fEntryId);
2870  TGHotString *tmp = new TGHotString(*fMenuLabel);
2871  SetText(tmp);
2872  }
2873 
2874  fSplit = split;
2875  DoRedraw();
2876 }
2877 
2878 ////////////////////////////////////////////////////////////////////////////////
2879 /// Handle button events.
2880 
2881 Bool_t TGSplitButton::HandleButton(Event_t *event)
2882 {
2883  if (fState == kButtonDisabled) return kFALSE;
2884 
2885  if (fSplit) return HandleSButton(event);
2886 
2887  Bool_t in = (event->fX >= 0) && (event->fY >= 0) &&
2888  (event->fX <= (Int_t)fWidth) && (event->fY <= (Int_t)fHeight);
2889 
2890  Bool_t activate = kFALSE;
2891  Bool_t click = kFALSE;
2892 
2893  if (in) {
2894  if (event->fType == kButtonPress) {
2895  fgReleaseBtn = 0;
2896  if (fState == kButtonEngaged) {
2897  return kTRUE;
2898  }
2899  SetState(kButtonDown);
2900  Pressed();
2901  gVirtualX->GrabPointer(fId, kButtonPressMask | kButtonReleaseMask |
2902  kPointerMotionMask, kNone, fDefaultCursor);
2903  } else { // ButtonRelease
2904  if (fState == kButtonEngaged) {
2905  SetState(kButtonUp);
2906  SetMenuState(kFALSE);
2907  Released();
2908  click = kTRUE;
2909  gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE); // ungrab pointer
2910  } else {
2911  click = (fState == kButtonDown);
2912  if (click && fStayDown) {
2913  SetState(kButtonEngaged);
2914  SetMenuState(kTRUE);
2915  fgReleaseBtn = 0;
2916  } else {
2917  SetState(kButtonUp);
2918  Released();
2919  fgReleaseBtn = fId;
2920  }
2921  }
2922  fKeyNavigate = kFALSE;
2923  }
2924  } else {
2925  if (event->fType == kButtonPress) {
2926  fgReleaseBtn = 0;
2927  } else { // ButtonRelease
2928  SetState(kButtonUp);
2929  SetMenuState(kFALSE);
2930  gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE); // ungrab pointer
2931  activate = kTRUE;
2932  }
2933  }
2934  if (click) {
2935  Clicked();
2936  SendMessage(fMsgWindow, MK_MSG(kC_COMMAND, kCM_BUTTON), fWidgetId,
2937  (Long_t) fUserData);
2938  fClient->ProcessLine(fCommand, MK_MSG(kC_COMMAND, kCM_BUTTON), fWidgetId,
2939  (Long_t) fUserData);
2940  }
2941  if (activate && !fKeyNavigate) {
2942  TGMenuEntry *entry = fPopMenu->GetCurrent();
2943  if (entry) {
2944  if ((entry->GetStatus() & kMenuEnableMask) &&
2945  !(entry->GetStatus() & kMenuHideMask) &&
2946  (entry->GetType() != kMenuSeparator) &&
2947  (entry->GetType() != kMenuLabel)) {
2948  Int_t id = entry->GetEntryId();
2949  fPopMenu->Activated(id);
2950  }
2951  }
2952  }
2953 
2954  return kTRUE;
2955 
2956 }
2957 
2958 ////////////////////////////////////////////////////////////////////////////////
2959 /// Handle mouse crossing event.
2960 
2961 Bool_t TGSplitButton::HandleCrossing(Event_t *event)
2962 {
2963  if (fSplit) {
2964  return HandleSCrossing(event);
2965  } else {
2966  return TGButton::HandleCrossing(event);
2967  }
2968 }
2969 
2970 ////////////////////////////////////////////////////////////////////////////////
2971 /// Handle key event. This function will be called when the hotkey is hit.
2972 
2973 Bool_t TGSplitButton::HandleKey(Event_t *event)
2974 {
2975  Bool_t click = kFALSE;
2976 
2977  if (fState == kButtonDisabled) return kTRUE;
2978 
2979  if(fSplit) return HandleSKey(event);
2980 
2981  if (event->fType == kGKeyPress) {
2982  gVirtualX->SetKeyAutoRepeat(kFALSE);
2983  } else {
2984  gVirtualX->SetKeyAutoRepeat(kTRUE);
2985  }
2986 
2987  if (fTip && event->fType == kGKeyPress) fTip->Hide();
2988 
2989  // We don't need to check the key number as GrabKey will only
2990  // allow fHotchar events if Alt button is pressed (kKeyMod1Mask)
2991  if (event->fState & kKeyMod1Mask) {
2992  RequestFocus();
2993  fKeyNavigate = kTRUE;
2994  if (event->fType == kGKeyPress) {
2995  if (fState == kButtonEngaged) return kTRUE;
2996  SetState(kButtonDown);
2997  Pressed();
2998  } else if (event->fType == kKeyRelease) {
2999  click = kTRUE;
3000  if (fState == kButtonEngaged) {
3001  SetState(kButtonUp);
3002  SetMenuState(kFALSE);
3003  gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);
3004  } else if (fState == kButtonDown && fStayDown) {
3005  SetState(kButtonEngaged);
3006  SetMenuState(kTRUE);
3007  gVirtualX->GrabPointer(fId, kButtonPressMask | kButtonReleaseMask |
3008  kPointerMotionMask, kNone, fDefaultCursor);
3009  TGMenuEntry *entry = 0;
3010  TIter next(fPopMenu->GetListOfEntries());
3011 
3012  while ((entry = (TGMenuEntry *) next())) {
3013  if ((entry->GetStatus() & kMenuEnableMask) &&
3014  !(entry->GetStatus() & kMenuHideMask) &&
3015  (entry->GetType() != kMenuSeparator) &&
3016  (entry->GetType() != kMenuLabel)) break;
3017  }
3018  if (entry) {
3019  fPopMenu->Activate(entry);
3020  }
3021  } else {
3022  Released();
3023  SetState(kButtonUp);
3024  }
3025  }
3026  } else {
3027  fKeyNavigate = kTRUE;
3028  if (event->fType == kGKeyPress) {
3029  Event_t ev;
3030  ev.fX = ev.fY = 1;
3031  UInt_t keysym;
3032  char tmp[2];
3033 
3034  gVirtualX->LookupString(event, tmp, sizeof(tmp), keysym);
3035 
3036  TGMenuEntry *ce = 0;
3037  TIter next(fPopMenu->GetListOfEntries());
3038 
3039  while ((ce = (TGMenuEntry*)next())) {
3040  UInt_t hot = 0;
3041  if (ce->GetLabel()) hot = ce->GetLabel()->GetHotChar();
3042  if (!hot || (hot != keysym)) continue;
3043 
3044  fPopMenu->Activate(ce);
3045  gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);
3046  SetMenuState(kFALSE);
3047  ev.fType = kButtonRelease;
3048  ev.fWindow = fPopMenu->GetId();
3049  fKeyNavigate = kFALSE;
3050  return HandleButton(&ev);
3051  }
3052 
3053  ce = fPopMenu->GetCurrent();
3054 
3055  switch ((EKeySym)keysym) {
3056  case kKey_Up:
3057  if (ce) ce = (TGMenuEntry*)fPopMenu->GetListOfEntries()->Before(ce);
3058  while (ce && ((ce->GetType() == kMenuSeparator) ||
3059  (ce->GetType() == kMenuLabel) ||
3060  !(ce->GetStatus() & kMenuEnableMask))) {
3061  ce = (TGMenuEntry*)fPopMenu->GetListOfEntries()->Before(ce);
3062  }
3063  if (!ce) ce = (TGMenuEntry*)fPopMenu->GetListOfEntries()->Last();
3064  break;
3065  case kKey_Down:
3066  if (ce) ce = (TGMenuEntry*)fPopMenu->GetListOfEntries()->After(ce);
3067  while (ce && ((ce->GetType() == kMenuSeparator) ||
3068  (ce->GetType() == kMenuLabel) ||
3069  !(ce->GetStatus() & kMenuEnableMask))) {
3070  ce = (TGMenuEntry*)fPopMenu->GetListOfEntries()->After(ce);
3071  }
3072  if (!ce) ce = (TGMenuEntry*)fPopMenu->GetListOfEntries()->First();
3073  break;
3074  case kKey_Enter:
3075  case kKey_Return:
3076  gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);
3077  SetMenuState(kFALSE);
3078  ev.fType = kButtonRelease;
3079  ev.fWindow = fPopMenu->GetId();
3080  fKeyNavigate = kFALSE;
3081  HandleButton(&ev);
3082  break;
3083  case kKey_Escape:
3084  gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);
3085  SetMenuState(kFALSE);
3086  break;
3087  default:
3088  break;
3089  }
3090  if (ce) fPopMenu->Activate(ce);
3091  }
3092  }
3093  if (click) {
3094  Clicked();
3095  SendMessage(fMsgWindow, MK_MSG(kC_COMMAND, kCM_BUTTON), fWidgetId,
3096  (Long_t) fUserData);
3097  fClient->ProcessLine(fCommand, MK_MSG(kC_COMMAND, kCM_BUTTON), fWidgetId,
3098  (Long_t) fUserData);
3099  }
3100 
3101  return kTRUE;
3102 }
3103 
3104 ////////////////////////////////////////////////////////////////////////////////
3105 /// Handle a motion event in a TGSplitButton.
3106 
3107 Bool_t TGSplitButton::HandleMotion(Event_t *event)
3108 {
3109  if (fKeyNavigate) return kTRUE;
3110 
3111  if (fSplit) {
3112  if (fMBState == kButtonDown) {
3113  if (event->fX < (Int_t)fTBWidth) {
3114  SetMBState(kButtonUp);
3115  SetState(kButtonDown);
3116  }
3117  } else if (fState == kButtonDown) {
3118  if (event->fX > (Int_t)fTBWidth) {
3119  SetState(kButtonUp);
3120  SetMBState(kButtonDown);
3121  }
3122 
3123  }
3124  }
3125  return kTRUE;
3126 }
3127 
3128 ////////////////////////////////////////////////////////////////////////////////
3129 /// layout text button
3130 
3131 void TGSplitButton::Layout()
3132 {
3133  UInt_t dummya = 0, dummyb = 0;
3134  delete fTLayout;
3135 
3136  TGFont *font = fClient->GetFontPool()->FindFont(fFontStruct);
3137  if (!font) {
3138  font = fClient->GetFontPool()->GetFont(fgDefaultFont);
3139  if (font) fFontStruct = font->GetFontStruct();
3140  }
3141  if (font) {
3142  fTLayout = font->ComputeTextLayout(fLabel->GetString(),
3143  fLabel->GetLength(),
3144  fWrapLength, kTextLeft, 0,
3145  &dummya, &dummyb);
3146  UInt_t dummy = 0;
3147  font->ComputeTextLayout(fWidestLabel.GetString(), fWidestLabel.GetLength(),
3148  fWrapLength, kTextLeft, 0,
3149  &fTWidth, &dummy);
3150  font->ComputeTextLayout(fHeighestLabel.GetString(), fHeighestLabel.GetLength(),
3151  fWrapLength, kTextLeft, 0,
3152  &dummy, &fTHeight);
3153  }
3154  fTBWidth = fTWidth + 8;
3155  fWidth = fTBWidth + fMBWidth;
3156  fHeight = fTHeight + 7;
3157  fClient->NeedRedraw(this);
3158 }
3159 
3160 ////////////////////////////////////////////////////////////////////////////////
3161 /// Handle a menu item activation.
3162 
3163 void TGSplitButton::HandleMenu(Int_t id)
3164 {
3165  SetMenuState(kFALSE);
3166 
3167  if (fSplit) {
3168  SetMBState(kButtonUp);
3169  Disconnect(this, "Clicked()", this);
3170  // connect clicked to the ItemClicked signal with the correct id
3171  Connect("Clicked()", "TGSplitButton", this,
3172  TString::Format("ItemClicked(=%d)", id));
3173 
3174  // reenable hidden entries
3175  const TList *list = fPopMenu->GetListOfEntries();
3176  TIter iter(list);
3177  fPopMenu->EnableEntry(fEntryId);
3178  TGMenuEntry *entry = fPopMenu->GetEntry(id);
3179  if (entry) {
3180  TGHotString *label = entry->GetLabel();
3181  TGHotString *tmp = new TGHotString(*label);
3182  SetText(tmp);
3183  }
3184  fPopMenu->HideEntry(id);
3185  if (entry) fEntryId = entry->GetEntryId();
3186  } else {
3187  SetState(kButtonUp);
3188  ItemClicked(id);
3189  }
3190  DoRedraw();
3191 }