Back to index

plt-scheme  4.2.1
MenuBar.cc
Go to the documentation of this file.
00001 /*                                                      -*- C++ -*-
00002  *
00003  * Purpose: menu bar class
00004  *
00005  * Authors: Markus Holzem and Julian Smart
00006  *
00007  * Copyright: (C) 2004-2009 PLT Scheme Inc.
00008  * Copyright: (C) 1995, AIAI, University of Edinburgh (Julian)
00009  * Copyright: (C) 1995, GNU (Markus)
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00024  * 02110-1301 USA.
00025  */
00026 
00027 #ifdef __GNUG__
00028 #pragma implementation "MenuBar.h"
00029 #endif
00030 
00031 #define  Uses_XtIntrinsic
00032 #define  Uses_wxLayout
00033 #define  Uses_wxMenuBar
00034 #include "wx.h"
00035 #define  Uses_EnforcerWidget
00036 #define  Uses_MenuWidget
00037 #include "widgets.h"
00038 
00039 //-----------------------------------------------------------------------------
00040 // constructor and destructor
00041 //-----------------------------------------------------------------------------
00042 
00043 wxMenuBar::wxMenuBar(void) : wxItem(NULL)
00044 {
00045     __type = wxTYPE_MENU_BAR;
00046 
00047     top = topdummy = help = last = 0;
00048     // if a title is associated with a menu, it may not be removed
00049     Append(NULL, NULL); // to have something if associated to frame
00050     topdummy = top;
00051 }
00052 
00053 wxMenuBar::~wxMenuBar(void)
00054 {
00055     menu_item *item = (menu_item*)top;
00056 
00057     while (item) {
00058        menu_item *temp = item;
00059        item = item->next;
00060        if (temp->contents) { // has submenu?
00061          wxMenu *mnu;
00062 
00063          FREE_MENU_STRING(temp->label);
00064          FREE_MENU_STRING(temp->help_text);
00065 
00066          mnu = EXTRACT_TOP_MENU(temp);
00067 #ifdef MZ_PRECISE_GC
00068          children->DeleteObject(mnu);
00069 #endif
00070          DELETE_OBJ mnu; 
00071          FREE_TOP_POINTER(temp->user_data);
00072        }
00073        FREE_MENU_ITEM(temp);
00074     }
00075 }
00076 
00077 //-----------------------------------------------------------------------------
00078 // create and destroy menubar
00079 //-----------------------------------------------------------------------------
00080 
00081 Bool wxMenuBar::Create(wxPanel *panel)
00082 {
00083     int ph, pw;
00084     Dimension hh, ww;
00085     wxWindow_Xintern *parenth;
00086     Widget wgt;
00087 
00088     ChainToPanel(panel, 0, "menubar");
00089 
00090     parenth = panel->GetHandle();
00091 
00092     // create widgets
00093     wgt = XtVaCreateManagedWidget
00094        ("menubar", xfwfEnforcerWidgetClass, parenth->handle,
00095         XtNtraversalOn, FALSE, XtNhighlightThickness, 0,
00096         NULL);
00097     X->frame = wgt;
00098     wgt = XtVaCreateWidget
00099        ("menubar", menuWidgetClass, X->frame,
00100         XtNbackground,  wxGREY_PIXEL,
00101         XtNforeground,  wxBLACK_PIXEL,
00102         XtNhighlightPixel,  wxCTL_HIGHLIGHT_PIXEL,
00103         XtNhMargin,     4,
00104         XtNfont,        font->GetInternalFont(),
00105 #ifdef WX_USE_XFT
00106         XtNmenuXftFont, font->GetInternalAAFont(),
00107 #endif
00108         XtNmenu,        top,
00109         XtNcursor,      None,
00110         NULL);
00111     X->handle = wgt;
00112     // callbacks
00113     XtAddCallback(X->handle, XtNonSelect,  wxMenuBar::CommandEventCallback, saferef);
00114     XtAddCallback(X->handle, XtNonNewItem, wxMenuBar::SelectEventCallback, saferef);
00115 
00116     // Panel width needed
00117     panel->GetSize(&pw, &ph);
00118 
00119     // position menubar
00120     XtVaGetValues(X->handle, XtNheight, &hh, XtNwidth, &ww, NULL);
00121     ww = pw;
00122     XtVaSetValues(X->frame,  XtNheight,  hh, XtNwidth,  ww, NULL);
00123     wxLC_MEM(constraints->top, Absolute(-hh));
00124     wxLC_MEM(constraints->left, Absolute(0));
00125     wxLC_MEM(constraints->width, SameAs(panel->GetWinSafeRef(), wxWidth, 0));
00126     wxLC_MEM(constraints->height, Absolute(hh));
00127 
00128     // menubar may now be managed
00129     XtManageChild(X->handle);
00130     AddEventHandlers();
00131 
00132     return TRUE;
00133 }
00134 
00135 void wxMenuBar::Destroy(void)
00136 {
00137     if (parent)    parent->RemoveChild(this);
00138     if (X->frame)  XtDestroyWidget(X->frame);
00139     parent = NULL;
00140     X->frame = X->handle = 0;
00141 }
00142 
00143 //-----------------------------------------------------------------------------
00144 // add items to menu
00145 //-----------------------------------------------------------------------------
00146 
00147 void wxMenuBar::Append(wxMenu *menu, char *title)
00148 {
00149     menu_item *item = 0;
00150     void *tm;
00151     char *ms;
00152 
00153     if (!menu || !title) // I need menu and title
00154        return;
00155 
00156     /* MATTHEW: enforce safety */
00157     if (menu->owner)
00158       return;
00159 
00160     Stop();
00161 
00162     // create new menu item or use topdummy
00163     if (topdummy) {
00164       item = (menu_item*)topdummy;
00165       FREE_MENU_STRING(item->label);
00166       FREE_TOP_POINTER(item->user_data);
00167       topdummy = 0;
00168     } else {
00169       item = MALLOC_MENU_ITEM();
00170     }
00171     // initialize menu_item
00172     wxGetLabelAndKey(title, &item->label, &item->key_binding);
00173     ms = MAKE_MENU_STRING(item->label);
00174     item->label     = ms;
00175     item->help_text = NULL;
00176     item->ID        = -1; 
00177     item->enabled   = TRUE;
00178     item->set       = FALSE;
00179     item->contents  = (menu_item*)menu->top;
00180     menu->owner     = (wxMenuItem **)item;
00181     item->next      = NULL;
00182     tm = BUNDLE_TOP_MENU(menu);
00183     item->user_data = tm;
00184 #ifdef MZ_PRECISE_GC
00185     children->Append(menu);
00186 #endif
00187 #if 0
00188     /* This "Help"-detection code has been disabled: */
00189     {
00190       _e_menu_item_type t;
00191       t = (!strcmp(item->label, "Help")) ? MENU_HELP : MENU_CASCADE;
00192       item->type    = t;
00193     }
00194 #else
00195     item->type    = MENU_CASCADE;
00196 #endif
00197     // chain or initialize menu_item list
00198     if (last) {
00199       menu_item *prev = (menu_item*)last;
00200       prev->next = item;
00201       item->prev = prev;
00202       last = (wxMenuItem*)item;
00203     } else {
00204       top = last = (wxMenuItem*)item;
00205       item->prev = NULL;
00206     }
00207     if (X->handle) { // redisplay if menu added
00208       XtVaSetValues(X->handle, XtNmenu, top, XtNrefresh, True, NULL);
00209     }
00210 }
00211 
00212 Bool wxMenuBar::Delete(wxMenu *menu, int pos)
00213 {
00214   menu_item *i;
00215   int counter;
00216 
00217   if (!menu && (pos < 0))
00218     return FALSE;
00219 
00220   for (i = (menu_item *)top, counter = 0; 
00221        i && ((menu && (EXTRACT_TOP_MENU(i) != menu))
00222             || (!menu && (counter < pos)));
00223        counter++) {
00224     i = i->next;
00225   }
00226 
00227   if (i) {
00228     Stop();
00229 
00230     if (i == (menu_item *)top)
00231       top = (wxMenuItem *)i->next;
00232     if (i == (menu_item *)last)
00233       last = (wxMenuItem *)i->prev;
00234     if (i->prev)
00235       i->prev->next = i->next;
00236     if (i->next)
00237       i->next->prev = i->prev;
00238     
00239     if (!top) {
00240       Append(NULL, NULL); // to have something if associated to frame
00241       topdummy = top;
00242     }
00243 
00244     if (i->contents) {
00245       wxMenu *mnu;
00246       FREE_MENU_STRING(i->label);
00247       FREE_MENU_STRING(i->help_text);
00248       /* Release menu: */
00249       mnu = EXTRACT_TOP_MENU(i);
00250       mnu->owner = NULL;
00251 #ifdef MZ_PRECISE_GC
00252       children->DeleteObject(mnu);
00253 #endif
00254       FREE_TOP_POINTER(i->user_data);
00255     }
00256 
00257     FREE_MENU_ITEM(i);
00258 
00259     if (X->handle) { // redisplay
00260       XtVaSetValues(X->handle, XtNmenu, top, XtNrefresh, True, NULL);
00261     }
00262 
00263     return TRUE;
00264   } else
00265     return FALSE;
00266 }
00267 
00268 int wxMenuBar::Number()
00269 {
00270   menu_item *i;
00271   int counter = 0;
00272 
00273   for (i = (menu_item *)top; i; i = i->next) {
00274     counter++;
00275   }
00276 
00277   if (counter && topdummy)
00278     --counter;
00279 
00280   return counter;
00281 }
00282 
00283 //-----------------------------------------------------------------------------
00284 // modify items
00285 //-----------------------------------------------------------------------------
00286 
00287 void wxMenuBar::Check(long id, Bool flag)
00288 {
00289     menu_item *found;
00290     found = (menu_item*)FindItemForId(id);
00291     if (found)
00292        found->set = flag;
00293 }
00294 
00295 Bool wxMenuBar::Checked(long id)
00296 {
00297     menu_item *found;
00298     found = (menu_item*)FindItemForId(id);
00299     if (found)
00300        return found->set;
00301     return FALSE;
00302 }
00303 
00304 void wxMenuBar::Enable(long id, Bool flag)
00305 {
00306     menu_item *found;
00307     found = (menu_item*)FindItemForId(id);
00308     if (found)
00309        found->enabled = flag;
00310 }
00311 
00312 void wxMenuBar::EnableTop(int pos, Bool flag)
00313 {
00314     menu_item *item = (menu_item*)top;
00315     int i;
00316 
00317     for (i=0; item && i<pos; ++i) {
00318        item = item->next;
00319     }
00320     if (item) {
00321       Stop();
00322       if (X->handle) {
00323        item->enabled = flag;
00324        XtVaSetValues(X->handle, XtNmenu, top, XtNrefresh, True, NULL);
00325       }
00326     }
00327 }
00328 
00329 char *wxMenuBar::GetHelpString(long id)
00330 {
00331     menu_item *found;
00332     found = (menu_item*)FindItemForId(id);
00333     if (found)
00334        return found->help_text;
00335     return NULL;
00336 }
00337 
00338 char *wxMenuBar::GetLabel(long id)
00339 {
00340     menu_item *found;
00341     found = (menu_item*)FindItemForId(id);
00342     if (found)
00343        return found->label;
00344     return NULL;
00345 }
00346 
00347 char *wxMenuBar::GetLabelTop(int pos)
00348 {
00349     menu_item *item = (menu_item*)top;
00350 
00351     for (int i=0; item && i<pos; ++i) {
00352        item = item->next;
00353     }
00354     if (item)
00355        return item->label;
00356     return NULL;
00357 }
00358 
00359 void wxMenuBar::SetHelpString(long id, char *help)
00360 {
00361   menu_item *found;
00362   found = (menu_item*)FindItemForId(id);
00363   if (found) {
00364     char *hs;
00365     hs = MAKE_MENU_STRING(help);
00366     found->help_text = hs;
00367   }
00368 }
00369 
00370 void wxMenuBar::SetLabel(long id, char *label)
00371 {
00372   menu_item *found;
00373   char *ms;
00374   found = (menu_item*)FindItemForId(id);
00375   if (found) {
00376     FREE_MENU_STRING(found->label);
00377     wxGetLabelAndKey(label, &found->label, &found->key_binding);
00378     ms = MAKE_MENU_STRING(found->label);
00379     found->label = ms;
00380   }
00381 }
00382 
00383 void wxMenuBar::SetLabelTop(int pos, char *label)
00384 {
00385     menu_item *item = (menu_item*)top;
00386     int i;
00387 
00388     for (i=0; item && i<pos; ++i) {
00389       item = item->next;
00390     }
00391     if (item) {
00392       char *ms;
00393       Stop();
00394       FREE_MENU_STRING(item->label);
00395       wxGetLabelAndKey(label, &item->label, &item->key_binding);
00396       ms = MAKE_MENU_STRING(item->label);
00397       item->label = ms;
00398       if (X->handle) { // redisplay if menu added
00399        XtVaSetValues(X->handle, XtNmenu, top, XtNrefresh, True, NULL);
00400       }
00401     }
00402 }
00403 
00404 //-----------------------------------------------------------------------------
00405 // find items by ID or by label
00406 //-----------------------------------------------------------------------------
00407 
00408 int wxMenuBar::FindMenuItem(char *menu, char *itemstring)
00409 {
00410     char *label, *key;
00411     int  answer = -1;
00412     menu_item *item;
00413 
00414     wxGetLabelAndKey(menu, &label, &key);
00415 
00416     for (item = (menu_item*)top; item; item=item->next) {
00417       if (!strcmp(item->label, label) && item->contents) {
00418        answer = EXTRACT_TOP_MENU(item)->FindItem(itemstring);
00419        break;
00420       }
00421     }
00422     DELETE_VAL label;
00423     return answer;
00424 }
00425 
00426 wxMenuItem *wxMenuBar::FindItemForId(long id, wxMenu **req_menu)
00427 {
00428     menu_item *answer=NULL;
00429 
00430     for (menu_item *item = (menu_item*)top; item; item=item->next) {
00431       if (item->contents)
00432        if ((answer = (menu_item *)(EXTRACT_TOP_MENU(item)->FindItemForId(id))))
00433          break; // found
00434     }
00435     if (req_menu)
00436       *req_menu = EXTRACT_TOP_MENU(answer);
00437     return ((wxMenuItem*)answer);
00438 }
00439 
00440 //-----------------------------------------------------------------------------
00441 // callbacks for wxMenuBar
00442 //-----------------------------------------------------------------------------
00443 
00444 void wxMenuBar::CommandEventCallback(Widget WXUNUSED(w),
00445                                  XtPointer dclient, XtPointer dcall)
00446 {
00447   wxMenuBar *menu  = (wxMenuBar *)GET_SAFEREF(dclient);
00448   menu_item *item  = (menu_item*)dcall;
00449 
00450   if (menu) {
00451     if (item->ID != -1) {
00452       if (item->type == MENU_TOGGLE)
00453        item->set = (!item->set);
00454       
00455       // call OnMenuCommandt of parent (usually of a frame)
00456       if (menu->parent)
00457        menu->parent->OnMenuCommand(item->ID);
00458     }
00459   }
00460 
00461 #ifdef MZ_PRECISE_GC
00462 # ifndef GC_STACK_CALLEE_RESTORE
00463   /* Stupid call forces creation of __gc_var_stack__: */
00464   if (menu) menu->GetParent();
00465   
00466   XFORM_RESET_VAR_STACK;
00467 # endif
00468 #endif
00469 }
00470 
00471 void wxMenuBar::SelectEventCallback(Widget WXUNUSED(w),
00472                                 XtPointer dclient, XtPointer dcall)
00473 {
00474   wxMenuBar *menu  = (wxMenuBar *)GET_SAFEREF(dclient);
00475   menu_item *item  = (menu_item*)dcall;
00476 
00477   if (menu) {  
00478     // call OnMenuSelect of parent (usually of a frame)
00479     if (menu->parent)
00480        menu->parent->OnMenuSelect(item->ID);
00481   }
00482 
00483 #ifdef MZ_PRECISE_GC
00484 # ifndef GC_STACK_CALLEE_RESTORE
00485   /* Stupid call forces creation of __gc_var_stack__: */
00486   if (menu) menu->GetParent();
00487   
00488   XFORM_RESET_VAR_STACK;
00489 # endif
00490 #endif
00491 }
00492 
00493 void wxMenuBar::Stop(void)
00494 {
00495   XtCallActionProc(X->handle, "select", NULL, NULL, 0);
00496 }
00497 
00498 extern "C" int xwMenuIsPoppedUp(Widget w);
00499 
00500 int wxMenuBar::InProgress(void)
00501 {
00502   return xwMenuIsPoppedUp(X->handle);
00503 }
00504 
00505 void wxMenuBar::SelectAMenu(wxMenu *at_menu)
00506 {
00507   GC_CAN_IGNORE XEvent xevent;
00508   Position x, y;
00509   int new_root_x, new_root_y, dx = 0;
00510   Window child;
00511 
00512   if (xwMenuIsPoppedUp(X->handle)) {
00513     Stop();
00514     return;
00515   }
00516 
00517   Stop();
00518 
00519   if (at_menu) {
00520     menu_item *i;
00521     for (i = (menu_item *)top; i; i = i->next) {
00522       if (EXTRACT_TOP_MENU(i) == at_menu) {
00523        dx = i->start;
00524        break;
00525       }
00526     }
00527   }
00528 
00529   /* Get the menu started: */
00530   XtVaGetValues(X->handle, XtNx, &x, XtNy, &y, NULL);
00531   {
00532     Display *disp;
00533     Window win;
00534     disp = XtDisplay(X->handle);
00535     win = XtWindow(X->handle);
00536     XTranslateCoordinates(disp, 
00537                        win, 
00538                        DefaultRootWindow(disp),
00539                        x, y, 
00540                        &new_root_x, &new_root_y, &child);
00541   }
00542 
00543   xevent.xmotion.x_root = new_root_x + 5 + dx;
00544   xevent.xmotion.x = 5 + dx;
00545   xevent.xmotion.y_root = new_root_y + 5;
00546   xevent.xmotion.y = 5;
00547   
00548   XtCallActionProc(X->handle, "start", &xevent, NULL, 0);
00549 }