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

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

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


static struct {
    int  length;
    char dash_list [4];
} line_styles [ ] = {
    {1, {1}},                 /* solid (not really used) */
    {2, {3, 3}},        /* dashed            */
    {2, {3, 1}},        /* dotted            */
    {4, {7, 2, 1, 2}},        /* dot-dashed              */
    {2, {7, 7}},        /* long-dashed             */
};


/************************************************************************
   Function:      DW_CreateFigure
   Description:   Creates a new figure by allocating memory and
              initializing.
 ************************************************************************/

Figure DW_CreateFigure (dw, type, flag, arg)
    DrawingWidget dw;
    FigureType      type;
    BOOLEAN   flag;
    int             arg;
{
    Figure fig;


    fig = XtNew (struct figure);

    fig -> type         = type;
    fig -> prev         = NULL;
    fig -> next         = NULL;
    fig -> line_width = dw -> drawing.line_width;
    fig -> line_style = dw -> drawing.line_style;
    fig -> fg           = dw -> drawing.fg;
    fig -> visible    = True;
    fig -> group      = NULL;
    fig -> color_data = dw -> drawing.color_data;

    DW_CacheAddRef (fig -> color_data);

    switch (fig -> type) {
    case LineFigure:
    case PixmapFigure:
    case BitmapFigure:
      break;

    case PolygonFigure:
      fig -> info.polygon.filled  = False;
      fig -> info.polygon.scaled  = flag;
      fig -> info.polygon.npoints = arg;
      fig -> info.polygon.region  = NULL;
      fig -> info.polygon.points  = (Point *) XtMalloc (sizeof (Point) * arg);
      fig -> info.polygon.xpoints = (XPoint *) XtMalloc (sizeof (XPoint)*arg);
      break;

    case RectangleFigure:
      fig -> info.rectangle.filled = arg ? True : False;
      fig -> info.rectangle.scaled = flag;
      break;

    case ArcFigure:
      fig -> info.arc.filled = arg ? True : False;
      fig -> info.arc.scaled = flag;
      break;

    case TextFigure:
      fig -> info.text.font = dw -> drawing.font;
      fig -> info.text.scaled = flag;
      fig -> info.text.font_data = dw -> drawing.font_data;
      DW_CacheAddRef (fig -> info.text.font_data);
      break;

    case GroupFigure:
      fig -> info.group.fig = (Figure *) XtMalloc (sizeof (Figure) * arg);
      fig -> info.group.nfigs = arg;
      break;
    }

    return fig;
}


/************************************************************************
   Function:      DestroyFigure
   Description:   Destroys an figure by deallocating its memory.
 ************************************************************************/

void DW_DestroyFigure (fig)
    Figure fig;
{
    if (fig -> type == PolygonFigure) {
      XtFree ((char *) fig -> info.polygon.points);
      XtFree ((char *) fig -> info.polygon.xpoints);
      if (fig -> info.polygon.region)
          XDestroyRegion (fig -> info.polygon.region);

    } else if (fig -> type == TextFigure) {
      DW_CacheDelRef (fig -> info.text.font_data);
      XtFree ((char *) fig -> info.text.string);

    } else if (fig -> type == GroupFigure)
      XtFree ((char *) fig -> info.group.fig);

    DW_CacheDelRef (fig -> color_data);
    XtFree ((char *) fig);
}


/************************************************************************
   Function:      DW_AppendFigure
   Description: Adds a figure to the end of the display list.
 ************************************************************************/

void DW_AppendFigure (dw, fig)
    DrawingWidget dw;
    Figure    fig;
{
    fig -> prev = dw -> drawing.tail;
    if (dw -> drawing.tail != NULL)
      dw -> drawing.tail -> next = fig;
    else
      dw -> drawing.head = fig;

    dw -> drawing.tail = fig;
}


/************************************************************************
   Function:      DW_PrependFigure
   Description:   Adds a figure to the beginning of the display list.
 ************************************************************************/

void DW_PrependFigure (dw, fig)
    DrawingWidget dw;
    Figure        fig;
{
    fig -> next = dw -> drawing.head;
    if (dw -> drawing.head != NULL)
      dw -> drawing.head -> prev = fig;
    else
      dw -> drawing.tail = fig;

    dw -> drawing.head = fig;
}


/************************************************************************
   Function:      DW_DeleteFigure
   Description:   Deletes a figure from the display list.
 ************************************************************************/

void DW_DeleteFigure (dw, fig)
    DrawingWidget dw;
    Figure        fig;
{
    if (fig -> next != NULL)
      fig -> next -> prev = fig -> prev;
    else
      dw -> drawing.tail = fig -> prev;

    if (fig -> prev != NULL)
      fig -> prev -> next = fig -> next;
    else
      dw -> drawing.head = fig -> next;

    fig -> prev = fig -> next = NULL;
}


/************************************************************************
   Function:      DW_ScaleFigure
   Description:   Scale a figure to window coordinates.
 ************************************************************************/

void DW_ScaleFigure (dw, fig)
    DrawingWidget dw;
    Figure        fig;
{
    int           i;
    int           direction;
    int           ascent;
    int           descent;
    unsigned      dont_care;
    short   minx;
    short   maxx;
    short   miny;
    short   maxy;
    short   x;
    short   y;
    Window  root;
    Figure  member;
    XCharStruct overall;


    switch (fig -> type) {
    case LineFigure:
      fig -> info.line.xpoints [0].x = XAbs (fig -> info.line.points [0].x);
      fig -> info.line.xpoints [0].y = YAbs (fig -> info.line.points [0].y);
      fig -> info.line.xpoints [1].x = XAbs (fig -> info.line.points [1].x);
      fig -> info.line.xpoints [1].y = YAbs (fig -> info.line.points [1].y);

      if (fig -> info.line.xpoints [0].x < fig -> info.line.xpoints [1].x) {
          fig -> x = fig -> info.line.xpoints [0].x;
          fig -> width = fig -> info.line.xpoints [1].x - fig -> x;
      } else {
          fig -> x = fig -> info.line.xpoints [1].x;
          fig -> width = fig -> info.line.xpoints [0].x - fig -> x;
      }

      if (fig -> info.line.xpoints [0].y < fig -> info.line.xpoints [1].y) {
          fig -> y = fig -> info.line.xpoints [0].y;
          fig -> height = fig -> info.line.xpoints [1].y - fig -> y;
      } else {
          fig -> y = fig -> info.line.xpoints [1].y;
          fig -> height = fig -> info.line.xpoints [0].y - fig -> y;
      }
      break;


    case PolygonFigure:
      minx = maxx = XAbs (fig -> info.polygon.points [0].x);
      miny = maxy = YAbs (fig -> info.polygon.points [0].y);

      if (fig -> info.polygon.scaled == True) {
          for (i = 0; i < fig -> info.polygon.npoints; i ++) {
            x = fig -> info.polygon.xpoints [i].x =
                XAbs (fig -> info.polygon.points [i].x);
            y = fig -> info.polygon.xpoints [i].y =
                YAbs (fig -> info.polygon.points [i].y);

            if (x < minx)
                minx = x;
            else if (x > maxx)
                maxx = x;

            if (y < miny)
                miny = y;
            else if (y > maxy)
                maxy = y;
          }
      } else {
      }


      if (fig -> info.polygon.filled == True) {
          if (fig -> info.polygon.region)
            XDestroyRegion (fig -> info.polygon.region);

          fig -> info.polygon.region = XPolygonRegion (
            fig -> info.polygon.xpoints, fig -> info.polygon.npoints,
            EvenOddRule);
      }

      if (minx < maxx) {
          fig -> x = minx;
          fig -> width = maxx - minx;
      } else {
          fig -> x = maxx;
          fig -> width = minx - maxx;
      }

      if (miny < maxy) {
          fig -> y = miny;
          fig -> height = maxy - miny;
      } else {
          fig -> y = maxy;
          fig -> height = miny - maxy;
      }
      break;


    case RectangleFigure:
      if (fig -> info.rectangle.width > 0) {
          if (fig -> info.rectangle.scaled == True)
            fig -> width = XRel (fig -> info.rectangle.width);
          else
            fig -> width = Round (fig -> info.rectangle.width);
          fig -> x = XAbs (fig -> info.rectangle.x);

      } else {
          if (fig -> info.rectangle.scaled == True)
            fig -> width = -XRel (fig -> info.rectangle.width);
          else
            fig -> width = Round (-fig -> info.rectangle.width);
          fig -> x = XAbs (fig -> info.rectangle.x) - fig -> width;
      }

      if (fig -> info.rectangle.height > 0) {
          if (fig -> info.rectangle.scaled == True)
            fig -> height = YRel (fig -> info.rectangle.height);
          else
            fig -> height = Round (fig -> info.rectangle.height);
          fig -> y = YAbs (fig -> info.rectangle.y) - fig -> height;

      } else {
          if (fig -> info.rectangle.scaled == True)
            fig -> height = -YRel (fig -> info.rectangle.height);
          else
            fig -> height = Round (-fig -> info.rectangle.height);
          fig -> y = YAbs (fig -> info.rectangle.y);
      }
      break;


    case ArcFigure:
      if (fig -> info.arc.width > 0)
          if (fig -> info.arc.scaled == True)
            fig -> width = XRel (fig -> info.arc.width);
          else
            fig -> width = Round (fig -> info.arc.width);
      else
          if (fig -> info.arc.scaled == True)
            fig -> width = -XRel (fig -> info.arc.width);
          else
            fig -> width = Round (-fig -> info.arc.width);

      if (fig -> info.arc.height > 0)
          if (fig -> info.arc.scaled == True)
            fig -> height = XRel (fig -> info.arc.height);
          else
            fig -> height = Round (fig -> info.arc.height);
      else
          if (fig -> info.arc.scaled == True)
            fig -> height = -XRel (fig -> info.arc.height);
          else
            fig -> height = Round (-fig -> info.arc.height);

      fig -> x = XAbs (fig -> info.arc.x) - fig -> width / 2;
      fig -> y = YAbs (fig -> info.arc.y) - fig -> height / 2;
      break;


    case TextFigure:
      fig -> info.text.x = XAbs (fig -> info.text.rx);
      fig -> info.text.y = YAbs (fig -> info.text.ry);
      XTextExtents (fig -> info.text.font, fig -> info.text.string,
                  fig -> info.text.length, &direction, &ascent, &descent,
                  &overall);

      fig -> x = fig -> info.text.x + overall.lbearing;
      fig -> y = fig -> info.text.y - overall.ascent;
      fig -> width = overall.rbearing - overall.lbearing;
      fig -> height = overall.descent + overall.ascent;
      break;


    case GroupFigure:
      if (fig -> info.group.nfigs > 0) {
          minx = fig -> info.group.fig [0] -> x;
          miny = fig -> info.group.fig [0] -> y;
          maxx = minx + fig -> info.group.fig [0] -> width;
          maxy = miny + fig -> info.group.fig [0] -> height;
      } else {
          minx = miny = maxx = maxy = 0;
      }

      for (i = 1; i < fig -> info.group.nfigs; i ++) {
          member = fig -> info.group.fig [i];
          if (minx > member -> x)
            minx = member -> x;
          if (miny > member -> y)
            miny = member -> y;
          if (maxx < member -> x + member -> width)
            maxx = member -> x + member -> width;
          if (maxy < member -> y + member -> height)
            maxy = member -> y + member -> height;
      }

      if (minx < maxx) {
          fig -> x = minx;
          fig -> width = maxx - minx;
      } else {
          fig -> x = maxx;
          fig -> width = minx - maxx;
      }

      if (miny < maxy) {
          fig -> y = miny;
          fig -> height = maxy - miny;
      } else {
          fig -> y = maxy;
          fig -> height = miny - maxy;
      }
      break;


    case PixmapFigure:
    case BitmapFigure:
      XGetGeometry (XtDisplay ((Widget) dw), fig -> info.pixmap.pixmap,
          &root, (int *) &dont_care, (int *) &dont_care, &fig -> width,
          &fig -> height, &dont_care, &dont_care);

      fig -> x = XAbs (fig -> info.pixmap.x);
      fig -> y = YAbs (fig -> info.pixmap.y) - fig -> height;
      break;
    }
}


/************************************************************************
   Function:      DW_DrawFigure
   Description:   Draws a figure in the window of the specified widget.
 ************************************************************************/

void DW_DrawFigure (dw, fig)
    DrawingWidget dw;
    Figure        fig;
{
    Display        *display;
    Window        window;
    GC                  drawgc;
    Font          font;
    unsigned long valuemask;
    XGCValues           values;
    Boolean       first_time;


    if (fig -> visible == False)
      return;

    valuemask = 0;
    display = XtDisplay ((Widget) dw);
    window = XtWindow ((Widget) dw);
    drawgc = dw -> drawing.drawgc;
    first_time = dw -> drawing.last_style == -1 ? True : False;

    if (first_time || dw -> drawing.last_fg != fig -> fg) {
      valuemask |= GCForeground;
      values.foreground = dw -> drawing.last_fg = fig -> fg;
    }

    if (first_time || dw -> drawing.last_width != fig -> line_width) {
      valuemask |= GCLineWidth;
      values.line_width = dw -> drawing.last_width = fig -> line_width;
    }

    if (first_time || dw -> drawing.last_style != fig -> line_style) {
      dw -> drawing.last_style = fig -> line_style;
      valuemask |= GCLineStyle;
      if (fig -> line_style != DW_LineSolid) {
          values.line_style = LineOnOffDash;
          XSetDashes (display, dw -> drawing.drawgc, 0,
                  line_styles [fig -> line_style].dash_list,
                  line_styles [fig -> line_style].length);
          XSetDashes (display, dw -> drawing.intergc, 0,
                  line_styles [fig -> line_style].dash_list,
                  line_styles [fig -> line_style].length);
      } else
          values.line_style = LineSolid;
    }

    if (valuemask) {
      XChangeGC (display, drawgc, valuemask, &values);
      XChangeGC (display, dw -> drawing.intergc, valuemask, &values);
    }


    switch (fig -> type) {
    case LineFigure:
      XDrawLine (display, window, drawgc,
          fig -> info.line.xpoints [0].x, fig -> info.line.xpoints [0].y,
          fig -> info.line.xpoints [1].x, fig -> info.line.xpoints [1].y);
      break;


    case PolygonFigure:
      if (fig -> info.polygon.filled == True)
          XFillPolygon (display, window, drawgc,
            fig -> info.polygon.xpoints, fig -> info.polygon.npoints,
            Complex, CoordModeOrigin);
      else
          XDrawLines (display, window, drawgc,
            fig -> info.polygon.xpoints, fig -> info.polygon.npoints,
            CoordModeOrigin);
      break;


    case RectangleFigure:
      if (fig -> info.rectangle.filled == True)
          XFillRectangle (display, window, drawgc, fig -> x, fig -> y,
            fig -> width, fig -> height);
      else
          XDrawRectangle (display, window, drawgc, fig -> x, fig -> y,
            fig -> width, fig -> height);
      break;


    case ArcFigure:
      if (fig -> info.arc.filled == True)
          XFillArc (display, window, drawgc, fig -> x, fig -> y, fig -> width,
            fig -> height, fig -> info.arc.start, fig -> info.arc.length);
      else
          XDrawArc (display, window, drawgc, fig -> x, fig -> y, fig -> width,
            fig -> height, fig -> info.arc.start, fig -> info.arc.length);
      break;


    case TextFigure:
      font = fig -> info.text.font -> fid;
      if (first_time || dw -> drawing.last_font != font) {
          dw -> drawing.last_font = font;
          XSetFont (display, drawgc, font);
          XSetFont (display, dw -> drawing.intergc, font);
      }

      XDrawString (display, window, drawgc, fig -> info.text.x,
          fig -> info.text.y, fig -> info.text.string,
          fig -> info.text.length);
      break;


    case GroupFigure:
      break;


    case PixmapFigure:
      XCopyArea (display, fig -> info.pixmap.pixmap, window, drawgc,
          0, 0, fig -> width, fig -> height, fig -> x, fig -> y);
      break;


    case BitmapFigure:
      XSetFunction   (display, drawgc, GXand);
      XSetBackground (display, drawgc, 255);
      XCopyPlane (display, fig -> info.pixmap.pixmap, window, drawgc,
          0, 0, fig -> width, fig -> height, fig -> x, fig -> y, 1L);

      XSetFunction (display, drawgc, GXor);
      XSetBackground (display, drawgc, 0);
      XCopyPlane (display, fig -> info.pixmap.pixmap, window, drawgc,
          0, 0, fig -> width, fig -> height, fig -> x, fig -> y, 1L);

      if (dw -> drawing.interactive == True)
          XSetFunction (display, drawgc, GXxor);
      else
          XSetFunction (display, drawgc, GXcopy);
      XSetBackground (display, drawgc, dw -> core.background_pixel);
      break;
    }

    first_time = 0;
}


/************************************************************************
   Function:      DW_ClearFigure
   Description:   Clears the area occupied by a figure.
 ************************************************************************/

void DW_ClearFigure (dw, fig)
    DrawingWidget dw;
    Figure        fig;
{
    XRectangle rect;


    if (fig -> visible == False)
      return;

    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;
      if (dw -> drawing.redraw == True)
          XClearArea (XtDisplay ((Widget) dw), XtWindow ((Widget) dw),
                  rect.x, rect.y, rect.width, rect.height, True);
      else
          XUnionRectWithRegion (&rect, dw -> drawing.bufferRegion,
                               dw -> drawing.bufferRegion);
    }
}


/************************************************************************
   Function:      DW_Detach
   Description:   Detach a figure from a group.
 ************************************************************************/

void DW_Detach (dw, fig)
    DrawingWidget dw;
    Figure        fig;
{
    unsigned i;
    unsigned j;
    Figure   leader;


    if (fig -> group != NULL) {
      leader = fig -> group;

      for (i = 0; i < leader -> info.group.nfigs; i ++)
          if (leader -> info.group.fig [i] == fig) {
            for (j = i + 1; j < leader -> info.group.nfigs; j ++)
                leader->info.group.fig [j - 1] = leader->info.group.fig [j];
            leader -> info.group.nfigs --;
            break;
          }

      DW_ScaleFigure (dw, leader);
    }
}


/************************************************************************
   Function:      DW_Attach
   Description:   Attach a figure to a group.
 ************************************************************************/

void DW_Attach (dw, fig, group)
    DrawingWidget dw;
    Figure    fig;
    Figure    group;
{
    if (fig -> group == group)
      return;

    if (group != NULL) {
      group -> info.group.fig = (Figure *) XtRealloc ((char *) group ->
          info.group.fig, sizeof (Figure) * (group -> info.group.nfigs + 1));
      group -> info.group.fig [group -> info.group.nfigs] = fig;
      group -> info.group.nfigs ++;
      DW_ScaleFigure (dw, group);
    }

    fig -> group = group;
}

Generated by  Doxygen 1.6.0   Back to index