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

Drawing.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:    Drawing.c                                 *
 *                                                    *
 * Description:   This file contains the widget functions for the Drawing     *
 *          widget.                                         *
 ************************************************************************/

# include <stdio.h>
# include <math.h>
# include <X11/IntrinsicP.h>
# include <X11/StringDefs.h>
# include <X11/Xaw/XawInit.h>
# include "DrawingP.h"


/* Private functions */

static void    ClassInitialize ( );
static void    Initialize ( );
static void    Realize ( );
static void    Redisplay ( );
static void    Destroy ( );
static Boolean SetValues ( );


/* Resource defaults */

# define DefaultGrid          FALSE
# define DefaultGridSize      1.00
# define DefaultSnap          FALSE
# define DefaultSnapSize      0.25
# define DefaultXMin          0.00
# define DefaultXMax          10.0
# define DefaultYMin          0.00
# define DefaultYMax          10.0
# define DefaultXScale        50.0
# define DefaultYScale        50.0
# define DefaultCursor        "crosshair"


/* Private variables */

static float defaultgridsize  = DefaultGridSize;
static float defaultsnapsize  = DefaultSnapSize;
static float defaultxmin      = DefaultXMin;
static float defaultxmax      = DefaultXMax;
static float defaultymin      = DefaultYMin;
static float defaultymax      = DefaultYMax;
static float defaultxscale    = DefaultXScale;
static float defaultyscale    = DefaultYScale;


/* Resources */

# define offset(field) XtOffsetOf(DrawingRec, field)

static XtResource resources[] = {
{XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
    offset(drawing.foreground), XtRString, (XtPointer) XtDefaultForeground},
{XtNfont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
    offset(drawing.font), XtRString, (XtPointer) XtDefaultFont},
{XtNcoordinates, XtCCoordinates, XtRWidget, sizeof (Widget),
    offset(drawing.coord), XtRWidget, (XtPointer) NULL},
{XtNgrid, XtCGrid, XtRBoolean, sizeof (Boolean),
    offset(drawing.grid), XtRImmediate, (XtPointer) DefaultGrid},
{XtNgridSize, XtCGridSize, XtRFloat, sizeof (float),
    offset(drawing.gridSize), XtRFloat, (XtPointer) &defaultgridsize},
{XtNsnap, XtCSnap, XtRBoolean, sizeof (Boolean),
    offset(drawing.snap), XtRImmediate, (XtPointer) DefaultSnap},
{XtNsnapSize, XtCSnapSize, XtRFloat, sizeof (float),
    offset(drawing.snapSize), XtRFloat, (XtPointer) &defaultsnapsize},
{XtNxMin, XtCXMin, XtRFloat, sizeof (float),
    offset(drawing.xMin), XtRFloat, (XtPointer) &defaultxmin},
{XtNxMax, XtCXMax, XtRFloat, sizeof (float),
    offset(drawing.xMax), XtRFloat, (XtPointer) &defaultxmax},
{XtNyMin, XtCYMin, XtRFloat, sizeof (float),
    offset(drawing.yMin), XtRFloat, (XtPointer) &defaultymin},
{XtNyMax, XtCYMax, XtRFloat, sizeof (float),
    offset(drawing.yMax), XtRFloat, (XtPointer) &defaultymax},
{XtNxScale, XtCXScale, XtRFloat, sizeof (float),
    offset(drawing.xScale), XtRFloat, (XtPointer) &defaultxscale},
{XtNyScale, XtCYScale, XtRFloat, sizeof (float),
    offset(drawing.yScale), XtRFloat, (XtPointer) &defaultyscale},
{XtNbuttonCallback, XtCButtonCallback, XtRCallback, sizeof (XtPointer),
    offset(drawing.button), XtRImmediate, (XtPointer) NULL},
{XtNmotionCallback, XtCMotionCallback, XtRCallback, sizeof (XtPointer),
    offset(drawing.motion), XtRImmediate, (XtPointer) NULL},
{XtNinteractive, XtCInteractive, XtRBoolean, sizeof (Boolean),
    offset(drawing.interactive), XtRImmediate, (XtPointer) FALSE},
{XtNautoFind, XtCAutoFind, XtRBoolean, sizeof (Boolean),
    offset(drawing.search), XtRImmediate, (XtPointer) FALSE},
{XtNautoRedraw, XtCAutoRedraw, XtRBoolean, sizeof (Boolean),
    offset(drawing.redraw), XtRImmediate, (XtPointer) TRUE},
{XtNcursor, XtCCursor, XtRCursor, sizeof (Cursor),
    offset(simple.cursor), XtRString, (XtPointer) DefaultCursor},
};
# undef offset


DrawingClassRec drawingClassRec = {
  { /* core fields */
    /* superclass       */    (WidgetClass) &simpleClassRec,
    /* class_name       */    "Drawing",
    /* widget_size            */    sizeof (DrawingRec),
    /* class_initialize       */    ClassInitialize,
    /* class_part_initialize  */    NULL,
    /* class_inited           */    FALSE,
    /* initialize       */    Initialize,
    /* initialize_hook        */    NULL,
    /* realize                */    Realize,
    /* actions                */    NULL,
    /* num_actions            */    0,
    /* resources        */    resources,
    /* num_resources          */    XtNumber (resources),
    /* xrm_class        */    NULLQUARK,
    /* compress_motion        */    FALSE,
    /* compress_exposure      */    TRUE,
    /* compress_enterleave    */    TRUE,
    /* visible_interest       */    TRUE,
    /* destroy                */    Destroy,
    /* resize                 */    NULL,
    /* expose                 */    Redisplay,
    /* set_values       */    SetValues,
    /* set_values_hook        */    NULL,
    /* set_values_almost      */    XtInheritSetValuesAlmost,
    /* get_values_hook        */    NULL,
    /* accept_focus           */    NULL,
    /* version                */    XtVersion,
    /* callback_private       */    NULL,
    /* tm_table               */    NULL,
    /* query_geometry         */    XtInheritQueryGeometry,
    /* display_accelerator    */    XtInheritDisplayAccelerator,
    /* extension        */    NULL
  },
  { /* simple fields */
    /* change_sensitive       */    XtInheritChangeSensitive
  },
  { /* drawing fields */
    /* empty                  */    0
  }
};


WidgetClass drawingWidgetClass = (WidgetClass) &drawingClassRec;


/* Private functions */

/************************************************************************
   Function:      SnapCoord
   Description:   Snap the coordinates to the snap grid if enabled.
 ************************************************************************/

static void SnapCoord (dw, x, y)
    DrawingWidget dw;
    float    *x;
    float    *y;
{
    double snap;

    if (dw -> drawing.snap == True) {
      snap = dw -> drawing.snapSize;
      *x = (int) ((*x + snap / (*x >= 0 ? 2 : -2)) / snap) * snap;
      *y = (int) ((*y + snap / (*y >= 0 ? 2 : -2)) / snap) * snap;
    }
}



/************************************************************************
   Function:      MotionHandler
   Description:   Handles motion events when a button is not depressed.
 ************************************************************************/

static void MotionHandler (gw, clientData, event, cont)
    Widget    gw;
    XtPointer clientData;
    XEvent   *event;
    Boolean  *cont;
{
    DrawingReport report;
    DrawingWidget dw;
    Arg             al [1];
    char      string [40];
    float     realx;
    float     realy;
    int             x;
    int             y;


    dw = (DrawingWidget) gw;
    x = event -> xmotion.x;
    y = event -> xmotion.y;

    if (x < 0 || x > (int) dw -> drawing.width)
      return;

    if (y < 0 || y > (int) dw -> drawing.height)
      return;

    realx = RealX (x);
    realy = RealY (y);

    report.event       = event;
    report.unsnapped.x = realx;
    report.unsnapped.y = realy;
    report.snapped.x   = realx;
    report.snapped.y   = realy;
    SnapCoord (dw, &report.snapped.x, &report.snapped.y);

    if (dw -> drawing.coord != NULL) {
      sprintf (string, "%.*f,%.*f", dw -> drawing.xprecision,
      report.snapped.x, dw -> drawing.yprecision, report.snapped.y);
      XtSetArg (al [0], XtNlabel, string);
      XtSetValues (dw -> drawing.coord, al, 1);
    }

    XtCallCallbacks (gw, XtNmotionCallback, (XtPointer) &report);
}


/************************************************************************
   Function:      ButtonHandler
   Description:   Handles mouse events when a button is depressed.
 ************************************************************************/

static void ButtonHandler (gw, clientData, event, cont)
    Widget    gw;
    XtPointer clientData;
    XEvent   *event;
    Boolean  *cont;
{
    static DrawingReport report;
    DrawingWidget  dw;
    float          realx;
    float          realy;
    int                  x;
    int                  y;


    dw = (DrawingWidget) gw;
    x = event -> xmotion.x;
    y = event -> xmotion.y;

    if (x < 0)
      x = 0;
    else if (x > (int) dw -> drawing.width)
      x = dw -> drawing.width;

    if (y < 0)
      y = 0;
    else if (y > (int) dw -> drawing.height)
      y = dw -> drawing.height;


    realx = RealX (x);
    realy = RealY (y);

    report.event       = event;
    report.unsnapped.x = realx;
    report.unsnapped.y = realy;
    report.snapped.x   = realx;
    report.snapped.y   = realy;
    SnapCoord (dw, &report.snapped.x, &report.snapped.y);


    if (event -> type == ButtonPress)
      if (dw -> drawing.search == True)
          report.figure = DW_FindFigure (gw, realx, realy);
      else
          report.figure = NULL;

    XtCallCallbacks (gw, XtNbuttonCallback, (XtPointer) &report);
}


/************************************************************************
   Function:      SetClipRegion
   Description:   Sets the clip region to the size of the widget.
 ************************************************************************/

static void SetClipRegion (dw)
    DrawingWidget dw;
{
    Region     nullRegion;
    XRectangle rect;


    rect.x = 0;
    rect.y = 0;
    rect.width = dw -> drawing.width;
    rect.height = dw -> drawing.height;

    nullRegion = dw -> drawing.nullRegion;
    XIntersectRegion (nullRegion, dw -> drawing.region, dw -> drawing.region);
    XUnionRectWithRegion (&rect, dw -> drawing.region, dw -> drawing.region);
}


/************************************************************************
   Function:      DrawGrid
   Description:   Draw the grid on the window.
 ************************************************************************/

static void DrawGrid (gw)
    Widget gw;
{
    int             coord;
    float     size;
    float     x;
    float     y;
    float     min;
    float     max;
    float     scale;
    Display  *display;
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    display = XtDisplay (gw);

    min   = dw -> drawing.xMin;
    max   = dw -> drawing.xMax;
    size  = dw -> drawing.gridSize;
    scale = dw -> drawing.xScale;

    for (x = min - size; x <= max + size; x += size) {
      coord = ((int) (x / size) * size - min) * scale;
      XDrawLine (display, XtWindow (gw), dw -> drawing.gridgc, coord, 0,
               coord, dw -> drawing.height);
    }

    min   = dw -> drawing.yMin;
    max   = dw -> drawing.yMax;
    scale = dw -> drawing.yScale;

    for (y = min - size; y <= max + size; y += size) {
      coord = (max - (int) (y / size) * size) * scale;
      XDrawLine (display, XtWindow (gw), dw -> drawing.gridgc, 0, coord,
               dw -> drawing.width, coord);
    }
}


/************************************************************************
   Function:      DrawList
   Description:   Draws the display list.
 ************************************************************************/

static void DrawList (dw)
    DrawingWidget dw;
{
    Figure fig;


    for (fig = dw -> drawing.head; fig != NULL; fig = fig -> next)
      DW_DrawFigure (dw, fig);
}


/************************************************************************
   Function:      ScaleList
   Description:   Scales the display list.
 ************************************************************************/

static void ScaleList (dw)
    DrawingWidget dw;
{
    Figure fig;


    for (fig = dw -> drawing.head; fig != NULL; fig = fig -> next)
      DW_ScaleFigure (dw, fig);
}


/* Widget class functions */

/************************************************************************
   Function:      ClassInitialize
   Description: Initializes the widget class.
 ************************************************************************/

static void ClassInitialize ( )
{
    XawInitializeWidgetSet ( );
}


/************************************************************************
   Function:      Initialize
   Description:   Initializes the widget.
 ************************************************************************/

static void Initialize (request, new, argv, argc)
    Widget   request;
    Widget   new;
    ArgList  argv;
    Cardinal argc;
{
    Display  *display;
    XtArgVal        value;
    CacheData       data;
    DrawingWidget dw;


    dw = (DrawingWidget) new;
    display = XtDisplay (new);


    if (dw -> drawing.xMin >= dw -> drawing.xMax) {
      dw -> drawing.xMin = DefaultXMin;
      dw -> drawing.xMax = DefaultXMax;
    }

    if (dw -> drawing.yMin >= dw -> drawing.yMax) {
      dw -> drawing.yMin = DefaultYMin;
      dw -> drawing.yMax = DefaultYMax;
    }

    if (dw -> drawing.xScale <= 0)
      dw -> drawing.xScale = DefaultXScale;

    if (dw -> drawing.yScale <= 0)
      dw -> drawing.yScale = DefaultYScale;

    if (dw -> drawing.gridSize <= 0)
      dw -> drawing.gridSize = DefaultGridSize;

    if (dw -> drawing.snapSize <= 0)
      dw -> drawing.snapSize = DefaultSnapSize;


    dw -> drawing.width  = (dw -> drawing.xMax - dw -> drawing.xMin) *
                      dw -> drawing.xScale;
    dw -> drawing.height = (dw -> drawing.yMax - dw -> drawing.yMin) *
                      dw -> drawing.yScale;

    dw -> core.width  = dw -> drawing.width;
    dw -> core.height = dw -> drawing.height;

    dw -> drawing.gridgc = NULL;
    dw -> drawing.drawgc = NULL;
    dw -> drawing.head   = NULL;
    dw -> drawing.tail   = NULL;

    dw -> drawing.xprecision  = ceil (log10 (dw -> drawing.xScale));
    dw -> drawing.yprecision  = ceil (log10 (dw -> drawing.yScale));
    dw -> drawing.line_width  = 0;
    dw -> drawing.line_style  = DW_LineSolid;
    dw -> drawing.search      = False;
    dw -> drawing.interactive = False;
    dw -> drawing.redraw      = True;
    dw -> drawing.last_style  = -1;
    dw -> drawing.last_fg     = -1;
    dw -> drawing.last_width  = 0;
    dw -> drawing.last_font   = 0;

    dw -> drawing.color_cache = DW_CacheCreate ( );
    dw -> drawing.font_cache = DW_CacheCreate ( );

    value = (XtArgVal) dw -> drawing.foreground;
    data = DW_CacheInsert (dw -> drawing.color_cache, "initial", value);
    dw -> drawing.fg = dw -> drawing.foreground;
    dw -> drawing.color_data = data;

    value = (XtArgVal) dw -> drawing.font;
    data = DW_CacheInsert (dw -> drawing.font_cache, "initial", value);
    dw -> drawing.font_data = data;
}


/************************************************************************
   Function:      Realize
   Description: Realizes the widget by realizing the superclass.  Adds
            events handlers and creates the GCs.
 ************************************************************************/

static void Realize (gw, valuemaskp, attr)
    Widget          gw;
    XtValueMask          *valuemaskp;
    XSetWindowAttributes *attr;
{
    Display  *display;
    DrawingWidget dw;
    unsigned long mask;
    XGCValues       values;
    static char   dashes [ ] = {1, 4};


    dw = (DrawingWidget) gw;
    display = XtDisplay (gw);

    (*drawingWidgetClass -> core_class.superclass -> core_class.realize)
      (gw, valuemaskp, attr);

    mask = ButtonPressMask | ButtonReleaseMask | OwnerGrabButtonMask;
    mask |= Button1MotionMask | Button2MotionMask | Button3MotionMask;
    XtAddEventHandler (gw, mask, False, ButtonHandler, NULL);
    XtAddEventHandler (gw, PointerMotionMask, False, MotionHandler, NULL);


    mask = GCFunction | GCForeground | GCBackground | GCLineStyle;

    values.function   = GXcopy;
    values.line_style = LineOnOffDash;
    values.background = dw -> core.background_pixel;
    values.foreground = dw -> drawing.foreground;

    dw -> drawing.gridgc = XCreateGC (display, XtWindow (gw), mask, &values);
    XSetDashes (display, dw -> drawing.gridgc, 0, dashes, 2);


    mask = GCFunction | GCForeground | GCBackground;

    values.function   = GXcopy;
    values.background = dw -> core.background_pixel;
    values.foreground = dw -> drawing.foreground;

    dw -> drawing.drawgc = XCreateGC (display, XtWindow (gw), mask, &values);


    mask = GCFunction | GCForeground | GCBackground;

    values.function   = GXxor;
    values.background = dw -> core.background_pixel;
    values.foreground = dw -> drawing.foreground ^ values.background;

    if (values.foreground == values.background)
      values.function = GXequiv;

    dw -> drawing.intergc = XCreateGC (display, XtWindow (gw), mask, &values);


    dw -> drawing.region = XCreateRegion ( );
    dw -> drawing.nullRegion = XCreateRegion ( );
    dw -> drawing.bufferRegion = XCreateRegion ( );
    SetClipRegion (dw);
}


/************************************************************************
   Function:      Destroy
   Description:   Destroys private resources.
 ************************************************************************/

static void Destroy (gw)
    Widget gw;
{
    Figure    fig;
    Figure    next;
    Display  *display;
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    display = XtDisplay (gw);

    if (dw -> drawing.region)
      XDestroyRegion (dw -> drawing.region);

    if (dw -> drawing.gridgc)
      XFreeGC (display, dw -> drawing.gridgc);

    if (dw -> drawing.drawgc)
      XFreeGC (display, dw -> drawing.drawgc);

    if (dw -> drawing.intergc)
      XFreeGC (display, dw -> drawing.intergc);

    fig = dw -> drawing.head;
    while (fig != NULL) {
      next = fig -> next;
      DW_DestroyFigure (fig);
      fig = next;
    }

    DW_CacheDestroy (dw -> drawing.font_cache);
    DW_CacheDestroy (dw -> drawing.color_cache);
}


/************************************************************************
   Function:      Redisplay
   Description:   Redisplays the widget.
 ************************************************************************/

static void Redisplay (gw, event, region)
    Widget  gw;
    XEvent *event;
    Region  region;
{
    Display  *display;
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    display = XtDisplay (gw);

    if (dw -> core.visible == True) {
      XIntersectRegion (region, dw -> drawing.region, region);
      XSetRegion (display, dw -> drawing.gridgc, region);
      XSetRegion (display, dw -> drawing.drawgc, region);

      if (dw -> drawing.grid == True)
          DrawGrid (gw);

      DrawList (dw);
      XSetRegion (display, dw -> drawing.gridgc, dw -> drawing.region);
      XSetRegion (display, dw -> drawing.drawgc, dw -> drawing.region);
    }
}


/************************************************************************
   Function:      SetValues
   Description:   Checks validity of new values and updates private
            information.
 ************************************************************************/

static Boolean SetValues (old, request, new, argv, argc)
    Widget   old;
    Widget   request;
    Widget   new;
    ArgList  argv;
    Cardinal argc;
{
    Boolean       resize;
    Boolean   rescale;
    Boolean       redisplay;
    DrawingWidget odw;
    DrawingWidget ndw;


    odw = (DrawingWidget) old;
    ndw = (DrawingWidget) new;

    resize    = False;
    rescale   = False;
    redisplay = False;


    if (ndw -> drawing.xMin >= ndw -> drawing.xMax) {
      ndw -> drawing.xMin = odw -> drawing.xMin;
      ndw -> drawing.xMax = odw -> drawing.xMax;
    }

    if (ndw -> drawing.yMin >= ndw -> drawing.yMax) {
      ndw -> drawing.yMin = odw -> drawing.yMin;
      ndw -> drawing.yMax = odw -> drawing.yMax;
    }

    if (ndw -> drawing.xScale <= 0)
      ndw -> drawing.xScale = odw -> drawing.xScale;

    if (ndw -> drawing.yScale <= 0)
      ndw -> drawing.yScale = odw -> drawing.yScale;

    if (ndw -> drawing.gridSize <= 0)
      ndw -> drawing.gridSize = odw -> drawing.gridSize;

    if (ndw -> drawing.snapSize <= 0)
      ndw -> drawing.snapSize = odw -> drawing.snapSize;


    ndw -> drawing.width  = (ndw -> drawing.xMax - ndw -> drawing.xMin) *
                       ndw -> drawing.xScale;
    ndw -> drawing.height = (ndw -> drawing.yMax - ndw -> drawing.yMin) *
                       ndw -> drawing.yScale;

    ndw -> drawing.xprecision  = ceil (log10 (ndw -> drawing.xScale));
    ndw -> drawing.yprecision  = ceil (log10 (ndw -> drawing.yScale));


    if (odw -> drawing.xMin != ndw -> drawing.xMin)
      redisplay = rescale = True;
    if (odw -> drawing.xMax != ndw -> drawing.xMax)
      redisplay = rescale = True;
    if (odw -> drawing.yMin != ndw -> drawing.yMin)
      redisplay = rescale = True;
    if (odw -> drawing.yMax != ndw -> drawing.yMax)
      redisplay = rescale = True;
    if (odw -> drawing.xScale != ndw -> drawing.xScale)
      redisplay = rescale = True;
    if (odw -> drawing.yScale != ndw -> drawing.yScale)
      redisplay = rescale = True;
    if (odw -> drawing.width != ndw -> drawing.width)
      redisplay = resize = True;
    if (odw -> drawing.height != ndw -> drawing.height)
      redisplay = resize = True;
    if (odw -> drawing.gridSize != ndw -> drawing.gridSize)
      redisplay = resize = True;
    if (odw -> drawing.grid != ndw -> drawing.grid)
      redisplay = True;

    if (odw -> drawing.interactive != ndw -> drawing.interactive)
      DW_SetInteractive (new, ndw -> drawing.interactive);

    if (odw -> drawing.redraw != ndw -> drawing.redraw)
      DW_SetAutoRedraw (new, ndw -> drawing.redraw);


    ndw -> core.width = ndw -> drawing.width;
    ndw -> core.height = ndw -> drawing.height;


    if (resize == True)
      SetClipRegion (ndw);

    if (rescale == True)
      ScaleList (ndw);

    return redisplay;
}

Generated by  Doxygen 1.6.0   Back to index