1 /*  $Id: vibmouse.c,v 6.4 2001/03/28 01:40:48 juran Exp $
2 * ===========================================================================
3 *
4 *                            PUBLIC DOMAIN NOTICE
5 *            National Center for Biotechnology Information (NCBI)
6 *
7 *  This software/database is a "United States Government Work" under the
8 *  terms of the United States Copyright Act.  It was written as part of
9 *  the author's official duties as a United States Government employee and
10 *  thus cannot be copyrighted.  This software/database is freely available
11 *  to the public for use. The National Library of Medicine and the U.S.
12 *  Government do not place any restriction on its use or reproduction.
13 *  We would, however, appreciate having the NCBI and the author cited in
14 *  any work or product based on this material
15 *
16 *  Although all reasonable efforts have been taken to ensure the accuracy
17 *  and reliability of the software and data, the NLM and the U.S.
18 *  Government do not and cannot warrant the performance or results that
19 *  may be obtained by using this software or data. The NLM and the U.S.
20 *  Government disclaim all warranties, express or implied, including
21 *  warranties of performance, merchantability or fitness for any particular
22 *  purpose.
23 *
24 * ===========================================================================
25 *
26 * Author:  Denis Vakatov
27 *
28 * File Description:
29 *   user interface to manage mouse-event callbacks
30 *   program interface to describe groups of mouse-event callbacks
31 *
32 * ===========================================================================
33 * $Log: vibmouse.c,v $
34 * Revision 6.4  2001/03/28 01:40:48  juran
35 * "for (...) { continue; }", squelch warning
36 *
37 * Revision 6.3  1999/04/06 14:23:25  lewisg
38 * add opengl replacement for viewer3d
39 *
40 * Revision 6.2  1998/07/02 18:24:34  vakatov
41 * Cleaned the code & made it pass through the C++ compilation
42 *
43 * Revision 6.1  1997/11/26 21:30:31  vakatov
44 * Fixed errors and warnings issued by C and C++ (GNU and Sun) compilers
45 *
46 * Revision 6.0  1997/08/25 18:57:21  madden
47 * Revision changed to 6.0
48 *
49 * Revision 1.3  1997/05/06 16:27:07  vakatov
50 * Ignore the MA_Drag and MA_Release events not preceded by MA_Press
51 *
52  * Revision 1.2  1997/03/21  16:15:12  vakatov
53  * Removed #<ni_list.h> -- as the list stuff has been moved to "ncbimisk.[ch]"
54  *
55  * Revision 1.1  1997/03/20  16:23:26  vakatov
56  * Initial revision
57  *
58 *
59 * ==========================================================================
60 */
61 
62 #ifdef VAR_ARGS
63 #include <varargs.h>
64 #else
65 #include <stdarg.h>
66 #endif
67 #include <vibrant.h>  /* move out of header.  lyg */
68 #include <vibmouse.h>
69 
70 
71 #define BAD ASSERT(FALSE)
72 
73 
74 /*****************************************************************************
75  *  Internal Data and Type Definitions
76 *****************************************************************************/
77 
78 static const Char *MA_name[MK_Default][MA_Init] =
79 {
80   {
81     "Click",
82     "Press",
83     "DoubleClick",
84     "Hold",
85     "Drag",
86     "Release",
87     "Cancel"
88   },
89 
90   {
91     "Shift-Click",
92     "Shift-Press",
93     "Shift-DoubleClick",
94     "Shift-Hold",
95     "Shift-Drag",
96     "Shift-Release",
97     "Shift-Cancel"
98   },
99 
100   {
101     "Ctrl-Click",
102     "Ctrl-Press",
103     "Ctrl-DoubleClick",
104     "Ctrl-Hold",
105     "Ctrl-Drag",
106     "Ctrl-Release",
107     "Ctrl-Cancel"
108   }
109 };
110 
111 
112 typedef struct _MAction
113 {
114   enumMKey     mod_key;
115   enumMAction  type;
116   MA_Func      func;
117   VoidPtr      data;
118   CharPtr      name;
119   IteM         item;
120   MAPtr        ma;
121 }
122 MAction;
123 
124 typedef struct _MA_Group
125 {
126   CharPtr    name;  /* the group name as it appears in the group menu */
127   MActionPtr init;
128   MActionPtr done;
129   MActionPtr action[MK_Default][MA_Init];
130   Boolean    only  [MK_Default][MA_Init]; /* TRUE if cannot be replaced by a
131                          "foreign" callback while the group is active */
132   IteM       item;
133   MAPtr      ma;
134 }
135 MA_Group;
136 
137 
138 
139 typedef struct _MA
140 {
141   /* interface */
142   MenU        group_menu;
143   MenU        action_menu;
144   MenU        menu[MK_Default][MA_Init];
145 
146   /* all registered actions and groups */
147   NodePtr     actions;
148   NodePtr     groups;
149 
150   /* presently active groups and actions */
151   NodePtr     active_groups;
152   MActionPtr  action[MK_Default][MA_Init];
153   Boolean     only  [MK_Default][MA_Init];
154 
155   /* presently active(snapshot during the last "Press" action) modifier */
156   enumMKey    mod_key;
157 
158   /* type and position of the most recent mouse action(but MA_Hold) */
159   enumMAction last_type;
160   PoinT       last_pos;
161 
162   /* auxiliary temporary store area shared between the action callbacks */
163   MA_Trace    trace;
164 
165   /* presently linked panel(slate) */
166   PaneL       panel;
167 
168   /* user-specified pointer to an extra data */
169   VoidPtr     extra;
170 }
171 MA;
172 
173 
174 
175 /*****************************************************************************
176  *  Internal (Static)  Functions
177 *****************************************************************************/
178 
179 /* In the "action->ma", find the active group containing
180  * the "only" action of type "action->mod_key/type"
181  */
GroupOfOnlyAction(MActionPtr action)182 static MA_GroupPtr GroupOfOnlyAction(MActionPtr action)
183 {
184   MAPtr   ma   = action->ma;
185   NodePtr node = ma->active_groups;
186 
187   ASSERT ( ma->only[action->mod_key][action->type] );
188 
189   while ( node )
190     {
191       MA_GroupPtr mag = (MA_GroupPtr)node->elem;
192       if ( mag->only[action->mod_key][action->type] )
193         return mag;
194 
195       node = ListGetNext( node );
196     }
197 
198   BAD;
199   return NULL;
200 }
201 
202 
203 /* Set current action according to the submenu item click
204  */
MA_ActionItemCB(IteM item)205 static void MA_ActionItemCB(IteM item)
206 {
207   MActionPtr action = (MActionPtr)GetObjectExtra( item );
208 
209   VERIFY ( MA_SetAction(action, TRUE) );
210 }
211 
212 
213 /* Add the action item to the relevant submenu
214  */
MA_ShowAction(MActionPtr action)215 static Boolean MA_ShowAction(MActionPtr action)
216 {
217   MAPtr ma;
218   if (action == NULL  ||  action->name == NULL  ||
219       (ma = action->ma) == NULL  ||  ma->action_menu == NULL  ||
220       !ma->action_menu  ||  !ma->menu[action->mod_key][action->type])
221     return FALSE;
222 
223   if (action->item != NULL)
224     return TRUE;
225 
226   action->item = CommandItem(ma->menu[action->mod_key][action->type],
227                              action->name, MA_ActionItemCB);
228   if ( !action->item )
229     return FALSE;
230 
231   SetObjectExtra(action->item, action, NULL);
232   return TRUE;
233 }
234 
235 
236 /*  Activate/deactivate the mouse callback group "group"
237  */
MA_GroupItemCB(IteM item)238 static void MA_GroupItemCB(IteM item)
239 {
240   MA_GroupPtr group = (MA_GroupPtr)GetObjectExtra( item );
241 
242   if ( GetStatus( item ) )
243     VERIFY ( MA_SetGroup( group ) );
244   else
245     VERIFY ( MA_UnsetGroup( group ) );
246 }
247 
248 
249 /*  Add the "group"'s name to the list of mouse callback groups
250  */
MA_ShowGroup(MA_GroupPtr group)251 static Boolean MA_ShowGroup(MA_GroupPtr group)
252 {
253   if (group                 != NULL  &&
254       group->name           != NULL  &&
255       group->ma             != NULL  &&
256       group->ma->group_menu != NULL  &&
257       (group->item = StatusItem(group->ma->group_menu, group->name,
258                                 MA_GroupItemCB)) != NULL)
259     {
260       SetObjectExtra(group->item, group, NULL);
261       return TRUE;
262     }
263 
264   return FALSE;
265 }
266 
267 
268 /* Measure distance between the two points
269  */
PointDist(PoinT p1,PoinT p2)270 static double PointDist(PoinT p1, PoinT p2)
271 {
272   return sqrt( (double)((p2.x - p1.x) * (p2.x - p1.x) +
273                         (p2.y - p1.y) * (p2.y - p1.y)));
274 }
275 
276 /* The Panel-to-MA callback dispatcher
277  */
MA_Execute(MAPtr ma,PoinT pt,enumMAction type)278 static void MA_Execute(MAPtr ma, PoinT pt, enumMAction type)
279 {
280   ASSERT ( 0 <= type  &&  type < MA_Init );
281 
282   /* set the key status of the action in progress */
283   if (type == MA_Press  ||  type == MA_DClick  ||  ma->mod_key == MK_Default)
284     ma->mod_key = Nlm_shftKey ? MK_Shift :
285                   Nlm_ctrlKey ? MK_Ctrl  :
286                   MK_Normal;
287 
288   /* Refuse MA_Drag and MA_Release not preceded by MA_Press */
289   if ((type == MA_Drag  ||  type == MA_Release)  &&
290       ma->last_type != MA_Press  &&  ma->last_type != MA_Drag)
291     return;
292 
293   /* MA_Click vs. MA_Drag|MA_Release */
294   if (ma->last_type == MA_Press)
295     {
296       double CLICK_RADIUS = (double)8;
297       switch ( type )
298         {
299         case MA_Drag:
300           if (PointDist(pt, ma->last_pos) <= CLICK_RADIUS)
301             return;
302           break;
303 
304         case MA_Release:
305           if (PointDist(pt, ma->last_pos) <= CLICK_RADIUS)
306             type = MA_Click;
307           break;
308 
309         default:
310           break;
311         }
312     }
313 
314   {{ /* call the relevant user-specified action callback, if any */
315     MActionPtr action = ma->action[ma->mod_key][type];
316     if ( action )
317       {
318         ASSERT ( action->ma   == ma   );
319         ASSERT ( action->type == type );
320         (*action->func)(ma, &ma->trace, pt, action->data);
321       }
322   }}
323 
324   if (type == MA_Release  ||  type == MA_Cancel  ||  type == MA_DClick)
325     ma->mod_key = MK_Default;  /* no action in progress */
326 
327   if (type != MA_Hold)
328     {
329       ma->last_type = type;
330       ma->last_pos  = pt;
331     }
332 }
333 
MA_ExecuteP(PaneL panel,PoinT pt,enumMAction type)334 static void MA_ExecuteP(PaneL panel, PoinT pt, enumMAction type)
335 {
336   MAPtr ma = NULL;
337   GetPanelExtra(panel, &ma);
338   MA_Execute(ma, pt, type);
339 }
340 
341 
342 /* MA wrappers of the panel callbacks
343  */
MA_ClickCB(PaneL panel,PoinT pt)344 static void MA_ClickCB(PaneL panel, PoinT pt)
345 {
346   if ( Nlm_dblClick )
347     MA_ExecuteP(panel, pt, MA_DClick);
348   else
349     MA_ExecuteP(panel, pt, MA_Press);
350 }
351 
352 
MA_HoldCB(PaneL panel,PoinT pt)353 static void MA_HoldCB(PaneL panel, PoinT pt)
354 {
355   MA_ExecuteP(panel, pt, MA_Hold);
356 }
357 
358 
MA_DragCB(PaneL panel,PoinT pt)359 static void MA_DragCB(PaneL panel, PoinT pt)
360 {
361   MA_ExecuteP(panel, pt, MA_Drag);
362 }
363 
364 
MA_ReleaseCB(PaneL panel,PoinT pt)365 static void MA_ReleaseCB(PaneL panel, PoinT pt)
366 {
367   MA_ExecuteP(panel, pt, MA_Release);
368 }
369 
370 
371 
372 /*****************************************************************************
373  *  External Functions
374 *****************************************************************************/
375 
376 /* Creation functions
377  */
MA_Create(MenU group_menu,MenU action_menu)378 extern MAPtr MA_Create(MenU group_menu, MenU action_menu)
379 {
380   MAPtr ma = (MAPtr)MemNew( sizeof(MA) );
381   if ( !ma ) {
382     BAD;
383     return NULL;
384   }
385 
386   ma->group_menu  = group_menu;
387   ma->action_menu = action_menu;
388 
389   MA_Reset( ma );
390   return ma;
391 }
392 
393 
394 /* DUMMY MA callback function
395  */
DoNothingMA(MAPtr ma,MA_TracePtr trace,PoinT point,VoidPtr extra)396 extern void DoNothingMA(MAPtr ma, MA_TracePtr trace, PoinT point,
397                         VoidPtr extra)
398 {
399   /* do nothing */
400 }
401 
402 
MA_AddAction(MAPtr ma,enumMKey mod_key,enumMAction type,MA_Func func,VoidPtr data,const Char PNTR name)403 extern MActionPtr MA_AddAction(MAPtr            ma,
404                                enumMKey         mod_key,
405                                enumMAction      type,
406                                MA_Func          func,
407                                VoidPtr          data,
408                                const Char PNTR  name)
409 {
410   MActionPtr new_action;
411   NodePtr    new_node;
412 
413   if (ma == NULL  ||  mod_key == MK_Default  ||  type == MA_Default  ||
414       func == NULL)
415     {
416       BAD;
417       return NULL;
418     }
419   ASSERT ( name == NULL  ||  *name != '\0' );
420 
421   new_action = (MActionPtr) MemNew( sizeof(MAction) );
422   new_node = ListInsertPrev(new_action, ma->actions);
423   if (new_node == NULL)
424     {
425       BAD;
426       MemFree( new_action );
427       return NULL;
428     }
429   if (ma->actions == NULL)
430     ma->actions = new_node;
431 
432   new_action->mod_key = mod_key;
433   new_action->type    = type;
434   new_action->func    = func;
435   new_action->data    = data;
436   new_action->name    = StringSave( name );
437   new_action->ma      = ma;
438   MA_ShowAction( new_action );
439 
440   return new_action;
441 }
442 
443 
MA_SetAction(MActionPtr action,Boolean can_unset_group)444 extern Boolean MA_SetAction(MActionPtr action, Boolean can_unset_group)
445 {
446   MAPtr       ma        = action->ma;
447   MActionPtr *ma_action = &ma->action[action->mod_key][action->type];
448 
449   if ( ma->only[action->mod_key][action->type] )
450     {
451       if ( can_unset_group )
452         {
453           VERIFY ( MA_UnsetGroup( GroupOfOnlyAction(action) ) );
454           ASSERT ( !ma->only[action->mod_key][action->type] );
455         }
456       else
457         return FALSE;
458     }
459 
460   if (*ma_action  &&  (*ma_action)->item)
461     Enable( (*ma_action)->item );
462   if (action  &&  action->item)
463     Disable( action->item );
464 
465   *ma_action = action;
466   return TRUE;
467 }
468 
469 
MA_UnsetAll(MAPtr ma)470 extern Boolean MA_UnsetAll(MAPtr ma)
471 {
472   while ( ma->active_groups )
473     if ( !MA_UnsetGroup( (MA_GroupPtr)ma->active_groups->elem ) )
474       {
475         BAD;
476         return FALSE;
477       }
478 
479   {{
480     int i,j;
481     for (i = 0;  i < MK_Default;  i++)
482     for (j = 0;  j < MA_Init;     j++)
483       {
484         ASSERT ( !ma->only[i][j] );
485         if ( ma->action[i][j] )
486           {
487             if ( ma->action[i][j]->item )
488               Enable( ma->action[i][j]->item );
489             ma->action[i][j] = NULL;
490           }
491       }
492   }}
493 
494   return TRUE;
495 }
496 
497 
498 #ifdef VAR_ARGS
499 extern MA_GroupPtr MA_AddGroup(ma, name, action, only, va_alist)
500 MAPtr            ma;
501 const Char PNTR  name;
502 MActionPtr       action;
503 long             only;
504 va_dcl
505 #else
506 extern MA_GroupPtr MA_AddGroup(MAPtr ma,  const Char PNTR name,
507                                MActionPtr action,  long only,
508                                /* and more pairs: <action>, <only>; */
509                                /* then, the last arg. must be NULL! */
510                                ...)
511 #endif
512 {
513   MA_GroupPtr new_group;
514 
515   if (ma == NULL  ||  name == NULL  ||  action == NULL)
516     {
517       BAD;
518       return NULL;
519     }
520 
521   new_group = (MA_GroupPtr)MemNew( sizeof(MA_Group) );
522 
523   {{ /* Extract the group actions from the list of arguments */
524     va_list args;
525 #ifdef VAR_ARGS
526     va_start(args);
527 #else
528     va_start(args, only);
529 #endif
530     for ( ; action != NULL;
531          action = va_arg(args, MActionPtr),
532          only   = va_arg(args, long))
533       {
534         MActionPtr *dest_action = NULL;
535 
536         switch ( action->type )
537           {
538           case MA_Init:
539             dest_action = &new_group->init;
540             break;
541 
542           case MA_Done:
543             dest_action = &new_group->done;
544             break;
545 
546           default:
547             dest_action = &new_group->action[action->mod_key][action->type];
548             new_group->only[action->mod_key][action->type] =
549               (Boolean)(only == MA_ONLY);
550             break;
551           }
552 
553         if (*dest_action != NULL)
554           {
555             BAD;
556             MemFree( new_group );
557             return NULL;
558           }
559 
560         *dest_action = action;
561       }
562     va_end(args);
563   }}
564 
565   {{ /* Insert the new group to the end of the list of groups */
566     NodePtr new_node = ListInsertPrev(new_group, ma->groups);
567     if (new_node == NULL)
568       {
569         BAD;
570         MemFree( new_group );
571         return NULL;
572       }
573     if (ma->groups == NULL)
574       ma->groups = new_node;
575   }}
576 
577   new_group->name = StringSave( name );
578   new_group->ma   = ma;
579   MA_ShowGroup( new_group );
580 
581   return new_group;
582 }
583 
584 
MA_UnsetGroup(MA_GroupPtr group)585 extern Boolean MA_UnsetGroup(MA_GroupPtr group)
586 {
587   MAPtr ma = group->ma;
588 
589   {{ /* find and exclude the "group" from the list of active groups */
590     NodePtr node;
591     for (node = ma->active_groups;
592          node  &&  node->elem != group;
593          node = ListGetNext( node ))
594     {
595       continue;
596     }
597 
598     if ( !node )
599       return FALSE;
600 
601     if (node == ma->active_groups)
602       ma->active_groups = ListDelete( node );
603     else
604       ListDelete( node );
605   }}
606 
607   {{ /* unset the "group"'s "only" actions */
608     int i, j;
609     for (i = 0;  i < MK_Default;  i++)
610     for (j = 0;  j < MA_Init;     j++)
611       if ( group->only[i][j] )
612           {
613             ASSERT ( ma->action[i][j] == group->action[i][j] );
614             ASSERT ( ma->only  [i][j] );
615             if ( ma->menu[i][j] )
616               Enable( ma->menu[i][j] );
617             ma->action[i][j] = NULL;
618             ma->only  [i][j] = FALSE;
619           }
620   }}
621 
622   /* call the group's "done" method(i.e. the user-defined group destructor);
623      always call the "cancel" method before -- if there is a mouse
624      action "in progress" */
625   if (ma->mod_key != MK_Default)
626     MA_Execute(ma, ma->trace.end, MA_Cancel);
627 
628   if (group->item != NULL)
629     SetStatus(group->item, FALSE);
630 
631   if ( group->done )
632     (*group->done->func)(ma, &ma->trace, ma->trace.end, group->done->data);
633 
634   return TRUE;
635 }
636 
637 
MA_SetGroup(MA_GroupPtr group)638 extern Boolean MA_SetGroup(MA_GroupPtr group)
639 {
640   int   i, j;
641   MAPtr ma = group->ma;
642 
643   {{ /* check for the "only"-actions double-crossing; in that case
644       * unset all "only" actions of the old group(i.e. unset the group) */
645     for (i = 0;  i < MK_Default;  i++)
646     for (j = 0;  j < MA_Init;     j++)
647       if (ma->only[i][j]  &&  group->only[i][j]  &&
648           !MA_UnsetGroup( GroupOfOnlyAction(group->action[i][j]) ))
649         {
650           BAD;
651           return FALSE;
652         }
653   }}
654 
655   /* replace all old non-"only" actions with these from the "group" */
656   for (i = 0;  i < MK_Default;  i++)
657   for (j = 0;  j < MA_Init;     j++)
658     {
659       if (group->action[i][j] != NULL)
660         {
661           ASSERT ( !group->only[i][j]  ||  !ma->only[i][j]);
662           if ( ma->only[i][j] )
663             {
664               ASSERT ( !group->only[i][j] );
665             }
666           else
667             {
668               if (ma->action[i][j]  &&  ma->action[i][j]->item)
669                 Enable( ma->action[i][j]->item );
670               ma->action[i][j] = group->action[i][j];
671               ma->only  [i][j] = group->only  [i][j];
672             }
673         }
674 
675       if ( ma->only[i][j] )
676         Disable( ma->menu[i][j] );
677     }
678 
679   ListConnectRing( ma->active_groups );
680   ma->active_groups = ListInsertPrev(group, ma->active_groups);
681   ListBreakRing( ma->active_groups );
682 
683   if (group->item != NULL)
684     SetStatus(group->item, TRUE);
685 
686   /* call the group "init" method (user-defined group constructor) */
687   ma->trace.end.x = ma->trace.end.y = 0;
688   ma->trace.start = ma->trace.end;
689   if ( group->init )
690     (*group->init->func)(ma, &ma->trace, ma->trace.end, group->init->data);
691 
692   return TRUE;
693 }
694 
695 
MA_LinkPanel(MAPtr ma,PaneL panel)696 extern Boolean MA_LinkPanel(MAPtr ma, PaneL panel)
697 {
698   if (ma == NULL  ||  panel == NULL)
699     return FALSE;
700 
701   SetPanelClick(panel, MA_ClickCB, MA_DragCB, MA_HoldCB, MA_ReleaseCB);
702   SetPanelExtra(panel, &ma);
703   ma->panel = panel;
704   return TRUE;
705 }
706 
707 
MA_GetPanel(MAPtr ma)708 extern PaneL MA_GetPanel(MAPtr ma)
709 {
710   return (PaneL) (ma ? ma->panel : NULL);
711 }
712 
713 
MA_UnlinkPanel(MAPtr ma)714 extern void MA_UnlinkPanel(MAPtr ma)
715 {
716   MAPtr ma_NULL = NULL;
717 
718   if (ma == NULL  ||  ma->panel == NULL)
719     return;
720 
721   SetPanelClick(ma->panel, NULL, NULL, NULL, NULL);
722   SetPanelExtra(ma->panel, &ma_NULL);
723   ma->panel = NULL;
724 }
725 
726 
MA_SetVisible(MAPtr ma,Boolean visibility)727 extern Boolean MA_SetVisible(MAPtr ma, Boolean visibility)
728 {
729   if (!ma  ||  (!ma->group_menu  &&  !ma->action_menu))
730     return FALSE;
731 
732   if ( visibility )
733     {
734       Show( ma->group_menu  );
735       Show( ma->action_menu );
736     }
737   else
738     {
739       Hide( ma->group_menu  );
740       Hide( ma->action_menu );
741     }
742 
743   return TRUE;
744 }
745 
746 
MA_GetVisible(MAPtr ma)747 extern Boolean MA_GetVisible(MAPtr ma)
748 {
749   return (Boolean)
750     (ma  &&
751      ((ma->group_menu   &&  Visible(ma->group_menu )) ||
752       (ma->action_menu  &&  Visible(ma->action_menu))));
753 }
754 
755 
MA_SetExtra(MAPtr ma,VoidPtr extra)756 extern void MA_SetExtra(MAPtr ma, VoidPtr extra)
757 {
758   ma->extra = extra;
759 }
760 
761 
MA_GetExtra(MAPtr ma)762 extern VoidPtr MA_GetExtra(MAPtr ma)
763 {
764   return (ma ? ma->extra : NULL);
765 }
766 
767 
MA_Reset(MAPtr ma)768 extern void MA_Reset(MAPtr ma)
769 {
770   int i, j;
771 
772   /* unset all presently active groups */
773   while ( ma->active_groups )
774     VERIFY ( MA_UnsetGroup( (MA_GroupPtr)ma->active_groups->elem ) );
775 
776   /* Unlink panel */
777   MA_UnlinkPanel( ma );
778 
779   /* Reset menu-based interface */
780   if ( ma->action_menu )
781     {
782       Reset( ma->action_menu );
783 
784       for (i = 0;  i < MK_Default;  i++)
785       for (j = 0;  j < MA_Init;     j++)
786         ma->menu[i][j] = SubMenu(ma->action_menu, (CharPtr)MA_name[i][j]);
787     }
788 
789   if ( ma->group_menu )
790     {
791       if (ma->group_menu == ma->action_menu)
792         SeparatorItem( ma->action_menu );
793       else
794         Reset( ma->group_menu );
795     }
796 
797   /* Reset internal data */
798   MA_SetExtra(ma, NULL);
799 
800   while (ma->groups != NULL)
801     {
802       MemFree( ((MA_GroupPtr)ma->groups->elem)->name );
803       MemFree( ma->groups->elem );
804       ma->groups = ListDelete( ma->groups );
805     }
806 
807   for (i = 0;  i < MK_Default;  i++)
808   for (j = 0;  j < MA_Init;     j++)
809     {
810       ma->action[i][j] = NULL;
811       ma->only  [i][j] = FALSE;
812     }
813 
814   while ( ma->actions )
815     {
816       MemFree( ((MActionPtr)ma->actions->elem)->name );
817       MemFree( ma->actions->elem );
818       ma->actions = ListDelete( ma->actions );
819     }
820 
821   ma->mod_key   = MK_Default;
822   ma->last_type = MA_Default;
823 }
824 
825 
MA_Destroy(MAPtr ma)826 extern void MA_Destroy(MAPtr ma)
827 {
828   MA_Reset( ma );
829   MemFree( ma );
830 }
831 
832 
833 /* EOF ($RCSfile: vibmouse.c,v $) */
834 
835