/* +-------------------------------------------------------------------+ */ /* | Copyright 1992, 1993, David Koblas (koblas@netcom.com) | */ /* | | */ /* | Permission to use, copy, modify, and to distribute this software | */ /* | and its documentation for any purpose is hereby granted without | */ /* | fee, provided that the above copyright notice appear in all | */ /* | copies and that both that copyright notice and this permission | */ /* | notice appear in supporting documentation. There is no | */ /* | representations about the suitability of this software for | */ /* | any purpose. this software is provided "as is" without express | */ /* | or implied warranty. | */ /* | | */ /* +-------------------------------------------------------------------+ */ /* $Id: menu.c,v 1.17 2005/03/20 20:15:32 demailly Exp $ */ #include #include #include #include "xaw_incdir/MenuButton.h" #include "xaw_incdir/SimpleMenu.h" #include "xaw_incdir/SmeBSB.h" #include "xaw_incdir/SmeLine.h" #include "xaw_incdir/Form.h" #include "Paint.h" #include "menu.h" #include "misc.h" #include "xpaint.h" #include "bitmaps/xbm/checkmark.xbm" #include "bitmaps/xbm/pullright.xbm" #define MAX_GROUPS 4 typedef struct group_s { int size; Widget group[16]; struct group_s *next; } GroupList; typedef struct rightlist_s { Widget widget; Widget shell; struct rightlist_s *next; } RightList; static GroupList *groupHead = NULL; static RightList *rightHead = NULL; static Pixmap checkBitmap = None, pullBitmap = None; static void popupMainAction(Widget, XEvent *, String *, Cardinal *); static void pullRightAction(Widget, XEvent *, String *, Cardinal *); static GroupList * findGroup(Widget w) { GroupList *cur = groupHead; int i; if (w == None) return NULL; while (cur != NULL) { for (i = 0; i < cur->size; i++) if (cur->group[i] == w) return cur; cur = cur->next; } return NULL; } static void initMenu(Widget w) { static XtActionsRec act[] = { {"popup-main-menu", (XtActionProc) popupMainAction}, {"popup-menu-pullright", (XtActionProc) pullRightAction} }; if (checkBitmap != None) return; checkBitmap = XCreateBitmapFromData(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), (char *) checkmark_bits, checkmark_width, checkmark_height); pullBitmap = XCreateBitmapFromData(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), (char *) pullright_bits, pullright_width, pullright_height); XtAppAddActions(XtWidgetToApplicationContext(w), act, 2); } static void destroy(Widget w, XtPointer data, XtPointer junk) { XtFree((XtPointer) data); } static void popupMainAction(Widget w, XEvent * event, String * params, Cardinal * nparams) { String paramseq[] = { "popup-menu" }; WidgetList wlist; Widget editmenu; Position x, y; Dimension width; int zoom; if (strcmp(XtName(w), "paint") || ThereIsNoMenuBar() || IsFullPopup()) { mainpopup: XtCallActionProc(w, "MenuPopup", event, paramseq, 1); return; } wlist = None; XtVaGetValues(w, XtNmenuwidgets, &wlist, NULL); if (!wlist) goto mainpopup; if (!wlist[8]) goto mainpopup; XtVaGetValues(w, XtNzoom, &zoom, NULL); XtTranslateCoords(w, zoom*event->xbutton.x, zoom*event->xbutton.y, &x, &y); editmenu = GetShell(wlist[8]); XtVaGetValues(editmenu, XtNwidth, &width, NULL); XtMoveWidget(editmenu, x-width/2, y-8); XtPopup(editmenu, XtGrabNone); } static void pullRightAction(Widget w, XEvent * event, String * params, Cardinal * nparams) { Dimension width, height; int x, y; RightList *cur; Widget cw = XawSimpleMenuGetActiveEntry(w); if (cw == None || event->type != MotionNotify) return; x = event->xmotion.x; y = event->xmotion.y; XtVaGetValues(w, XtNwidth, &width, XtNheight, &height, NULL); if (x < 0 || x >= width || y < 0 || y >= height) return; /* ** Only the second half of the menu is sensitive to pulls */ if (x < width / 2) return; for (cur = rightHead; cur != NULL && cur->widget != cw; cur = cur->next); if (cur == NULL) return; x = event->xmotion.x_root - 20; y = event->xmotion.y_root - 20; XtVaSetValues(cur->shell, XtNx, x, XtNy, y, NULL); XtPopup(cur->shell, XtGrabNone); } static void closeparent(Widget w, XtPointer data, XtPointer junk) { if (strstr(XtName(XtParent(w)), "-right")) XtPopdown(XtParent(w)); if (strstr(XtName(XtParent(XtParent(w))), "popup-menu")) XtPopdown(XtParent(XtParent(w))); } static void createItem(Widget parent, PaintMenuItem * item, Widget groups[MAX_GROUPS]) { int grp = -1; Widget entry; int nargs = 0; Arg args[4]; if (item->name[0] == '\0') { entry = XtVaCreateManagedWidget("separator", smeLineObjectClass, parent, NULL); } else if (item->flags & MF_CHECK) { entry = XtVaCreateManagedWidget(item->name, smeBSBObjectClass, parent, XtNleftMargin, checkmark_width + 4, NULL); } else if (item->right != NULL && item->nright != 0) { int i; RightList *cur; String nm; entry = XtVaCreateManagedWidget(item->name, smeBSBObjectClass, parent, XtNrightMargin, pullright_width, XtNrightBitmap, pullBitmap, NULL); nm = (String) XtMalloc(strlen(XtName(parent)) + strlen(item->name) + 16); sprintf(nm, "%s-right", item->name); item->rightShell = XtVisCreatePopupShell(nm, simpleMenuWidgetClass, parent, args, nargs); XtAddCallback(item->rightShell, XtNdestroyCallback, destroy, (XtPointer) nm); for (i = 0; i < item->nright; i++) createItem(item->rightShell, &item->right[i], groups); cur = XtNew(RightList); cur->shell = item->rightShell; cur->widget = entry; cur->next = rightHead; rightHead = cur; } else { entry = XtVaCreateManagedWidget(item->name, smeBSBObjectClass, parent, NULL); } if (item->flags & MF_GROUP1) grp = 0; else if (item->flags & MF_GROUP2) grp = 1; else if (item->flags & MF_GROUP3) grp = 2; else if (item->flags & MF_GROUP4) grp = 3; if (grp != -1) { GroupList *c = findGroup(groups[grp]); if (c == NULL) { /* XXX GroupList entry leaked */ c = XtNew(GroupList); c->next = groupHead; groupHead = c; c->size = 0; groups[grp] = entry; } c->group[c->size++] = entry; } if ((item->flags & MF_CHECKON) == MF_CHECKON) XtVaSetValues(entry, XtNleftBitmap, checkBitmap, NULL); if (item->callback != NULL) XtAddCallback(entry, XtNcallback, (XtCallbackProc) item->callback, item->data); XtAddCallback(entry, XtNcallback, (XtCallbackProc) closeparent, item->data); item->widget = entry; } Widget MenuBarCreate(Widget parent, int nbar, PaintMenuBar bar[]) { int list, item; Widget button = None, menu; Widget prevButton = None; char menuPopupName[80]; int i; Widget groups[MAX_GROUPS]; Arg args[4]; int nargs; initMenu(parent); /* ** If there is more than one entry in this bar ** reparent it. */ if (nbar > 1) parent = XtVaCreateManagedWidget("menu", formWidgetClass, parent, XtNborderWidth, 0, XtNbottom, XtChainTop, XtNright, XtChainLeft, XtNleft, XtChainLeft, NULL); for (list = 0; list < nbar; list++) { char *nm; strcpy(menuPopupName, bar[list].name); strcat(menuPopupName, "Menu"); nm = XtNewString(menuPopupName); button = XtVaCreateManagedWidget(bar[list].name, menuButtonWidgetClass, parent, XtNmenuName, nm, XtNfromHoriz, prevButton, #ifdef XAW3D XtNhorizDistance, 2, XtNborderWidth, 0, #else XtNhorizDistance, 3, XtNborderWidth, 1, #endif NULL); XtAddCallback(button, XtNdestroyCallback, destroy, (XtPointer) nm); prevButton = button; nargs = 0; menu = XtVisCreatePopupShell(menuPopupName, simpleMenuWidgetClass, button, args, nargs); bar[list].widget = menu; for (i = 0; i < MAX_GROUPS; i++) groups[i] = None; for (item = 0; item < bar[list].nitems; item++) createItem(menu, &bar[list].items[item], groups); } return (nbar > 1) ? parent : button; } Widget MenuPopupCreate(Widget parent, char *name, int nitems, PaintMenuItem items[]) { static XtTranslations trans = None; Widget groups[MAX_GROUPS]; Widget menu; Arg args[4]; /* XtVisCreatePopupShell modified args internally */ int i, nargs = 0; for (i = 0; i < MAX_GROUPS; i++) groups[i] = None; initMenu(parent); menu = XtVisCreatePopupShell(name, simpleMenuWidgetClass, parent, args, nargs); if (trans == None) trans = XtParseTranslationTable( "Escape: MenuPopdown(popup-menu)\n" ": XawPositionSimpleMenu(popup-menu) popup-main-menu()"); XtOverrideTranslations(parent, trans); for (i = 0; i < nitems; i++) createItem(menu, &items[i], groups); return menu; } void MenuCheckItem(Widget w, Boolean flag) { GroupList *c; if (w == None) return; if ((c = findGroup(w)) != NULL) { int i; for (i = 0; i < c->size; i++) XtVaSetValues(c->group[i], XtNleftBitmap, None, NULL); } XtVaSetValues(w, XtNleftBitmap, flag ? checkBitmap : None, NULL); } Boolean IsItemChecked(Widget w) { Pixmap p; if (w == None) return False; XtVaGetValues(w, XtNleftBitmap, &p, NULL); return ( p != None); }