TGMenu.cxx

Go to the documentation of this file.
00001 // @(#)root/gui:$Id: TGMenu.cxx 35622 2010-09-23 08:29:15Z bellenot $
00002 // Author: Fons Rademakers   09/01/98
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 /**************************************************************************
00012 
00013     This source is based on Xclass95, a Win95-looking GUI toolkit.
00014     Copyright (C) 1996, 1997 David Barth, Ricky Ralston, Hector Peraza.
00015 
00016     Xclass95 is free software; you can redistribute it and/or
00017     modify it under the terms of the GNU Library General Public
00018     License as published by the Free Software Foundation; either
00019     version 2 of the License, or (at your option) any later version.
00020 
00021 **************************************************************************/
00022 
00023 //////////////////////////////////////////////////////////////////////////
00024 //                                                                      //
00025 // TGMenuBar, TGPopupMenu, TGMenuTitle and TGMenuEntry                  //
00026 //                                                                      //
00027 // The TGMenu.h header contains all different menu classes.             //
00028 //                                                                      //
00029 // The TGMenuBar class implements a menu bar widget. It is used to      //
00030 // specify and provide access to common and frequently used application //
00031 // actions grouped under menu titles (TGMenuTitle class). The menu bar  //
00032 // takes the highest-level of the menu system and it is a starting      //
00033 // point for many interactions. It is always visible and allows using   //
00034 // the keyboard equivalents. The geometry of the menu bar is            //
00035 // automatically set to the parent widget, i.e. the menu bar            //
00036 // automatically resizes itself so that it has the same width as its    //
00037 // parent (typically TGMainFrame). A menu bar contains one or more      //
00038 // popup menus and usually is placed along the top of the application   //
00039 // window. Any popup menu is invisible until the user invokes it by     //
00040 // using the mouse pointer or the keyboard.                             //
00041 //                                                                      //
00042 // Popup menus implemented by TGPopupMenu class are unique in that,     //
00043 // by convention, they are not placed with the other GUI components in  //
00044 // the user interfaces. Instead, a popup menu usually appears either in //
00045 // a menu bar or as a context menu on the TOP of the GUI. For that      //
00046 // reason it needs gClient->GetDefaultRoot() as a parent to get the     //
00047 // pointer to the root (i.e. desktop) window. This way a popup menu     //
00048 // will never be embedded.                                              //
00049 // NOTE: Using gClient->GetRoot() as a parent of TGPopupMenu will not   //
00050 // avoid the possibility of embedding the corresponding popup menu      //
00051 // because the current window hierarchy can be changed by using         //
00052 // gClient->SetRoot() method.                                           //
00053 //                                                                      //
00054 // As a context menus TGPopupMenu shows up after pressing the right     //
00055 // mouse button, over a popup-enabled component. The popup menu then    //
00056 // appears under the mouse pointer.                                     //
00057 //                                                                      //
00058 // Selecting a menu item will generate the event:                       //
00059 // kC_COMMAND, kCM_MENU, menu id, user data.                            //
00060 //                                                                      //
00061 //////////////////////////////////////////////////////////////////////////
00062 
00063 #include "TGMenu.h"
00064 #include "TGResourcePool.h"
00065 #include "TTimer.h"
00066 #include "TMath.h"
00067 #include "TSystem.h"
00068 #include "TList.h"
00069 #include "Riostream.h"
00070 #include "KeySymbols.h"
00071 #include "TGButton.h"
00072 #include "TQConnection.h"
00073 #include "TParameter.h"
00074 
00075 const TGGC   *TGPopupMenu::fgDefaultGC = 0;
00076 const TGGC   *TGPopupMenu::fgDefaultSelectedGC = 0;
00077 const TGGC   *TGPopupMenu::fgDefaultSelectedBackgroundGC = 0;
00078 const TGFont *TGPopupMenu::fgDefaultFont = 0;
00079 const TGFont *TGPopupMenu::fgHilightFont = 0;
00080 
00081 const TGGC   *TGMenuTitle::fgDefaultGC = 0;
00082 const TGGC   *TGMenuTitle::fgDefaultSelectedGC = 0;
00083 const TGFont *TGMenuTitle::fgDefaultFont = 0;
00084 
00085 
00086 ClassImp(TGMenuBar)
00087 ClassImp(TGMenuTitle)
00088 ClassImpQ(TGPopupMenu)
00089 
00090 
00091 //______________________________________________________________________________
00092 class TPopupDelayTimer : public TTimer {
00093 private:
00094    TGPopupMenu   *fPopup;   // popup menu
00095 public:
00096    TPopupDelayTimer(TGPopupMenu *p, Long_t ms) : TTimer(ms, kTRUE) { fPopup = p; }
00097    Bool_t Notify();
00098 };
00099 
00100 //______________________________________________________________________________
00101 Bool_t TPopupDelayTimer::Notify()
00102 {
00103    // Notify when timer times out and reset the timer.
00104 
00105    fPopup->HandleTimer(0);
00106    Reset();
00107    return kFALSE;
00108 }
00109 
00110 
00111 //////////////////////////////////////////////////////////////////////////
00112 //                                                                      //
00113 // TGMenuBar member functions.                                          //
00114 //                                                                      //
00115 //////////////////////////////////////////////////////////////////////////
00116 
00117 //______________________________________________________________________________
00118 TGMenuBar::TGMenuBar(const TGWindow *p, UInt_t w, UInt_t h, UInt_t options)
00119    : TGHorizontalFrame(p, w, h, options | kHorizontalFrame)
00120 {
00121    // Create a menu bar object.
00122 
00123    fCurrent       = 0;
00124    fTitles        = new TList;
00125    fStick         = kTRUE;
00126    fDefaultCursor = fClient->GetResourcePool()->GetGrabCursor();
00127    fTrash         = new TList();
00128 
00129    gVirtualX->GrabButton(fId, kButton1, kAnyModifier,
00130                        kButtonPressMask | kButtonReleaseMask | kEnterWindowMask,
00131                        kNone, kNone);
00132 
00133    fKeyNavigate = kFALSE;
00134 
00135    fMenuMore = new TGPopupMenu(gClient->GetDefaultRoot());
00136    fMenuMore->AddLabel("Hidden Menus");
00137    fMenuMore->AddSeparator();
00138    fMenuBarMoreLayout = new TGLayoutHints(kLHintsTop | kLHintsRight);
00139 
00140    fWithExt = kFALSE;
00141    fOutLayouts = new TList();
00142    fNeededSpace = new TList();
00143 }
00144 
00145 //______________________________________________________________________________
00146 TGMenuBar::~TGMenuBar()
00147 {
00148    // Delete menu bar object. Removes also the hot keys from the main frame,
00149    // so hitting them will not cause the menus to popup.
00150 
00151    TGFrameElement *el;
00152    TGMenuTitle    *t;
00153    Int_t           keycode;
00154 
00155    if (!MustCleanup()) {
00156       fTrash->Delete();
00157    }
00158    delete fTrash;
00159 
00160    const TGMainFrame *main = (TGMainFrame *)GetMainFrame();
00161 
00162    if (!MustCleanup()) {
00163       TIter next(fList);
00164       while ((el = (TGFrameElement *) next())) {
00165          t = (TGMenuTitle *) el->fFrame;
00166          if ((keycode = t->GetHotKeyCode()) != 0 && main) {
00167             main->RemoveBind(this, keycode, kKeyMod1Mask);
00168          }
00169       }
00170    }
00171 
00172    // delete TGMenuTitles
00173    if (fTitles && !MustCleanup()) fTitles->Delete();
00174    delete fTitles;
00175 
00176    delete fOutLayouts;
00177    fNeededSpace->Delete();
00178    delete fNeededSpace;
00179    delete fMenuMore;
00180    delete fMenuBarMoreLayout;
00181 }
00182 
00183 //______________________________________________________________________________
00184 void TGMenuBar::Layout()
00185 {
00186    // Clculates whether the >> menu must be shown or not and 
00187    // which menu titles are hidden. 
00188 
00189    if (GetDefaultWidth() > GetWidth()) {
00190       while (!(GetDefaultWidth() < GetWidth() || 
00191                GetList()->GetSize() <= 1)) {
00192          TGFrameElement* entry = GetLastOnLeft();
00193          TGMenuTitle* menuTitle = (TGMenuTitle*) entry->fFrame;
00194          fNeededSpace->AddLast(new TParameter<Int_t>("", menuTitle->GetWidth() + 
00195                                                          entry->fLayout->GetPadLeft() + 
00196                                                          entry->fLayout->GetPadRight() ) );
00197          fOutLayouts->AddLast( entry->fLayout );
00198          fMenuMore->AddPopup( menuTitle->GetName(), menuTitle->GetMenu() );
00199          menuTitle->GetMenu()->Connect("PoppedUp()", "TGMenuBar", this, "PopupConnection()");
00200          RemovePopup( menuTitle->GetName() );
00201       }
00202    }
00203 
00204    if (fNeededSpace->GetSize() > 0) {
00205       Int_t neededWidth = ((TParameter<Int_t>*) fNeededSpace->Last())->GetVal();
00206       Bool_t fit = kFALSE;
00207       if (fNeededSpace->GetSize() > 1)
00208          fit = GetDefaultWidth() + neededWidth + 5 < GetWidth();
00209       else 
00210          fit = GetDefaultWidth() + neededWidth - 7 < GetWidth();
00211       while (fit) {
00212          TGMenuEntry* menu = (TGMenuEntry*) fMenuMore->GetListOfEntries()->Last();
00213          TGLayoutHints* layout = (TGLayoutHints*) fOutLayouts->Last();
00214          ULong_t  hints = layout->GetLayoutHints();
00215          TGPopupMenu* beforeMenu = 0;
00216          if (hints & kLHintsRight) {
00217             TGFrameElement* entry = GetLastOnLeft();
00218             TGMenuTitle* beforeMenuTitle = (TGMenuTitle*) entry->fFrame;
00219             beforeMenu = beforeMenuTitle->GetMenu();
00220          }
00221 
00222          menu->GetPopup()->Disconnect("PoppedUp()", this, "PopupConnection()");
00223          AddPopup( menu->GetName(), menu->GetPopup(), layout, beforeMenu );
00224          fOutLayouts->Remove( fOutLayouts->Last() );
00225          fNeededSpace->Remove( fNeededSpace->Last() );
00226          fMenuMore->DeleteEntry(menu);
00227 
00228          if (fNeededSpace->GetSize() > 0) {
00229             neededWidth = ((TParameter<Int_t>*)fNeededSpace->Last())->GetVal();
00230             if (fNeededSpace->GetSize() > 1)
00231                fit = GetDefaultWidth() + neededWidth + 5 < GetWidth();
00232             else 
00233                fit = GetDefaultWidth() + neededWidth - 7 < GetWidth();
00234          } else 
00235             fit = kFALSE;
00236       }
00237    }
00238 
00239    if (fNeededSpace->GetSize() > 0) {
00240       if (!fWithExt) {
00241          AddPopup(">>", fMenuMore, fMenuBarMoreLayout,
00242                   ((TGMenuTitle*)((TGFrameElement*)GetList()->First())->fFrame)->GetMenu());
00243          fWithExt = kTRUE;
00244       }
00245    } else {
00246       RemovePopup(">>");
00247       fWithExt = kFALSE;
00248    }
00249 
00250    MapSubwindows();
00251    TGHorizontalFrame::Layout();
00252 }
00253 
00254 //______________________________________________________________________________
00255 TGFrameElement* TGMenuBar::GetLastOnLeft()
00256 {
00257    // Returns the last visible menu title on the left of the '>>' 
00258    // in the menu bar.
00259 
00260    TIter next(GetList());
00261    while (TGFrameElement *entry = (TGFrameElement*) next()) {
00262    
00263       TGMenuTitle* menuTitle = (TGMenuTitle*) entry->fFrame;
00264       TGLayoutHints* tmpLayout = (TGLayoutHints*) entry->fLayout;
00265       ULong_t  hints = tmpLayout->GetLayoutHints();
00266 
00267       if (hints & kLHintsRight && menuTitle->GetMenu() != fMenuMore) {
00268          return entry;
00269       }
00270    }
00271 
00272    return ((TGFrameElement*)GetList()->Last());
00273 }
00274 
00275 //______________________________________________________________________________
00276 void TGMenuBar::PopupConnection()
00277 {
00278    // Connects the corresponding cascaded menu to the proper slots,
00279    // according to the highlighted menu entry in '>>' menu.
00280 
00281    // Disconnect all previous signals
00282    TList* slots = fMenuMore->GetListOfSignals();
00283    TIter next (slots);
00284    while (TList* connlist = (TList*) next()) {
00285    
00286       const char* signal_name = connlist->GetName();
00287       TIter next2(connlist);
00288       while (TQConnection* conn = (TQConnection*) next2()) {
00289          const char* slot_name = conn->GetName();
00290          void* receiver = conn->GetReceiver();
00291          fMenuMore->Disconnect(signal_name, receiver, slot_name);
00292       }
00293    }
00294    fMenuMore->fMsgWindow = 0;
00295 
00296    // Check wheter the current entry is a menu or not (just in case)
00297    TGMenuEntry* currentEntry = fMenuMore->GetCurrent();
00298    if (currentEntry->GetType() != kMenuPopup) return;
00299 
00300    // Connect the corresponding active signals to the >> menu
00301    TGPopupMenu* currentMenu = currentEntry->GetPopup();
00302 
00303    slots = currentMenu->GetListOfSignals();
00304    TIter next3 (slots);
00305    while (TList* connlist = (TList*) next3()) {
00306    
00307       const char* signal_name = connlist->GetName();
00308       if (strcmp(signal_name, "Activated(int)") == 0) {
00309          TIter next2(connlist);
00310          while (TQConnection* conn = (TQConnection*) next2()) {
00311 
00312             const char* slot_name = conn->GetName();
00313             const char* class_name = conn->GetClassName();
00314             void* receiver = conn->GetReceiver();
00315             fMenuMore->Connect(signal_name, class_name, receiver, slot_name);
00316          }
00317       }
00318    }
00319 
00320    fMenuMore->fMsgWindow = currentMenu->fMsgWindow;
00321 }
00322 
00323 //______________________________________________________________________________
00324 void TGMenuBar::BindKeys(Bool_t on)
00325 {
00326    // If on kTRUE bind arrow, popup menu hot keys, otherwise
00327    // remove key bindings.
00328 
00329    gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(kKey_Left), kAnyModifier, on);
00330    gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(kKey_Right), kAnyModifier, on);
00331    gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(kKey_Up), kAnyModifier, on);
00332    gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(kKey_Down), kAnyModifier, on);
00333    gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(kKey_Enter), kAnyModifier, on);
00334    gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(kKey_Return), kAnyModifier, on);
00335    gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(kKey_Escape), kAnyModifier, on);
00336 
00337    if (fCurrent && fCurrent->GetMenu()) {
00338       BindMenu(fCurrent->GetMenu(), on);
00339    }
00340 }
00341 
00342 //______________________________________________________________________________
00343 void TGMenuBar::BindMenu(TGPopupMenu* subMenu, Bool_t on) 
00344 {
00345    // If on kTRUE bind subMenu hot keys, otherwise remove key bindings.
00346 
00347    TGMenuEntry *e;
00348    TIter next(subMenu->GetListOfEntries());
00349    
00350    while ((e = (TGMenuEntry*)next())) {
00351       Int_t hot = 0;
00352       if ( e->GetType() == kMenuPopup )
00353          BindMenu(e->GetPopup(), on);
00354       if (e->GetLabel()) {
00355          hot = e->GetLabel()->GetHotChar();
00356       }
00357       if (!hot) continue;
00358       gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(hot), 0, on);
00359       gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(hot), kKeyShiftMask, on);
00360       gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(hot), kKeyLockMask, on);
00361       gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(hot), kKeyMod2Mask, on);
00362       gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(hot), kKeyShiftMask | kKeyLockMask, on);
00363       gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(hot), kKeyShiftMask | kKeyMod2Mask, on);
00364       gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(hot), kKeyLockMask  | kKeyMod2Mask, on);
00365       gVirtualX->GrabKey(fId, gVirtualX->KeysymToKeycode(hot), kKeyShiftMask | kKeyLockMask | kKeyMod2Mask, on);
00366    }
00367 }
00368 
00369 
00370 //______________________________________________________________________________
00371 void TGMenuBar::BindHotKey(Int_t keycode, Bool_t on)
00372 {
00373    // If on kTRUE bind hot keys, otherwise remove key binding.
00374 
00375    const TGMainFrame *main = (TGMainFrame *) GetMainFrame();
00376 
00377    if (!main || !main->InheritsFrom("TGMainFrame")) return;
00378 
00379    if (on) {
00380       // case unsensitive bindings
00381       main->BindKey(this, keycode, kKeyMod1Mask);
00382       main->BindKey(this, keycode, kKeyMod1Mask | kKeyShiftMask);
00383       main->BindKey(this, keycode, kKeyMod1Mask | kKeyLockMask);
00384       main->BindKey(this, keycode, kKeyMod1Mask | kKeyShiftMask | kKeyLockMask);
00385 
00386       main->BindKey(this, keycode, kKeyMod1Mask | kKeyMod2Mask);
00387       main->BindKey(this, keycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask);
00388       main->BindKey(this, keycode, kKeyMod1Mask | kKeyMod2Mask | kKeyLockMask);
00389       main->BindKey(this, keycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask | kKeyLockMask);
00390    } else {
00391       main->RemoveBind(this, keycode, kKeyMod1Mask);
00392       main->RemoveBind(this, keycode, kKeyMod1Mask | kKeyShiftMask);
00393       main->RemoveBind(this, keycode, kKeyMod1Mask | kKeyLockMask);
00394       main->RemoveBind(this, keycode, kKeyMod1Mask | kKeyShiftMask | kKeyLockMask);
00395 
00396       main->RemoveBind(this, keycode, kKeyMod1Mask | kKeyMod2Mask);
00397       main->RemoveBind(this, keycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask);
00398       main->RemoveBind(this, keycode, kKeyMod1Mask | kKeyMod2Mask | kKeyLockMask);
00399       main->RemoveBind(this, keycode, kKeyMod1Mask | kKeyShiftMask | kKeyMod2Mask | kKeyLockMask);
00400    }
00401 }
00402 
00403 //______________________________________________________________________________
00404 void TGMenuBar::AddPopup(TGHotString *s, TGPopupMenu *menu, TGLayoutHints *l,
00405                          TGPopupMenu *before)
00406 {
00407    // Add popup menu to menu bar. The hot string will be adopted by the
00408    // menubar (actually the menu title) and deleted when possible.
00409    // If before is not 0 the menu will be added before it.
00410 
00411    TGMenuTitle *t;
00412    Int_t keycode;
00413 
00414    AddFrameBefore(t = new TGMenuTitle(this, s, menu), l, before);
00415    fTitles->Add(t);  // keep track of menu titles for later cleanup in dtor
00416 
00417    if ((keycode = t->GetHotKeyCode()) != 0) {
00418       BindHotKey(keycode, kTRUE);
00419    }
00420 }
00421 
00422 //______________________________________________________________________________
00423 void TGMenuBar::AddTitle(TGMenuTitle *title, TGLayoutHints *l, TGPopupMenu *before)
00424 {
00425    // Add popup via created before menu title.
00426 
00427    Int_t keycode;
00428 
00429    AddFrameBefore(title, l, before);
00430    fTitles->Add(title);  // keep track of menu titles for later cleanup in dtor
00431 
00432    if ((keycode = title->GetHotKeyCode()) != 0) {
00433       BindHotKey(keycode, kTRUE);
00434    }
00435 }
00436 
00437 //______________________________________________________________________________
00438 void TGMenuBar::AddPopup(const char *s, TGPopupMenu *menu, TGLayoutHints *l,
00439                          TGPopupMenu *before)
00440 {
00441    // Add popup menu to menu bar. If before is not 0 the menu will be
00442    // added before it.
00443 
00444    AddPopup(new TGHotString(s), menu, l, before);
00445 }
00446 
00447 //______________________________________________________________________________
00448 TGPopupMenu *TGMenuBar::AddPopup(const TString &s, Int_t padleft, Int_t padright,
00449                                  Int_t padtop, Int_t padbottom)
00450 {
00451    // Add popup menu to menu bar.
00452    //
00453    // Comment:
00454    //    This method is valid  only for horizontal menu bars.
00455    //    The most common case is menu bar containing equidistant titles padding left side.
00456    //       TGMenuBar *bar;
00457    //       bar->AddPopup("title1", 10);
00458    //       bar->AddPopup("title2", 10);
00459    //       ...
00460    //
00461    //    To add equidistant titles  padding right side padleft must be 0.
00462    //       TGMenuBar *bar;
00463    //       bar->AddPopup("title1", 0, 10);
00464    //       bar->AddPopup("title2", 0, 10);
00465    //       ...
00466    //
00467    //    This method guarantee automatic cleanup when menu bar is destroyed.
00468    //    Do not delete returned popup-menu
00469 
00470    ULong_t hints = kLHintsTop;
00471 
00472    if (padleft)  {
00473       hints |= kLHintsLeft;
00474    } else {
00475       hints |= kLHintsRight;
00476    }
00477 
00478    TGLayoutHints *l = new TGLayoutHints(hints, padleft, padright,
00479                                                padtop, padbottom);
00480    fTrash->Add(l);
00481 
00482    TGPopupMenu *menu = new TGPopupMenu(fClient->GetDefaultRoot());
00483    AddPopup(new TGHotString(s), menu, l, 0);
00484    fTrash->Add(menu);
00485    return menu;
00486 }
00487 
00488 //______________________________________________________________________________
00489 void TGMenuBar::AddFrameBefore(TGFrame *f, TGLayoutHints *l,
00490                                TGPopupMenu *before)
00491 {
00492    // Private version of AddFrame for menubar, to make sure that we
00493    // indeed only add TGMenuTitle objects to it. If before is not 0
00494    // the menu will be added before it.
00495 
00496    if (!f->InheritsFrom("TGMenuTitle")) {
00497       Error("AddFrameBefore", "may only add TGMenuTitle objects to a menu bar");
00498       return;
00499    }
00500 
00501    if (!before) {
00502       AddFrame(f, l);
00503       return;
00504    }
00505 
00506    TGFrameElement *nw;
00507 
00508    nw = new TGFrameElement;
00509    nw->fFrame  = f;
00510    nw->fLayout = l ? l : fgDefaultHints;
00511    nw->fState  = 1;
00512 
00513    TGFrameElement *el;
00514    TIter next(fList);
00515    while ((el = (TGFrameElement *) next())) {
00516       TGMenuTitle *t = (TGMenuTitle *) el->fFrame;
00517       if (t->GetMenu() == before) {
00518          fList->AddBefore(el, nw);
00519          return;
00520       }
00521    }
00522    fList->Add(nw);
00523 }
00524 
00525 //______________________________________________________________________________
00526 TGPopupMenu *TGMenuBar::GetPopup(const char *s)
00527 {
00528    // Return popup menu with the specified name. Returns 0 if menu is
00529    // not found. Returnes menu can be used as "before" in AddPopup().
00530    // Don't use hot key (&) in name.
00531 
00532    if (!GetList()) return 0;
00533 
00534    TGFrameElement *el;
00535    TIter next(GetList());
00536    TString str = s;
00537 
00538    while ((el = (TGFrameElement *) next())) {
00539       TGMenuTitle *t = (TGMenuTitle *) el->fFrame;
00540       if (str == t->GetName())
00541          return t->GetMenu();
00542    }
00543    return 0;
00544 }
00545 
00546 //______________________________________________________________________________
00547 TGPopupMenu *TGMenuBar::RemovePopup(const char *s)
00548 {
00549    // Remove popup menu from menu bar. Returned menu has to be deleted by
00550    // the user, or can be re-used in another AddPopup(). Returns 0 if
00551    // menu is not found. Don't use hot key (&) in name.
00552 
00553    if (!GetList()) return 0;
00554 
00555    TGFrameElement *el;
00556    TIter next(GetList());
00557    TString str = s;
00558 
00559    while ((el = (TGFrameElement *) next())) {
00560       TGMenuTitle *t = (TGMenuTitle *) el->fFrame;
00561       if (str == t->GetName()) {
00562          Int_t keycode;
00563          if ((keycode = t->GetHotKeyCode())) {
00564             BindHotKey(keycode, kFALSE);  // remove bind
00565          }
00566          TGPopupMenu *m = t->GetMenu();
00567          fTitles->Remove(t);
00568          t->DestroyWindow();
00569          RemoveFrame(t);
00570          delete t;
00571          return m;
00572       }
00573    }
00574    return 0;
00575 }
00576 
00577 //______________________________________________________________________________
00578 Bool_t TGMenuBar::HandleMotion(Event_t *event)
00579 {
00580    // Handle a mouse motion event in a menu bar.
00581 
00582    if (fKeyNavigate) return kTRUE;
00583 
00584    Int_t        dummy;
00585    Window_t     wtarget;
00586    TGMenuTitle *target = 0;
00587 
00588    if (!(event->fState & kButton1Mask))
00589       fStick = kFALSE; // use some threshold!
00590 
00591    gVirtualX->TranslateCoordinates(fId, fId, event->fX, event->fY,
00592                                    dummy, dummy, wtarget);
00593    if (wtarget) target = (TGMenuTitle*) fClient->GetWindowById(wtarget);
00594 
00595    if (fCurrent && target && (target != fCurrent)) {
00596       // deactivate all others
00597       TGFrameElement *el;
00598       TIter next(fList);
00599       while ((el = (TGFrameElement *) next()))
00600          ((TGMenuTitle*)el->fFrame)->SetState(kFALSE);
00601 
00602       fStick   = kTRUE;
00603       fCurrent = target;
00604       target->SetState(kTRUE);
00605    }
00606 
00607    return kTRUE;
00608 }
00609 
00610 //______________________________________________________________________________
00611 Bool_t TGMenuBar::HandleButton(Event_t *event)
00612 {
00613    // Handle a mouse button event in a menubar.
00614 
00615    Int_t        dummy;
00616    Window_t     wtarget;
00617    TGMenuTitle *target;
00618 
00619    // We don't need to check the button number as GrabButton will
00620    // only allow button1 events
00621 
00622    if (event->fType == kButtonPress) {
00623 
00624       gVirtualX->TranslateCoordinates(fId, fId, event->fX, event->fY,
00625                                       dummy, dummy, wtarget);
00626       target = (TGMenuTitle*) fClient->GetWindowById(wtarget);
00627 
00628       if (target != 0) {
00629          fStick = kTRUE;
00630 
00631          if (target != fCurrent) {
00632             // deactivate all others
00633             TGFrameElement *el;
00634             TIter next(fList);
00635             while ((el = (TGFrameElement *) next()))
00636                ((TGMenuTitle*)el->fFrame)->SetState(kFALSE);
00637 
00638             fStick   = kTRUE;
00639             fCurrent = target;
00640             target->SetState(kTRUE);
00641 
00642             gVirtualX->GrabPointer(fId, kButtonPressMask | kButtonReleaseMask |
00643                                    kPointerMotionMask, kNone, fDefaultCursor);
00644          }
00645       }
00646    }
00647 
00648    if (event->fType == kButtonRelease) {
00649       if (fStick) {
00650          fStick = kFALSE;
00651          return kTRUE;
00652       }
00653 
00654       TGFrameElement *el;
00655       TIter next(fList);
00656       while ((el = (TGFrameElement *) next()))
00657          ((TGMenuTitle*)el->fFrame)->SetState(kFALSE);
00658 
00659       gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);  // ungrab pointer
00660 
00661       if (fCurrent != 0) {
00662          target   = fCurrent; // tricky, because WaitFor
00663          fCurrent = 0;
00664          if (!fKeyNavigate)
00665             target->DoSendMessage();
00666       }
00667       fKeyNavigate = kFALSE;
00668    }
00669 
00670    return kTRUE;
00671 }
00672 
00673 //______________________________________________________________________________
00674 Bool_t TGMenuBar::HandleKey(Event_t *event)
00675 {
00676    // Handle keyboard events in a menu bar.
00677 
00678    TGMenuTitle *target = 0;
00679    TGFrameElement *el;
00680    void *dummy;
00681    Int_t    ax, ay;
00682    Window_t wdummy;
00683    TIter next(fList);
00684 
00685    if (event->fType == kGKeyPress) {
00686       UInt_t keysym;
00687       char tmp[2];
00688 
00689       gVirtualX->LookupString(event, tmp, sizeof(tmp), keysym);
00690 
00691       if (event->fState & kKeyMod1Mask) {
00692          while ((el = (TGFrameElement *) next())) {
00693             target = (TGMenuTitle *) el->fFrame;
00694             if ((Int_t)event->fCode == target->GetHotKeyCode()) {
00695                RequestFocus();
00696                fKeyNavigate = kTRUE;
00697                break;
00698             }
00699          }
00700          if (el == 0) target = 0;
00701       } else {
00702          fKeyNavigate = kTRUE;
00703 
00704          if (fCurrent) {
00705             TGFrameElement *cur  = 0;
00706             TGPopupMenu    *menu = 0;
00707             next.Reset();
00708             el = 0;
00709             while ((el = (TGFrameElement *) next())) {
00710                if (el->fFrame == fCurrent) {
00711                   cur = el;
00712                   menu = ((TGMenuTitle*)el->fFrame)->GetMenu();
00713                   break;
00714                }
00715             }
00716 
00717             if (!menu || !menu->fPoppedUp) return kFALSE;
00718 
00719             TGMenuEntry *ce = 0;
00720 
00721             TGPopupMenu* currentMenu = fCurrent->GetMenu();
00722             TGMenuEntry* currentEntry = currentMenu->GetCurrent();
00723             while ( currentEntry ) {
00724                if ( currentEntry->GetType() == kMenuPopup )
00725                   currentMenu = currentEntry->GetPopup();
00726                if ( currentEntry != currentMenu->GetCurrent() )
00727                   currentEntry = currentMenu->GetCurrent();
00728                else
00729                   currentEntry = 0;
00730             }
00731 
00732             TIter next2(currentMenu->GetListOfEntries());
00733 
00734             while ((ce = (TGMenuEntry*)next2())) {
00735                UInt_t hot = 0;
00736                if (ce->GetLabel()) hot = ce->GetLabel()->GetHotChar();
00737                if (!hot || (hot != keysym)) continue;
00738 
00739                currentMenu->Activate(ce);
00740                if (ce->GetType() != kMenuPopup) {
00741                   gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);
00742                   fCurrent->SetState(kFALSE);
00743                   currentMenu->fStick = kFALSE;
00744                   Event_t ev;
00745                   ev.fType = kButtonRelease;
00746                   ev.fWindow = currentMenu->GetId();
00747                   fCurrent = 0;
00748                   return currentMenu->HandleButton(&ev);
00749                }
00750                else {
00751                   gVirtualX->TranslateCoordinates(currentMenu->fId,
00752                                  (ce->fPopup->GetParent())->GetId(),
00753                                   ce->fEx+currentMenu->fMenuWidth, ce->fEy,
00754                                   ax, ay, wdummy);
00755                   ce->fPopup->PlaceMenu(ax-5, ay-1, kFALSE, kFALSE);
00756                }
00757             }
00758 
00759             ce = menu->GetCurrent();
00760             TGPopupMenu *submenu = 0;
00761 
00762             while (ce && (ce->GetType() == kMenuPopup)) {
00763                submenu = ce->GetPopup();
00764                if (!submenu->fPoppedUp) break;
00765                ce =  submenu->GetCurrent();
00766                menu = submenu;
00767             }
00768             switch ((EKeySym)keysym) {
00769                case kKey_Left:
00770                   if ((submenu) && (submenu->fPoppedUp)) {
00771                      submenu->EndMenu(dummy);
00772                      break;
00773                   }
00774                   el = (TGFrameElement*)fList->Before(cur);
00775                   if (!el) el = (TGFrameElement*)fList->Last();
00776                   break;
00777                case kKey_Right:
00778                   if (submenu) {
00779                      if (submenu->fPoppedUp) {
00780                         if (!submenu->GetCurrent()) {
00781                            ce = (TGMenuEntry*)submenu->GetListOfEntries()->First();
00782                         } else {
00783                            submenu->EndMenu(dummy);
00784                         }
00785                      }
00786                      else {
00787                         gVirtualX->TranslateCoordinates(menu->fId,
00788                                        (submenu->GetParent())->GetId(),
00789                                        ce->fEx+menu->fMenuWidth, ce->fEy,
00790                                        ax, ay, wdummy);
00791 
00792                         submenu->PlaceMenu(ax-5, ay-1, kFALSE, kFALSE);
00793                      }
00794                      break;
00795                   }
00796                   el = (TGFrameElement*)fList->After(cur);
00797                   if (!el) el = (TGFrameElement*)fList->First();
00798                   break;
00799                case kKey_Up:
00800                   if (ce) ce = (TGMenuEntry*)menu->GetListOfEntries()->Before(ce);
00801                   while (ce && ((ce->GetType() == kMenuSeparator) ||
00802                          (ce->GetType() == kMenuLabel) ||
00803                          !(ce->GetStatus() & kMenuEnableMask))) {
00804                      ce = (TGMenuEntry*)menu->GetListOfEntries()->Before(ce);
00805                   }
00806                   if (!ce) ce = (TGMenuEntry*)menu->GetListOfEntries()->Last();
00807                   break;
00808                case kKey_Down:
00809                   if (ce) ce = (TGMenuEntry*)menu->GetListOfEntries()->After(ce);
00810                   while (ce && ((ce->GetType() == kMenuSeparator) ||
00811                          (ce->GetType() == kMenuLabel) ||
00812                          !(ce->GetStatus() & kMenuEnableMask))) {
00813                      ce = (TGMenuEntry*)menu->GetListOfEntries()->After(ce);
00814                   }
00815                   if (!ce) ce = (TGMenuEntry*)menu->GetListOfEntries()->First();
00816                   break;
00817                case kKey_Enter:
00818                case kKey_Return: {
00819                   gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);
00820                   fCurrent->SetState(kFALSE);
00821                   menu->fStick = kFALSE;
00822                   Event_t ev;
00823                   ev.fType = kButtonRelease;
00824                   ev.fWindow = menu->GetId();
00825                   fCurrent = 0;
00826                   return menu->HandleButton(&ev);
00827                }
00828                case kKey_Escape:
00829                   gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);
00830                   fCurrent->SetState(kFALSE);
00831                   fStick = kFALSE;
00832                   fCurrent = 0;
00833                   return menu->EndMenu(dummy);
00834                default:
00835                   break;
00836             }
00837             if (ce) menu->Activate(ce);
00838 
00839             el = el ? el : cur;
00840             if (el) target = (TGMenuTitle*)el->fFrame;
00841          } else {
00842             return kFALSE;
00843          }
00844       }
00845 
00846       if (target != 0) {
00847          fStick = kTRUE;
00848 
00849          if (target != fCurrent) {
00850             // deactivate all others
00851             next.Reset();
00852             while ((el = (TGFrameElement *) next()))
00853                ((TGMenuTitle*)el->fFrame)->SetState(kFALSE);
00854 
00855             fCurrent = target;
00856             target->SetState(kTRUE);
00857             fStick   = kTRUE;
00858 
00859             gVirtualX->GrabPointer(fId, kButtonPressMask | kButtonReleaseMask |
00860                                    kPointerMotionMask, kNone, fDefaultCursor);
00861 
00862             TGMenuEntry *ptr;
00863             TIter nexte(target->GetMenu()->GetListOfEntries());
00864 
00865             while ((ptr = (TGMenuEntry *) nexte())) {
00866                if ((ptr->GetStatus() & kMenuEnableMask) &&
00867                   !(ptr->GetStatus() & kMenuHideMask) &&
00868                    (ptr->GetType() != kMenuSeparator) &&
00869                    (ptr->GetType() != kMenuLabel)) break;
00870             }
00871             if (ptr)
00872                target->GetMenu()->Activate(ptr);
00873 
00874             return kTRUE;
00875          }
00876       } else {
00877          return kFALSE;
00878       }
00879    }
00880 
00881    if (event->fType == kKeyRelease) {
00882       if (fStick) {
00883          fStick = kFALSE;
00884          return kTRUE;
00885       }
00886       gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);  // ungrab pointer
00887 
00888       next.Reset();
00889       while ((el = (TGFrameElement *) next()))
00890          ((TGMenuTitle*)el->fFrame)->SetState(kFALSE);
00891 
00892       if (fCurrent != 0) {
00893          target   = fCurrent; // tricky, because WaitFor
00894          fCurrent = 0;
00895          target->DoSendMessage();
00896       }
00897    }
00898 
00899    return kTRUE;
00900 }
00901 
00902 
00903 //////////////////////////////////////////////////////////////////////////
00904 //                                                                      //
00905 // TGPopupMenu member functions.                                        //
00906 //                                                                      //
00907 //////////////////////////////////////////////////////////////////////////
00908 
00909 //______________________________________________________________________________
00910 TGPopupMenu::TGPopupMenu(const TGWindow *p, UInt_t w, UInt_t h, UInt_t options)
00911     : TGFrame(p, w, h, options | kOwnBackground)
00912 {
00913    // Create a popup menu.
00914 
00915    fNormGC        = GetDefaultGC()();
00916    fSelGC         = GetDefaultSelectedGC()();
00917    fSelbackGC     = GetDefaultSelectedBackgroundGC()();
00918    fFontStruct    = GetDefaultFontStruct();
00919    fHifontStruct  = GetHilightFontStruct();
00920    fDefaultCursor = fClient->GetResourcePool()->GetGrabCursor();
00921 
00922    // We need to change the default context to actually use the
00923    // Menu Fonts.  [Are we actually changing the global settings?]
00924    GCValues_t    gcval;
00925    gcval.fMask = kGCFont;
00926    gcval.fFont = gVirtualX->GetFontHandle(fFontStruct);
00927    gVirtualX->ChangeGC(fNormGC, &gcval);
00928    gVirtualX->ChangeGC(fSelGC, &gcval);
00929 
00930    fDelay     = 0;
00931    fEntryList = new TList;
00932 
00933    // in case any of these magic values is changes, check also Reposition()
00934    fBorderWidth = 3;
00935    fMenuHeight  = 6;
00936    fMenuWidth   = 8;
00937    fXl          = 16;
00938    fMsgWindow   = p;
00939    fStick       = kTRUE;
00940    fCurrent     = 0;
00941    fHasGrab     = kFALSE;
00942    fPoppedUp    = kFALSE;
00943    fMenuBar     = 0;
00944    fSplitButton = 0;
00945    fEntrySep    = 3;
00946 
00947    SetWindowAttributes_t wattr;
00948    wattr.fMask             = kWAOverrideRedirect | kWASaveUnder;
00949    wattr.fOverrideRedirect = kTRUE;
00950    wattr.fSaveUnder        = kTRUE;
00951 
00952    gVirtualX->ChangeWindowAttributes(fId, &wattr);
00953 
00954    AddInput(kPointerMotionMask | kEnterWindowMask | kLeaveWindowMask);
00955 }
00956 
00957 //______________________________________________________________________________
00958 TGPopupMenu::~TGPopupMenu()
00959 {
00960    // Delete a popup menu.
00961 
00962    if (fEntryList) fEntryList->Delete();
00963    delete fEntryList;
00964    delete fDelay;
00965 }
00966 
00967 //______________________________________________________________________________
00968 void TGPopupMenu::AddEntry(TGHotString *s, Int_t id, void *ud,
00969                            const TGPicture *p, TGMenuEntry *before)
00970 {
00971    // Add a menu entry. The hotstring is adopted by the menu (actually by
00972    // the TGMenuEntry) and deleted when possible. A possible picture is
00973    // borrowed from the picture pool and therefore not adopted.
00974    // If before is not 0, the entry will be added before it.
00975 
00976    if (!s) return;
00977    TGMenuEntry *nw = new TGMenuEntry;
00978    Ssiz_t tab = s->Index('\t');
00979    if (tab > 0) {
00980       TString ts(s->Data());
00981       TString shortcut = ts(tab+1, s->Length());
00982       nw->fShortcut = new TGString(shortcut.Data());
00983       nw->fLabel = new TGHotString(*s);
00984       nw->fLabel->Remove(tab);
00985    }
00986    else {
00987       nw->fLabel = s;
00988    }
00989    nw->fPic      = p;
00990    nw->fType     = kMenuEntry;
00991    nw->fEntryId  = id;
00992    nw->fUserData = ud;
00993    nw->fPopup    = 0;
00994    nw->fStatus   = kMenuEnableMask;
00995    nw->fEx       = 2;
00996    nw->fEy       = fMenuHeight-2;
00997 
00998    if (before)
00999       fEntryList->AddBefore(before, nw);
01000    else
01001       fEntryList->Add(nw);
01002 
01003    UInt_t tw, ph = 0, pw = 0;
01004    tw = gVirtualX->TextWidth(fHifontStruct, s->GetString(), s->GetLength());
01005    if (p) {
01006       ph = p->GetHeight();
01007       pw = p->GetWidth();
01008       if (pw+12 > fXl) { fMenuWidth += pw+12-fXl; fXl = pw+12; }
01009    }
01010    if (nw->fShortcut) {
01011       tw += 10;
01012       delete s;
01013    }
01014 
01015    Int_t max_ascent, max_descent;
01016    nw->fEw = tw + pw /*+8*/+18+12;
01017    fMenuWidth = TMath::Max(fMenuWidth, nw->fEw);
01018    gVirtualX->GetFontProperties(fHifontStruct, max_ascent, max_descent);
01019    nw->fEh = max_ascent + max_descent + fEntrySep;
01020    if (nw->fEh < ph+fEntrySep) nw->fEh = ph+fEntrySep; 
01021    fMenuHeight += nw->fEh;
01022 
01023    if (before)
01024       Reposition();
01025    else
01026       Resize(fMenuWidth, fMenuHeight);
01027 }
01028 
01029 //______________________________________________________________________________
01030 void TGPopupMenu::AddEntry(const char *s, Int_t id, void *ud,
01031                            const TGPicture *p, TGMenuEntry *before)
01032 {
01033    // Add a menu entry. The string s in not adopted.
01034    // If before is not 0, the entry will be added before it.
01035 
01036    AddEntry(new TGHotString(s), id, ud, p, before);
01037 }
01038 
01039 //______________________________________________________________________________
01040 void TGPopupMenu::AddSeparator(TGMenuEntry *before)
01041 {
01042    // Add a menu separator to the menu.
01043    // If before is not 0, the entry will be added before it.
01044 
01045    TGMenuEntry *nw = new TGMenuEntry;
01046 
01047    nw->fLabel    = 0;
01048    nw->fPic      = 0;
01049    nw->fType     = kMenuSeparator;
01050    nw->fEntryId  = -1;
01051    nw->fUserData = 0;
01052    nw->fPopup    = 0;
01053    nw->fStatus   = kMenuEnableMask;
01054    nw->fEx       = 2;
01055    nw->fEy       = fMenuHeight-2;
01056 
01057    if (before)
01058       fEntryList->AddBefore(before, nw);
01059    else
01060       fEntryList->Add(nw);
01061 
01062    nw->fEw = 0;
01063    nw->fEh = 4;
01064    fMenuHeight += nw->fEh;
01065 
01066    if (before)
01067       Reposition();
01068    else
01069       Resize(fMenuWidth, fMenuHeight);
01070 }
01071 
01072 //______________________________________________________________________________
01073 void TGPopupMenu::AddLabel(TGHotString *s, const TGPicture *p,
01074                            TGMenuEntry *before)
01075 {
01076    // Add a menu label to the menu. The hotstring is adopted by the menu
01077    // (actually by the TGMenuEntry) and deleted when possible. A possible
01078    // picture is borrowed from the picture pool and therefore not adopted.
01079    // If before is not 0, the entry will be added before it.
01080 
01081    TGMenuEntry *nw = new TGMenuEntry;
01082 
01083    nw->fLabel    = s;
01084    nw->fPic      = p;
01085    nw->fType     = kMenuLabel;
01086    nw->fEntryId  = -1;
01087    nw->fUserData = 0;
01088    nw->fPopup    = 0;
01089    nw->fStatus   = kMenuEnableMask | kMenuDefaultMask;
01090    nw->fEx       = 2;
01091    nw->fEy       = fMenuHeight-2;
01092 
01093    if (before)
01094       fEntryList->AddBefore(before, nw);
01095    else
01096       fEntryList->Add(nw);
01097 
01098    UInt_t tw, ph = 0, pw = 0;
01099    tw = gVirtualX->TextWidth(fHifontStruct, s->GetString(), s->GetLength());
01100    if (p) {
01101       ph = p->GetHeight();
01102       pw = p->GetWidth();
01103       if (pw+12 > fXl) { fMenuWidth += pw+12-fXl; fXl = pw+12; }
01104    }
01105 
01106    Int_t max_ascent, max_descent;
01107    nw->fEw = tw + pw /*+8*/+18+12;
01108    fMenuWidth = TMath::Max(fMenuWidth, nw->fEw);
01109    gVirtualX->GetFontProperties(fHifontStruct, max_ascent, max_descent);
01110    nw->fEh = max_ascent + max_descent + fEntrySep;
01111    if (nw->fEh < ph+fEntrySep) nw->fEh = ph+fEntrySep; 
01112    fMenuHeight += nw->fEh;
01113 
01114    if (before)
01115       Reposition();
01116    else
01117       Resize(fMenuWidth, fMenuHeight);
01118 }
01119 
01120 //______________________________________________________________________________
01121 void TGPopupMenu::AddLabel(const char *s, const TGPicture *p,
01122                            TGMenuEntry *before)
01123 {
01124    // Add a menu label to the menu. The string s in not adopted.
01125    // If before is not 0, the entry will be added before it.
01126 
01127    AddLabel(new TGHotString(s), p, before);
01128 }
01129 
01130 //______________________________________________________________________________
01131 void TGPopupMenu::AddPopup(TGHotString *s, TGPopupMenu *popup,
01132                            TGMenuEntry *before, const TGPicture *p)
01133 {
01134    // Add a (cascading) popup menu to a popup menu. The hotstring is adopted
01135    // by the menu (actually by the TGMenuEntry) and deleted when possible.
01136    // If before is not 0, the entry will be added before it.
01137 
01138    TGMenuEntry *nw = new TGMenuEntry;
01139 
01140    nw->fLabel    = s;
01141    nw->fPic      = p;
01142    nw->fType     = kMenuPopup;
01143    nw->fEntryId  = -2;
01144    nw->fUserData = 0;
01145    nw->fPopup    = popup;
01146    nw->fStatus   = kMenuEnableMask;
01147    nw->fEx       = 2;
01148    nw->fEy       = fMenuHeight-2;
01149 
01150    if (before)
01151       fEntryList->AddBefore(before, nw);
01152    else
01153       fEntryList->Add(nw);
01154 
01155    UInt_t tw = gVirtualX->TextWidth(fHifontStruct, s->GetString(),
01156                                     s->GetLength());
01157 
01158    UInt_t ph = 0, pw = 8;
01159    if (p) {
01160       ph = p->GetHeight();
01161       pw = p->GetWidth();
01162       if (pw+12 > fXl) { fMenuWidth += pw+12-fXl; fXl = pw+12; }
01163    }
01164    Int_t max_ascent, max_descent;
01165    nw->fEw = tw + pw+18+12;
01166    fMenuWidth = TMath::Max(fMenuWidth, nw->fEw);
01167    gVirtualX->GetFontProperties(fHifontStruct, max_ascent, max_descent);
01168    nw->fEh = max_ascent + max_descent + fEntrySep;
01169    if (nw->fEh < ph+fEntrySep) nw->fEh = ph+fEntrySep; 
01170    fMenuHeight += nw->fEh;
01171 
01172    if (before)
01173       Reposition();
01174    else
01175       Resize(fMenuWidth, fMenuHeight);
01176 }
01177 
01178 //______________________________________________________________________________
01179 void TGPopupMenu::AddPopup(const char *s, TGPopupMenu *popup,
01180                            TGMenuEntry *before, const TGPicture *p)
01181 {
01182    // Add a (cascading) popup menu to a popup menu. The string s is not
01183    // adopted. If before is not 0, the entry will be added before it.
01184 
01185    AddPopup(new TGHotString(s), popup, before, p);
01186 }
01187 
01188 //______________________________________________________________________________
01189 void TGPopupMenu::Reposition()
01190 {
01191    // Reposition entries in popup menu. Called after menu item has been
01192    // hidden or removed or inserted at a specified location.
01193 
01194    // in case any of these magic values is changes, check also the ctor.
01195    fMenuHeight = 6;
01196    fMenuWidth  = 8;
01197    fXl         = 16;
01198 
01199    TGMenuEntry *ptr;
01200    TIter next(fEntryList);
01201 
01202    while ((ptr = (TGMenuEntry *) next())) {
01203 
01204       if (ptr->fStatus & kMenuHideMask) continue;
01205 
01206       if (ptr->fPic) {
01207          UInt_t pw = ptr->fPic->GetWidth();
01208          if (pw+12 > fXl) { fMenuWidth += pw+12-fXl; fXl = pw+12; }
01209       }
01210       ptr->fEx     = 2;
01211       ptr->fEy     = fMenuHeight-2;
01212       fMenuWidth   = TMath::Max(fMenuWidth, ptr->fEw);
01213       fMenuHeight += ptr->fEh;
01214    }
01215    Resize(fMenuWidth, fMenuHeight);
01216 }
01217 
01218 //______________________________________________________________________________
01219 void TGPopupMenu::PlaceMenu(Int_t x, Int_t y, Bool_t stick_mode, Bool_t grab_pointer)
01220 {
01221    // Popup a popup menu. If stick mode is true keep the menu up. If
01222    // grab_pointer is true the pointer will be grabbed, which means that
01223    // all pointer events will go to the popup menu, independent of in
01224    // which window the pointer is.
01225 
01226    void *ud;
01227    EndMenu(ud);
01228 
01229    Int_t  rx, ry;
01230    UInt_t rw, rh;
01231 
01232    fStick = stick_mode;
01233    fCurrent = 0;
01234 
01235    // Parent is root window for a popup menu
01236    gVirtualX->GetWindowSize(fParent->GetId(), rx, ry, rw, rh);
01237 
01238    if (x < 0) x = 0;
01239    if (x + fMenuWidth > rw) x = rw - fMenuWidth;
01240    if (y < 0) y = 0;
01241    if (y + fMenuHeight > rh) y = rh - fMenuHeight;
01242 
01243    Move(x, y);
01244    MapRaised();
01245 
01246    if (grab_pointer) {
01247       gVirtualX->GrabPointer(fId, kButtonPressMask | kButtonReleaseMask |
01248                              kPointerMotionMask, kNone, fDefaultCursor);
01249       fHasGrab = kTRUE;
01250    } else {
01251       fHasGrab = kFALSE;
01252    }
01253 
01254    fPoppedUp = kTRUE;
01255    PoppedUp();
01256    if (fMenuBar) fMenuBar->BindKeys(kTRUE);
01257 
01258    fClient->RegisterPopup(this);
01259 }
01260 
01261 //______________________________________________________________________________
01262 Int_t TGPopupMenu::EndMenu(void *&userData)
01263 {
01264    // Close menu and return ID of selected menu item.
01265    // In case of cascading menus, recursively close all menus.
01266 
01267    Int_t id;
01268 
01269    if (fDelay) fDelay->Remove();
01270 
01271    // destroy any cascaded childs and get any ID
01272 
01273    if (fCurrent != 0) {
01274 
01275       // deactivate the entry
01276       fCurrent->fStatus &= ~kMenuActiveMask;
01277 
01278       if ((fCurrent->fType == kMenuPopup) && fCurrent->fPopup) {
01279          id = fCurrent->fPopup->EndMenu(userData);
01280       } else {
01281          // return the ID if the entry is enabled, otherwise -1
01282          if (fCurrent->fStatus & kMenuEnableMask) {
01283             id       = fCurrent->fEntryId;
01284             userData = fCurrent->fUserData;
01285          } else {
01286             id       = -1;
01287             userData = 0;
01288          }
01289       }
01290 
01291    } else {
01292       // if no entry selected...
01293       id       = -1;
01294       userData = 0;
01295    }
01296 
01297    // then unmap itself
01298    UnmapWindow();
01299 
01300    gClient->UnregisterPopup(this);
01301    if (fMenuBar) fMenuBar->BindKeys(kFALSE);
01302 
01303    if (fPoppedUp) {
01304       fPoppedUp = kFALSE;
01305       PoppedDown();
01306    }
01307 
01308    return id;
01309 }
01310 
01311 //______________________________________________________________________________
01312 Bool_t TGPopupMenu::HandleButton(Event_t *event)
01313 {
01314    // Handle button event in the popup menu.
01315 
01316    int   id;
01317    void *ud;
01318 
01319    if (event->fType == kButtonRelease) {
01320       if (fStick) {
01321          fStick = kFALSE;
01322          return kTRUE;
01323       }
01324       //if (fCurrent != 0)
01325       //   if (fCurrent->fType == kMenuPopup) return kTRUE;
01326       id = EndMenu(ud);
01327       if (fHasGrab) gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);  // ungrab
01328       if (fCurrent != 0) {
01329          fCurrent->fStatus &= ~kMenuActiveMask;
01330          if (fCurrent->fStatus & kMenuEnableMask) {
01331             SendMessage(fMsgWindow, MK_MSG(kC_COMMAND, kCM_MENU), id,
01332                         (Long_t)ud);
01333             Activated(id);
01334          }
01335       }
01336    }
01337    return kTRUE;
01338 }
01339 
01340 //______________________________________________________________________________
01341 Bool_t TGPopupMenu::HandleCrossing(Event_t *event)
01342 {
01343    // Handle pointer crossing event in popup menu.
01344 
01345    if (event->fType == kEnterNotify) {
01346 
01347       TGMenuEntry *ptr;
01348       TIter next(fEntryList);
01349 
01350       while ((ptr = (TGMenuEntry *) next())) {
01351          if (ptr->fStatus & kMenuHideMask) continue;
01352 
01353          if ((event->fX >= ptr->fEx) && (event->fX <= ptr->fEx+(Int_t)fMenuWidth-10) &&
01354              (event->fY >= ptr->fEy) && (event->fY <= ptr->fEy+(Int_t)ptr->fEh))
01355             break;
01356       }
01357       Activate(ptr);
01358    } else {
01359       Activate((TGMenuEntry*)0);
01360    }
01361    if (fMenuBar) fMenuBar->fKeyNavigate = kFALSE;
01362    if (fSplitButton) fSplitButton->fKeyNavigate = kFALSE;
01363 
01364    return kTRUE;
01365 }
01366 
01367 //______________________________________________________________________________
01368 Bool_t TGPopupMenu::HandleMotion(Event_t *event)
01369 {
01370    // Handle pointer motion event in popup menu.
01371 
01372    TGFrame::HandleMotion(event);
01373 
01374    TGMenuEntry *ptr;
01375    TIter next(fEntryList);
01376 
01377    fStick = kFALSE;   // be careful with this, use some threshold
01378    while ((ptr = (TGMenuEntry *) next())) {
01379       if (ptr->fStatus & kMenuHideMask) continue;
01380 
01381       if ((event->fX >= ptr->fEx) && (event->fX <= ptr->fEx+(Int_t)fMenuWidth-4) &&  //fMenuWidth-10??
01382           (event->fY >= ptr->fEy) && (event->fY <= ptr->fEy+(Int_t)ptr->fEh))
01383          break;
01384    }
01385    Activate(ptr);
01386 
01387    return kTRUE;
01388 }
01389 
01390 //______________________________________________________________________________
01391 void TGPopupMenu::Activate(TGMenuEntry *entry)
01392 {
01393    // Activate a menu entry in a popup menu.
01394 
01395    if (entry == fCurrent) return;
01396 
01397    //-- Deactivate the current entry
01398 
01399    if (fCurrent != 0) {
01400       void *ud;
01401       if (entry == 0 && fCurrent->fType == kMenuPopup) return;
01402       if ((fCurrent->fType == kMenuPopup) && fCurrent->fPopup) 
01403          fCurrent->fPopup->EndMenu(ud);
01404       fCurrent->fStatus &= ~kMenuActiveMask;
01405       DrawEntry(fCurrent);
01406    }
01407 
01408    if (fDelay) fDelay->Remove();
01409 
01410    //-- Activate the new one
01411 
01412    if (entry) {
01413       entry->fStatus |= kMenuActiveMask;
01414       DrawEntry(entry);
01415       if (entry->fType == kMenuPopup) {
01416          if (!fDelay) fDelay = new TPopupDelayTimer(this, 350);
01417          fDelay->Reset();
01418          gSystem->AddTimer(fDelay);
01419          // after delay expires it will popup the cascading popup menu
01420          // iff it is still the current entry
01421       } else if (entry->fType == kMenuEntry) {
01422          // test...
01423          SendMessage(fMsgWindow, MK_MSG(kC_COMMAND, kCM_MENUSELECT),
01424                      entry->fEntryId, (Long_t)entry->fUserData);
01425          Highlighted(entry->fEntryId);
01426       }
01427    }
01428    fCurrent = entry;
01429 }
01430 
01431 //______________________________________________________________________________
01432 Bool_t TGPopupMenu::HandleTimer(TTimer *)
01433 {
01434    // If TPopupDelayTimer times out popup cascading popup menu (if it is
01435    // still the current entry).
01436 
01437    if (fCurrent != 0) {
01438       if ((fCurrent->fType == kMenuPopup) && fCurrent->fPopup) {
01439          Int_t    ax, ay;
01440          Window_t wdummy;
01441 
01442          gVirtualX->TranslateCoordinates(fId,
01443                                        (fCurrent->fPopup->GetParent())->GetId(),
01444                                        fCurrent->fEx+fMenuWidth, fCurrent->fEy,
01445                                        ax, ay, wdummy);
01446 
01447          fCurrent->fPopup->PlaceMenu(ax-5, ay-1, kFALSE, kFALSE);
01448       }
01449    }
01450    fDelay->Remove();
01451 
01452    return kTRUE;
01453 }
01454 
01455 //______________________________________________________________________________
01456 void TGPopupMenu::DoRedraw()
01457 {
01458    // Draw popup menu.
01459 
01460    TGFrame::DoRedraw();
01461 
01462    TGMenuEntry *ptr;
01463    TIter next(fEntryList);
01464 
01465    while ((ptr = (TGMenuEntry *) next()))
01466       DrawEntry(ptr);
01467 }
01468 
01469 //______________________________________________________________________________
01470 void TGPopupMenu::DrawEntry(TGMenuEntry *entry)
01471 {
01472    // Draw popup menu entry.
01473 
01474    FontStruct_t  font;
01475    GCValues_t    gcval;
01476 
01477    if (entry->fStatus & kMenuHideMask)
01478       return;
01479 
01480    if (entry->fStatus & kMenuDefaultMask) {
01481       font = fHifontStruct;
01482       gcval.fMask = kGCFont;
01483       gcval.fFont = gVirtualX->GetFontHandle(font);
01484       gVirtualX->ChangeGC(fNormGC, &gcval);
01485       gVirtualX->ChangeGC(fSelGC, &gcval);
01486    } else {
01487       font = fFontStruct;
01488    }
01489 
01490    UInt_t tw = 0;
01491    int max_ascent, max_descent;
01492    gVirtualX->GetFontProperties(font, max_ascent, max_descent);
01493    int tx = entry->fEx + fXl;
01494    // center text
01495    int offset = (entry->fEh - (max_ascent + max_descent)) / 2;
01496    int ty = entry->fEy + max_ascent + offset - 1;
01497    if (entry->fShortcut)
01498       tw = 7 + gVirtualX->TextWidth(fFontStruct, entry->fShortcut->Data(), entry->fShortcut->Length());
01499 
01500    switch (entry->fType) {
01501       case kMenuPopup:
01502       case kMenuLabel:
01503       case kMenuEntry:
01504          if ((entry->fStatus & kMenuActiveMask) && entry->fType != kMenuLabel) {
01505             gVirtualX->FillRectangle(fId, fSelbackGC, entry->fEx+1, entry->fEy-1,
01506                                      fMenuWidth-6, entry->fEh);
01507             if (entry->fType == kMenuPopup)
01508                DrawTrianglePattern(fSelGC, fMenuWidth-10, entry->fEy+fEntrySep, fMenuWidth-6, entry->fEy+11);
01509             if (entry->fStatus & kMenuCheckedMask)
01510                DrawCheckMark(fSelGC, 6, entry->fEy+fEntrySep, 14, entry->fEy+11);
01511             if (entry->fStatus & kMenuRadioMask)
01512                DrawRCheckMark(fSelGC, 6, entry->fEy+fEntrySep, 14, entry->fEy+11);
01513             if (entry->fPic != 0)
01514                entry->fPic->Draw(fId, fSelGC, 8, entry->fEy+1);
01515             entry->fLabel->Draw(fId,
01516                            (entry->fStatus & kMenuEnableMask) ? fSelGC : GetShadowGC()(),
01517                            tx, ty);
01518             if (entry->fShortcut)
01519                entry->fShortcut->Draw(fId, (entry->fStatus & kMenuEnableMask) ? fSelGC : GetShadowGC()(),
01520                                       fMenuWidth - tw, ty);
01521          } else {
01522             gVirtualX->FillRectangle(fId, GetBckgndGC()(), entry->fEx+1, entry->fEy-1,
01523                                      fMenuWidth-6, entry->fEh);
01524             if (entry->fType == kMenuPopup)
01525                DrawTrianglePattern(fNormGC, fMenuWidth-10, entry->fEy+fEntrySep, fMenuWidth-6, entry->fEy+11);
01526             if (entry->fStatus & kMenuCheckedMask)
01527                DrawCheckMark(fNormGC, 6, entry->fEy+fEntrySep, 14, entry->fEy+11);
01528             if (entry->fStatus & kMenuRadioMask)
01529                DrawRCheckMark(fNormGC, 6, entry->fEy+fEntrySep, 14, entry->fEy+11);
01530             if (entry->fPic != 0)
01531                entry->fPic->Draw(fId, fNormGC, 8, entry->fEy+1);
01532             if (entry->fStatus & kMenuEnableMask) {
01533                entry->fLabel->Draw(fId, fNormGC, tx, ty);
01534                if (entry->fShortcut)
01535                   entry->fShortcut->Draw(fId, fNormGC, fMenuWidth - tw, ty);
01536             } else {
01537                entry->fLabel->Draw(fId, GetHilightGC()(), tx+1, ty+1);
01538                entry->fLabel->Draw(fId, GetShadowGC()(), tx, ty);
01539                if (entry->fShortcut) {
01540                   entry->fShortcut->Draw(fId, GetHilightGC()(), fMenuWidth - tw+1, ty+1);
01541                   entry->fShortcut->Draw(fId, GetShadowGC()(), fMenuWidth - tw, ty);
01542                }
01543             }
01544          }
01545          break;
01546 
01547       case kMenuSeparator:
01548          gVirtualX->DrawLine(fId, GetShadowGC()(),  2, entry->fEy, fMenuWidth-fEntrySep, entry->fEy);
01549          gVirtualX->DrawLine(fId, GetHilightGC()(), 2, entry->fEy+1, fMenuWidth-fEntrySep, entry->fEy+1);
01550          break;
01551    }
01552 
01553    // restore font
01554    if (entry->fStatus & kMenuDefaultMask) {
01555       gcval.fFont = gVirtualX->GetFontHandle(fFontStruct);
01556       gVirtualX->ChangeGC(fNormGC, &gcval);
01557       gVirtualX->ChangeGC(fSelGC, &gcval);
01558    }
01559 }
01560 
01561 //______________________________________________________________________________
01562 void TGPopupMenu::DrawBorder()
01563 {
01564    // Draw border round popup menu.
01565 
01566    gVirtualX->DrawLine(fId, GetBckgndGC()(), 0, 0, fMenuWidth-2, 0);
01567    gVirtualX->DrawLine(fId, GetBckgndGC()(), 0, 0, 0, fMenuHeight-2);
01568    gVirtualX->DrawLine(fId, GetHilightGC()(), 1, 1, fMenuWidth-fEntrySep, 1);
01569    gVirtualX->DrawLine(fId, GetHilightGC()(), 1, 1, 1, fMenuHeight-fEntrySep);
01570 
01571    gVirtualX->DrawLine(fId, GetShadowGC()(),  1, fMenuHeight-2, fMenuWidth-2, fMenuHeight-2);
01572    gVirtualX->DrawLine(fId, GetShadowGC()(),  fMenuWidth-2, fMenuHeight-2, fMenuWidth-2, 1);
01573    gVirtualX->DrawLine(fId, GetBlackGC()(), 0, fMenuHeight-1, fMenuWidth-1, fMenuHeight-1);
01574    gVirtualX->DrawLine(fId, GetBlackGC()(), fMenuWidth-1, fMenuHeight-1, fMenuWidth-1, 0);
01575 }
01576 
01577 //______________________________________________________________________________
01578 void TGPopupMenu::DrawTrianglePattern(GContext_t gc, Int_t l, Int_t t,
01579                                       Int_t r, Int_t b)
01580 {
01581    // Draw triangle pattern. Used for menu entries that are of type
01582    // kMenuPopup (i.e. cascading menus).
01583 
01584    Point_t  points[3];
01585 
01586    int m = (t + b) >> 1;
01587 
01588    points[0].fX = l;
01589    points[0].fY = t;
01590    points[1].fX = l;
01591    points[1].fY = b;
01592    points[2].fX = r;
01593    points[2].fY = m;
01594 
01595    gVirtualX->FillPolygon(fId, gc, points, 3);
01596 }
01597 
01598 //______________________________________________________________________________
01599 void TGPopupMenu::DrawCheckMark(GContext_t gc, Int_t l, Int_t t, Int_t, Int_t b)
01600 {
01601    // Draw check mark. Used for checked button type menu entries.
01602 
01603    Segment_t seg[6];
01604 
01605    t = (t + b - 8) >> 1; ++t;
01606 
01607    seg[0].fX1 = 1+l; seg[0].fY1 = 3+t; seg[0].fX2 = 3+l; seg[0].fY2 = 5+t;
01608    seg[1].fX1 = 1+l; seg[1].fY1 = 4+t; seg[1].fX2 = 3+l; seg[1].fY2 = 6+t;
01609    seg[2].fX1 = 1+l; seg[2].fY1 = 5+t; seg[2].fX2 = 3+l; seg[2].fY2 = 7+t;
01610    seg[3].fX1 = 3+l; seg[3].fY1 = 5+t; seg[3].fX2 = 7+l; seg[3].fY2 = 1+t;
01611    seg[4].fX1 = 3+l; seg[4].fY1 = 6+t; seg[4].fX2 = 7+l; seg[4].fY2 = 2+t;
01612    seg[5].fX1 = 3+l; seg[5].fY1 = 7+t; seg[5].fX2 = 7+l; seg[5].fY2 = 3+t;
01613 
01614    gVirtualX->DrawSegments(fId, gc, seg, 6);
01615 }
01616 
01617 //______________________________________________________________________________
01618 void TGPopupMenu::DrawRCheckMark(GContext_t gc, Int_t l, Int_t t, Int_t r, Int_t b)
01619 {
01620    // Draw radio check mark. Used for radio button type menu entries.
01621 
01622    Segment_t seg[5];
01623 
01624    t = (t + b - 5) >> 1; ++t;
01625    l = (l + r - 5) >> 1; ++l;
01626 
01627    seg[0].fX1 = 1+l; seg[0].fY1 = 0+t; seg[0].fX2 = 3+l; seg[0].fY2 = 0+t;
01628    seg[1].fX1 = 0+l; seg[1].fY1 = 1+t; seg[1].fX2 = 4+l; seg[1].fY2 = 1+t;
01629    seg[2].fX1 = 0+l; seg[2].fY1 = 2+t; seg[2].fX2 = 4+l; seg[2].fY2 = 2+t;
01630    seg[3].fX1 = 0+l; seg[3].fY1 = 3+t; seg[3].fX2 = 4+l; seg[3].fY2 = 3+t;
01631    seg[4].fX1 = 1+l; seg[4].fY1 = 4+t; seg[4].fX2 = 3+l; seg[4].fY2 = 4+t;
01632 
01633    gVirtualX->DrawSegments(fId, gc, seg, 5);
01634 }
01635 
01636 //______________________________________________________________________________
01637 void TGPopupMenu::DefaultEntry(Int_t id)
01638 {
01639    // Set default entry (default entries are drawn with bold text).
01640 
01641    TGMenuEntry *ptr;
01642    TIter next(fEntryList);
01643 
01644    while ((ptr = (TGMenuEntry *) next())) {
01645       if (ptr->fEntryId == id)
01646          ptr->fStatus |= kMenuDefaultMask;
01647       else
01648          ptr->fStatus &= ~kMenuDefaultMask;
01649    }
01650 }
01651 
01652 //______________________________________________________________________________
01653 void TGPopupMenu::EnableEntry(Int_t id)
01654 {
01655    // Enable entry. By default entries are enabled.
01656 
01657    TGMenuEntry *ptr;
01658    TIter next(fEntryList);
01659 
01660    while ((ptr = (TGMenuEntry *) next()))
01661       if (ptr->fEntryId == id) {
01662          ptr->fStatus |= kMenuEnableMask;
01663          if (ptr->fStatus & kMenuHideMask) {
01664             ptr->fStatus &= ~kMenuHideMask;
01665             Reposition();
01666          }
01667          break;
01668       }
01669 }
01670 
01671 //______________________________________________________________________________
01672 void TGPopupMenu::DisableEntry(Int_t id)
01673 {
01674    // Disable entry (disabled entries appear in a sunken relieve).
01675 
01676    TGMenuEntry *ptr;
01677    TIter next(fEntryList);
01678 
01679    while ((ptr = (TGMenuEntry *) next()))
01680       if (ptr->fEntryId == id) { ptr->fStatus &= ~kMenuEnableMask; break; }
01681 }
01682 
01683 //______________________________________________________________________________
01684 Bool_t TGPopupMenu::IsEntryEnabled(Int_t id)
01685 {
01686    // Return true if menu entry is enabled.
01687 
01688    TGMenuEntry *ptr;
01689    TIter next(fEntryList);
01690 
01691    while ((ptr = (TGMenuEntry *) next()))
01692       if (ptr->fEntryId == id)
01693          return (ptr->fStatus & kMenuEnableMask) ? kTRUE : kFALSE;
01694    return kFALSE;
01695 }
01696 
01697 //______________________________________________________________________________
01698 void TGPopupMenu::HideEntry(Int_t id)
01699 {
01700    // Hide entry (hidden entries are not shown in the menu).
01701    // To enable a hidden entry call EnableEntry().
01702 
01703    TGMenuEntry *ptr;
01704    TIter next(fEntryList);
01705 
01706    while ((ptr = (TGMenuEntry *) next()))
01707       if (ptr->fEntryId == id) {
01708          ptr->fStatus |=  kMenuHideMask;
01709          ptr->fStatus &= ~kMenuEnableMask;
01710          Reposition();
01711          break;
01712       }
01713 }
01714 
01715 //______________________________________________________________________________
01716 Bool_t TGPopupMenu::IsEntryHidden(Int_t id)
01717 {
01718    // Return true if menu entry is hidden.
01719 
01720    TGMenuEntry *ptr;
01721    TIter next(fEntryList);
01722 
01723    while ((ptr = (TGMenuEntry *) next()))
01724       if (ptr->fEntryId == id)
01725          return (ptr->fStatus & kMenuHideMask) ? kTRUE : kFALSE;
01726    return kFALSE;
01727 }
01728 
01729 //______________________________________________________________________________
01730 void TGPopupMenu::CheckEntry(Int_t id)
01731 {
01732    // Check a menu entry (i.e. add a check mark in front of it).
01733 
01734    TGMenuEntry *ptr;
01735    TIter next(fEntryList);
01736 
01737    while ((ptr = (TGMenuEntry *) next()))
01738       if (ptr->fEntryId == id) { ptr->fStatus |= kMenuCheckedMask; break; }
01739 }
01740 
01741 //______________________________________________________________________________
01742 void TGPopupMenu::CheckEntryByData(void *user_data)
01743 {
01744    // Check a menu entry (i.e. add a check mark in front of it).
01745    // The input argument is user data associated with entry
01746 
01747    TGMenuEntry *ptr;
01748    TIter next(fEntryList);
01749 
01750    while ((ptr = (TGMenuEntry *) next()))
01751       if (ptr->fUserData == user_data) { ptr->fStatus |= kMenuCheckedMask; break; }
01752 }
01753 
01754 //______________________________________________________________________________
01755 void TGPopupMenu::UnCheckEntry(Int_t id)
01756 {
01757    // Uncheck menu entry (i.e. remove check mark).
01758 
01759    TGMenuEntry *ptr;
01760    TIter next(fEntryList);
01761 
01762    while ((ptr = (TGMenuEntry *) next()))
01763       if (ptr->fEntryId == id) { ptr->fStatus &= ~kMenuCheckedMask; break; }
01764 }
01765 
01766 //______________________________________________________________________________
01767 void TGPopupMenu::UnCheckEntries()
01768 {
01769    // Uncheck all entries.
01770 
01771    TGMenuEntry *ptr;
01772    TIter next(fEntryList);
01773 
01774    while ((ptr = (TGMenuEntry *) next())) {
01775       ptr->fStatus &= ~kMenuCheckedMask;
01776    }
01777 }
01778 
01779 //______________________________________________________________________________
01780 void TGPopupMenu::UnCheckEntryByData(void *user_data)
01781 {
01782    // Uncheck a menu entry (i.e. remove check mark in front of it).
01783    // The input argument is user data associated with entry
01784 
01785    TGMenuEntry *ptr;
01786    TIter next(fEntryList);
01787 
01788    while ((ptr = (TGMenuEntry *) next()))
01789       if (ptr->fUserData == user_data) { ptr->fStatus  &= ~kMenuCheckedMask; break; }
01790 }
01791 
01792 //______________________________________________________________________________
01793 Bool_t TGPopupMenu::IsEntryChecked(Int_t id)
01794 {
01795    // Return true if menu item is checked.
01796 
01797    TGMenuEntry *ptr;
01798    TIter next(fEntryList);
01799 
01800    while ((ptr = (TGMenuEntry *) next()))
01801       if (ptr->fEntryId == id)
01802          return (ptr->fStatus & kMenuCheckedMask) ? kTRUE : kFALSE;
01803    return kFALSE;
01804 }
01805 
01806 //______________________________________________________________________________
01807 void TGPopupMenu::RCheckEntry(Int_t id, Int_t IDfirst, Int_t IDlast)
01808 {
01809    // Radio-select entry (note that they cannot be unselected,
01810    // the selection must be moved to another entry instead).
01811 
01812    TGMenuEntry *ptr;
01813    TIter next(fEntryList);
01814 
01815    while ((ptr = (TGMenuEntry *) next()))
01816       if (ptr->fEntryId == id)
01817          ptr->fStatus |= kMenuRadioMask | kMenuRadioEntryMask;
01818       else
01819          if (ptr->fEntryId >= IDfirst && ptr->fEntryId <= IDlast) {
01820             ptr->fStatus &= ~kMenuRadioMask;
01821             ptr->fStatus |=  kMenuRadioEntryMask;
01822          }
01823 }
01824 
01825 //______________________________________________________________________________
01826 Bool_t TGPopupMenu::IsEntryRChecked(Int_t id)
01827 {
01828    // Return true if menu item has radio check mark.
01829 
01830    TGMenuEntry *ptr;
01831    TIter next(fEntryList);
01832 
01833    while ((ptr = (TGMenuEntry *) next()))
01834       if (ptr->fEntryId == id)
01835          return (ptr->fStatus & kMenuRadioMask) ? kTRUE : kFALSE;
01836    return kFALSE;
01837 }
01838 
01839 //______________________________________________________________________________
01840 TGMenuEntry *TGPopupMenu::GetEntry(Int_t id)
01841 {
01842    // Find entry with specified id. Use the returned entry in DeleteEntry()
01843    // or as the "before" item in the AddXXXX() methods. Returns 0 if entry
01844    // is not found. To find entries that don't have an id like the separators,
01845    // use the GetListOfEntries() method to get the complete entry
01846    // list and iterate over it and check the type of each entry
01847    // to find the separators.
01848 
01849    TGMenuEntry *ptr;
01850    TIter next(fEntryList);
01851 
01852    while ((ptr = (TGMenuEntry *) next()))
01853       if (ptr->fEntryId == id)
01854          return ptr;
01855    return 0;
01856 }
01857 
01858 //______________________________________________________________________________
01859 TGMenuEntry *TGPopupMenu::GetEntry(const char *s)
01860 {
01861    // Find entry with specified name. Name must match the original
01862    // name without hot key symbol, like "Print" and not "&Print".
01863    // Use the returned entry in DeleteEntry() or as the "before" item
01864    // in the AddXXXX() methods. Returns 0 if entry is not found.
01865    // To find entries that don't have a name like the separators,
01866    // use the GetListOfEntries() method to get the complete entry
01867    // list and iterate over it and check the type of each entry
01868    // to find the separators.
01869 
01870    return (TGMenuEntry*) fEntryList->FindObject(s);
01871 }
01872 
01873 //______________________________________________________________________________
01874 void TGPopupMenu::DeleteEntry(Int_t id)
01875 {
01876    // Delete entry with specified id from menu.
01877 
01878    TGMenuEntry *ptr;
01879    TIter next(fEntryList);
01880 
01881    while ((ptr = (TGMenuEntry *) next()))
01882       if (ptr->fEntryId == id) {
01883          fEntryList->Remove(ptr);
01884          delete ptr;
01885          Reposition();
01886          if (fCurrent == ptr)
01887             fCurrent = 0;
01888          return;
01889       }
01890 }
01891 
01892 //______________________________________________________________________________
01893 void TGPopupMenu::DeleteEntry(TGMenuEntry *entry)
01894 {
01895    // Delete specified entry from menu.
01896 
01897    TGMenuEntry *ptr;
01898    TIter next(fEntryList);
01899 
01900    while ((ptr = (TGMenuEntry *) next()))
01901       if (ptr == entry) {
01902          fEntryList->Remove(ptr);
01903          delete ptr;
01904          Reposition();
01905          if (fCurrent == ptr)
01906             fCurrent = 0;
01907          return;
01908       }
01909 }
01910 
01911 //______________________________________________________________________________
01912 const TGGC &TGPopupMenu::GetDefaultGC()
01913 {
01914    // Return default graphics context.
01915 
01916    if (!fgDefaultGC)
01917       fgDefaultGC = gClient->GetResourcePool()->GetFrameGC();
01918    return *fgDefaultGC;
01919 }
01920 
01921 //______________________________________________________________________________
01922 const TGGC &TGPopupMenu::GetDefaultSelectedGC()
01923 {
01924    // Return the selection graphics context in use.
01925 
01926    if (!fgDefaultSelectedGC)
01927       fgDefaultSelectedGC = gClient->GetResourcePool()->GetSelectedGC();
01928    return *fgDefaultSelectedGC;
01929 }
01930 
01931 //______________________________________________________________________________
01932 const TGGC &TGPopupMenu::GetDefaultSelectedBackgroundGC()
01933 {
01934    // Return the selection background graphics context in use.
01935 
01936    if (!fgDefaultSelectedBackgroundGC)
01937       fgDefaultSelectedBackgroundGC = gClient->GetResourcePool()->GetSelectedBckgndGC();
01938    return *fgDefaultSelectedBackgroundGC;
01939 }
01940 
01941 //______________________________________________________________________________
01942 FontStruct_t TGPopupMenu::GetDefaultFontStruct()
01943 {
01944    // Return the default font structure in use.
01945 
01946    if (!fgDefaultFont)
01947       fgDefaultFont = gClient->GetResourcePool()->GetMenuFont();
01948    return fgDefaultFont->GetFontStruct();
01949 }
01950 
01951 //______________________________________________________________________________
01952 FontStruct_t TGPopupMenu::GetHilightFontStruct()
01953 {
01954    // Return the font structure in use for highlighted menu entries.
01955 
01956    if (!fgHilightFont)
01957       fgHilightFont = gClient->GetResourcePool()->GetMenuHiliteFont();
01958    return fgHilightFont->GetFontStruct();
01959 }
01960 
01961 
01962 //////////////////////////////////////////////////////////////////////////
01963 //                                                                      //
01964 // TGMenuTitle member functions.                                        //
01965 //                                                                      //
01966 //////////////////////////////////////////////////////////////////////////
01967 
01968 //______________________________________________________________________________
01969 TGMenuTitle::TGMenuTitle(const TGWindow *p, TGHotString *s, TGPopupMenu *menu,
01970                          GContext_t norm, FontStruct_t font, UInt_t options)
01971     : TGFrame(p, 1, 1, options)
01972 {
01973    // Create a menu title. This object is created by a menu bar when adding
01974    // a popup menu. The menu title adopts the hotstring.
01975 
01976    fLabel      = s;
01977    fMenu       = menu;
01978    fFontStruct = font;
01979    fSelGC      = GetDefaultSelectedGC()();
01980    fNormGC     = norm;
01981    fState      = kFALSE;
01982    fTitleId    = -1;
01983    fTextColor  = GetForeground();
01984 
01985    Int_t hotchar;
01986    if (s && (hotchar = s->GetHotChar()) != 0)
01987       fHkeycode = gVirtualX->KeysymToKeycode(hotchar);
01988    else
01989       fHkeycode = 0;
01990 
01991    UInt_t tw = 0;
01992    Int_t  max_ascent, max_descent;
01993    if (fLabel)
01994       tw = gVirtualX->TextWidth(fFontStruct, fLabel->GetString(), fLabel->GetLength());
01995    gVirtualX->GetFontProperties(fFontStruct, max_ascent, max_descent);
01996 
01997    Resize(tw + 8, max_ascent + max_descent + 7);
01998 
01999    if (p && p->InheritsFrom(TGMenuBar::Class())) {
02000       TGMenuBar *bar = (TGMenuBar*)p;
02001       fMenu->SetMenuBar(bar);
02002    }
02003 }
02004 
02005 //______________________________________________________________________________
02006 void TGMenuTitle::SetState(Bool_t state)
02007 {
02008    // Set state of menu title.
02009 
02010    fState = state;
02011    if (state) {
02012       if (fMenu != 0) {
02013          Int_t    ax, ay;
02014          Window_t wdummy;
02015 
02016          gVirtualX->TranslateCoordinates(fId, (fMenu->GetParent())->GetId(),
02017                                          0, 0, ax, ay, wdummy);
02018 
02019          // place the menu just under the window:
02020          fMenu->PlaceMenu(ax-1, ay+fHeight, kTRUE, kFALSE); //kTRUE);
02021       }
02022    } else {
02023       if (fMenu != 0) {
02024          fTitleId = fMenu->EndMenu(fTitleData);
02025       }
02026    }
02027    fOptions &= ~(kSunkenFrame | kRaisedFrame);
02028    fClient->NeedRedraw(this);
02029 }
02030 
02031 //______________________________________________________________________________
02032 void TGMenuTitle::DoRedraw()
02033 {
02034    // Draw a menu title.
02035 
02036    TGFrame::DoRedraw();
02037 
02038    int x, y, max_ascent, max_descent;
02039    x = y = 4;
02040 
02041    gVirtualX->GetFontProperties(fFontStruct, max_ascent, max_descent);
02042 
02043    if (fState) {
02044       gVirtualX->SetForeground(fNormGC, GetDefaultSelectedBackground());
02045       gVirtualX->FillRectangle(fId,fNormGC, 0, 0, fWidth, fHeight);
02046       gVirtualX->SetForeground(fNormGC, GetForeground());
02047       fLabel->Draw(fId, fSelGC, x, y + max_ascent);
02048    } else {
02049       // Use same background color than the menu bar
02050       Pixel_t back = GetDefaultFrameBackground();
02051       if (fMenu && fMenu->fMenuBar && fMenu->fMenuBar->GetBackground() != back)
02052          back = fMenu->fMenuBar->GetBackground();
02053       gVirtualX->SetForeground(fNormGC, back);
02054       gVirtualX->FillRectangle(fId,fNormGC, 0, 0, fWidth, fHeight);
02055       gVirtualX->SetForeground(fNormGC, fTextColor);
02056       fLabel->Draw(fId, fNormGC, x, y + max_ascent);
02057       if (fTextColor != GetForeground())
02058          gVirtualX->SetForeground(fNormGC, GetForeground());
02059    }
02060 }
02061 
02062 //______________________________________________________________________________
02063 void TGMenuTitle::DoSendMessage()
02064 {
02065    // Send final selected menu item to be processed.
02066 
02067    if (fMenu)
02068       if (fTitleId != -1) {
02069          SendMessage(fMenu->fMsgWindow, MK_MSG(kC_COMMAND, kCM_MENU), fTitleId,
02070                      (Long_t)fTitleData);
02071          fMenu->Activated(fTitleId);
02072       }
02073 }
02074 
02075 //______________________________________________________________________________
02076 FontStruct_t TGMenuTitle::GetDefaultFontStruct()
02077 {
02078    // Return default font structure in use.
02079 
02080    if (!fgDefaultFont)
02081       fgDefaultFont = gClient->GetResourcePool()->GetMenuFont();
02082    return fgDefaultFont->GetFontStruct();
02083 }
02084 
02085 //______________________________________________________________________________
02086 const TGGC &TGMenuTitle::GetDefaultGC()
02087 {
02088    // Return default graphics context in use.
02089 
02090    if (!fgDefaultGC)
02091       fgDefaultGC = gClient->GetResourcePool()->GetFrameGC();
02092    return *fgDefaultGC;
02093 }
02094 
02095 //______________________________________________________________________________
02096 const TGGC &TGMenuTitle::GetDefaultSelectedGC()
02097 {
02098    // Return default selection graphics context in use.
02099 
02100    if (!fgDefaultSelectedGC)
02101       fgDefaultSelectedGC = gClient->GetResourcePool()->GetSelectedGC();
02102    return *fgDefaultSelectedGC;
02103 }
02104 
02105 //______________________________________________________________________________
02106 void TGPopupMenu::SavePrimitive(ostream &out, Option_t *option /*= ""*/)
02107 {
02108    // Save a popup menu widget as a C++ statement(s) on output stream out.
02109 
02110    char quote = '"';
02111 
02112    out << "   TGPopupMenu *";
02113    out << GetName() << " = new TGPopupMenu(gClient->GetDefaultRoot()"
02114        << "," << GetWidth() << "," << GetHeight() << "," << GetOptionString() << ");" << endl;
02115 
02116    Bool_t hasradio = kFALSE;
02117    Int_t r_first, r_last, r_active;
02118    r_active = r_first = r_last = -1;
02119 
02120    TGMenuEntry *mentry;
02121    TIter next(GetListOfEntries());
02122 
02123    while ((mentry = (TGMenuEntry *) next())) {
02124       const char *text;
02125       Int_t i, lentext, hotpos;
02126       char shortcut[80];
02127       char *outext;
02128 
02129       switch (mentry->GetType()) {
02130          case kMenuEntry:
02131             text = mentry->GetName();
02132             lentext = mentry->fLabel->GetLength();
02133             hotpos = mentry->fLabel->GetHotPos();
02134             outext = new char[lentext+2];
02135             i=0;
02136             while (lentext) {
02137                if (i == hotpos-1) {
02138                   outext[i] = '&';
02139                   i++;
02140                }
02141                outext[i] = *text;
02142                i++; text++; lentext--;
02143             }
02144             outext[i]=0;
02145             if (mentry->fShortcut) {
02146                snprintf(shortcut, 80, "\\t%s", mentry->GetShortcutText());
02147             }
02148             else {
02149                memset(shortcut, 0, 80);
02150             }
02151 
02152             out << "   " << GetName() << "->AddEntry(" << quote
02153                 << gSystem->ExpandPathName(gSystem->UnixPathName(outext)) // can be a file name
02154                 << shortcut
02155                 << quote << "," << mentry->GetEntryId();
02156             if (mentry->fUserData) {
02157                out << "," << mentry->fUserData;
02158             }
02159             if (mentry->fPic) {
02160                out << ",gClient->GetPicture(" << quote
02161                    << gSystem->ExpandPathName(gSystem->UnixPathName(mentry->fPic->GetName()))
02162                    << quote << ")";
02163             }
02164             out << ");" << endl;
02165             delete [] outext;
02166             break;
02167          case kMenuPopup:
02168             out << endl;
02169             out << "   // cascaded menu " << quote << mentry->GetName() << quote <<endl;
02170             mentry->fPopup->SavePrimitive(out, option);
02171             text = mentry->GetName();
02172             lentext = mentry->fLabel->GetLength();
02173             hotpos = mentry->fLabel->GetHotPos();
02174             outext = new char[lentext+2];
02175             i=0;
02176             while (lentext) {
02177                if (i == hotpos-1) {
02178                   outext[i] = '&';
02179                   i++;
02180                }
02181                outext[i] = *text;
02182                i++; text++; lentext--;
02183             }
02184             outext[i]=0;
02185 
02186             out << "   " << GetName() << "->AddPopup(" << quote
02187                 << outext << quote << "," << mentry->fPopup->GetName()
02188                 << ");" << endl;
02189             delete [] outext;
02190             break;
02191          case kMenuLabel:
02192             out << "   " << GetName() << "->AddLabel(" << quote
02193                 << mentry->GetName() << quote;
02194             if (mentry->fPic) {
02195                out << ",gClient->GetPicture(" << quote
02196                    << mentry->fPic->GetName()
02197                    << quote << ")";
02198             }
02199             out << ");" << endl;
02200             break;
02201          case kMenuSeparator:
02202             out << "   " << GetName() << "->AddSeparator();" << endl;
02203             break;
02204       }
02205 
02206       if (!(mentry->GetStatus() & kMenuEnableMask)) {
02207          out<< "   " << GetName() << "->DisableEntry(" << mentry->GetEntryId()
02208             << ");" << endl;
02209       }
02210       if (mentry->GetStatus() & kMenuHideMask) {
02211          out<< "   " << GetName() << "->HideEntry(" << mentry->GetEntryId()
02212             << ");" << endl;
02213       }
02214       if (mentry->GetStatus() & kMenuCheckedMask) {
02215          out<< "   " << GetName() << "->CheckEntry(" << mentry->GetEntryId()
02216             << ");" << endl;
02217       }
02218       if (mentry->GetStatus() & kMenuDefaultMask) {
02219          out<< "   "<< GetName() << "->DefaultEntry(" << mentry->GetEntryId()
02220             << ");" << endl;
02221       }
02222       if (mentry->GetStatus() & kMenuRadioEntryMask) {
02223          if (hasradio) {
02224             r_last = mentry->GetEntryId();
02225             if (IsEntryRChecked(mentry->GetEntryId())) r_active = mentry->GetEntryId();
02226          }
02227          else {
02228             r_first = mentry->GetEntryId();
02229             hasradio = kTRUE;
02230             if (IsEntryRChecked(mentry->GetEntryId())) r_active = mentry->GetEntryId();
02231          }
02232       } else if (hasradio) {
02233          out << "   " << GetName() << "->RCheckEntry(" << r_active << "," << r_first
02234              << "," << r_last << ");" << endl;
02235          hasradio = kFALSE;
02236          r_active = r_first = r_last = -1;
02237       }
02238    }
02239 }
02240 
02241 //______________________________________________________________________________
02242 void TGMenuTitle::SavePrimitive(ostream &out, Option_t *option /*= ""*/)
02243 {
02244     // Save a title menu widget as a C++ statement(s) on output stream out.
02245 
02246    char quote = '"';
02247 
02248    out << endl;
02249    out << "   // " << quote << fLabel->GetString() << quote <<" menu" << endl;
02250 
02251    fMenu->SavePrimitive(out, option);
02252 
02253    const char *text = fLabel->GetString();
02254    Int_t lentext = fLabel->GetLength();
02255    Int_t hotpos = fLabel->GetHotPos();
02256    char *outext = new char[lentext+2];
02257    Int_t i=0;
02258    while (lentext) {
02259       if (i == hotpos-1) {
02260          outext[i] = '&';
02261          i++;
02262       }
02263       outext[i] = *text;
02264       i++; text++; lentext--;
02265    }
02266    outext[i]=0;
02267    out << "   " << fParent->GetName() << "->AddPopup(" << quote << outext
02268        << quote << "," << fMenu->GetName();
02269 
02270    delete [] outext;
02271 }
02272 
02273 //______________________________________________________________________________
02274 void TGMenuBar::SavePrimitive(ostream &out, Option_t *option /*= ""*/)
02275 {
02276     // Save a menu bar widget as a C++ statement(s) on output stream out.
02277 
02278    out << endl;
02279    out << "   // menu bar" << endl;
02280 
02281    out << "   TGMenuBar *";
02282    out << GetName() << " = new TGMenuBar(" << fParent->GetName()
02283        << "," << GetWidth() << "," << GetHeight() << "," << GetOptionString() << ");" << endl;
02284    if (option && strstr(option, "keep_names"))
02285       out << "   " << GetName() << "->SetName(\"" << GetName() << "\");" << endl;
02286 
02287    if (!fList) return;
02288 
02289    TGFrameElement *el;
02290    TIter next(fList);
02291 
02292    while ((el = (TGFrameElement *)next())) {
02293       el->fFrame->SavePrimitive(out, option);
02294       el->fLayout->SavePrimitive(out, option);
02295       out << ");" << endl;
02296    }
02297 }

Generated on Tue Jul 5 14:22:02 2011 for ROOT_528-00b_version by  doxygen 1.5.1