1
/* $Id: vibmouse.c,v 6.4 2001/03/28 01:40:48 juran Exp $
2
* ===========================================================================
5
* National Center for Biotechnology Information (NCBI)
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
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
24
* ===========================================================================
26
* Author: Denis Vakatov
29
* user interface to manage mouse-event callbacks
30
* program interface to describe groups of mouse-event callbacks
32
* ===========================================================================
33
* $Log: vibmouse.c,v $
34
* Revision 6.4 2001/03/28 01:40:48 juran
35
* "for (...) { continue; }", squelch warning
37
* Revision 6.3 1999/04/06 14:23:25 lewisg
38
* add opengl replacement for viewer3d
40
* Revision 6.2 1998/07/02 18:24:34 vakatov
41
* Cleaned the code & made it pass through the C++ compilation
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
46
* Revision 6.0 1997/08/25 18:57:21 madden
47
* Revision changed to 6.0
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
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]"
55
* Revision 1.1 1997/03/20 16:23:26 vakatov
59
* ==========================================================================
67
#include <vibrant.h> /* move out of header. lyg */
71
#define BAD ASSERT(FALSE)
74
/*****************************************************************************
75
* Internal Data and Type Definitions
76
*****************************************************************************/
78
static const Char *MA_name[MK_Default][MA_Init] =
112
typedef struct _MAction
124
typedef struct _MA_Group
126
CharPtr name; /* the group name as it appears in the group menu */
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 */
144
MenU menu[MK_Default][MA_Init];
146
/* all registered actions and groups */
150
/* presently active groups and actions */
151
NodePtr active_groups;
152
MActionPtr action[MK_Default][MA_Init];
153
Boolean only [MK_Default][MA_Init];
155
/* presently active(snapshot during the last "Press" action) modifier */
158
/* type and position of the most recent mouse action(but MA_Hold) */
159
enumMAction last_type;
162
/* auxiliary temporary store area shared between the action callbacks */
165
/* presently linked panel(slate) */
168
/* user-specified pointer to an extra data */
175
/*****************************************************************************
176
* Internal (Static) Functions
177
*****************************************************************************/
179
/* In the "action->ma", find the active group containing
180
* the "only" action of type "action->mod_key/type"
182
static MA_GroupPtr GroupOfOnlyAction(MActionPtr action)
184
MAPtr ma = action->ma;
185
NodePtr node = ma->active_groups;
187
ASSERT ( ma->only[action->mod_key][action->type] );
191
MA_GroupPtr mag = (MA_GroupPtr)node->elem;
192
if ( mag->only[action->mod_key][action->type] )
195
node = ListGetNext( node );
203
/* Set current action according to the submenu item click
205
static void MA_ActionItemCB(IteM item)
207
MActionPtr action = (MActionPtr)GetObjectExtra( item );
209
VERIFY ( MA_SetAction(action, TRUE) );
213
/* Add the action item to the relevant submenu
215
static Boolean MA_ShowAction(MActionPtr action)
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])
223
if (action->item != NULL)
226
action->item = CommandItem(ma->menu[action->mod_key][action->type],
227
action->name, MA_ActionItemCB);
231
SetObjectExtra(action->item, action, NULL);
236
/* Activate/deactivate the mouse callback group "group"
238
static void MA_GroupItemCB(IteM item)
240
MA_GroupPtr group = (MA_GroupPtr)GetObjectExtra( item );
242
if ( GetStatus( item ) )
243
VERIFY ( MA_SetGroup( group ) );
245
VERIFY ( MA_UnsetGroup( group ) );
249
/* Add the "group"'s name to the list of mouse callback groups
251
static Boolean MA_ShowGroup(MA_GroupPtr group)
254
group->name != NULL &&
256
group->ma->group_menu != NULL &&
257
(group->item = StatusItem(group->ma->group_menu, group->name,
258
MA_GroupItemCB)) != NULL)
260
SetObjectExtra(group->item, group, NULL);
268
/* Measure distance between the two points
270
static double PointDist(PoinT p1, PoinT p2)
272
return sqrt( (double)((p2.x - p1.x) * (p2.x - p1.x) +
273
(p2.y - p1.y) * (p2.y - p1.y)));
276
/* The Panel-to-MA callback dispatcher
278
static void MA_Execute(MAPtr ma, PoinT pt, enumMAction type)
280
ASSERT ( 0 <= type && type < MA_Init );
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 :
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)
293
/* MA_Click vs. MA_Drag|MA_Release */
294
if (ma->last_type == MA_Press)
296
double CLICK_RADIUS = (double)8;
300
if (PointDist(pt, ma->last_pos) <= CLICK_RADIUS)
305
if (PointDist(pt, ma->last_pos) <= CLICK_RADIUS)
314
{{ /* call the relevant user-specified action callback, if any */
315
MActionPtr action = ma->action[ma->mod_key][type];
318
ASSERT ( action->ma == ma );
319
ASSERT ( action->type == type );
320
(*action->func)(ma, &ma->trace, pt, action->data);
324
if (type == MA_Release || type == MA_Cancel || type == MA_DClick)
325
ma->mod_key = MK_Default; /* no action in progress */
329
ma->last_type = type;
334
static void MA_ExecuteP(PaneL panel, PoinT pt, enumMAction type)
337
GetPanelExtra(panel, &ma);
338
MA_Execute(ma, pt, type);
342
/* MA wrappers of the panel callbacks
344
static void MA_ClickCB(PaneL panel, PoinT pt)
347
MA_ExecuteP(panel, pt, MA_DClick);
349
MA_ExecuteP(panel, pt, MA_Press);
353
static void MA_HoldCB(PaneL panel, PoinT pt)
355
MA_ExecuteP(panel, pt, MA_Hold);
359
static void MA_DragCB(PaneL panel, PoinT pt)
361
MA_ExecuteP(panel, pt, MA_Drag);
365
static void MA_ReleaseCB(PaneL panel, PoinT pt)
367
MA_ExecuteP(panel, pt, MA_Release);
372
/*****************************************************************************
374
*****************************************************************************/
376
/* Creation functions
378
extern MAPtr MA_Create(MenU group_menu, MenU action_menu)
380
MAPtr ma = (MAPtr)MemNew( sizeof(MA) );
386
ma->group_menu = group_menu;
387
ma->action_menu = action_menu;
394
/* DUMMY MA callback function
396
extern void DoNothingMA(MAPtr ma, MA_TracePtr trace, PoinT point,
403
extern MActionPtr MA_AddAction(MAPtr ma,
408
const Char PNTR name)
410
MActionPtr new_action;
413
if (ma == NULL || mod_key == MK_Default || type == MA_Default ||
419
ASSERT ( name == NULL || *name != '\0' );
421
new_action = (MActionPtr) MemNew( sizeof(MAction) );
422
new_node = ListInsertPrev(new_action, ma->actions);
423
if (new_node == NULL)
426
MemFree( new_action );
429
if (ma->actions == NULL)
430
ma->actions = new_node;
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 );
438
MA_ShowAction( new_action );
444
extern Boolean MA_SetAction(MActionPtr action, Boolean can_unset_group)
446
MAPtr ma = action->ma;
447
MActionPtr *ma_action = &ma->action[action->mod_key][action->type];
449
if ( ma->only[action->mod_key][action->type] )
451
if ( can_unset_group )
453
VERIFY ( MA_UnsetGroup( GroupOfOnlyAction(action) ) );
454
ASSERT ( !ma->only[action->mod_key][action->type] );
460
if (*ma_action && (*ma_action)->item)
461
Enable( (*ma_action)->item );
462
if (action && action->item)
463
Disable( action->item );
470
extern Boolean MA_UnsetAll(MAPtr ma)
472
while ( ma->active_groups )
473
if ( !MA_UnsetGroup( (MA_GroupPtr)ma->active_groups->elem ) )
481
for (i = 0; i < MK_Default; i++)
482
for (j = 0; j < MA_Init; j++)
484
ASSERT ( !ma->only[i][j] );
485
if ( ma->action[i][j] )
487
if ( ma->action[i][j]->item )
488
Enable( ma->action[i][j]->item );
489
ma->action[i][j] = NULL;
499
extern MA_GroupPtr MA_AddGroup(ma, name, action, only, va_alist)
501
const Char PNTR name;
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! */
513
MA_GroupPtr new_group;
515
if (ma == NULL || name == NULL || action == NULL)
521
new_group = (MA_GroupPtr)MemNew( sizeof(MA_Group) );
523
{{ /* Extract the group actions from the list of arguments */
528
va_start(args, only);
530
for ( ; action != NULL;
531
action = va_arg(args, MActionPtr),
532
only = va_arg(args, long))
534
MActionPtr *dest_action = NULL;
536
switch ( action->type )
539
dest_action = &new_group->init;
543
dest_action = &new_group->done;
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);
553
if (*dest_action != NULL)
556
MemFree( new_group );
560
*dest_action = action;
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)
570
MemFree( new_group );
573
if (ma->groups == NULL)
574
ma->groups = new_node;
577
new_group->name = StringSave( name );
579
MA_ShowGroup( new_group );
585
extern Boolean MA_UnsetGroup(MA_GroupPtr group)
587
MAPtr ma = group->ma;
589
{{ /* find and exclude the "group" from the list of active groups */
591
for (node = ma->active_groups;
592
node && node->elem != group;
593
node = ListGetNext( node ))
601
if (node == ma->active_groups)
602
ma->active_groups = ListDelete( node );
607
{{ /* unset the "group"'s "only" actions */
609
for (i = 0; i < MK_Default; i++)
610
for (j = 0; j < MA_Init; j++)
611
if ( group->only[i][j] )
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;
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);
628
if (group->item != NULL)
629
SetStatus(group->item, FALSE);
632
(*group->done->func)(ma, &ma->trace, ma->trace.end, group->done->data);
638
extern Boolean MA_SetGroup(MA_GroupPtr group)
641
MAPtr ma = group->ma;
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]) ))
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++)
659
if (group->action[i][j] != NULL)
661
ASSERT ( !group->only[i][j] || !ma->only[i][j]);
662
if ( ma->only[i][j] )
664
ASSERT ( !group->only[i][j] );
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];
675
if ( ma->only[i][j] )
676
Disable( ma->menu[i][j] );
679
ListConnectRing( ma->active_groups );
680
ma->active_groups = ListInsertPrev(group, ma->active_groups);
681
ListBreakRing( ma->active_groups );
683
if (group->item != NULL)
684
SetStatus(group->item, TRUE);
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;
690
(*group->init->func)(ma, &ma->trace, ma->trace.end, group->init->data);
696
extern Boolean MA_LinkPanel(MAPtr ma, PaneL panel)
698
if (ma == NULL || panel == NULL)
701
SetPanelClick(panel, MA_ClickCB, MA_DragCB, MA_HoldCB, MA_ReleaseCB);
702
SetPanelExtra(panel, &ma);
708
extern PaneL MA_GetPanel(MAPtr ma)
710
return (PaneL) (ma ? ma->panel : NULL);
714
extern void MA_UnlinkPanel(MAPtr ma)
716
MAPtr ma_NULL = NULL;
718
if (ma == NULL || ma->panel == NULL)
721
SetPanelClick(ma->panel, NULL, NULL, NULL, NULL);
722
SetPanelExtra(ma->panel, &ma_NULL);
727
extern Boolean MA_SetVisible(MAPtr ma, Boolean visibility)
729
if (!ma || (!ma->group_menu && !ma->action_menu))
734
Show( ma->group_menu );
735
Show( ma->action_menu );
739
Hide( ma->group_menu );
740
Hide( ma->action_menu );
747
extern Boolean MA_GetVisible(MAPtr ma)
751
((ma->group_menu && Visible(ma->group_menu )) ||
752
(ma->action_menu && Visible(ma->action_menu))));
756
extern void MA_SetExtra(MAPtr ma, VoidPtr extra)
762
extern VoidPtr MA_GetExtra(MAPtr ma)
764
return (ma ? ma->extra : NULL);
768
extern void MA_Reset(MAPtr ma)
772
/* unset all presently active groups */
773
while ( ma->active_groups )
774
VERIFY ( MA_UnsetGroup( (MA_GroupPtr)ma->active_groups->elem ) );
777
MA_UnlinkPanel( ma );
779
/* Reset menu-based interface */
780
if ( ma->action_menu )
782
Reset( ma->action_menu );
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]);
789
if ( ma->group_menu )
791
if (ma->group_menu == ma->action_menu)
792
SeparatorItem( ma->action_menu );
794
Reset( ma->group_menu );
797
/* Reset internal data */
798
MA_SetExtra(ma, NULL);
800
while (ma->groups != NULL)
802
MemFree( ((MA_GroupPtr)ma->groups->elem)->name );
803
MemFree( ma->groups->elem );
804
ma->groups = ListDelete( ma->groups );
807
for (i = 0; i < MK_Default; i++)
808
for (j = 0; j < MA_Init; j++)
810
ma->action[i][j] = NULL;
811
ma->only [i][j] = FALSE;
814
while ( ma->actions )
816
MemFree( ((MActionPtr)ma->actions->elem)->name );
817
MemFree( ma->actions->elem );
818
ma->actions = ListDelete( ma->actions );
821
ma->mod_key = MK_Default;
822
ma->last_type = MA_Default;
826
extern void MA_Destroy(MAPtr ma)
833
/* EOF ($RCSfile: vibmouse.c,v $) */