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

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

# include <stdio.h>
# include <math.h>
# include <string.h>
# include <X11/IntrinsicP.h>
# include "DrawingP.h"

# define PUSH 0
# define POP  1
# define Inside(a,x,b)  ((a) <= (x) && (x) <= (b))
# define Sqr(x)         ((x) * (x))


/************************************************************************
   Function:      SetColor
   Description:   Sets the cached color of the widget or a figure.
 ************************************************************************/

static Boolean SetColor (dw, old_data, name, pixel)
    DrawingWidget dw;
    CacheData      *old_data;
    String    name;
    Pixel    *pixel;
{
    Display  *display;
    CacheData data;
    XColor    color;


    display = XtDisplay ((Widget) dw);

    if ((data = DW_CacheLookup (dw -> drawing.color_cache, name)) != NULL) {
      if (*old_data != data) {
          DW_CacheDelRef (*old_data);
          DW_CacheAddRef (*old_data = data);
      }
      *pixel = (Pixel) data -> value;
      return True;
    }

    if (!XParseColor (display, dw -> core.colormap, name, &color))
      return False;

    if (!XAllocColor (display, dw -> core.colormap, &color))
      return False;

    *pixel = color.pixel;
    data = DW_CacheInsert (dw -> drawing.color_cache, name, (XtArgVal) *pixel);
    DW_CacheDelRef (*old_data);
    *old_data = data;
    return True;
}


/************************************************************************
   Function:      SetFont
   Description:   Sets the cached font of the widget or a figure.
 ************************************************************************/

static Boolean SetFont (dw, old_data, name, font)
    DrawingWidget dw;
    CacheData      *old_data;
    String    name;
    XFontStruct   **font;
{
    Display  *display;
    CacheData data;


    display = XtDisplay ((Widget) dw);

    if ((data = DW_CacheLookup (dw -> drawing.font_cache, name)) != NULL) {
      if (*old_data != data) {
          DW_CacheDelRef (*old_data);
          DW_CacheAddRef (*old_data = data);
      }
      *font = (XFontStruct *) data -> value;
      return True;
    }


    if ((*font = XLoadQueryFont (display, name)) == NULL)
      return False;

    data = DW_CacheInsert (dw -> drawing.font_cache, name, (XtArgVal) *font);
    DW_CacheDelRef (*old_data);
    *old_data = data;
    return True;
}


/************************************************************************
   Function:      StackAutoRedraw
   Description:   Stacks the auto redraw status for group operations.
 ************************************************************************/

static void StackAutoRedraw (gw, op)
   Widget gw;
   int    op;
{
   static unsigned depth = 0;
   static Boolean  redraw;


   if (op == PUSH && !depth ++) {
      redraw = ((DrawingWidget) gw) -> drawing.redraw;
      DW_SetAutoRedraw (gw, False);
   }

   if (op == POP && ! -- depth)
      DW_SetAutoRedraw (gw, redraw);
}


/************************************************************************
   Function:      GroupLeader
   Description:   Return the group leader of a figure.
 ************************************************************************/

static Figure GroupLeader (fig)
    Figure fig;
{
    while (fig -> group != NULL)
      fig = fig -> group;

    return fig;
}


/************************************************************************
   Function:      DW_DrawLine
   Description: Adds a line figure to the display list.
 ************************************************************************/

Figure DW_DrawLine (gw, x1, y1, x2, y2)
    Widget  gw;
    FLOAT   x1;
    FLOAT   y1;
    FLOAT   x2;
    FLOAT   y2;
{
    Figure    fig;
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    fig = DW_CreateFigure (dw, LineFigure, False, 2);

    fig -> info.line.points [0].x = x1;
    fig -> info.line.points [0].y = y1;
    fig -> info.line.points [1].x = x2;
    fig -> info.line.points [1].y = y2;

    DW_AppendFigure (dw, fig);
    DW_ScaleFigure  (dw, fig);
    DW_DrawFigure   (dw, fig);

    return fig;
}


/************************************************************************
   Function:      DW_DrawPolygon
   Description: Adds a polygon figure to the display list.
 ************************************************************************/

Figure DW_DrawPolygon (gw, scaled, points, npoints)
    Widget  gw;
    BOOLEAN scaled;
    Point   points [ ];
    int     npoints;
{
    int             i;
    Figure    fig;
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    fig = DW_CreateFigure (dw, PolygonFigure, scaled, npoints);

    for (i = 0; i < npoints; i ++)
      fig -> info.polygon.points [i] = points [i];

    DW_AppendFigure (dw, fig);
    DW_ScaleFigure  (dw, fig);
    DW_DrawFigure   (dw, fig);

    return fig;
}


/************************************************************************
   Function:      DW_FillPolygon
   Description: Adds a filled polygon figure to the display list.
 ************************************************************************/

Figure DW_FillPolygon (gw, scaled, points, npoints)
    Widget  gw;
    BOOLEAN scaled;
    Point   points [ ];
    int     npoints;
{
    int             i;
    Figure    fig;
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    fig = DW_CreateFigure (dw, PolygonFigure, scaled, npoints);
    fig -> info.polygon.filled = True;

    for (i = 0; i < npoints; i ++)
      fig -> info.polygon.points [i] = points [i];

    DW_AppendFigure (dw, fig);
    DW_ScaleFigure  (dw, fig);
    DW_DrawFigure   (dw, fig);

    return fig;
}

/************************************************************************
   Function:      DW_DrawRectangle
   Description: Adds a rectangle figure to the display list.
 ************************************************************************/

Figure DW_DrawRectangle (gw, scaled, x, y, width, height)
    Widget  gw;
    BOOLEAN scaled;
    FLOAT   x;
    FLOAT   y;
    FLOAT   width;
    FLOAT   height;
{
    Figure    fig;
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    fig = DW_CreateFigure (dw, RectangleFigure, scaled, 0);

    fig -> info.rectangle.x      = x;
    fig -> info.rectangle.y      = y;
    fig -> info.rectangle.width  = width;
    fig -> info.rectangle.height = height;

    DW_AppendFigure (dw, fig);
    DW_ScaleFigure  (dw, fig);
    DW_DrawFigure   (dw, fig);

    return fig;
}


/************************************************************************
   Function:      DW_FillRectangle
   Description: Adds a filled rectangle figure to the display list.
 ************************************************************************/

Figure DW_FillRectangle (gw, scaled, x, y, width, height)
    Widget  gw;
    BOOLEAN scaled;
    FLOAT   x;
    FLOAT   y;
    FLOAT   width;
    FLOAT   height;
{
    Figure    fig;
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    fig = DW_CreateFigure (dw, RectangleFigure, scaled, 1);

    fig -> info.rectangle.x      = x;
    fig -> info.rectangle.y      = y;
    fig -> info.rectangle.width  = width;
    fig -> info.rectangle.height = height;

    DW_AppendFigure (dw, fig);
    DW_ScaleFigure  (dw, fig);
    DW_DrawFigure   (dw, fig);

    return fig;
}


/************************************************************************
   Function:      DW_DrawArc
   Description: Adds an arc figure to the display list.
 ************************************************************************/

Figure DW_DrawArc (gw, scaled, x, y, width, height, start, length)
    Widget  gw;
    BOOLEAN scaled;
    FLOAT   x;
    FLOAT   y;
    FLOAT   width;
    FLOAT   height;
    FLOAT   start;
    FLOAT   length;
{
    Figure    fig;
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    fig = DW_CreateFigure (dw, ArcFigure, scaled, 0);

    fig -> info.arc.x      = x;
    fig -> info.arc.y      = y;
    fig -> info.arc.width  = width;
    fig -> info.arc.height = height;
    fig -> info.arc.start  = start * 64;
    fig -> info.arc.length = length * 64;

    DW_AppendFigure (dw, fig);
    DW_ScaleFigure  (dw, fig);
    DW_DrawFigure   (dw, fig);

    return fig;
}


/************************************************************************
   Function:      DW_FillArc
   Description: Adds an filled arc figure to the display list.
 ************************************************************************/

Figure DW_FillArc (gw, scaled, x, y, width, height, start, length)
    Widget  gw;
    BOOLEAN scaled;
    FLOAT   x;
    FLOAT   y;
    FLOAT   width;
    FLOAT   height;
    FLOAT   start;
    FLOAT   length;
{
    Figure    fig;
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    fig = DW_CreateFigure (dw, ArcFigure, scaled, 1);

    fig -> info.arc.x      = x;
    fig -> info.arc.y      = y;
    fig -> info.arc.width  = width;
    fig -> info.arc.height = height;
    fig -> info.arc.start  = start * 64;
    fig -> info.arc.length = length * 64;

    DW_AppendFigure (dw, fig);
    DW_ScaleFigure  (dw, fig);
    DW_DrawFigure   (dw, fig);

    return fig;
}


/************************************************************************
   Function:      DW_DrawText
   Description: Adds a text figure to the display list.
 ************************************************************************/

Figure DW_DrawText (gw, scaled, x, y, text)
    Widget  gw;
    BOOLEAN scaled;
    FLOAT   x;
    FLOAT   y;
    String  text;
{
    Figure    fig;
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    fig = DW_CreateFigure (dw, TextFigure, scaled, 0);

    fig -> info.text.rx     = x;
    fig -> info.text.ry     = y;
    fig -> info.text.string = XtNewString (text);
    fig -> info.text.length = strlen (text);

    DW_AppendFigure (dw, fig);
    DW_ScaleFigure  (dw, fig);
    DW_DrawFigure   (dw, fig);

    return fig;
}


/************************************************************************
   Function:      DW_DrawPixmap
   Description:   Adds a pixmap figure to the display list.  The pixmap is
            is neither copied nor scaled.
 ************************************************************************/

Figure DW_DrawPixmap (gw, x, y, pixmap)
    Widget gw;
    FLOAT  x;
    FLOAT  y;
    Pixmap pixmap;
{
    Figure        fig;
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    fig = DW_CreateFigure (dw, PixmapFigure, False, 0);

    fig -> info.pixmap.x      = x;
    fig -> info.pixmap.y      = y;
    fig -> info.pixmap.pixmap = pixmap;

    DW_AppendFigure (dw, fig);
    DW_ScaleFigure  (dw, fig);
    DW_DrawFigure   (dw, fig);

    return fig;
}


/************************************************************************
   Function:      DW_DrawBitmap
   Description:   Adds a bitmap figure to the display list.  The pixmap is
            is neither copied nor scaled.  The difference between
            a Pixmap and a Bitmap is that a Pixmap is copied into
            the window while a Bitmap is rendered such that only the
            pixels which are set are displayed in the foreground
            color and the pixels which are not set are ignored.
 ************************************************************************/

Figure DW_DrawBitmap (gw, x, y, pixmap)
    Widget gw;
    FLOAT  x;
    FLOAT  y;
    Pixmap pixmap;
{
    Figure        fig;
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    fig = DW_CreateFigure (dw, BitmapFigure, False, 0);

    fig -> info.pixmap.x      = x;
    fig -> info.pixmap.y      = y;
    fig -> info.pixmap.pixmap = pixmap;

    DW_AppendFigure (dw, fig);
    DW_ScaleFigure  (dw, fig);
    DW_DrawFigure   (dw, fig);

    return fig;
}


/************************************************************************
   Function:      DW_SetForeground
   Description:   Sets the foreground pixel value for drawing.
 ************************************************************************/

Boolean DW_SetForeground (gw, name)
    Widget gw;
    String name;
{
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    return SetColor (dw, &dw -> drawing.color_data, name, &dw -> drawing.fg);
}


/************************************************************************
   Function:      DW_SetFont
   Description:   Sets the font for drawing.
 ************************************************************************/

Boolean DW_SetFont (gw, name)
    Widget gw;
    String name;
{
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    return SetFont (dw, &dw -> drawing.font_data, name, &dw -> drawing.font);
}

/************************************************************************
   Function:      DW_GetTextExtents
   Description:   Gets the scaled width and height of a text string
 ************************************************************************/

void DW_GetTextExtents (gw, string, w, h)
    Widget  gw;
    String  string;
    float  *w;
    float  *h;
{
    DrawingWidget dw;
    int               far;
    int           dr;
    int           fdr;
    XCharStruct   cstruct;    

    dw = (DrawingWidget) gw;

    XTextExtents (dw -> drawing.font, string, strlen (string), 
                  &dr, &far, &fdr, &cstruct);

    *w = cstruct.width / dw -> drawing.xScale;
    *h = (cstruct.ascent + cstruct.descent) / dw -> drawing.yScale;
} 

/************************************************************************
   Function:      DW_SetLineWidth
   Description:   Sets the line width for drawing.
 ************************************************************************/

void DW_SetLineWidth (gw, width)
    Widget   gw;
    unsigned width;
{
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    dw -> drawing.line_width = width;
}


/************************************************************************
   Function:      DW_SetLineStyle
   Description:   Sets the line style for drawing.
 ************************************************************************/

void DW_SetLineStyle (gw, style)
    Widget gw;
    int    style;
{
    DrawingWidget dw;


    if (style >= DW_LineSolid && style <= DW_LineLongDashed) {
      dw = (DrawingWidget) gw;
      dw -> drawing.line_style = style;
    }
}


/************************************************************************
   Function:      DW_RaiseFigure
   Description:   Place the figure at the top of the display list.
 ************************************************************************/

void DW_RaiseFigure (gw, fig)
    Widget gw;
    Figure fig;
{
    unsigned i;


    if (fig != NULL) {
      if (fig -> type == GroupFigure)
          for (i = 0; i < fig -> info.group.nfigs; i ++)
            DW_RaiseFigure (gw, fig -> info.group.fig [i]);
      else {
          DW_DeleteFigure ((DrawingWidget) gw, fig);
          DW_AppendFigure ((DrawingWidget) gw, fig);
          DW_DrawFigure   ((DrawingWidget) gw, fig);
      }
    }
}


/************************************************************************
   Function:      DW_LowerFigure
   Description:   Place the figure at the bottom of the display list.
 ************************************************************************/

void DW_LowerFigure (gw, fig)
    Widget gw;
    Figure fig;
{
    unsigned i;


    if (fig != NULL) {
      if (fig -> type == GroupFigure) {
          StackAutoRedraw (gw, PUSH);
          for (i = 0; i < fig -> info.group.nfigs; i ++)
            DW_LowerFigure (gw, fig -> info.group.fig [i]);
          StackAutoRedraw (gw, POP);
      } else {
          DW_DeleteFigure  ((DrawingWidget) gw, fig);
          DW_PrependFigure ((DrawingWidget) gw, fig);
          DW_ClearFigure   ((DrawingWidget) gw, fig);
      }
    }
}


/************************************************************************
   Function:      DW_RemoveFigure
   Description:   Remove the figure from the display list.
 ************************************************************************/

void DW_RemoveFigure (gw, fig)
    Widget gw;
    Figure fig;
{
    unsigned i;


    if (fig != NULL) {
      if (fig -> type == GroupFigure) {
          StackAutoRedraw (gw, PUSH);
          for (i = 0; i < fig -> info.group.nfigs; i ++)
            DW_RemoveFigure (gw, fig -> info.group.fig [i]);
          StackAutoRedraw (gw, POP);
      } else {
          DW_DeleteFigure  ((DrawingWidget) gw, fig);
          DW_ClearFigure   ((DrawingWidget) gw, fig);
      }
      DW_DestroyFigure (fig);
    }
}


/************************************************************************
   Function:      DW_RemoveAll
   Descripton:    Remove all figures from the display list.
 ************************************************************************/

void DW_RemoveAll (gw)
    Widget gw;
{
    Figure        fig;
    Figure    next;
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    fig = dw -> drawing.head;

    while (fig != NULL) {
      next = fig -> next;
      DW_DestroyFigure (fig);
      fig = next;
    }

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

    XClearArea (XtDisplay (gw), XtWindow (gw), 0, 0, dw -> drawing.width,
            dw -> drawing.height, True);
}


/************************************************************************
   Function:      DW_Redraw
   Description:   Force a total redraw of the widget.
 ************************************************************************/

void DW_Redraw (gw)
    Widget gw;
{
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    XClearArea (XtDisplay (gw), XtWindow (gw), 0, 0, dw -> drawing.width,
            dw -> drawing.height, True);
}


/************************************************************************
   Function:      DW_GetAttributes
   Description: Get the attributes of a figure.
 ************************************************************************/

void DW_GetAttributes (gw, fig, values)
    Widget            gw;
    Figure            fig;
    FigureAttributes *values;
{
    if (fig == NULL || values == NULL)
      return;


    values -> type       = fig -> type;
    values -> color      = fig -> color_data -> name;
    values -> user_data  = fig -> userdata;
    values -> visible    = fig -> visible;
    values -> group      = fig -> group;


    switch (fig -> type) {
    case LineFigure:
      values -> line_width = fig -> line_width;
      values -> line_style = fig -> line_style;
      values -> points     = fig -> info.line.points;
      values -> npoints    = 2;
      break;


    case PolygonFigure:
      values -> line_width = fig -> line_width;
      values -> line_style = fig -> line_style;
      values -> filled     = fig -> info.polygon.filled;
      values -> scaled     = fig -> info.polygon.scaled;
      values -> points     = fig -> info.polygon.points;
      values -> npoints    = fig -> info.polygon.npoints;
      break;


    case RectangleFigure:
      values -> line_width = fig -> line_width;
      values -> line_style = fig -> line_style;
      values -> filled     = fig -> info.rectangle.filled;
      values -> scaled     = fig -> info.rectangle.scaled;
      values -> x      = fig -> info.rectangle.x;
      values -> y      = fig -> info.rectangle.y;
      values -> width        = fig -> info.rectangle.width;
      values -> height     = fig -> info.rectangle.height;
      break;


    case ArcFigure:
      values -> line_width = fig -> line_width;
      values -> line_style = fig -> line_style;
      values -> filled     = fig -> info.arc.filled;
      values -> scaled     = fig -> info.arc.scaled;
      values -> x      = fig -> info.arc.x;
      values -> y      = fig -> info.arc.y;
      values -> width        = fig -> info.arc.width;
      values -> height     = fig -> info.arc.height;
      values -> arc_start  = fig -> info.arc.start / 64.0;
      values -> arc_length = fig -> info.arc.length / 64.0;
      break;


    case TextFigure:
      values -> scaled      = fig -> info.text.scaled;
      values -> x       = fig -> info.text.rx;
      values -> y       = fig -> info.text.ry;
      values -> text          = fig -> info.text.string;
      values -> font          = fig -> info.text.font_data -> name;
      values -> font_struct = fig -> info.text.font;
      break;


    case GroupFigure:
      values -> figures  = fig -> info.group.fig;
      values -> nfigures = fig -> info.group.nfigs;
      break;


    case PixmapFigure:
    case BitmapFigure:
      values -> x      = fig -> info.pixmap.x;
      values -> y      = fig -> info.pixmap.y;
      values -> pixmap = fig -> info.pixmap.pixmap;
      break;
    }
}


/************************************************************************
   Function:      DW_SetAttributes
   Description: Set the attributes of a figure.
 ************************************************************************/

Boolean DW_SetAttributes (gw, fig, valuemask, values)
    Widget        gw;
    Figure        fig;
    unsigned long     valuemask;
    FigureAttributes *values;
{
    int             i;
    int             style;
    Boolean   redraw;
    Boolean   status;
    Region    buffer;
    XRectangle      rect;
    DrawingWidget dw;
    struct figure copy;


    if (fig == NULL || values == NULL)
      return True;


    if (fig -> type == GroupFigure) {
      for (i = 0; i < fig -> info.group.nfigs; i ++)
          (void) DW_SetAttributes (gw, fig -> info.group.fig [i], valuemask,
                                                      values);
      return True;
    }


    copy = *fig;
    redraw = False;
    status = True;
    dw = (DrawingWidget) gw;
    buffer = dw -> drawing.bufferRegion;


    if (valuemask & DW_FigureGroup) {
      DW_Detach (dw, fig);
      DW_Attach (dw, fig, values -> group);
    }


    if (valuemask & DW_FigureLineWidth) {
      switch (fig -> type) {
      case LineFigure:
      case PolygonFigure:
      case RectangleFigure:
      case ArcFigure:
          redraw = True;
          fig -> line_width = values -> line_width;
          break;
      default:
          status = False;
      }
    }


    if (valuemask & DW_FigureLineStyle) {
      style = values -> line_style;
      if (style >= DW_LineSolid && style <= DW_LineLongDashed) {
          switch (fig -> type) {
          case LineFigure:
          case PolygonFigure:
          case RectangleFigure:
          case ArcFigure:
            redraw = True;
            fig -> line_style = values -> line_style;
            break;
          default:
            status = False;
          }
      } else
          status = False;
    }


    if (valuemask & DW_FigureVisible) {
      redraw = fig -> visible != values -> visible ? True : False;
      fig -> visible = values -> visible;
    }


    if (valuemask & DW_FigureFilled) {
      switch (fig -> type) {
      case PolygonFigure:
          redraw = True;
          fig -> info.polygon.filled = values -> filled;
          break;
      case RectangleFigure:
          redraw = True;
          fig -> info.rectangle.filled = values -> filled;
          break;
      case ArcFigure:
          redraw = True;
          fig -> info.arc.filled = values -> filled;
          break;
      default:
          status = False;
      }
    }


    if (valuemask & DW_FigureScaled) {
      switch (fig -> type) {
      case PolygonFigure:
          redraw = True;
          fig -> info.polygon.scaled = values -> scaled;
          break;
      case RectangleFigure:
          redraw = True;
          fig -> info.rectangle.scaled = values -> scaled;
          break;
      case ArcFigure:
          redraw = True;
          fig -> info.arc.scaled = values -> scaled;
          break;
      case TextFigure:
          redraw = True;
          fig -> info.text.scaled = values -> scaled;
          break;
      default:
          status = False;
      }
    }


    if (valuemask & DW_FigureColor) {
      redraw = True;
      if (SetColor (dw, &fig -> color_data, values -> color, &fig -> fg))
          status = False;
    }


    if (valuemask & DW_FigureFont) {
      switch (fig -> type) {
      case TextFigure:
          redraw = True;
          if (SetFont (dw, &fig -> info.text.font_data, values -> font,
          &fig -> info.text.font))
            status = False;
          break;
      default:
          status = False;
      }
    }


    if (valuemask & DW_FigureText) {
      switch (fig -> type) {
      case TextFigure:
          redraw = True;
          fig -> info.text.string = XtNewString (values -> text);
          fig -> info.text.length = strlen (values -> text);
          break;
      default:
          status = False;
      }
    }


    if (valuemask & DW_FigureX) {
      switch (fig -> type) {
      case RectangleFigure:
          redraw = True;
          fig -> info.rectangle.x = values -> x;
          break;
      case ArcFigure:
          redraw = True;
          fig -> info.arc.x = values -> x;
          break;
      case TextFigure:
          redraw = True;
          fig -> info.text.rx = values -> x;
          break;
      case PixmapFigure:
      case BitmapFigure:
          redraw = True;
          fig -> info.pixmap.x = values -> x;
          break;
      default:
          status = False;
      }
    }


    if (valuemask & DW_FigureY) {
      switch (fig -> type) {
      case RectangleFigure:
          redraw = True;
          fig -> info.rectangle.y = values -> y;
          break;
      case ArcFigure:
          redraw = True;
          fig -> info.arc.y = values -> y;
          break;
      case TextFigure:
          redraw = True;
          fig -> info.text.ry = values -> y;
          break;
      case PixmapFigure:
      case BitmapFigure:
          redraw = True;
          fig -> info.pixmap.y = values -> y;
          break;
      default:
          status = False;
      }
    }


    if (valuemask & DW_FigureWidth) {
      switch (fig -> type) {
      case RectangleFigure:
          redraw = True;
          fig -> info.rectangle.width = values -> width;
          break;
      case ArcFigure:
          redraw = True;
          fig -> info.arc.width = values -> width;
          break;
      default:
          status = False;
      }
    }


    if (valuemask & DW_FigureHeight) {
      switch (fig -> type) {
      case RectangleFigure:
          redraw = True;
          fig -> info.rectangle.height = values -> height;
          break;
      case ArcFigure:
          redraw = True;
          fig -> info.arc.height = values -> height;
          break;
      default:
          status = False;
      }
    }


    if (valuemask & DW_FigureArcStart) {
      switch (fig -> type) {
      case ArcFigure:
          redraw = True;
          fig -> info.arc.start = values -> arc_start * 64;
          break;
      default:
          status = False;
      }
    }


    if (valuemask & DW_FigureArcLength) {
      switch (fig -> type) {
      case ArcFigure:
          redraw = True;
          fig -> info.arc.length = values -> arc_length * 64;
          break;
      default:
          status = False;
      }
    }


    if (valuemask & DW_FigurePoints) {
      switch (fig -> type) {
      case LineFigure:
          redraw = True;
          fig -> info.line.points [0] = values -> points [0];
          fig -> info.line.points [1] = values -> points [1];
          break;
      case PolygonFigure:
          redraw = True;
          break;
      default:
          status = False;
      }
    }


    if (valuemask & DW_FigurePixmap) {
      switch (fig -> type) {
      case PixmapFigure:
      case BitmapFigure:
          redraw = True;
          fig -> info.pixmap.pixmap = values -> pixmap;
          break;
      default:
          status = False;
      }
    }


    if (valuemask & DW_FigureUserData)
      fig -> userdata = values -> user_data;


    if (redraw == True) {
      if (dw -> drawing.interactive == True)
          DW_DrawFigure (dw, &copy);
      else {
          DW_ClipBox (&copy, &rect);
          rect.x -= copy.line_width + 1;
          rect.y -= copy.line_width + 1;
          rect.width += 2 * copy.line_width + 2;
          rect.height += 2 * copy.line_width + 2;
          XUnionRectWithRegion (&rect, buffer, buffer);
      }


      if (valuemask & DW_FigureText)
          XtFree (copy.info.text.string);

      if (valuemask & DW_FigurePoints && fig -> type == PolygonFigure) {
          fig -> info.polygon.points  = values -> points;
          fig -> info.polygon.npoints = values -> npoints;
      }


      DW_ScaleFigure (dw, fig);

      if (dw -> drawing.interactive == True)
          DW_DrawFigure  (dw, fig);
      else {
          DW_ClipBox (fig, &rect);
          rect.x -= fig -> line_width + 1;
          rect.y -= fig -> line_width + 1;
          rect.width += 2 * fig -> line_width + 2;
          rect.height += 2 * fig -> line_width + 2;
          XUnionRectWithRegion (&rect, buffer, buffer);

          if (dw -> drawing.redraw == True) {
            XClipBox (buffer, &rect);
            XClearArea (XtDisplay (gw), XtWindow (gw), rect.x, rect.y,
                      rect.width, rect.height, True);
            XIntersectRegion (dw -> drawing.nullRegion, buffer, buffer);
          }
      }
    }

    return status;
}
    

/************************************************************************
   Function:      online
   Description: Determines if a point lies close to a line.
 ************************************************************************/

static int online (start, end, x, y, delta)
    XPoint start;
    XPoint end;
    int    x;
    int    y;
    int    delta;
{
    int deltax;
    int deltay;
    int distx;
    int disty;
    int temp;


    deltax = start.x - end.x;
    deltay = start.y - end.y;
    distx  = x - start.x;
    disty  = y - start.y;

    if (Inside (-4, deltax, 4))
      return Inside (-6, distx, 6);

    temp = deltay * distx / deltax;
    return Inside (temp - delta, disty, temp + delta);
}


/************************************************************************
   Function:      DW_FindFigure
   Description:   Find the topmost figure containing the specified
            coordinates.
 ************************************************************************/

Figure DW_FindFigure (gw, realx, realy)
    Widget gw;
    FLOAT  realx;
    FLOAT  realy;
{
    Figure    fig;
    int             i;
    int             x;
    int             y;
    float     theta;
    float     cx;
    float     cy;
    float     rx;
    float     ry;
    int             fx;
    int             fy;
    unsigned        wd;
    unsigned        ht;
    unsigned        hw;
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    fig = dw -> drawing.tail;

    x = XAbs (realx);
    y = YAbs (realy);

    while (fig != NULL) {
      if (fig -> visible == False) {
          fig = fig -> prev;
          continue;
      }

      fx = fig -> x;
      fy = fig -> y;
      wd = fig -> width;
      ht = fig -> height;

      if (Inside (fx - 2, x, fx + wd + 2) && Inside (fy - 2, y, fy + ht + 2)){

          hw = (fig -> line_width + 1) / 2;
          if (hw < 5)
            hw = 5;

          switch (fig -> type) {
          case TextFigure:
          case PixmapFigure:
          case BitmapFigure:
            return GroupLeader (fig);


          case LineFigure:
            if (online (fig -> info.line.xpoints [0],
                      fig -> info.line.xpoints [1], x, y, hw))
                return GroupLeader (fig);
            break;


          case PolygonFigure:
            if (fig -> info.polygon.filled == True) {
                if (XPointInRegion (fig -> info.polygon.region, x, y)==True)
                  return GroupLeader (fig);
            } else
                for (i = 1; i < fig -> info.polygon.npoints; i ++)
                  if (online (fig -> info.polygon.xpoints [i - 1],
                      fig -> info.polygon.xpoints [i], x, y, hw))
                      return GroupLeader (fig);
            break;


          case RectangleFigure:
            if (fig -> info.rectangle.filled == True)
                 return GroupLeader (fig);

            if (Inside (fx - hw, x, fx + hw) ||
                Inside (fy - hw, y, fy + hw) ||
                Inside (fx + wd - hw, x, fx + wd + hw) ||
                Inside (fy + ht - hw, y, fy + ht + hw))
                return GroupLeader (fig);

            break;


          case ArcFigure:
            rx = wd / 2;
            ry = ht / 2;
            cx = x - fx - rx;
            cy = -y + fy + ry;
            theta = cx || cy ? atan2 (cy, cx) * 180 / 3.14159 : 0;
            if (theta < 0) theta = 360 + theta;
            theta *= 64;

            if (theta < fig -> info.arc.start)
                break;

            if (theta > fig -> info.arc.start + fig -> info.arc.length)
                break;

            if (fig -> info.arc.filled == True) {
                if (Sqr(cx)/Sqr(rx) + Sqr(cy)/Sqr(ry) <= 1)
                  return GroupLeader (fig);

            } else {
                if (Sqr(cx)/Sqr(rx+hw) + Sqr(cy)/Sqr(ry+hw) <= 1 &&
                  Sqr(cx)/Sqr(rx-hw) + Sqr(cy)/Sqr(ry-hw) >= 1)
                  return GroupLeader (fig);
            }
            break;


          case GroupFigure:
            break;
          }
      }

      fig = fig -> prev;
    }

    return NULL;
}


/************************************************************************
   Function:      DW_ClipBox
   Description:   Retrieves the clip box of a figure.
 ************************************************************************/

void DW_ClipBox (fig, rect)
    Figure      fig;
    XRectangle *rect;
{
    if (fig != NULL) {
      rect -> x      = fig -> x;
      rect -> y      = fig -> y;
      rect -> width  = fig -> width;
      rect -> height = fig -> height;
    }
}


/************************************************************************
   Function:      DW_SetInteractive
   Description: Set the interactive mode.
 ************************************************************************/

void DW_SetInteractive (gw, interactive)
    Widget  gw;
    BOOLEAN interactive;
{
    GC              gc;
    DrawingWidget dw;


    dw = (DrawingWidget) gw;

    if (interactive != dw -> drawing.interactive) {
      dw -> drawing.interactive = interactive;
      gc = dw -> drawing.drawgc;
      dw -> drawing.drawgc = dw -> drawing.intergc;
      dw -> drawing.intergc = gc;
    }
}


/************************************************************************
   Function:      DW_SetAutoFind
   Description: Set the auto find mode.
 ************************************************************************/

void DW_SetAutoFind (gw, autofind)
    Widget  gw;
    BOOLEAN autofind;
{
    ((DrawingWidget) gw) -> drawing.search = autofind;
}


/************************************************************************
   Function:      DW_SetAutoRedraw
   Description: Set the auto redraw mode.
 ************************************************************************/

void DW_SetAutoRedraw (gw, autoredraw)
    Widget  gw;
    BOOLEAN autoredraw;
{
    Region        null;
    Region        buffer;
    XRectangle    rect;
    DrawingWidget dw;


    dw = (DrawingWidget) gw;
    null = dw -> drawing.nullRegion;
    buffer = dw -> drawing.bufferRegion;

    if (dw -> drawing.redraw == False && autoredraw == True) {
      XClipBox (buffer, &rect);
      XClearArea (XtDisplay (gw), XtWindow (gw), rect.x - 1, rect.y - 1,
                rect.width + 2, rect.height + 2, True);

    } else if (dw -> drawing.redraw == True && autoredraw == False)
      XIntersectRegion (null, buffer, buffer);


    dw -> drawing.redraw = autoredraw;
}


/************************************************************************
   Function:      DW_SearchArea
   Description:   Return all figures with an area.
 ************************************************************************/

Figure *DW_SearchArea (gw, points, npoints, nfigs)
    Widget    gw;
    Point     points [ ];
    unsigned  npoints;
    unsigned *nfigs;
{
    int             loc;
    unsigned        i;
    Figure    fig;
    Figure   *figs;
    unsigned        size;
    XPoint   *xpoints;
    Region    region;
    DrawingWidget dw;
    int           x;
    int           y;
    unsigned      width;
    unsigned      height;
    unsigned      line_width;


    dw = (DrawingWidget) gw;
    xpoints = (XPoint *) XtMalloc (sizeof (XPoint) * npoints);

    for (i = 0; i < npoints; i ++) {
      xpoints [i].x = XAbs (points [i].x);
      xpoints [i].y = YAbs (points [i].y);
    }

    *nfigs = 0;
    size = 0;
    figs = NULL;
    region = XPolygonRegion (xpoints, npoints, EvenOddRule);

    for (fig = dw -> drawing.tail; fig != NULL; fig = fig -> prev) {
      if (fig -> visible == False)
          continue;

      line_width = fig -> line_width;
      if (line_width == 0)
          line_width = 1;

      x = fig -> x - line_width;
      y = fig -> y - line_width;
      width = fig -> width + 2 * line_width;
      height = fig -> height + 2 * line_width;

      loc = XRectInRegion (region, x, y, width, height);
      if (loc == RectangleIn) {
          if (*nfigs == size) {
            size = size ? size << 1 : 8;
            figs = (Figure *) XtRealloc ((char *) figs,sizeof(Figure)*size);
          }

          figs [(*nfigs) ++] = fig;
      }
    }

    XDestroyRegion (region);
    XtFree ((char *) xpoints);
    return figs;
}


/************************************************************************
   Function:      DW_RetrieveAll
   Description:   Retrieve all the figures on the display list.
 ************************************************************************/

Figure *DW_RetrieveAll (gw, visible, nfigs)
    Widget    gw;
    BOOLEAN   visible;
    unsigned *nfigs;
{
    Figure    fig;
    Figure   *figs;
    unsigned        size;
    DrawingWidget dw;


    dw = (DrawingWidget) gw;

    *nfigs = 0;
    size = 0;
    figs = NULL;

    for (fig = dw -> drawing.tail; fig != NULL; fig = fig -> prev) {
      if (visible == True && fig -> visible == False)
          continue;

      if (*nfigs == size) {
          size = size ? size << 1 : 8;
          figs = (Figure *) XtRealloc ((char *) figs,sizeof (Figure) * size);
      }

      figs [(*nfigs) ++] = fig;
    }

    return figs;
}


/************************************************************************
   Function:      DW_Group
   Description:   Create a group figure from a set of figures.
 ************************************************************************/

Figure DW_Group (gw, figs, nfigs)
    Widget   gw;
    Figure   figs [ ];
    unsigned nfigs;
{
    unsigned i;
    Figure   fig;


    fig = DW_CreateFigure ((DrawingWidget) gw, GroupFigure, False, nfigs);

    for (i = 0; i < nfigs; i ++) {
      fig -> info.group.fig [i] = figs [i];
      DW_Detach ((DrawingWidget) gw, figs [i]);
    }

    return fig;
}


/************************************************************************
   Function:      DW_Ungroup
   Description:   Remove a group figure.
 ************************************************************************/

void DW_Ungroup (gw, fig)
    Widget gw;
    Figure fig;
{
    unsigned i;


    if (fig != NULL && fig -> type == GroupFigure) {
      for (i = 0; i < fig -> info.group.nfigs; i ++)
          fig -> info.group.fig [i] -> group = NULL;

      DW_DestroyFigure (fig);
    }
}


/************************************************************************
   Function:      DW_CreatePixmap
   Description:   Utility function to create a pixmap of a specified width
            and height and of the same depth as the drawing widget.
 ************************************************************************/

Pixmap DW_CreatePixmap (gw, width, height)
    Widget   gw;
    unsigned width;
    unsigned height;
{
    unsigned depth;


    depth = ((DrawingWidget) gw) -> core.depth;
    return XCreatePixmap (XtDisplay (gw), XtWindow (gw), width, height, depth);
}


/************************************************************************
   Function:      DW_CreateBitmap
   Description:   Utility function to create a pixmap of a specified width
            and height but of depth one (a bitmap).
 ************************************************************************/

Pixmap DW_CreateBitmap (gw, width, height)
    Widget   gw;
    unsigned width;
    unsigned height;
{
    return XCreatePixmap (XtDisplay (gw), XtWindow (gw), width, height, 1);
}


/************************************************************************
   Function:      DW_TranslateCoords
   Description:   Translate from window coordinates to real coordinates
            (useful in action procedures).
 ************************************************************************/

void DW_TranslateCoords (gw, x, y, rx, ry)
    Widget gw;
    int    x;
    int    y;
    float *rx;
    float *ry;
{
    DrawingWidget dw;


    dw = (DrawingWidget) gw;

    *rx = RealX (x);
    *ry = RealY (y);
}


/************************************************************************
   Function:      Float2Arg
   Description:   Convert a floating point argument to an XtArgVal suitable
            for use with XtSetArg.
 ************************************************************************/

XtArgVal Float2Arg (value)
    FLOAT value;
{
    float   *new_float;
    float    float_val;
    XtArgVal arg_val;


    /* This is in case the float was promoted to a double. */

    float_val = value;


    /* The simple case of when a float will fit within an XtArgVal. */

    if (sizeof (float) <= sizeof (XtArgVal)) {
      arg_val = *(XtArgVal *) &float_val;
      return arg_val;
    }


    /* The difficult case of when a float will not fit within an XtArgVal
       and thus we need to pass the address of a float to XtSetArg so we
       have to do a malloc to be safe. */

    new_float = XtNew (float);
    *new_float = float_val;
    return (XtArgVal) new_float;
}

Generated by  Doxygen 1.6.0   Back to index