/*
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;
}
syntax highlighted by Code2HTML, v. 0.9.1