/*
This file is part of the FElt finite element analysis package.
Copyright (C) 1993-2000 Jason I. Gobat and Darren C. Atkinson
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/************************************************************************
* File: post.c *
* *
* Description: This file contains the public and private function *
* definitions for the postable menu mechanism. *
************************************************************************/
# include <stdio.h>
# include <X11/keysym.h>
# include <X11/cursorfont.h>
# include <X11/Intrinsic.h>
# include <X11/StringDefs.h>
# include <X11/Xaw/MenuButton.h>
# include <X11/Xaw/SimpleMenu.h>
#define printf do_nothing
void do_nothing ( ) { }
static Position x1;
static Position y1;
static Position x2;
static Position y2;
static Time when = 0;
static Boolean posted = False;
static Boolean from_inside = False;
static Boolean from_button = False;
static Cursor default_cursor;
static String new_table =
"<EnterWindow>: no-op()\n\
<LeaveWindow>: no-op()";
static XtTranslations new_translations;
static String old_table =
"<EnterWindow>: highlight()\n\
<LeaveWindow>: unhighlight()";
static XtTranslations old_translations;
static String post_table =
"<Key>: PostMenu()\n\
<BtnDown>: PostMenu()\n\
<BtnUp>: PostMenu()";
static XtTranslations post_translations;
/************************************************************************
* Function: highlight *
* *
* Description: Highlights a menu entry given by event location. *
************************************************************************/
static void highlight (w, event)
Widget w;
XEvent *event;
{
if (XtClass (w) == simpleMenuWidgetClass)
XtCallActionProc (w, "highlight", event, NULL, 0);
}
/************************************************************************
* Function: notify *
* *
* Description: Notifies a menu entry given by event location. *
************************************************************************/
static void notify (w, event)
Widget w;
XEvent *event;
{
if (XtClass (w) == simpleMenuWidgetClass)
XtCallActionProc (w, "notify", event, NULL, 0);
}
/************************************************************************
* Function: unhighlight *
* *
* Description: Unhighlights a menu entry given by event location. *
************************************************************************/
static void unhighlight (w, event)
Widget w;
XEvent *event;
{
if (XtClass (w) == simpleMenuWidgetClass)
XtCallActionProc (w, "unhighlight", event, NULL, 0);
}
/************************************************************************
* Function: move *
* *
* Description: Highlights the next or previous menu entry. *
************************************************************************/
static void move (w, sign)
Widget w;
int sign;
{
Arg args [3];
Position y;
Position min;
Position max;
Position value;
Dimension height;
Dimension width;
WidgetList children;
Cardinal i;
Cardinal num_children;
Widget entry;
Widget next;
XEvent event;
/* Make sure we have a menu and not something else. */
if (XtClass (w) != simpleMenuWidgetClass)
return;
/* Get information from the menu. */
XtSetArg (args [0], XtNwidth, &width);
XtSetArg (args [1], XtNchildren, &children);
XtSetArg (args [2], XtNnumChildren, &num_children);
XtGetValues (w, args, 3);
/* Determine the y coordinate of the active entry. */
entry = XawSimpleMenuGetActiveEntry (w);
if (entry != NULL) {
XtSetArg (args [0], XtNy, &value);
XtGetValues (entry, args, 1);
} else
value = -1;
/* Find the widget with the least y coordinate greater than our own. */
if (sign >= 0) {
next = NULL;
min = 32767;
for (i = 0; i < num_children; i ++)
if (XtIsSensitive (children [i]) && XtIsManaged (children [i])) {
XtSetArg (args [0], XtNy, &y);
XtGetValues (children [i], args, 1);
if (y < min && y > value) {
min = y;
next = children [i];
}
}
event.xbutton.y = min;
/* Find the widget with the greatest y coordinate less than our own. */
} else {
next = NULL;
max = -1;
for (i = 0; i < num_children; i ++)
if (XtIsSensitive (children [i]) && XtIsManaged (children [i])) {
XtSetArg (args [0], XtNy, &y);
XtGetValues (children [i], args, 1);
if (y > max && y < value) {
max = y;
next = children [i];
}
}
event.xbutton.y = max;
}
/* Nothing to do. */
if (next == NULL || next == entry)
return;
/* Construct a synthetic event and highlight the entry. */
XtSetArg (args [0], XtNheight, &height);
XtGetValues (next, args, 1);
event.type = ButtonPress;
event.xbutton.x = width / 2;
event.xbutton.y += height / 2;
highlight (w, &event);
}
/************************************************************************
* Function: grab *
* *
* Description: Grabs the keyboard and pointer. *
************************************************************************/
static void grab (w, time)
Widget w;
Time time;
{
Arg args [1];
Widget v;
Cursor cursor;
if (XtClass (w) != menuButtonWidgetClass) {
cursor = None;
for (v = w; v && !cursor; v = XtParent (v)) {
XtSetArg (args [0], XtNcursor, &cursor);
XtGetValues (v, args, 1);
}
if (cursor == None)
cursor = default_cursor;
XtGrabKeyboard (w, True, GrabModeAsync, GrabModeAsync, time);
XtGrabPointer (w, True, ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, None, cursor, time);
}
}
/************************************************************************
* Function: ungrab *
* *
* Description: Ungrabs the keyboard and pointer *
************************************************************************/
static void ungrab (w, time)
Widget w;
Time time;
{
if (XtClass (w) != menuButtonWidgetClass) {
XtUngrabKeyboard (w, time);
XtUngrabPointer (w, time);
}
}
/************************************************************************
* Function: inside *
* *
* Description: Determines if the pointer is inside a rectangle. *
************************************************************************/
static int inside (event)
XEvent *event;
{
Position x;
Position y;
x = event -> xbutton.x_root;
y = event -> xbutton.y_root;
return x >= x1 && x <= x2 && y >= y1 && y <= y2;
}
/************************************************************************
* Function: popup *
* *
* Description: Pops up the menu. *
************************************************************************/
static void popup (w)
Widget w;
{
Arg args [4];
Position x;
Position y;
Dimension width;
Dimension height;
/* Make sure we have the menu button and not the menu. */
if (XtClass (w) != menuButtonWidgetClass)
return;
/* Retrieve and save the location of the button. */
XtSetArg (args [0], XtNx, &x);
XtSetArg (args [1], XtNy, &y);
XtSetArg (args [2], XtNwidth, &width);
XtSetArg (args [3], XtNheight, &height);
XtGetValues (w, args, 4);
XtTranslateCoords (XtParent (w), x, y, &x1, &y1);
XtTranslateCoords (XtParent (w), x + width, y + height, &x2, &y2);
/* Pop up the menu. */
XtCallActionProc (w, "PopupMenu", NULL, NULL, 0);
posted = True;
from_inside = False;
}
/************************************************************************
* Function: popdown *
* *
* Description: Pops down the menu. *
************************************************************************/
static void popdown (w)
Widget w;
{
if (XtClass (w) == simpleMenuWidgetClass)
XtOverrideTranslations (w, old_translations);
XtPopdown (w);
from_inside = False;
posted = False;
}
/************************************************************************
* Function: nop *
* *
* Description: Empty action procedure. *
************************************************************************/
static void nop (w, event, params, num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
}
/************************************************************************
* Function: action *
* *
* Description: Action procedure to handle events occuring on a *
* postable menu. *
************************************************************************/
void action (w, event, params, num_params)
Widget w;
XEvent *event;
String *params;
Cardinal *num_params;
{
Time now;
KeySym keysym;
Modifiers modifiers;
printf ("%s ", XtName (w));
switch (event -> type) {
case KeyPress:
printf ("key ");
now = event -> xkey.time;
keysym = XtGetActionKeysym (event, &modifiers);
switch (keysym) {
case XK_Return:
case XK_space:
if (!posted && when != now) {
printf ("popup");
grab (w, now);
popup (w);
when = now;
} else if (posted && when != now) {
printf ("popdown");
ungrab (w, now);
popdown (w);
notify (w, event);
unhighlight (w, event);
} else if (when == now) {
printf ("here");
grab (w, now);
if (XtClass (w) == simpleMenuWidgetClass)
XtOverrideTranslations (w, new_translations);
} else
printf ("%d %d\n", when, now);
break;
case XK_Down:
if (posted) {
move (w, 1);
break;
}
case XK_Up:
if (posted) {
move (w, -1);
break;
}
default:
if (!posted && when != now) {
printf ("popup");
grab (w, now);
popup (w);
when = now;
} else if (posted && when != now) {
printf ("popdown");
ungrab (w, now);
popdown (w);
unhighlight (w, event);
} else if (when == now) {
printf ("here");
grab (w, now);
if (XtClass (w) == simpleMenuWidgetClass)
XtOverrideTranslations (w, new_translations);
}
break;
}
break;
case ButtonPress:
printf ("down ");
now = event -> xbutton.time;
if (XtClass (w) == menuButtonWidgetClass)
from_button = True;
if (posted && when != now) {
printf ("highlight");
highlight (w, event);
} else if (!posted) {
printf ("popup");
grab (w, now);
popup (w);
when = now;
}
break;
case ButtonRelease:
printf ("up ");
now = event -> xbutton.time;
if (from_button && !from_inside && inside (event)) {
printf ("inside");
XtOverrideTranslations (w, new_translations);
grab (w, now);
when = now;
from_inside = True;
} else if (when != now) {
printf ("popdown");
ungrab (w, now);
popdown (w);
notify (w, event);
unhighlight (w, event);
}
break;
}
printf ("\n");
}
/************************************************************************
* Function: AddPostMenuActions *
* *
* Description: Adds the postable menu actions to the specified widget. *
************************************************************************/
void AddPostMenuActions (w)
Widget w;
{
static XtAppContext app_context = NULL;
static XtActionsRec actions [ ] = {{"PostMenu", action}, {"no-op", nop}};
if (app_context == NULL) {
app_context = XtWidgetToApplicationContext (w);
XtAppAddActions (app_context, actions, XtNumber (actions));
post_translations = XtParseTranslationTable (post_table);
new_translations = XtParseTranslationTable (new_table);
old_translations = XtParseTranslationTable (old_table);
default_cursor = XCreateFontCursor (XtDisplay (w), XC_top_left_arrow);
}
XtOverrideTranslations (w, post_translations);
}
syntax highlighted by Code2HTML, v. 0.9.1