/*
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, ©);
else {
DW_ClipBox (©, &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;
}
syntax highlighted by Code2HTML, v. 0.9.1