/* 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 # include # include # include # 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; }