Logo Search packages:      
Sourcecode: felt version File versions  Download package

post.c

/*
    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);
}

Generated by  Doxygen 1.6.0   Back to index