1 /**************************************************************************\
2 *
3 * This file is part of the Coin 3D visualization library.
4 * Copyright (C) by Kongsberg Oil & Gas Technologies.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * ("GPL") version 2 as published by the Free Software Foundation.
9 * See the file LICENSE.GPL at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using Coin with software that can not be combined with the GNU
13 * GPL, and for taking advantage of the additional benefits of our
14 * support services, please contact Kongsberg Oil & Gas Technologies
15 * about acquiring a Coin Professional Edition License.
16 *
17 * See http://www.coin3d.org/ for more information.
18 *
19 * Kongsberg Oil & Gas Technologies, Bygdoy Alle 5, 0257 Oslo, NORWAY.
20 * http://www.sim.no/ sales@sim.no coin-support@coin3d.org
21 *
22 \**************************************************************************/
23
24 #include <assert.h>
25 #include <stdio.h>
26
27 #include <Xm/RowColumn.h>
28 #include <Xm/SeparatoG.h>
29 #include <Xm/PushBG.h>
30 #include <Xm/ToggleBG.h>
31 #include <Xm/ToggleB.h>
32 #include <Xm/CascadeBG.h>
33
34 #include <Inventor/SoLists.h>
35 #include <Inventor/errors/SoDebugError.h>
36
37 #include <soxtdefs.h>
38 #include <Inventor/Xt/SoXt.h>
39 #include <Inventor/Xt/widgets/XtNativePopupMenu.h>
40
41 #define SOXT_POPUPMENU_DEBUG 0
42
43 // *************************************************************************
44
45 struct MenuRecord {
46 int menuid;
47 int pos;
48 char * name;
49 char * title;
50 Widget menu;
51 MenuRecord * parent;
52 }; // struct MenuRecord
53
54 struct ItemRecord {
55 int itemid;
56 int flags;
57 int pos;
58 char * name;
59 char * title;
60 Widget item;
61 MenuRecord * parent;
62 }; // struct ItemRecord
63
64 #define ITEM_MARKED 0x0001
65 #define ITEM_SEPARATOR 0x0002
66 #define ITEM_ENABLED 0x0004
67
68 // *************************************************************************
69
70 /*!
71 \class XtNativePopupMenu Inventor/Qt/widgets/XtNativePopupMenu.h
72 \brief The XtNativePopupMenu class implements a common interface for popup
73 menu management for all the Coin GUI toolkit libraries.
74 */
75
76 // *************************************************************************
77
XtNativePopupMenu(void)78 XtNativePopupMenu::XtNativePopupMenu(
79 void)
80 {
81 this->menus = new SbPList;
82 this->items = new SbPList;
83 this->dirty = TRUE;
84 this->popup = (Widget) NULL;
85 } // XtNativePopupMenu()
86
~XtNativePopupMenu(void)87 XtNativePopupMenu::~XtNativePopupMenu(// virtual
88 void)
89 {
90 const int numMenus = this->menus->getLength();
91 // QPopupMenu * popup = NULL;
92 int i;
93 for (i = 0; i < numMenus; i++) {
94 MenuRecord * rec = (MenuRecord *) (*this->menus)[i];
95 // if (rec->menuid == 0) popup = rec->menu;
96 delete [] rec->name;
97 delete [] rec->title;
98 // if (rec->parent == NULL) delete rec->menu; // menu not attached
99 delete rec;
100 }
101
102 const int numItems = this->items->getLength();
103 for (i = 0; i < numItems; i++) {
104 ItemRecord * rec = (ItemRecord *) (*this->items)[i];
105 delete [] rec->name;
106 delete [] rec->title;
107 delete rec;
108 }
109
110 // delete root popup menu
111 // delete popup;
112 } // ~XtNativePopupMenu()
113
114 // *************************************************************************
115
116 /*!
117 */
118
119 int
newMenu(const char * name,int menuid)120 XtNativePopupMenu::newMenu(
121 const char * name,
122 int menuid)
123 {
124 int id = menuid;
125 if (id == -1) {
126 id = 1;
127 while (this->getMenuRecord(id) != NULL) id++;
128 } else {
129 if (this->getMenuRecord(id) != NULL) {
130 #if SOXT_DEBUG
131 SoDebugError::postInfo("XtNativePopupMenu::NewMenu",
132 "requested menuid already taken");
133 #endif // SOXT_DEBUG
134 return -1;
135 }
136 }
137 // id contains ok ID
138 MenuRecord * rec = this->createMenuRecord(name);
139 rec->menuid = id;
140 this->menus->append((void *) rec);
141 return id;
142 } // newMenu()
143
144 /*!
145 */
146
147 int
getMenu(const char * name)148 XtNativePopupMenu::getMenu(
149 const char * name)
150 {
151 const int numMenus = this->menus->getLength();
152 int i;
153 for (i = 0; i < numMenus; i++)
154 if (strcmp(((MenuRecord *) (*this->menus)[i])->name, name) == 0)
155 return ((MenuRecord *) (*this->menus)[i])->menuid;
156 return -1;
157 } // getMenu()
158
159 /*!
160 */
161
162 void
setMenuTitle(int menuid,const char * title)163 XtNativePopupMenu::setMenuTitle(
164 int menuid,
165 const char * title)
166 {
167 MenuRecord * rec = this->getMenuRecord(menuid);
168 if (rec == NULL) {
169 SoDebugError::postWarning("XtNativePopupMenu::SetMenuTitle",
170 "no such menu (%d.title = \"%s\")", menuid, title);
171 return;
172 }
173 delete [] rec->title;
174 rec->title = strcpy(new char [strlen(title)+1], title);
175 // if (rec->parent)
176 // rec->parent->changeItem(rec->menuid, QString(rec->title));
177 } // setMenuTitle()
178
179 /*!
180 */
181
182 const char *
getMenuTitle(int menuid)183 XtNativePopupMenu::getMenuTitle(
184 int menuid)
185 {
186 MenuRecord * rec = this->getMenuRecord(menuid);
187 if (rec == NULL)
188 return NULL;
189 return rec->title;
190 } // getMenuTitle()
191
192 // *************************************************************************
193
194 /*!
195 */
196
197 int
newMenuItem(const char * name,int itemid)198 XtNativePopupMenu::newMenuItem(
199 const char * name,
200 int itemid)
201 {
202 // FIXME: this function is the same in the other So-libraries --
203 // move to common abstraction layer SoGuiPopupMenu of
204 // possible. 20031012 mortene.
205
206 int id = itemid;
207 if (id == -1) {
208 id = 1;
209 while (this->getItemRecord(id) != NULL) id++;
210 } else {
211 if (this->getItemRecord(itemid) != NULL) {
212 #if SOXT_DEBUG
213 SoDebugError::postInfo("XtNativePopupMenu::NewMenuItem",
214 "requested itemid already taken");
215 #endif // SOXT_DEBUG
216 return -1;
217 }
218 }
219 ItemRecord * rec = this->createItemRecord(name);
220 rec->itemid = id;
221 this->items->append(rec);
222 return id;
223 } // newMenuItem()
224
225 /*!
226 */
227
228 int
getMenuItem(const char * name)229 XtNativePopupMenu::getMenuItem(
230 const char * name)
231 {
232 const int numItems = this->items->getLength();
233 int i;
234 for (i = 0; i < numItems; i++)
235 if (strcmp(((ItemRecord *) (*this->items)[i])->name, name) == 0)
236 return ((ItemRecord *) (*this->items)[i])->itemid;
237 return -1;
238 } // getMenuItem()
239
240 /*!
241 */
242
243 void
setMenuItemTitle(int itemid,const char * title)244 XtNativePopupMenu::setMenuItemTitle(
245 int itemid,
246 const char * title)
247 {
248 ItemRecord * rec = this->getItemRecord(itemid);
249 if (rec == NULL)
250 return;
251 delete [] rec->title;
252 rec->title = strcpy(new char [strlen(title)+1], title);
253 // if (rec->parent)
254 // rec->parent->changeItem(rec->itemid, QString(rec->title));
255 } // setMenuItemTitle()
256
257 /*!
258 */
259
260 const char *
getMenuItemTitle(int itemid)261 XtNativePopupMenu::getMenuItemTitle(
262 int itemid)
263 {
264 ItemRecord * rec = this->getItemRecord(itemid);
265 if (rec == NULL) return NULL;
266 return rec->title;
267 } // getMenuItemTitle()
268
269 /*!
270 */
271
272 void
setMenuItemEnabled(int itemid,SbBool enabled)273 XtNativePopupMenu::setMenuItemEnabled(// virtual
274 int itemid,
275 SbBool enabled)
276 {
277 ItemRecord * rec = this->getItemRecord(itemid);
278 if (rec == NULL) {
279 #if SOXT_DEBUG
280 SoDebugError::postInfo("XtNativePopupMenu::SetMenuItemEnabled",
281 "no such menu item");
282 #endif // SOXT_DEBUG
283 return;
284 }
285 if (enabled)
286 rec->flags |= ITEM_ENABLED;
287 else
288 rec->flags &= ~ITEM_ENABLED;
289 if (rec->item != (Widget) NULL)
290 XtVaSetValues(rec->item, XmNsensitive, enabled ? True : False, NULL);
291 } // setMenuItemEnabled()
292
293 /*!
294 */
295
296 SbBool
getMenuItemEnabled(int itemid)297 XtNativePopupMenu::getMenuItemEnabled(
298 int itemid)
299 {
300 ItemRecord * rec = this->getItemRecord(itemid);
301 if (rec == NULL)
302 return FALSE;
303 return (rec->flags & ITEM_ENABLED) ? TRUE : FALSE;
304 } // getMenuItemEnabled()
305
306 /*!
307 */
308
309 void
_setMenuItemMarked(int itemid,SbBool marked)310 XtNativePopupMenu::_setMenuItemMarked(int itemid, SbBool marked)
311 {
312 ItemRecord * rec = this->getItemRecord(itemid);
313 if (rec == NULL)
314 return;
315 if (marked)
316 rec->flags |= ITEM_MARKED;
317 else
318 rec->flags &= ~ITEM_MARKED;
319
320 if (rec->item != NULL)
321 XmToggleButtonSetState(rec->item, marked ? True : False, False);
322 }
323
324 /*!
325 */
326
327 SbBool
getMenuItemMarked(int itemid)328 XtNativePopupMenu::getMenuItemMarked(
329 int itemid)
330 {
331 ItemRecord * rec = this->getItemRecord(itemid);
332 if (rec == NULL)
333 return FALSE;
334 return (rec->flags & ITEM_MARKED) ? TRUE : FALSE;
335 } // getMenuItemMarked()
336
337 // *************************************************************************
338
339 /*!
340 */
341
342 void
addMenu(int menuid,int submenuid,int pos)343 XtNativePopupMenu::addMenu(
344 int menuid,
345 int submenuid,
346 int pos)
347 {
348 MenuRecord * super = this->getMenuRecord(menuid);
349 MenuRecord * sub = this->getMenuRecord(submenuid);
350 if (super == NULL || sub == NULL) {
351 #if SOXT_DEBUG
352 SoDebugError::postInfo("XtNativePopupMenu::AddMenu",
353 "no such menu (super = 0x%08x, sub = 0x%08x)", super, sub);
354 #endif // SOXT_DEBUG
355 return;
356 }
357 if (pos == -1) {
358 int max = 0;
359 int i;
360 const int numItems = this->items->getLength();
361 for (i = 0; i < numItems; i++) {
362 ItemRecord * rec = (ItemRecord *) (*this->items)[i];
363 if (rec->parent == super) {
364 if (rec->pos >= max)
365 max = rec->pos + 1;
366 }
367 }
368 const int numMenus = this->menus->getLength();
369 for (i = 0; i < numMenus; i++) {
370 MenuRecord * rec = (MenuRecord *) (*this->menus)[i];
371 if (rec->parent == super) {
372 if (rec->pos >= max)
373 max = rec->pos + 1;
374 }
375 }
376 sub->pos = max;
377 sub->parent = super;
378 } else {
379 int i;
380 const int numItems = this->items->getLength();
381 for (i = 0; i < numItems; i++) {
382 ItemRecord * rec = (ItemRecord *) (*this->items)[i];
383 if (rec->parent == super) {
384 if (rec->pos >= pos)
385 rec->pos = rec->pos + 1;
386 }
387 }
388 const int numMenus = this->menus->getLength();
389 for (i = 0; i < numMenus; i++) {
390 MenuRecord * rec = (MenuRecord *) (*this->menus)[i];
391 if (rec->parent == super) {
392 if (rec->pos >= pos)
393 rec->pos = rec->pos + 1;
394 }
395 }
396 sub->pos = pos;
397 sub->parent = super;
398 }
399 } // addMenu()
400
401 /*!
402 */
403
404 void
addMenuItem(int menuid,int itemid,int pos)405 XtNativePopupMenu::addMenuItem(
406 int menuid,
407 int itemid,
408 int pos)
409 {
410 MenuRecord * menu = this->getMenuRecord(menuid);
411 ItemRecord * item = this->getItemRecord(itemid);
412 if (menu == NULL || item == NULL) {
413 #if SOXT_DEBUG
414 SoDebugError::postInfo("XtNativePopupMenu::AddMenuItem",
415 "no such item (menu = 0x%08x, item = 0x%08x)", menu, item);
416 #endif // SOXT_DEBUG
417 return;
418 }
419 if (pos == -1) {
420 int max = 0;
421 int i;
422 const int numItems = this->items->getLength();
423 for (i = 0; i < numItems; i++) {
424 ItemRecord * rec = (ItemRecord *) (*this->items)[i];
425 if (rec->parent == menu) {
426 if (rec->pos >= max)
427 max = rec->pos + 1;
428 }
429 }
430 const int numMenus = this->menus->getLength();
431 for (i = 0; i < numMenus; i++) {
432 MenuRecord * rec = (MenuRecord *) (*this->menus)[i];
433 if (rec->parent == menu) {
434 if (rec->pos >= max)
435 max = rec->pos + 1;
436 }
437 }
438 item->pos = max;
439 item->parent = menu;
440 } else {
441 int i;
442 const int numItems = this->items->getLength();
443 for (i = 0; i < numItems; i++) {
444 ItemRecord * rec = (ItemRecord *) (*this->items)[i];
445 if (rec->parent == menu) {
446 if (rec->pos >= pos)
447 rec->pos = rec->pos + 1;
448 }
449 }
450 const int numMenus = this->menus->getLength();
451 for (i = 0; i < numMenus; i++) {
452 MenuRecord * rec = (MenuRecord *) (*this->menus)[i];
453 if (rec->parent == menu) {
454 if (rec->pos >= pos)
455 rec->pos = rec->pos + 1;
456 }
457 }
458 item->pos = pos;
459 item->parent = menu;
460 }
461 } // addMenuItem()
462
463 void
addSeparator(int menuid,int pos)464 XtNativePopupMenu::addSeparator(
465 int menuid,
466 int pos)
467 {
468 MenuRecord * menu = this->getMenuRecord(menuid);
469 if (menu == NULL) {
470 SoDebugError::postWarning("XtNativePopupMenu::AddSeparator",
471 "no such menu (%d)", menuid);
472 return;
473 }
474 ItemRecord * sep = this->createItemRecord("separator");
475 sep->flags |= ITEM_SEPARATOR;
476 if (pos == -1) {
477 int max = 0;
478 int i;
479 const int numItems = this->items->getLength();
480 for (i = 0; i < numItems; i++) {
481 ItemRecord * rec = (ItemRecord *) (*this->items)[i];
482 if (rec->parent == menu) {
483 if (rec->pos >= max)
484 max = rec->pos + 1;
485 }
486 }
487 const int numMenus = this->menus->getLength();
488 for (i = 0; i < numMenus; i++) {
489 MenuRecord * rec = (MenuRecord *) (*this->menus)[i];
490 if (rec->parent == menu) {
491 if (rec->pos >= max)
492 max = rec->pos + 1;
493 }
494 }
495 sep->pos = max;
496 sep->parent = menu;
497 } else {
498 int i;
499 const int numItems = this->items->getLength();
500 for (i = 0; i < numItems; i++) {
501 ItemRecord * rec = (ItemRecord *) (*this->items)[i];
502 if (rec->parent == menu) {
503 if (rec->pos >= pos)
504 rec->pos = rec->pos + 1;
505 }
506 }
507 const int numMenus = this->menus->getLength();
508 for (i = 0; i < numMenus; i++) {
509 MenuRecord * rec = (MenuRecord *) (*this->menus)[i];
510 if (rec->parent == menu) {
511 if (rec->pos >= pos)
512 rec->pos = rec->pos + 1;
513 }
514 }
515 sep->pos = pos;
516 sep->parent = menu;
517 }
518 this->items->append(sep);
519 } // addSeparator()
520
521 /*!
522 This method removes the submenu with the given \a menuid.
523
524 A removed menu can be attached again later - its menuid will still be
525 allocated.
526 */
527
528 void
removeMenu(int menuid)529 XtNativePopupMenu::removeMenu(
530 int menuid)
531 {
532 MenuRecord * rec = this->getMenuRecord(menuid);
533 if (rec == NULL) {
534 #if SOXT_DEBUG
535 SoDebugError::postInfo("XtNativePopupMenu::RemoveMenu", "no such menu");
536 #endif // SOXT_DEBUG
537 return;
538 }
539 if (rec->menuid == 0) {
540 #if SOXT_DEBUG
541 SoDebugError::postInfo("XtNativePopupMenu::RemoveMenu", "can't remove root");
542 #endif // SOXT_DEBUG
543 return;
544 }
545 // if (rec->parent == NULL) {
546 // #if SOXT_DEBUG
547 // SoDebugError::postInfo("XtNativePopupMenu::RemoveMenu", "menu not attached");
548 // #endif // SOXT_DEBUG
549 // return;
550 // }
551 // rec->parent->removeItem(rec->menuid);
552 // rec->parent = NULL;
553 } // removeMenu()
554
555 /*!
556 This method removes the menu item with the given \a itemid.
557
558 A removed menu item can be attached again later - its itemid will still
559 be allocated.
560 */
561
562 void
removeMenuItem(int itemid)563 XtNativePopupMenu::removeMenuItem(
564 int itemid)
565 {
566 ItemRecord * rec = this->getItemRecord(itemid);
567 if (rec == NULL) {
568 #if SOXT_DEBUG
569 SoDebugError::postInfo("XtNativePopupMenu::RemoveMenu", "no such item");
570 #endif // SOXT_DEBUG
571 return;
572 }
573 int idx = this->items->find(rec);
574 assert(idx != -1);
575 this->items->removeFast(idx);
576 delete [] rec->name;
577 delete [] rec->title;
578 delete rec;
579 this->dirty = TRUE;
580 } // removeMenuItem()
581
582 // *************************************************************************
583
584 // Doc in superclass.
585 void
popUp(Widget inside,int x,int y)586 XtNativePopupMenu::popUp(Widget inside, int x, int y)
587 {
588 assert(inside != NULL);
589
590 MenuRecord * root = this->getMenuRecord(0);
591 if (root == NULL) {
592 #if SOXT_DEBUG
593 SoDebugError::postInfo("XtNativePopupMenu::PopUp", "no root menu");
594 #endif // SOXT_DEBUG
595 return;
596 }
597 // FIXME: build menu
598 if (this->dirty) {
599 if (this->popup != (Widget) NULL) {
600 // FIXME: destroy existing menu widget hierarchy
601 }
602 this->popup = this->build(inside);
603 }
604 this->dirty = FALSE;
605
606 // Find global mouse pointer coordinates.
607 Display * display = XtDisplay(inside);
608 XButtonEvent pos;
609 Window dummyarg;
610 Bool b = XTranslateCoordinates(display,
611 XtWindow(inside),
612 DefaultRootWindow(display),
613 x, y, &pos.x_root, &pos.y_root, &dummyarg);
614 assert(b == True); // or we've got a bug
615
616 XmMenuPosition(this->popup, &pos);
617 XtManageChild(this->popup);
618 } // popUp()
619
620 // *************************************************************************
621
622 /*!
623 */
624
625 Widget
traverseBuild(Widget parent,MenuRecord * menu,int indent)626 XtNativePopupMenu::traverseBuild(
627 Widget parent,
628 MenuRecord * menu,
629 int indent)
630 {
631 assert(indent < 24);
632 int i;
633 #if SOXT_POPUPMENU_DEBUG
634 char pre[24];
635 for (i = 0; i < indent; i++) pre[i] = ' ';
636 pre[i] = '\0';
637 #endif // SOXT_POPUPMENU_DEBUG
638 int j = 0;
639 MenuRecord * sub;
640 ItemRecord * item;
641 do {
642 sub = (MenuRecord *) NULL;
643 item = (ItemRecord *) NULL;
644 const int numMenus = this->menus->getLength();
645 for (i = 0; i < numMenus; i++) {
646 sub = (MenuRecord *) (*this->menus)[i];
647 if ((sub->pos == j) && (sub->parent == menu)) {
648 #if SOXT_POPUPMENU_DEBUG
649 fprintf(stderr, "%s%s {\n", pre, sub->name);
650 #endif // SOXT_POPUPMENU_DEBUG
651 Display * dpy = SoXt::getDisplay();
652 const int screen = DefaultScreen(dpy);
653 Visual * visual = DefaultVisual(dpy, screen);
654 Colormap colormap = DefaultColormap(dpy, screen);
655 int depth = DefaultDepth(dpy, screen);
656 Arg args[10];
657 int argc = 0;
658 XtSetArg(args[argc], XmNvisual, visual); argc++;
659 XtSetArg(args[argc], XmNdepth, depth); argc++;
660 XtSetArg(args[argc], XmNcolormap, colormap); argc++;
661 Widget submenu = XmCreatePulldownMenu(parent, sub->name, args, argc);
662 sub->menu = XtVaCreateManagedWidget(sub->name,
663 xmCascadeButtonGadgetClass, parent,
664 XmNsubMenuId, submenu,
665 XtVaTypedArg,
666 XmNlabelString, XmRString,
667 sub->title, strlen(sub->title) + 1,
668 NULL);
669 this->traverseBuild(submenu, sub, indent + 2);
670 #if SOXT_POPUPMENU_DEBUG
671 fprintf(stderr, "%s}\n", pre);
672 #endif // SOXT_POPUPMENU_DEBUG
673 break;
674 } else {
675 sub = (MenuRecord *) NULL;
676 }
677 }
678 if (sub == NULL) {
679 const int numItems = this->items->getLength();
680 for (i = 0; i < numItems; i++) {
681 item = (ItemRecord *) (*this->items)[i];
682 if ((item->pos == j) && (item->parent == menu)) {
683 #if SOXT_POPUPMENU_DEBUG
684 fprintf(stderr, "%s%s\n", pre, item->name);
685 #endif // SOXT_POPUPMENU_DEBUG
686 if (item->flags & ITEM_SEPARATOR) {
687 item->item = XtVaCreateManagedWidget(item->title,
688 xmSeparatorGadgetClass, parent, NULL);
689 } else {
690 item->item = XtVaCreateManagedWidget(item->title,
691 xmToggleButtonGadgetClass, parent,
692 XmNsensitive, (item->flags & ITEM_ENABLED) ? True : False,
693 XtVaTypedArg,
694 XmNlabelString, XmRString,
695 item->title, strlen(item->title)+1,
696 NULL);
697 XtAddCallback(item->item, XmNvalueChangedCallback,
698 XtNativePopupMenu::itemSelectionCallback, this);
699 XmToggleButtonSetState(item->item,
700 (item->flags & ITEM_MARKED) ? True : False,
701 False);
702 }
703 break;
704 } else {
705 item = (ItemRecord *) NULL;
706 }
707 }
708 }
709 j++;
710 } while ((sub != NULL) || (item != NULL));
711 return parent;
712 } // traverseBuild()
713
714 /*!
715 */
716
717 Widget
build(Widget parent)718 XtNativePopupMenu::build(
719 Widget parent)
720 {
721 MenuRecord * root = this->getMenuRecord(0);
722 assert(root != NULL);
723
724 #if SOXT_POPUPMENU_DEBUG
725 setbuf(stderr, NULL);
726 fprintf(stderr, "building popup menu\n");
727 #endif // SOXT_POPUPMENU_DEBUG
728
729 Display * dpy = SoXt::getDisplay();
730 const int screen = DefaultScreen(dpy);
731 Visual * visual = DefaultVisual(dpy, screen);
732 Colormap colormap = DefaultColormap(dpy, screen);
733 int depth = DefaultDepth(dpy, screen);
734
735 Arg args[10];
736 int argc = 0;
737 XtSetArg(args[argc], XmNvisual, visual); argc++;
738 XtSetArg(args[argc], XmNdepth, depth); argc++;
739 XtSetArg(args[argc], XmNcolormap, colormap); argc++;
740 Widget popup = XmCreatePopupMenu(parent, root->name, args, argc);
741
742 #if SOXT_POPUPMENU_DEBUG
743 fprintf(stderr, "%s {\n", root->name);
744 #endif // SOXT_POPUPMENU_DEBUG
745 (void) this->traverseBuild(popup, root, 2);
746 #if SOXT_POPUPMENU_DEBUG
747 fprintf(stderr, "}\n");
748 #endif // SOXT_POPUPMENU_DEBUG
749 return popup;
750 } // build()
751
752 // *************************************************************************
753
754 /*!
755 */
756
757 MenuRecord *
getMenuRecord(int menuid)758 XtNativePopupMenu::getMenuRecord(
759 int menuid)
760 {
761 const int numMenus = this->menus->getLength();
762 int i;
763 for (i = 0; i < numMenus; i++)
764 if (((MenuRecord *) (*this->menus)[i])->menuid == menuid)
765 return (MenuRecord *) (*this->menus)[i];
766 return (MenuRecord *) NULL;
767 } // getMenuRecord()
768
769 /*!
770 */
771
772 ItemRecord *
getItemRecord(int itemid)773 XtNativePopupMenu::getItemRecord(
774 int itemid)
775 {
776 const int numItems = this->items->getLength();
777 int i;
778 for (i = 0; i < numItems; i++)
779 if (((ItemRecord *) (*this->items)[i])->itemid == itemid)
780 return (ItemRecord *) (*this->items)[i];
781 return (ItemRecord *) NULL;
782 } // getItemRecord()
783
784 // *************************************************************************
785
786 /*!
787 */
788
789 MenuRecord *
createMenuRecord(const char * name)790 XtNativePopupMenu::createMenuRecord(
791 const char * name)
792 {
793 MenuRecord * rec = new MenuRecord;
794 rec->menuid = -1;
795 rec->pos = -1;
796 rec->name = strcpy(new char [strlen(name)+1], name);
797 rec->title = strcpy(new char [strlen(name)+1], name);
798 rec->menu = (Widget) NULL;
799 rec->parent = NULL;
800 return rec;
801 } // create()
802
803 /*!
804 */
805
806 ItemRecord *
createItemRecord(const char * name)807 XtNativePopupMenu::createItemRecord(
808 const char * name)
809 {
810 ItemRecord * rec = new ItemRecord;
811 rec->itemid = -1;
812 rec->pos = -1;
813 rec->flags = 0 | ITEM_ENABLED;
814 rec->name = strcpy(new char [strlen(name)+1], name);
815 rec->title = strcpy(new char [strlen(name)+1], name);
816 rec->item = (Widget) NULL;
817 rec->parent = NULL;
818 return rec;
819 } // create()
820
821 // *************************************************************************
822
823 /*!
824 */
825
826 void
itemSelection(Widget w,XtPointer call)827 XtNativePopupMenu::itemSelection(// private
828 Widget w,
829 XtPointer call)
830 {
831 if (w == NULL)
832 return;
833 XmToggleButtonCallbackStruct * data = (XmToggleButtonCallbackStruct *) call;
834 const int numItems = this->items->getLength();
835 int i;
836 for (i = 0; i < numItems; i++) {
837 ItemRecord * rec = (ItemRecord *) (*this->items)[i];
838 if (rec->item == w) {
839 int groupid = this->getRadioGroup(rec->itemid);
840 if (data->set && groupid != -1) {
841 this->setMenuItemMarked(rec->itemid, TRUE);
842 this->invokeMenuSelection(rec->itemid);
843 } else {
844 if (groupid == -1) {
845 this->setMenuItemMarked(rec->itemid, FALSE);
846 this->invokeMenuSelection(rec->itemid);
847 } else if (this->getRadioGroupSize(groupid) > 1) {
848 this->setMenuItemMarked(rec->itemid, TRUE);
849 this->invokeMenuSelection(rec->itemid);
850 } else {
851 this->setMenuItemMarked(rec->itemid, FALSE);
852 this->invokeMenuSelection(rec->itemid);
853 }
854 }
855 }
856 }
857 } // itemSelection()
858
859 /*!
860 */
861
862 void
itemSelectionCallback(Widget w,XtPointer client_data,XtPointer call_data)863 XtNativePopupMenu::itemSelectionCallback(// private, static
864 Widget w,
865 XtPointer client_data,
866 XtPointer call_data)
867 {
868 assert(client_data != NULL);
869 XtNativePopupMenu * popup = (XtNativePopupMenu *) client_data;
870 popup->itemSelection(w, call_data);
871 } // itemSelectionCallback()
872
873 // *************************************************************************
874
875