/* drawings.c - for doing modifiable line drawings in a window Copyright (C) 1996-2000 Paul Sheer 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ #define DRAWINGS_C #include #include #include #include #include #include #include #include "lkeysym.h" #include "stringtools.h" #include "app_glob.c" #include "coolwidget.h" #include "coollocal.h" #include "mad.h" #include "drawings.h" /* the bounds are the maximum extents of the elements. only events withing the bounds are evaluated. */ void extendbounds (CWidget *wdt, int x1, int y1, int x2, int y2) { int xb = max (x1, x2); int xa = min (x1, x2); int yb = max (y1, y2); int ya = min (y1, y2); if (wdt->pic->x1 > xa) wdt->pic->x1 = xa; if (wdt->pic->x2 < xb) wdt->pic->x2 = xb; if (wdt->pic->y1 > ya) wdt->pic->y1 = ya; if (wdt->pic->y2 < yb) wdt->pic->y2 = yb; } /* returns 1 on error */ int CSetDrawingTarget (const char *picture_ident) { return (!(CDrawTarget = CIdent(picture_ident))); } void expose_picture(CWidget *wdt) { CExposeWindowArea (wdt->parentid, 0, wdt->pic->x1 + wdt->x, wdt->pic->y1 + wdt->y, wdt->pic->x2 - wdt->pic->x1 + 1, wdt->pic->y2 - wdt->pic->y1 + 1); } void destroy_picture (CWidget *wdt) { if (wdt->pic->pp) { free (wdt->pic->pp); wdt->pic->pp = 0; } if (wdt->pic) { free (wdt->pic); wdt->pic->pp = 0; } } void cw_reboundpic(CWidget *wdt) { int j; wdt->pic->x1 = 30000; wdt->pic->x2 = -30000; wdt->pic->y1 = 30000; wdt->pic->y2 = -30000; if (wdt->pic->numelements) { for (j = 0; j < wdt->pic->numelements; j++) { CPicturePrimative *pp = &(wdt->pic->pp[j]); switch (pp->type) { case CRECTANGLE: case CFILLED_RECTANGLE: extendbounds (wdt, pp->x, pp->y, pp->x + pp->a, pp->y + pp->b); break; case CLINE: extendbounds (wdt, pp->x, pp->y, pp->a, pp->b); break; } } } } CWidget *CDrawPicture (const char *identifier, Window parent, int x, int y, int max_num_elements) { CWidget **w; w = find_empty_widget_entry (); /*find first unused list entry in list of widgets*/ *w = allocate_widget (0, identifier, parent, x, y, 0, 0, C_PICTURE_WIDGET); (*w)->pic = CMalloc(sizeof(CPicture)); memset((*w)->pic, 0, sizeof(CPicture)); (*w)->pic->pp = CMalloc(sizeof(CPicturePrimative) * max_num_elements); cw_reboundpic(*w); (*w)->eh = default_event_handler(C_PICTURE_WIDGET); (*w)->destroy = destroy_picture; CSetDrawingTarget (identifier); return (*w); } void CClearPicture(void) { CWidget *wdt = CDrawTarget; wdt->pic->numelements = 0; expose_picture (wdt); cw_reboundpic(wdt); } int CDrawLine (float x1, float y1, float x2, float y2, unsigned long c) { CWidget *wdt = CDrawTarget; int last = wdt->pic->numelements; wdt->pic->pp[last].x = x1; wdt->pic->pp[last].y = y1; wdt->pic->pp[last].a = x2; wdt->pic->pp[last].b = y2; wdt->pic->pp[last].color = c; wdt->pic->pp[last].type = CLINE; wdt->pic->numelements++; extendbounds (wdt, x1, y1, x2, y2); expose_picture (wdt); return last; } int CDrawRectangle (float x, float y, float w, float h, unsigned long c) { CWidget *wdt = CDrawTarget; int last = wdt->pic->numelements; wdt->pic->pp[last].x = x; wdt->pic->pp[last].y = y; wdt->pic->pp[last].a = w; wdt->pic->pp[last].b = h; wdt->pic->pp[last].color = c; wdt->pic->pp[last].type = CRECTANGLE; wdt->pic->numelements++; extendbounds (wdt, x, y, x + w, y + h); expose_picture (wdt); return last; } void CRemovePictureElement (int j) { if (CDrawTarget->pic->numelements <= j || j < 0) return; if (CDrawTarget->pic->numelements - 1 == j) CDrawTarget->pic->numelements--; else CDrawTarget->pic->pp[j].type = 0; expose_picture (CDrawTarget); cw_reboundpic(CDrawTarget); } void CScalePicture (float s) { CWidget *wdt = CDrawTarget; int j = 0; if (s == 1) return; if (s < 1) expose_picture (wdt); for (; j < wdt->pic->numelements; j++) { CPicturePrimative *pp = &(wdt->pic->pp[j]); pp->x *= s; pp->y *= s; pp->a *= s; pp->b *= s; } wdt->pic->x1 *= s; wdt->pic->x2 *= s; wdt->pic->y1 *= s; wdt->pic->y2 *= s; cw_reboundpic (wdt); if (s > 1) expose_picture (wdt); } #define is_between(a,b,c) \ ((a) >= (b) && (a) <= (c)) int eh_picture (CWidget *wdt, XEvent * xevent, CEvent * cwevent) { int last = wdt->pic->numelements; CPicturePrimative *pp = wdt->pic->pp; Window win = wdt->parentid; int x = wdt->x; int y = wdt->y; switch (xevent->type) { case Expose: if (last) { /* check if the expose covers the region of the picture */ int w = max (max (xevent->xexpose.x, xevent->xexpose.x + xevent->xexpose.width), wdt->pic->x2 + x) - min (min (xevent->xexpose.x, xevent->xexpose.x + xevent->xexpose.width), wdt->pic->x1 + x); int h = max (max (xevent->xexpose.y, xevent->xexpose.y + xevent->xexpose.height), wdt->pic->y2 + y) - min (min (xevent->xexpose.y, xevent->xexpose.y + xevent->xexpose.height), wdt->pic->y1 + y); if (h < wdt->pic->y2 - wdt->pic->y1 + abs (xevent->xexpose.height) && w < wdt->pic->x2 - wdt->pic->x1 + abs (xevent->xexpose.width)) { int j = 0; for (; j < last; j++) switch (pp[j].type) { case CLINE: CSetColor (pp[j].color); CLine (win, pp[j].x + x, pp[j].y + y, pp[j].a + x, pp[j].b + y); break; case CFILLED_RECTANGLE: CSetColor (pp[j].color); CRectangle (win, pp[j].x + x, pp[j].y + y, pp[j].a, pp[j].b); break; case CRECTANGLE: CSetColor (pp[j].color); CLine (win, pp[j].x + x, pp[j].y + y, pp[j].x + x + pp[j].a, pp[j].y + y); CLine (win, pp[j].x + x, pp[j].y + y, pp[j].x + x, pp[j].y + y + pp[j].b); CLine (win, pp[j].x + x + pp[j].a, pp[j].y + y + pp[j].b, pp[j].x + x + pp[j].a, pp[j].y + y); CLine (win, pp[j].x + x + pp[j].a, pp[j].y + y + pp[j].b, pp[j].x + x, pp[j].y + y + pp[j].b); break; } } } break; case ButtonPress: break; } return 0; }