/* 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 # include # include # include # include # include # include #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 = ": no-op()\n\ : no-op()"; static XtTranslations new_translations; static String old_table = ": highlight()\n\ : unhighlight()"; static XtTranslations old_translations; static String post_table = ": PostMenu()\n\ : PostMenu()\n\ : 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); }