File: vmenu.cxx

package info (click to toggle)
v1 1.17-4
  • links: PTS
  • area: main
  • in suites: hamm
  • size: 5,812 kB
  • ctags: 6,780
  • sloc: cpp: 43,604; ansic: 5,003; makefile: 955; sh: 30
file content (807 lines) | stat: -rw-r--r-- 21,201 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
//===============================================================
// vMenu.cxx - vMenuPane class functions - X11R5
//
// Copyright (C) 1995,1996  Bruce E. Wampler
//
// This file is part of the V C++ GUI Framework, and is covered
// under the terms of the GNU Library General Public License,
// Version 2. This library has NO WARRANTY. See the source file
// vapp.cxx for more complete information about license terms.
//===============================================================

#include <v/vmenu.h>		// our header
#include <v/vctlclrs.h>

extern "C"
{
#include <X11/Core.h>
#include <X11/Shell.h>

#ifdef Motif
#include <Xm/RowColumn.h>
#include <Xm/CascadeB.h>
#include <Xm/Separator.h>
#include <Xm/PushB.h>
#define setLabel(x,y) XmString x = XmStringCreateLocalized(y);
#define freeLabel(x) XmStringFree(x);
#define Ncallback XmNactivateCallback
#define Nsensitive XmNsensitive
#define Nlabel XmNlabelString

#else		// ATHENA

#include <X11/Xaw/MenuButton.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/SmeBSB.h>
#include <X11/Xaw/SmeLine.h>
#include <X11/Xaw/Sme.h>

#define setLabel(x,y) char* x = y;
#define freeLabel(x)
#define Ncallback XtNcallback
#define Nsensitive XtNsensitive
#define Nlabel XtNlabel

#endif

}

#include <v/vcmdwin.h>		// we need access to vcmdwin

#include <stdlib.h>

// Define static data of the class

#define menux_width 9
#define menux_height 9
static char menux_bits[] = {
   0xff, 0x01, 0x83, 0x01, 0x45, 0x01, 0x29, 0x01, 0x11, 0x01, 0x29, 0x01,
   0x45, 0x01, 0x83, 0x01, 0xff, 0x01};
static Pixmap menux_bitmap = 0;		// the check for menus

#define menuclr_width 9
#define menuclr_height 9
static char menuclr_bits[] = {
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
static Pixmap menuclr_bitmap = 0;	// the no-check for menus

#define rtarrow_width 9
#define rtarrow_height 9
static char rtarrow_bits[] = {
   0x03, 0x00, 0x0f, 0x00, 0x3f, 0x00, 0xff, 0x00, 0xff, 0x01, 0xff, 0x00,
   0x3f, 0x00, 0x0f, 0x00, 0x03, 0x00};
static Pixmap rtarrow_bitmap = 0;	// right arrow for submenus


static void subMenuAction(Widget, XEvent *, String *, Cardinal *);

#ifndef Motif
static XtActionsRec submenu_action = { "popupSubmenu",
     (XtActionProc)subMenuAction };
static XtTranslations   SMtrans = 0, SMtrans2 = 0;
#endif

static char curLbl[100];	// for fixed labels
static char _Mnemonic;

//==================>>> vMenuPane::vMenuPane <<<===========================
  vMenuPane::vMenuPane(vMenu* menu) : vPane(P_Menu)
  {
    int i;

    // set up menus -----------------------------------------------

    SysDebug(Constructor,"vMenuPane::vMenuPane() constructor\n")

    
    _nextMenuButton = 0;	// no menus defined so far

    for (i = 0 ; i < MAX_MENU_BUTTONS ; ++i)
      {
	_mb[i].label = 0; // null out menu button array
	_mb[i].XMenuButton = 0;
	_mb[i].SubMenu = 0;
      }

    // copy the menus as defined to our array

    for (i = 0 ; i < MAX_MENU_BUTTONS && &menu[i] != 0 && menu[i].label; ++i)
      {
	_mb[i].label = menu[i].label;
	_mb[i].SubMenu = menu[i].SubMenu;
      }
    _nextSubMenu =		// we will start submenus here
    _nextMenuButton = i;	// this many menus defined

  }

//==================>>> vMenuPane::vMenuPane <<<===========================
  vMenuPane::vMenuPane(const vMenuPane& m) : vPane(m)
  {

    vSysError("V Semantics do not allow copy constructors.");
  }

//====================>>> vMenuPane::~vMenuPane <<<=======================
  vMenuPane::~vMenuPane()			// destructor
  {

    SysDebug(Destructor,"vMenuPane::~vMenuPane() destructor\n")

    for (int i = 0 ; i < _nextSubMenu ; ++i)	// all menus
      {
	delete _mb[i].mInfo;		// free the space
      }

  }

//======================>>> vMenuPane::fixLabel <<<========================
  void vMenuPane::fixLabel(char* lbl, char* key, int isMainMenu)
  {
    // copy label to global curLbl

    char* cp;
    int ix = 0;

    _Mnemonic = 0;

#ifdef Motif
    if (!isMainMenu)
      {
	curLbl[0] = ' '; curLbl[1] = ' '; ix = 2;
      }
#endif
    for (cp = lbl ; *cp && ix < 99 ; ++cp)	// Scan label
      {
 	if (*cp != '&')
	  {
	    curLbl[ix++] = *cp;
	  }
	else
	    _Mnemonic = *(cp+1);
      }

#ifndef Motif		// ATHENA ONLY
    if (key && *key)
      {
	curLbl[ix++] = ' '; curLbl[ix++] = ' '; curLbl[ix++] = '<';
 	for (cp = key ; *cp && ix < 99 ; ++cp)
	  {
	    if (*cp != '&')
	      {
		curLbl[ix++] = *cp;
	      }
	  }
	curLbl[ix++] = '>';
      }
#endif

    curLbl[ix] = 0;		// finish off
  }

//======================>>> vMenuPane::doAddMenu <<<========================
  void vMenuPane::doAddMenu(int id, Widget parent)
  {
    // create a button on the menu button bar


    fixLabel(_mb[id].label,0,1);	// copy the label
    setLabel(tmp,curLbl);

#ifdef Motif

    // Motif does things in the reverse order of Athena --
    // create a menu popup off the menubar, then add
    // a cascade buttong to that

    if (parent == 0)
      {
	_mb[id].XPopUp = 
	  XmCreatePulldownMenu(_baseW,"pulldown",0,0);
      }
    else
      {
	_mb[id].XPopUp = parent;		// a submenu
      }

    // Create the cascade button

    if (parent == 0)
      {
	_mb[id].XMenuButton = XtVaCreateManagedWidget(
            "vMenuButton",				// name for widget
	    xmCascadeButtonWidgetClass,			// widget class 
	    _baseW,					// parent widget
	    Nlabel, tmp,				// display name
	    XmNsubMenuId,_mb[id].XPopUp,
	    XmNmnemonic, _Mnemonic,
	    NULL);					// argument list
      }
    else
      {
	_mb[id].XMenuButton = parent;		// a submenu
      }

#else

    if (parent == 0)			// adding a top level menu
      {
	_mb[id].XMenuButton = XtVaCreateManagedWidget(
	    "vMenuButton",				// name for widget
	    menuButtonWidgetClass,			// widget class 
	    _baseW,					// parent widget
	    XtNlabel, tmp,				// display name
	    XtNmenuName, _mb[id].label,
	    XtNbackground, _vMenuBarBG,
	    XtNborderWidth,0,	// label only, no border
	    NULL);					// argument list
      }
    else
      {
	_mb[id].XMenuButton = parent;		// a submenu
      }

    // Create the Popup Shell needed for this menu
    if (parent == 0)
      {
	_mb[id].XPopUp = XtVaCreatePopupShell(
	  _mb[id].label,
	  simpleMenuWidgetClass,			// menu
	  _mb[id].XMenuButton,			// parent
	  XtNbackground, _vMenuBarBG,
	  NULL);
      }
    else
      {
	_mb[id].XPopUp = XtVaCreatePopupShell(
	  _mb[id].label,				// name
	  simpleMenuWidgetClass,			// menu
	  _mb[id].XMenuButton,			// parent
	  XtNtranslations, SMtrans2,		// need these to work right
	  XtNbackground, _vMenuBarBG,
	  NULL);
      }
#endif

    freeLabel(tmp);

    // loop through the list

    _mb[id].mInfo = 0;			// empty list so far

    vMenu* item = _mb[id].SubMenu;	// The first item in list

    MenuInfo* info;			// for current info
    for (int ix = 0 ; item[ix].label != 0 ; ++ix)
      {
	info = new MenuInfo;		// new space or current tem
	info->NxtInfo = _mb[id].mInfo;	// add to front of list
	_mb[id].mInfo = info;		// fix front pointer
	info->ItemIndex = ix;		// index to item list
	info->SubMenuIndex = 0;		// no submenu normally

	if (item[ix].menuId == M_Line)
	  {
#ifdef Motif
	    info->WItem = XtVaCreateManagedWidget(
	        "-",			// widget name
	        xmSeparatorWidgetClass,	// widget class 
	        _mb[id].XPopUp,		// parent widget
	        NULL);			// argument list
#else
	    info->WItem = XtVaCreateManagedWidget(
	        "-",			// widget name
	        smeLineObjectClass,	// widget class 
	        _mb[id].XPopUp,		// parent widget
		XtNvertSpace, 0,
		XtNleftMargin,15,	// room for check-mark
		XtNrightMargin,10,
		XtNbackground, _vMenuBarBG,
	        NULL);			// argument list
#endif
	  }
	else if (item[ix].SubMenu != 0)	// a submenu
	  {
	    if(_nextSubMenu >= MAX_MENU_BUTTONS)
	      {
		SysDebug(BadVals,"Too many submenus!\n");
		continue;
	      }
	    fixLabel(item[ix].label);
	    setLabel(tmp,curLbl);

#ifdef Motif
	    // Create a pulldown for pullright

	    info->WItem =  XmCreatePulldownMenu(_mb[id].XPopUp,
		"vPullRight",0,0);
	    // Create the cascade button

	    _mb[id].XMenuButton = XtVaCreateManagedWidget(
	    	"vMenuButton",				// name for widget
		xmCascadeButtonWidgetClass,			// widget class 
	        _mb[id].XPopUp,		// parent widget
		Nlabel, tmp,				// display name
		XmNsubMenuId,info->WItem,
		XmNmnemonic, _Mnemonic,
		NULL);					// argument list

#else	// ATHENA

	    info->WItem = XtVaCreateManagedWidget(
		item[ix].label,
	        smeBSBObjectClass,	// widget class 
	        _mb[id].XPopUp,		// parent widget
		XtNlabel,tmp,	// item[ix].label, // the label on the item
		Nsensitive,item[ix].sensitive,  // if sensitive
		XtNvertSpace, 25,
		XtNleftMargin,15,	// room for check-mark
		XtNrightMargin,10,
		XtNrightBitmap,		// set the left side
		rtarrow_bitmap,		// to the X checkbox
	        NULL);			// argument list

	    // Override the PARENT to grab motion, which will cause
	    // the popup menu to come up

	    XtOverrideTranslations(_mb[id].XPopUp, SMtrans);
#endif
	    freeLabel(tmp);

	    // we will create a submenu
	    // copy the definitions, track the new index

	    int sub = _nextSubMenu++;	// get our index, bump for next time

	    _mb[sub].label = item[ix].label;
	    _mb[sub].XMenuButton = 0;
	    _mb[sub].SubMenu = item[ix].SubMenu;
	    info->SubMenuIndex = sub;		// no submenu normally
	    // Now, recursively call doAddMenu with the submenu
#ifdef Motif
	    doAddMenu(sub,info->WItem);
#else
	    doAddMenu(sub,_mb[id].XPopUp);
#endif
	  }
	else
	  {
	    // create the item widget

	    fixLabel(item[ix].label, item[ix].keyLabel);
#ifdef Motif
//
//@@@ Note: we don't yet support accelerators on Motif -- we
// have to convert the X keycode to a Motif "Alt<key>X" format...
//
	    if (item[ix].checked)	// was it checked?
		curLbl[0] = '*';	// flaky checks

	    setLabel(tmp,curLbl);

	    info->WItem = XtVaCreateManagedWidget(
		item[ix].label,
	        xmPushButtonWidgetClass,	// widget class 
	        _mb[id].XPopUp,		// parent widget
		Nlabel,tmp,	// item[ix].label, // the label on the item
		Nsensitive,item[ix].sensitive,  // if sensitive
		XmNfillOnSelect,1,
		XmNindicatorOn,0,
		XmNshadowThickness,1,
		XmNindicatorType,XmN_OF_MANY,
	        NULL);			// argument list
	
#else
	    setLabel(tmp,curLbl);
	    info->WItem = XtVaCreateManagedWidget(
		item[ix].label,
	        smeBSBObjectClass,	// widget class 
	        _mb[id].XPopUp,		// parent widget
		XtNlabel,tmp,	// item[ix].label, // the label on the item
		Nsensitive,item[ix].sensitive,  // if sensitive
		XtNvertSpace, 25,
		XtNleftMargin,15,	// room for check-mark
		XtNrightMargin,10,
		XtNbackground, _vMenuBarBG,
	        NULL);			// argument list

	    if (item[ix].checked)	// was it checked?
	      {
		XtVaSetValues(info->WItem,	// to this menu item
			XtNleftBitmap,		// set the left side
			menux_bitmap,		// to the X checkbox
			NULL);
	      }
#endif


	    // and add the call back for each item
	    freeLabel(tmp);

	    XtAddCallback(info->WItem,
	        Ncallback, CmenuCB, (XtPointer)this);
	  }
      }
  }

//====================>>> vMenuPane::CheckAccel <<<======================
  int vMenuPane::CheckAccel(vKey vkey, unsigned int shift, ItemVal& id)
  {
    // scan all menus in this window to see if this keystroke
    // matches an accelerator key

#ifndef Motif
    vMenu* item;

    // Search all menus in this list
    for (int ix = 0 ; ix < _nextSubMenu ; ++ix)
      {
	MenuInfo* info;			// for current info

	// scan the list of info for each menu entry

	for (info = _mb[ix].mInfo ; info != 0 ; info = info->NxtInfo)
	  {
	    item = _mb[ix].SubMenu;	// The current item in list
	    // see if its menuId is the same as the one we are setting
	    if (item[info->ItemIndex].accel == vkey
		 && item[info->ItemIndex].kShift == shift)
	      {
		id = item[info->ItemIndex].menuId;
		return 1;
	      }
	  }
      }
#endif

    id = 0;
    return 0;		// assume 0 if not found
  }

//====================>>> vMenuPane::GetPaneValue <<<======================
  int vMenuPane::GetPaneValue(ItemVal id, int& val)
  {
    // scan all menus in this window to retrieve the what value
    // then scan button bar if not found

    vMenu* item;

    // Search all menus in this list
    for (int ix = 0 ; ix < _nextSubMenu ; ++ix)
      {
	MenuInfo* info;			// for current info

	// scan the list of info for each menu entry

	for (info = _mb[ix].mInfo ; info != 0 ; info = info->NxtInfo)
	  {
	    item = _mb[ix].SubMenu;	// The current item in list
	    // see if its menuId is the same as the one we are setting
	    if (item[info->ItemIndex].menuId == id)
	      {
		// Ah Ha! We found the value we want
		val = item[info->ItemIndex].checked;
		return 1;
	      }
	  }
      }

    val = 0;
    return 0;		// assume 0 if not found
  }

//====================>>> vMenuPane::GetMenuThis <<<======================
  vMenuPane* vMenuPane::GetMenuThis(Widget w)
  {
    for (int ix = 0 ; ix < _nextSubMenu ; ++ix)
      {
	if (_mb[ix].XPopUp == w)
	    return this;
      }
    return 0;
  }

//======================>>> vMenuPane::initialize <<<=======================
  void vMenuPane::initialize(vWindow* pWin, Widget pWidget)
  {
    // First, create the Pixmaps, but only once!

    pWin->vAddMenuBar();				// Set up menubar

    vPane::initialize(pWin, pWidget);		// initialize these

#ifndef Motif
    if (menux_bitmap == 0)			// need to create stuff
      {
	// The bitmaps

	menux_bitmap = XCreateBitmapFromData(
	    XtDisplay(_parentWin->vHandle()),	// our display
	    DefaultRootWindow(XtDisplay(_parentWin->vHandle() )),  // a Drawable
	    menux_bits,			// the menux bitmap data
	    menux_width,		// from the file
	    menux_height);

	menuclr_bitmap = XCreateBitmapFromData(
	    XtDisplay(_parentWin->vHandle()),	// our display
	    DefaultRootWindow(XtDisplay(_parentWin->vHandle())),  // a Drawable
	    menuclr_bits,			// the menux bitmap data
	    menuclr_width,		// from the file
	    menuclr_height);

	rtarrow_bitmap = XCreateBitmapFromData(
	    XtDisplay(_parentWin->vHandle()),	// our display
	    DefaultRootWindow(XtDisplay(_parentWin->vHandle())),  // a Drawable
	    rtarrow_bits,		// the rtarrow bitmap data
	    rtarrow_width,		// from the file
	    rtarrow_height);

	// the action for submenus

	XtAppAddActions(XtWidgetToApplicationContext(_parentWin->vHandle()),
		 &submenu_action, 1);
      }

    if (SMtrans == 0)			// The translations needed
      {
	SMtrans = XtParseTranslationTable(
	  "<BtnMotion>: highlight() popupSubmenu()");
	SMtrans2 = XtParseTranslationTable(
	  "<LeaveWindow>: unhighlight() MenuPopdown()\n<BtnUp>: notify()\
 unhighlight() MenuPopdown()\n<BtnMotion>: highlight()");
      }
#endif

    // Now we have to add our menus

    for (int i = 0 ; i < _nextMenuButton ; ++i)
      {
	doAddMenu(i, 0);
      }
  }

//============================>>> vMenuPane::menuCB <<<==========================
  void vMenuPane::menuCB(Widget w)
  {
    //	menu button class callback
    //
    // We will do some work here
    // scan all menus until we find the widget

    vMenu* item;
    ItemVal menu_val = 0;

    // Scan all menus in this window looking for widget corresponding
    // to the widget that generated the callback
    for (int ix = 0 ; ix < _nextSubMenu ; ++ix)
      {
	MenuInfo* info;			// for current info

	for (info = _mb[ix].mInfo ; info != 0 ; info = info->NxtInfo)
	  {
	    if (info->WItem == w)	// found it!
	      {
		item = _mb[ix].SubMenu;	// The first item in list
		menu_val = item[info->ItemIndex].menuId;
		goto FoundIt;
	      }
	  }
      }
FoundIt:
    _parentWin->MenuCommand(menu_val);
  }

extern "C"
{
//============================>>> CmenuCB <<<==========================
  void CmenuCB(Widget w, XtPointer ItmPtr, XtPointer call_data)
  { 
    //	menu button "C" Call Back
    // ItmPtr will have the this pointer of our object

   ((vMenuPane*)ItmPtr)->menuCB(w);
  }
}

//==================>>> vMenuPane::SetPaneValue <<<========================
  void vMenuPane::SetPaneValue(ItemVal id, int val, ItemSetType setType)
  {
    // Set the given item on or off

    vMenu* item;

    // Search all menus in this list
    for (int ix = 0 ; ix < _nextSubMenu ; ++ix)
      {
	MenuInfo* info;			// for current info

	// scan the list of info for each menu entry
	for (info = _mb[ix].mInfo ; info != 0 ; info = info->NxtInfo)
	  {
	    item = _mb[ix].SubMenu;	// The current item in list
	    // see if its menuId is the same as the one we are setting
	    if (item[info->ItemIndex].menuId == id)
	      {
		// Ah Ha! We found the value we want
		switch (setType)
		  {
		    case Value:			// check box
		    case Checked:		// check box
			item[info->ItemIndex].checked = val;
			if (val)		// turning it on
			  {
// OK, I know this isn't the best, but I tried and couldn't
// get ToggleButtons to work like I wanted, so I'm faking
// check marks with an '*'. If Motif had nice lefthand
// Bitmaps like Athena....
#ifdef Motif
			    fixLabel(item[info->ItemIndex].label);
			    curLbl[0] = '*';
			    setLabel(tmp,curLbl);
			    XtVaSetValues(info->WItem,	// to this menu item
			        Nlabel,tmp,
				NULL);
			    freeLabel(tmp);
#else
			    XtVaSetValues(info->WItem,	// to this menu item
			        XtNleftBitmap,		// set the left side
				menux_bitmap,		// to the X checkbox
				NULL);
#endif
			  }
			else
			  {
#ifdef Motif
			    fixLabel(item[info->ItemIndex].label);
			    setLabel(tmp,curLbl);
			    XtVaSetValues(info->WItem,	// to this menu item
			        Nlabel,tmp,
				NULL);
			    freeLabel(tmp);
#else
			    XtVaSetValues(info->WItem,	// to this menu item
			        XtNleftBitmap,		// set the left side
				menuclr_bitmap,		// to the X clearbox
				NULL);
#endif
			  }
			break;

		    case Sensitive:			// sensitive
			item[info->ItemIndex].sensitive = val;
			XtVaSetValues(info->WItem,	// set sens or not
			    Nsensitive, val,		// how to set
			    NULL);
			break;
		  }	// end switch
	      }
	  }
      }
  }

//================>>> vMenuPane::SetPaneString <<<========================
  void vMenuPane::SetPaneString(ItemVal id, char* str) 
  {
    // Set the given item on or off

    vMenu* item;

    // Search all menus in this window 
    for (int ix = 0 ; ix < _nextSubMenu ; ++ix)
      {
	MenuInfo* info;			// for current info

	// scan the list of info for each menu entry
	for (info = _mb[ix].mInfo ; info != 0 ; info = info->NxtInfo)
	  {
	    item = _mb[ix].SubMenu;	// The current item in list

	    if (item[info->ItemIndex].menuId == id)
	      {
		// Ah Ha! We found the value we want
		fixLabel(str);
#ifdef Motif
		item[info->ItemIndex].label = str;
		// This is flakey, but you have to check for check here
		if (item[info->ItemIndex].checked)
		    curLbl[0] = '*';
#endif
		setLabel(tmp,curLbl);
	  
		XtVaSetValues(info->WItem,	// change label
		    Nlabel, tmp,
		    NULL);

		freeLabel(tmp);
	      }
	  }
      }
  }

//==================>>> vMenuPane::doSubMenu <<<========================
  void vMenuPane::doSubMenu(Widget parent, Widget subitem, int x, int y)
  {
    // Maybe popup a submenu

    // Scan all menus in this window looking for widget corresponding
    // to the widget that generated the callback
    for (int ix = 0 ; ix < _nextSubMenu ; ++ix)
      {
	if (_mb[ix].XPopUp == parent)
	  {
	    MenuInfo* info;			// for current info
	    for (info = _mb[ix].mInfo ; info != 0 ; info = info->NxtInfo)
	      {
		if (info->WItem == subitem)
		  {
		    vMenu* item = _mb[ix].SubMenu;  // The first item in list

		    // look at static definition to see if this one had a
		    // submenu. If so, then it is the one we are looking for.
		    if (item[info->ItemIndex].SubMenu != 0)
		      {
			// get the popup shell for the submenu and pop it up.
			Widget submenu = _mb[info->SubMenuIndex].XPopUp;
			XtVaSetValues(submenu, XtNx, x, XtNy, y, NULL);
			XtPopup(submenu, XtGrabExclusive);
			return;
		      }
		  }
	      }
	    break;
	  }
      }
    // we didn't find a value
  }

//================>>> subMenuAction <<<========================
  static void subMenuAction(Widget w, XEvent *event, 
	String *params, Cardinal *nparams)
  {
#ifndef Motif
    Dimension    width, height;
    int		x, y;
    Widget	cw = XawSimpleMenuGetActiveEntry(w);

    if (cw == 0 || 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 sensitve to pulls
    */
    if (x < (width - (width / 3)))
	return;

    vMenuPane* mypane = theApp->GetMenuThis(w);

    if (mypane == 0)
	return;

    // Don't mess with this too much -- the sub menu seems to need
    // to popup over the cursor, or it loses track of things.
    x = event->xmotion.x_root - 10 ;	// Make sure cursor shows
    y = event->xmotion.y_root - 10 ;

    mypane->doSubMenu(w, cw, x, y);

#ifdef ITWORKS
    for (cur = rightHead; cur != NULL && cur->widget != cw; cur = cur->next)
	;

    if (cur == NULL)
	return;

    XtVaSetValues(cur->shell, XtNx, x, XtNy, y, NULL);

    XtPopup(cur->shell, XtGrabExclusive);
#endif
#endif
  }