Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGDockableFrame.cxx
Go to the documentation of this file.
1 // @(#)root/gui:$Id$
2 // Author: Abdelhalim Ssadik 07/07/04
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2004, 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 // A TGDockableFrame is a frame with handles that allow it to be //
26 // undocked (i.e. put in a transient frame of its own) and to be docked //
27 // again or hidden and shown again. It uses the TGDockButton, which is //
28 // a button with two vertical bars (||) and TGDockHideButton, which is //
29 // a button with a small triangle. The TGUndockedFrame is a transient //
30 // frame that on closure will put the frame back in the dock. //
31 // //
32 //////////////////////////////////////////////////////////////////////////
33 
34 #include "TColor.h"
35 #include "TGFrame.h"
36 #include "TMessage.h"
37 #include "TGWidget.h"
38 #include "TGButton.h"
39 #include "TGDockableFrame.h"
40 #include "TGWindow.h"
41 #include "TList.h"
42 #include "TVirtualX.h"
43 #include "Riostream.h"
44 
45 
46 ClassImp(TGDockButton);
47 ClassImp(TGDockHideButton);
48 ClassImp(TGUndockedFrame);
49 ClassImp(TGDockableFrame);
50 
51 ////////////////////////////////////////////////////////////////////////////////
52 /// Create a dock button (i.e. button with two vertical bars).
53 
54 TGDockButton::TGDockButton(const TGCompositeFrame *p, int id) :
55  TGButton (p, id, GetDefaultGC()(), kChildFrame)
56 {
57  fWidgetFlags = kWidgetIsEnabled;
58  fMouseOn = kFALSE;
59  Resize(10, GetDefaultHeight());
60 
61  fNormBg = fBackground;
62 
63  Float_t r, g, b, h, l, s;
64  TColor::Pixel2RGB(fNormBg, r, g, b);
65  TColor::RGB2HLS(r, g, b, h, l, s);
66  l = l + (1. - l) * 45. / 100.;
67  TColor::HLS2RGB(h, l, s, r, g, b);
68  fHiBg = TColor::RGB2Pixel(r, g, b);
69 
70  AddInput(kEnterWindowMask | kLeaveWindowMask);
71  SetWindowName();
72 }
73 
74 ////////////////////////////////////////////////////////////////////////////////
75 /// Delete dock button.
76 
77 TGDockButton::~TGDockButton()
78 {
79 }
80 
81 ////////////////////////////////////////////////////////////////////////////////
82 /// Handle dock button crossing events.
83 
84 Bool_t TGDockButton::HandleCrossing(Event_t *event)
85 {
86  TGButton::HandleCrossing(event);
87  if (event->fType == kLeaveNotify) {
88  fMouseOn = kFALSE;
89  } else if (event->fType == kEnterNotify) {
90  fMouseOn = kTRUE;
91  }
92  if (IsEnabled())
93  fClient->NeedRedraw(this);
94 
95  return kTRUE;
96 }
97 
98 ////////////////////////////////////////////////////////////////////////////////
99 /// Draw borders of dock button.
100 
101 void TGDockButton::DrawBorder()
102 {
103  int options = GetOptions();
104 
105  if (fState == kButtonDown || fState == kButtonEngaged)
106  ;
107  else if (fMouseOn == kTRUE && IsEnabled()) {
108  SetBackgroundColor(fHiBg);
109  ChangeOptions(kChildFrame);
110  } else {
111  SetBackgroundColor(fNormBg);
112  ChangeOptions(kChildFrame);
113  }
114  gVirtualX->ClearWindow(fId);
115  TGFrame::DrawBorder();
116 
117  ChangeOptions(options);
118 }
119 
120 ////////////////////////////////////////////////////////////////////////////////
121 /// Draw the dock button, i.e. two vertical lines.
122 
123 void TGDockButton::DoRedraw()
124 {
125  int x = 1, y = 0;
126 
127  DrawBorder();
128  if (fState == kButtonDown || fState == kButtonEngaged) { ++x; ++y; }
129 
130  for (int i = 0; i < 5; i +=4) {
131  gVirtualX->DrawLine(fId, GetHilightGC()(), i+x, y+1, i+x, fHeight-y-3);
132  gVirtualX->DrawLine(fId, GetShadowGC()(), i+x+1, y+1, i+x+1, fHeight-y-3);
133  }
134 }
135 
136 
137 ////////////////////////////////////////////////////////////////////////////////
138 /// Create a dock hide button (i.e. button with small triangle).
139 
140 TGDockHideButton::TGDockHideButton(const TGCompositeFrame *p) :
141  TGDockButton (p, 2)
142 {
143  Resize(10, 8);
144  fAspectRatio = 0;
145  SetWindowName();
146 }
147 
148 ////////////////////////////////////////////////////////////////////////////////
149 /// Draw dock hide button.
150 
151 void TGDockHideButton::DoRedraw()
152 {
153  int x = 1, y = 0;
154 
155  DrawBorder();
156  if (fState == kButtonDown || fState == kButtonEngaged) { ++x; ++y; }
157 
158  if (fAspectRatio) {
159  gVirtualX->DrawLine(fId, GetBlackGC()(), x+1, y+1, x+5, y+3);
160  gVirtualX->DrawLine(fId, GetBlackGC()(), x+1, y+5, x+5, y+3);
161  gVirtualX->DrawLine(fId, GetHilightGC()(), x, y+1, x, y+5);
162  } else {
163  gVirtualX->DrawLine(fId, GetHilightGC()(), x+5, y+1, x+1, y+3);
164  gVirtualX->DrawLine(fId, GetHilightGC()(), x+5, y+5, x+1, y+3);
165  gVirtualX->DrawLine(fId, GetBlackGC()(), x+6, y+1, x+6, y+5);
166  }
167 }
168 
169 
170 ////////////////////////////////////////////////////////////////////////////////
171 /// Create the undocked (transient) frame.
172 
173 TGUndockedFrame::TGUndockedFrame(const TGWindow *p, TGDockableFrame *dockable) :
174  TGTransientFrame(p, dockable ? dockable->GetMainFrame() : 0, 10, 10)
175 {
176  SetWindowName("");
177  fDockable = dockable;
178 
179  SetMWMHints(kMWMDecorAll | kMWMDecorResizeH | kMWMDecorMaximize |
180  kMWMDecorMinimize | kMWMDecorMenu,
181  kMWMFuncAll | kMWMFuncResize | kMWMFuncMaximize |
182  kMWMFuncMinimize,
183  kMWMInputModeless);
184  SetWindowName();
185 }
186 
187 ////////////////////////////////////////////////////////////////////////////////
188 /// Delete undocked frame. Puts back dockable frame in its original container.
189 
190 TGUndockedFrame::~TGUndockedFrame()
191 {
192  if (fDockable && !fDockable->fDeleted) {
193  fDockable->DockContainer(kFALSE);
194  }
195 }
196 
197 ////////////////////////////////////////////////////////////////////////////////
198 /// Fix the size of the undocked frame so it cannot be changed via the WM.
199 
200 void TGUndockedFrame::FixSize()
201 {
202  ChangeOptions(GetOptions() | kFixedSize);
203  SetWMSize(fWidth, fHeight);
204  SetWMSizeHints(fWidth, fHeight, fWidth, fHeight, 0, 0);
205 }
206 
207 ////////////////////////////////////////////////////////////////////////////////
208 /// Close undocked frame (called via WM close button).
209 
210 void TGUndockedFrame::CloseWindow()
211 {
212  DeleteWindow();
213 }
214 
215 
216 ////////////////////////////////////////////////////////////////////////////////
217 /// Create a dockable frame widget.
218 
219 TGDockableFrame::TGDockableFrame(const TGWindow *p, int id, UInt_t /*options*/)
220  : TGCompositeFrame(p, 10, 10, kHorizontalFrame), TGWidget(id)
221 {
222  fMsgWindow = fParent;
223 
224  TGLayoutHints *l1 = new TGLayoutHints(kLHintsTop | kLHintsLeft);
225  TGLayoutHints *l2 = new TGLayoutHints(kLHintsExpandY | kLHintsLeft);
226  fLb = new TGLayoutHints(kLHintsExpandY | kLHintsLeft, 0, 2, 0, 0);
227  fLc = new TGLayoutHints(kLHintsExpandY | kLHintsExpandX);
228 
229  fButtons = new TGCompositeFrame(this, 10, 10, kVerticalFrame);
230  fButtons->SetCleanup();
231  fHideButton = new TGDockHideButton(fButtons);
232  fButtons->AddFrame(fHideButton, l1);
233  fDockButton = new TGDockButton(fButtons);
234  fButtons->AddFrame(fDockButton, l2);
235 
236  TGCompositeFrame::AddFrame(fButtons, fLb);
237 
238  fContainer = new TGCompositeFrame(this, 10, 10);
239 
240  TGCompositeFrame::AddFrame(fContainer, fLc);
241 
242  fEnableHide = kTRUE;
243  fEnableUndock = kTRUE;
244  fHidden = kFALSE;
245  fFrame = 0;
246  fDeleted = kFALSE;
247  fFixedSize = kTRUE;
248 
249  fDockButton->Associate(this);
250  fHideButton->Associate(this);
251 
252  MapSubwindows();
253  Resize(GetDefaultSize());
254  TGFrame::SetWindowName();
255 }
256 
257 ////////////////////////////////////////////////////////////////////////////////
258 /// Cleanup dockable frame.
259 
260 TGDockableFrame::~TGDockableFrame()
261 {
262  // Just set the flag and delete fFrame. The other components
263  // are deleted in TGCompositeFrame destructor.
264  if (fFrame) {
265  fDeleted = kTRUE;
266  delete fFrame;
267  }
268 }
269 
270 ////////////////////////////////////////////////////////////////////////////////
271 /// Add frame to dockable frame container. Frame and hints are NOT adopted.
272 
273 void TGDockableFrame::AddFrame(TGFrame *f, TGLayoutHints *hints)
274 {
275  f->ReparentWindow(fContainer);
276  fContainer->AddFrame(f, fHints = hints);
277  fContainer->Layout();
278 }
279 
280 ////////////////////////////////////////////////////////////////////////////////
281 /// Undock container.
282 
283 void TGDockableFrame::UndockContainer()
284 {
285  int ax, ay;
286  Window_t wdummy;
287 
288  if (fFrame || !fEnableUndock) return;
289 
290  fFrame = new TGUndockedFrame(fClient->GetDefaultRoot(), this);
291  fFrame->SetEditDisabled();
292 
293  TGDimension size = fContainer->GetSize();
294  RemoveFrame(fContainer);
295  fContainer->ReparentWindow(fFrame);
296  fFrame->AddFrame(fContainer, new TGLayoutHints(kLHintsExpandY | kLHintsExpandX));
297 
298  gVirtualX->TranslateCoordinates(GetId(), fClient->GetDefaultRoot()->GetId(), fX,
299  fY + fFrame->GetHeight(), ax, ay, wdummy);
300 
301  if (fDockName) fFrame->SetWindowName(fDockName);
302 
303  fFrame->MapSubwindows();
304  fFrame->Resize(size);
305  if (fFixedSize)
306  fFrame->FixSize();
307  fFrame->MapWindow();
308  fFrame->Move(ax, ay);
309 
310  if (((TGFrame *)fParent)->IsComposite()) // paranoia check
311  ((TGCompositeFrame *)fParent)->HideFrame(this);
312 
313  Layout();
314 
315  SendMessage(fMsgWindow, MK_MSG(kC_DOCK, kDOCK_UNDOCK), fWidgetId, 0);
316  Undocked();
317 }
318 
319 ////////////////////////////////////////////////////////////////////////////////
320 /// Dock container back to TGDockableFrame.
321 
322 void TGDockableFrame::DockContainer(Int_t del)
323 {
324  if (!fFrame) return;
325  if (del) {
326  delete fFrame; // this will call DockContainer again with del = kFALSE
327  return;
328  }
329 
330  fFrame->RemoveFrame(fContainer);
331  fContainer->ReparentWindow(this);
332  TGCompositeFrame::AddFrame(fContainer, new TGLayoutHints(kLHintsExpandY | kLHintsExpandX));
333 
334  // kludge! (for special case)
335  fDockButton->Resize(fDockButton->GetDefaultWidth(), 1);
336 
337  Layout();
338  if (((TGFrame *)fParent)->IsComposite()) // paranoia check
339  ((TGCompositeFrame *)fParent)->ShowFrame(this);
340 
341  // fFrame is just being deleted (we're here called by TGUndockedFrame's
342  // destructor) so just set it NULL below to avoid eventual problems in
343  // TGDockableFrame's destructor.
344 
345  fFrame = 0;
346 
347  SendMessage(fMsgWindow, MK_MSG(kC_DOCK, kDOCK_DOCK), fWidgetId, 0);
348  Docked();
349 }
350 
351 ////////////////////////////////////////////////////////////////////////////////
352 /// Show dock container.
353 
354 void TGDockableFrame::ShowContainer()
355 {
356  if (!fHidden) return;
357 
358  ShowFrame(fContainer);
359  if (fEnableUndock) fButtons->ShowFrame(fDockButton);
360  fHideButton->SetAspectRatio(0);
361  if (((TGFrame *)fParent)->IsComposite()) // paranoia check
362  ((TGCompositeFrame *)fParent)->Layout();
363  fHidden = kFALSE;
364 
365  SendMessage(fMsgWindow, MK_MSG(kC_DOCK, kDOCK_SHOW), fWidgetId, 0);
366 }
367 
368 ////////////////////////////////////////////////////////////////////////////////
369 /// Hide dock container.
370 
371 void TGDockableFrame::HideContainer()
372 {
373  if (fHidden || !fEnableHide) return;
374 
375  HideFrame(fContainer);
376  fButtons->HideFrame(fDockButton);
377  fHideButton->SetAspectRatio(1);
378  if (((TGFrame *)fParent)->IsComposite()) // paranoia check
379  ((TGCompositeFrame *)fParent)->Layout();
380  fHidden = kTRUE;
381 
382  SendMessage(fMsgWindow, MK_MSG(kC_DOCK, kDOCK_HIDE),fWidgetId, 0);
383 }
384 
385 ////////////////////////////////////////////////////////////////////////////////
386 /// Process dockable frame messages.
387 
388 Bool_t TGDockableFrame::ProcessMessage(Long_t msg, Long_t parm1, Long_t)
389 {
390  switch (GET_MSG(msg)) {
391  case kC_COMMAND:
392  switch (GET_SUBMSG(msg)) {
393  case kCM_BUTTON:
394  switch (parm1) {
395  case 1:
396  if (!fHidden) UndockContainer();
397  break;
398  case 2:
399  if (!fHidden)
400  HideContainer();
401  else
402  ShowContainer();
403  break;
404  }
405  break;
406  }
407  break;
408  }
409 
410  return kTRUE;
411 }
412 
413 ////////////////////////////////////////////////////////////////////////////////
414 /// Enable undocking.
415 
416 void TGDockableFrame::EnableUndock(Bool_t onoff)
417 {
418  fEnableUndock = onoff;
419  if (onoff)
420  fButtons->ShowFrame(fDockButton);
421  else
422  fButtons->HideFrame(fDockButton);
423  Layout();
424 }
425 
426 ////////////////////////////////////////////////////////////////////////////////
427 /// Enable hiding.
428 
429 void TGDockableFrame::EnableHide(Bool_t onoff)
430 {
431  fEnableHide = onoff;
432  if (onoff)
433  fButtons->ShowFrame(fHideButton);
434  else
435  fButtons->HideFrame(fHideButton);
436  Layout();
437 }
438 
439 ////////////////////////////////////////////////////////////////////////////////
440 /// Set window name so it appear as title of the undock window.
441 
442 void TGDockableFrame::SetWindowName(const char *name)
443 {
444  fDockName = "";
445  if (name) {
446  fDockName = name;
447  if (fFrame) fFrame->SetWindowName(fDockName);
448  }
449 }
450 
451 ////////////////////////////////////////////////////////////////////////////////
452 /// Save a dockable frame widget as a C++ statement(s) on output stream out.
453 
454 void TGDockableFrame::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/)
455 {
456  char quote = '"';
457 
458  out << std::endl << " // dockable frame" << std::endl;
459  out << " TGDockableFrame *";
460  out << GetName()<<" = new TGDockableFrame(" << fParent->GetName();
461 
462  if (GetOptions() == kHorizontalFrame) {
463  if (fWidgetId == -1) {
464  out << ");" << std::endl;
465  } else {
466  out << "," << fWidgetId << ");" << std::endl;
467  }
468  } else {
469  out << "," << fWidgetId << "," << GetOptionString() << ");" << std::endl;
470  }
471  if (option && strstr(option, "keep_names"))
472  out << " " << GetName() << "->SetName(\"" << GetName() << "\");" << std::endl;
473 
474  if (GetContainer()->GetList()->First()) {
475  out << " TGCompositeFrame *" << GetContainer()->GetName() << " = "
476  << GetName() << "->GetContainer();" << std::endl;
477 
478  TGFrameElement *el;
479  TIter next(GetContainer()->GetList());
480 
481  while ((el = (TGFrameElement *) next())) {
482  el->fFrame->SavePrimitive(out, option);
483  out << " " << GetName() << "->AddFrame(" << el->fFrame->GetName();
484  el->fLayout->SavePrimitive(out, option);
485  out << ");"<< std::endl;
486  }
487  }
488  out << std::endl << " // next lines belong to the dockable frame widget" << std::endl;
489  if (EnableUndock())
490  out << " " << GetName() << "->EnableUndock(kTRUE);" << std::endl;
491  else
492  out << " " << GetName() << "->EnableUndock(kFALSE);" << std::endl;
493 
494  if (EnableHide())
495  out << " " << GetName() << "->EnableHide(kTRUE);" << std::endl;
496  else
497  out << " " << GetName() << "->EnableHide(kFALSE);" << std::endl;
498 
499  if (fDockName != "")
500  out << " " << GetName() << "->SetWindowName(" << quote << fDockName
501  << quote << ");" << std::endl;
502 
503  if (IsUndocked())
504  out << " " << GetName() << "->UndockContainer();" << std::endl;
505  else
506  out << " " << GetName() << "->DockContainer();" << std::endl;
507 
508  if (IsHidden())
509  out << " " << GetName() << "->HideContainer();" << std::endl;
510 
511  out << std::endl;
512 }