Moved 3 rc promotion keywords from gschem into libgeda (fix for bug#1748143)
[geda-gaf/peter-b.git] / gschem / src / o_box.c
bloba59a0f3679a475f029a01d4dc9f1b9052d98e13f
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2007 Ales Hvezda
4 * Copyright (C) 1998-2007 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20 #include <config.h>
21 #include <math.h>
22 #include <stdio.h>
24 #include <libgeda/libgeda.h>
26 #include "../include/globals.h"
27 #include "../include/prototype.h"
29 #ifdef HAVE_LIBDMALLOC
30 #include <dmalloc.h>
31 #endif
33 /* Kazu on July 16, 1999 - Added these macros to simplify the code */
34 #define GET_BOX_WIDTH(w) \
35 abs((w)->last_x - (w)->start_x)
36 #define GET_BOX_HEIGHT(w) \
37 abs((w)->last_y - (w)->start_y)
38 #define GET_BOX_LEFT(w) \
39 min((w)->start_x, (w)->last_x);
40 #define GET_BOX_TOP(w) \
41 min((w)->start_y, (w)->last_y);
43 typedef void (*DRAW_FUNC)( GdkDrawable *w, GdkGC *gc, GdkColor *color,
44 GdkCapStyle cap, gint filled,
45 gint x, gint y, gint width, gint height,
46 gint line_width, gint length, gint space );
48 typedef void (*FILL_FUNC)( GdkDrawable *w, GdkGC *gc, GdkColor *color,
49 gint x, gint y, gint width, gint height,
50 gint fill_width, gint angle1, gint pitch1,
51 gint angle2, gint pitch2 );
53 /*! \brief Draw a box on the screen.
54 * \par Function Description
55 * This function is used to draw a box on screen. The box is described in
56 * the OBJECT which is referred by <B>o_current</B>. The box is displayed
57 * according to the current state, described in the TOPLEVEL object
58 * pointed by <B>w_current</B>.
60 * It first checks if the OBJECT pointed is valid or not. If not it
61 * returns and do not output anything. That should never happen though.
63 * \param [in] w_current The TOPLEVEL object.
64 * \param [in] o_current BOX OBJECT to draw.
66 void o_box_draw(TOPLEVEL *w_current, OBJECT *o_current)
68 int wleft, wright, wtop, wbottom; /* world bounds */
69 int s_upper_x, s_upper_y, s_lower_x, s_lower_y;
70 int line_width, length, space;
71 int fill_width, angle1, pitch1, angle2, pitch2;
72 GdkCapStyle box_end;
73 GdkColor *color;
74 DRAW_FUNC draw_func = NULL;
75 FILL_FUNC fill_func;
77 if (o_current->box == NULL) {
78 return;
81 /* Get read to check for visibility of this line by using it's
82 * bounding box */
83 world_get_box_bounds(w_current, o_current,
84 &wleft, &wtop, &wright, &wbottom);
86 if ( (w_current->DONT_REDRAW == 1) ||
87 (!visible(w_current, wleft, wtop, wright, wbottom)) ) {
88 return;
91 #if DEBUG
92 printf("drawing box\n\n");
94 printf("drawing box: %d %d %d %d\n",
95 o_current->box->upper_x,
96 o_current->box->upper_y,
97 o_current->box->upper_x +
98 abs(o_current->box->lower_x -
99 o_current->box->upper_x),
100 o_current->box->upper_y +
101 abs(o_current->box->lower_y -
102 o_current->box->upper_y));
103 #endif
106 * The drawing of the box is divided in two steps : first step is to
107 * draw the outline, the second is to draw the filling pattern inside
108 * (if any). Finally the function takes care of the grips.
110 if (w_current->override_color != -1 ) { /* Override */
111 color = x_get_color(w_current->override_color);
112 } else {
113 color = x_get_color(o_current->color);
117 * The values describing the line type are extracted from the <B>o_current</B>
118 * pointed structure. These are the width of the line, the field called
119 * length and the field called space and the desired end type for the line.
121 * Depending on the type of the line that has to be used to draw the box
122 * the appropriate function is called. Values of space and length are
123 * adapted to the type of line. The possible functions are the following :
124 * #o_box_draw_solid(), #o_box_draw_dotted(), #o_box_draw_dashed() and
125 * #o_box_draw_phantom().
127 * The combination <B>length</B> == 0 and <B>space</B> == 0 is avoided as it
128 * lead to an endless loop in function called after. If such a case is
129 * encountered the box is drawn as a solid box independently of its
130 * initial type.
132 line_width = SCREENabs( w_current, o_current->line_width );
133 if(line_width <= 0) {
134 line_width = 1;
137 switch(o_current->line_end) {
138 case END_NONE: box_end = GDK_CAP_BUTT; break;
139 case END_SQUARE: box_end = GDK_CAP_PROJECTING; break;
140 case END_ROUND: box_end = GDK_CAP_ROUND; break;
141 default: fprintf(stderr, _("Unknown end for box (%d)\n"), o_current->line_end);
142 box_end = GDK_CAP_BUTT;
143 break;
146 length = SCREENabs( w_current, o_current->line_length );
147 space = SCREENabs( w_current, o_current->line_space );
149 switch(o_current->line_type) {
150 case TYPE_SOLID:
151 length = -1;
152 space = -1;
153 draw_func = o_box_draw_solid;
154 break;
156 case TYPE_DOTTED:
157 length = -1; /* ..._draw_dotted only space is used */
158 draw_func = o_box_draw_dotted;
159 break;
161 case TYPE_DASHED:
162 draw_func = o_box_draw_dashed;
163 break;
165 case TYPE_CENTER:
166 draw_func = o_box_draw_center;
167 break;
169 case TYPE_PHANTOM:
170 draw_func = o_box_draw_phantom;
171 break;
173 case TYPE_ERASE:
174 break;
176 default:
177 length = -1;
178 space = -1;
179 line_width = 0; /* just to be careful */
180 draw_func = o_box_draw_solid;
181 fprintf(stderr, _("Unknown type for box !\n"));
182 break;
185 if((length == 0) || (space == 0))
186 draw_func = o_box_draw_solid;
188 WORLDtoSCREEN( w_current, o_current->box->upper_x, o_current->box->upper_y,
189 &s_upper_x, &s_upper_y );
190 WORLDtoSCREEN( w_current, o_current->box->lower_x, o_current->box->lower_y,
191 &s_lower_x, &s_lower_y );
193 (*draw_func)(w_current->window, w_current->gc, color, box_end,
194 FALSE,
195 s_upper_x, s_upper_y,
196 abs(s_lower_x - s_upper_x),
197 abs(s_lower_y - s_upper_y),
198 line_width, length, space);
199 (*draw_func)(w_current->backingstore, w_current->gc, color, box_end,
200 FALSE,
201 s_upper_x, s_upper_y,
202 abs(s_lower_x - s_upper_x),
203 abs(s_lower_y - s_upper_y),
204 line_width, length, space);
207 * The values needed for the fill operation are taken from the
208 * <B>o_current</B> pointed OBJECT. It include the type of fill required,
209 * the width of the lines (if the fill use line) and angles and pitchs
210 * for hatch based filling.
212 * Once again the width of the line is important as if it is equal to
213 * 0 it may not be displayed. That is definetely not what we are looking for.
215 * Depending on the type of fill that has to be used inside the box the
216 * appropriate function is called. Values of <B>angle1</B>,
217 * <B>angle2</B>, <B>pitch1</B> and <B>pitch2</B> are adapted to the type of
218 * filling. The possible functions are the following :
219 * #o_box_fill_hollow(), #o_box_fill_fill(), #o_box_fill_mesh() and
220 * #o_box_fill_hatch().
222 * The combination <B>pitch1</B> <= 0 and <B>pitch2</B> <= 0 is avoided as
223 * it lead to an endless loop in function called after. It happens when
224 * the zoom factor is too small for two lines separated by the pitch
225 * to be distinct. If such a case is encountered the circle is filled
226 * hollow (e.q. not filled).
228 fill_width = SCREENabs( w_current, o_current->fill_width );
229 if(fill_width <= 0) {
230 fill_width = 1;
233 angle1 = o_current->fill_angle1;
234 pitch1 = SCREENabs( w_current, o_current->fill_pitch1 );
235 angle2 = o_current->fill_angle2;
236 pitch2 = SCREENabs( w_current, o_current->fill_pitch2 );
238 switch(o_current->fill_type) {
239 case FILLING_HOLLOW:
240 angle1 = -1; angle2 = -1;
241 pitch1 = 1; pitch2 = 1;
242 /* this function is empty ! however if it do not use it we have to add
243 * a test before the call. Simply putting a return here instead is not
244 * possible as it would prevent any hollow box from having its grips
245 * drawn
247 fill_func = o_box_fill_hollow;
248 break;
250 case FILLING_FILL:
251 angle1 = -1; angle2 = -1;
252 pitch1 = 1; pitch2 = 1;
253 fill_func = o_box_fill_fill;
254 break;
256 case FILLING_MESH:
257 fill_func = o_box_fill_mesh;
258 break;
260 case FILLING_HATCH:
261 angle2 = -1;
262 pitch2 = 1;
263 fill_func = o_box_fill_hatch;
264 break;
266 case FILLING_VOID:
267 default:
268 angle1 = -1; angle2 = -1;
269 pitch1 = 1; pitch2 = 1;
270 fill_func = o_box_fill_hollow;
271 fprintf(stderr, _("Unknown type for box (fill)!\n"));
274 if((pitch1 <= 0) || (pitch2 <= 0)) {
275 fill_func = o_box_fill_fill;
278 (*fill_func)(w_current->window, w_current->gc, color,
279 s_upper_x, s_upper_y,
280 abs(s_lower_x - s_upper_x),
281 abs(s_lower_y - s_upper_y),
282 fill_width, angle1, pitch1, angle2, pitch2);
283 (*fill_func)(w_current->backingstore, w_current->gc, color,
284 s_upper_x, s_upper_y,
285 abs(s_lower_x - s_upper_x),
286 abs(s_lower_y - s_upper_y),
287 fill_width, angle1, pitch1, angle2, pitch2);
289 if ((o_current->draw_grips == TRUE) && (w_current->draw_grips == TRUE)) {
290 /* pb20011003 - modified to use the new o_box_[draw|erase]_grips() */
291 if (!o_current->selected) {
292 /* object is no more selected, erase the grips */
293 o_current->draw_grips = FALSE;
294 o_box_erase_grips(w_current, o_current);
295 } else {
296 /* object is selected, draw the grips on the box */
297 o_box_draw_grips(w_current, o_current);
302 /*! \brief Draw a box with a solid line type.
303 * \par Function Description
304 * This function draws a box with a solid line type. The length and space
305 * parameters are not used by this function.
307 * The function uses the functions previously defined in #o_line.c. It is
308 * called four times for each of the side of the box. Therefore note that
309 * the cap parameter is significant here even if it is a box (i.e. a closed
310 * shape).
312 * The box is defined in the same way as it is in GDK : one point and
313 * the width and height of the box.
315 * The unit of <B>x</B>, <B>y</B>, <B>width</B>, <B>height</B>,
316 * <B>line_width</B>, <B>length</B> and <B>space</B> is pixel.
318 * \param [in] w GdkDrawable to draw in.
319 * \param [in] gc GdkGC graphics context to draw on.
320 * \param [in] color Box line color.
321 * \param [in] cap Box line end cap type (unused).
322 * \param [in] filled (unused)
323 * \param [in] x Box upper x.
324 * \param [in] y Box upper y.
325 * \param [in] width Box width.
326 * \param [in] height Box height
327 * \param [in] line_width Width of line to draw box.
328 * \param [in] length (unused)
329 * \param [in] space (unused)
331 void o_box_draw_solid(GdkDrawable *w, GdkGC *gc, GdkColor *color,
332 GdkCapStyle cap, gint filled, gint x, gint y, gint width,
333 gint height, gint line_width, gint length, gint space)
335 o_line_draw_solid(w, gc, color, cap,
336 x, y, x + width, y, line_width, length, space);
337 o_line_draw_solid(w, gc, color, cap,
338 x + width, y, x + width, y + height, line_width,
339 length, space);
340 o_line_draw_solid(w, gc, color, cap,
341 x + width, y + height, x, y + height, line_width,
342 length, space);
343 o_line_draw_solid(w, gc, color, cap,
344 x, y + height, x, y, line_width, length, space);
347 /*! \brief Draw a box with a dotted line type.
348 * \par Function Description
349 * This function draws a box with a dotted line type. The parameter
350 * <B>space</B> represents the distance between two of the dots. The
351 * parameter <B>length</B> is unused. The diameter of the dots is given by
352 * the width of the line given by <B>width</B>.
354 * The function uses the functions previously defined in #o_line.c. It is
355 * called four times for each of the side of the box.
357 * The box is defined in the same way as it is in GDK : one point and
358 * the width and height of the box.
360 * The unit of <B>x</B>, <B>y</B>, <B>width</B>, <B>height</B>,
361 * <B>line_width</B>, <B>length</B> and <B>space</B> is pixel.
363 * A negative or null value for <B>space</B> leads to an endless loop
364 * in #o_line_draw_dotted().
366 * \param [in] w GdkDrawable to draw in.
367 * \param [in] gc GdkGC graphics context to draw on.
368 * \param [in] color Box line color.
369 * \param [in] cap Box line end cap type (unused).
370 * \param [in] filled (unused)
371 * \param [in] x Box upper x.
372 * \param [in] y Box upper y.
373 * \param [in] width Box width.
374 * \param [in] height Box height
375 * \param [in] line_width Width of line to draw box.
376 * \param [in] length (unused)
377 * \param [in] space Space in pixels between dots.
380 void o_box_draw_dotted(GdkDrawable *w, GdkGC *gc, GdkColor *color,
381 GdkCapStyle cap, gint filled, gint x, gint y,
382 gint width, gint height, gint line_width,
383 gint length, gint space)
385 o_line_draw_dotted(w, gc, color, cap,
386 x, y, x + width, y, line_width, length, space);
387 o_line_draw_dotted(w, gc, color, cap,
388 x + width, y, x + width, y + height,
389 line_width, length, space);
390 o_line_draw_dotted(w, gc, color, cap,
391 x + width, y + height, x, y+height,
392 line_width, length, space);
393 o_line_draw_dotted(w, gc, color, cap,
394 x, y + height, x, y, line_width, length, space);
398 /*! \brief Draw a box with a dashed line type.
399 * \par Function Description
400 * This function draws a box with a dashed line type. The parameter
401 * <B>space</B> represents the distance between two of the dash. The
402 * parameter <B>length</B> represents the length of a dash.
404 * The function uses the functions previously defined in #o_line.c. It is
405 * called four times for each of the side of the box.
407 * The box is defined in the same way as it is in GDK : one point and
408 * the width and height of the box.
410 * The unit of <B>x</B>, <B>y</B>, <B>width</B>, <B>height</B>,
411 * <B>line_width</B>, <B>length</B> and <B>space</B> is pixel.
413 * A negative or null value for length or space leads to an endless
414 * loop in #o_line_draw_dashed().
416 * \param [in] w GdkDrawable to draw in.
417 * \param [in] gc GdkGC graphics context to draw on.
418 * \param [in] color Box line color.
419 * \param [in] cap Box line end cap type (unused).
420 * \param [in] filled (unused)
421 * \param [in] x Box upper x.
422 * \param [in] y Box upper y.
423 * \param [in] width Box width.
424 * \param [in] height Box height
425 * \param [in] line_width Width of line to draw box.
426 * \param [in] length Length of dash in pixels.
427 * \param [in] space Space between dashes in pixels.
429 void o_box_draw_dashed(GdkDrawable *w, GdkGC *gc, GdkColor *color,
430 GdkCapStyle cap, gint filled, gint x, gint y,
431 gint width, gint height, gint line_width,
432 gint length, gint space)
434 o_line_draw_dashed(w, gc, color, cap,
435 x, y, x + width, y, line_width, length, space);
436 o_line_draw_dashed(w, gc, color, cap,
437 x + width, y, x + width, y + height,
438 line_width, length, space);
439 o_line_draw_dashed(w, gc, color, cap,
440 x + width, y + height, x, y+height,
441 line_width, length, space);
442 o_line_draw_dashed(w, gc, color, cap,
443 x, y + height, x, y, line_width, length, space);
446 /*! \brief Draw a box with a centered line type.
447 * \par Function Description
448 * This function draws a box with a centered line type. The parameter
449 * <B>space</B> represents the distance between a dot and the dash. The
450 * parameter <B>length</B> represents the length of a dash.
452 * The function uses the functions previously defined in #o_line.c. It is
453 * called four times for each of the side of the box.
455 * The box is defined in the same way as it is in GDK : one point and the
456 * width and height of the box.
458 * The unit of <B>x</B>, <B>y</B>, <B>width</B>, <B>height</B>,
459 * <B>line_width</B>, <B>length</B> and <B>space</B> is pixel.
461 * A negative or null value for length or space leads to an endless
462 * loop in #o_line_draw_center().
464 * \param [in] w GdkDrawable to draw in.
465 * \param [in] gc GdkGC graphics context to draw on.
466 * \param [in] color Box line color.
467 * \param [in] cap Box line end cap type (unused).
468 * \param [in] filled (unused)
469 * \param [in] x Box upper x.
470 * \param [in] y Box upper y.
471 * \param [in] width Box width.
472 * \param [in] height Box height
473 * \param [in] line_width Width of line to draw box.
474 * \param [in] length (unused)?
475 * \param [in] space (unused)?
477 void o_box_draw_center(GdkDrawable *w, GdkGC *gc, GdkColor *color,
478 GdkCapStyle cap, gint filled, gint x, gint y,
479 gint width, gint height, gint line_width,
480 gint length, gint space)
482 o_line_draw_center(w, gc, color, cap,
483 x, y, x + width, y, line_width, length, space);
484 o_line_draw_center(w, gc, color, cap,
485 x + width, y, x + width, y + height,
486 line_width, length, space);
487 o_line_draw_center(w, gc, color, cap,
488 x + width, y + height, x, y+height,
489 line_width, length, space);
490 o_line_draw_center(w, gc, color, cap,
491 x, y + height, x, y, line_width, length, space);
494 /*! \brief Draw a box with a phantom line type.
495 * \par Function Description
496 * This function draws a box with a phantom line type. The parameter
497 * <B>space</B> represents the distance between a dot and a dash.
498 * The parameter <B>length</B> represents the length of a dash.
500 * The function uses the functions previously defined in #o_line.c.
501 * It is called four times for each of the side of the box.
503 * The box is defined in the same way as it is in GDK : one point and the
504 * width and height of the box.
506 * The unit of <B>x</B>, <B>y</B>, <B>width</B>, <B>height</B>,
507 * <B>line_width</B>, <B>length</B> and <B>space</B> is pixel.
509 * A negative or null value for length or space leads to an endless loop
510 * in #o_line_draw_phantom().
512 * \param [in] w GdkDrawable to draw in.
513 * \param [in] gc GdkGC graphics context to draw on.
514 * \param [in] color Box line color.
515 * \param [in] cap Box line end cap type (unused).
516 * \param [in] filled (unused)
517 * \param [in] x Box upper x.
518 * \param [in] y Box upper y.
519 * \param [in] width Box width.
520 * \param [in] height Box height
521 * \param [in] line_width Width of line to draw box.
522 * \param [in] length (unused)?
523 * \param [in] space (unused)?
525 void o_box_draw_phantom(GdkDrawable *w, GdkGC *gc, GdkColor *color,
526 GdkCapStyle cap, gint filled, gint x, gint y,
527 gint width, gint height, gint line_width,
528 gint length, gint space)
530 o_line_draw_phantom(w, gc, color, cap,
531 x, y, x + width, y, line_width, length, space);
532 o_line_draw_phantom(w, gc, color, cap,
533 x + width, y, x + width, y+height,
534 line_width, length, space);
535 o_line_draw_phantom(w, gc, color, cap,
536 x + width, y + height, x, y+height,
537 line_width, length, space);
538 o_line_draw_phantom(w, gc, color, cap,
539 x, y + height, x, y, line_width, length, space);
542 /*! \brief Placeholder filling function.
543 * \par Function Description
544 * This function does nothing. It has the same prototype as all the
545 * filling functions. It prevent from making a difference between filling
546 * in function #o_box_draw().
548 * \param [in] w GdkDrawable to draw in.
549 * \param [in] gc GdkGC graphics context to draw on.
550 * \param [in] color Box fill color.
551 * \param [in] x Upper x coordinate of BOX.
552 * \param [in] y Upper y coordinate of BOX.
553 * \param [in] width Width of BOX.
554 * \param [in] height Height of BOX.
555 * \param [in] fill_width BOX pattern fill width.
556 * \param [in] angle1 1st angle for pattern.
557 * \param [in] pitch1 1st pitch for pattern.
558 * \param [in] angle2 2nd angle for pattern.
559 * \param [in] pitch2 2nd pitch for pattern.
561 void o_box_fill_hollow(GdkDrawable *w, GdkGC *gc, GdkColor *color,
562 gint x, gint y,
563 gint width, gint height,
564 gint fill_width,
565 gint angle1, gint pitch1,
566 gint angle2, gint pitch2)
571 /*! \brief Fill inside of box with a solid pattern.
572 * \par Function Description
573 * This function fills the inside of the box with a solid pattern.
574 * Parameters <B>angle1</B>, <B>pitch1</B> and <B>angle2</B>,
575 * <B>pitch2</B> and <B>fill_width</B> are unused here but kept for compatibility
576 * with other box filling functions.
578 * The box is defined in the same way as it is in GDK : one point and
579 * the width and height of the box.
581 * All parameters are given in pixel.
583 * The solid fill is done with the #gdk_draw_rectangle() function and
584 * its parameters <B>filled</B> set. The box is filled with the color
585 * <B>color</B> given as a parameter to the function.
587 * \param [in] w GdkDrawable to draw in.
588 * \param [in] gc GdkGC graphics context to draw on.
589 * \param [in] color Box fill color.
590 * \param [in] x Upper x coordinate of BOX.
591 * \param [in] y Upper y coordinate of BOX.
592 * \param [in] width Width of BOX.
593 * \param [in] height Height of BOX.
594 * \param [in] fill_width BOX pattern fill width.
595 * \param [in] angle1 (unused)
596 * \param [in] pitch1 (unused)
597 * \param [in] angle2 (unused)
598 * \param [in] pitch2 (unused)
600 void o_box_fill_fill(GdkDrawable *w, GdkGC *gc, GdkColor *color,
601 gint x, gint y,
602 gint width, gint height,
603 gint fill_width,
604 gint angle1, gint pitch1, gint angle2, gint pitch2)
606 gdk_gc_set_foreground(gc, color);
607 gdk_gc_set_line_attributes(gc, 1, GDK_LINE_SOLID,
608 GDK_CAP_BUTT, GDK_JOIN_MITER);
610 gdk_draw_rectangle(w, gc, TRUE, x, y, width, height);
614 /*! \brief Fill inside of box with single line pattern.
615 * \par Function Description
616 * This function fills the inside of the box with a pattern made of lines.
617 * The lines are drawn inside the box with an angle <B>angle1</B> from the
618 * horizontal. The distance between two of these lines is given by
619 * <B>pitch1</B> and their width by <B>fill_width</B>.
620 * Parameters <B>angle2</B> and <B>pitch2</B> are unused here but kept for
621 * compatbility with other box filling functions.
623 * The box is defined in the same way as it is in GDK : one point and the
624 * width and height of the box.
626 * All parameters are given in pixel.
628 * Negative or null values for <B>pitch1</B> are not allowed as it leads to
629 * an endless loop.
631 * \param [in] w GdkDrawable to draw in.
632 * \param [in] gc GdkGC graphics context to draw on.
633 * \param [in] color Box fill color.
634 * \param [in] x Upper x coordinate of BOX.
635 * \param [in] y Upper y coordinate of BOX.
636 * \param [in] width Width of BOX.
637 * \param [in] height Height of BOX.
638 * \param [in] fill_width BOX pattern fill width.
639 * \param [in] angle1 1st angle for pattern.
640 * \param [in] pitch1 1st pitch for pattern.
641 * \param [in] angle2 (unused)
642 * \param [in] pitch2 (unused)
644 void o_box_fill_hatch(GdkDrawable *w, GdkGC *gc, GdkColor *color,
645 gint x, gint y,
646 gint width, gint height,
647 gint fill_width,
648 gint angle1, gint pitch1, gint angle2, gint pitch2)
650 int x3, y3, x4, y4;
651 double cos_a_, sin_a_;
652 double x0, y0, r;
653 double x1, y1, x2, y2;
654 double amin, amax, a[4], min1, min2, max1, max2;
656 gdk_gc_set_line_attributes(gc, fill_width, GDK_LINE_SOLID,
657 GDK_CAP_BUTT, GDK_JOIN_MITER);
660 * The function uses a matrix. Its elements are obtained from the sinus
661 * and the cosinus of the angle <B>angle1</B>. It represents the rotation
662 * matrix that when applied to a point, rotate it of <B>angle1</B>.
664 cos_a_ = cos(((double) angle1) * M_PI/180);
665 sin_a_ = sin(((double) angle1) * M_PI/180);
668 * The function considers the smallest circle around the box. Its radius
669 * is given by the following relation. Its center is given by the point
670 * a the middle of the box horizontally and vertically (intersection of
671 * its two diagonals.
673 r = sqrt((double) (pow(width, 2) + pow(height, 2))) / 2;
676 * When drawing a line in a circle there is two intersections. With the
677 * previously described circle, these intersections are out of the box.
678 * They can be easily calculated, the first by resolution of an equation
679 * and the second one by symetry in relation to the vertical axis going
680 * through the center of the circle.
682 * These two points are then rotated of angle <B>angle1</B> using the matrix
683 * previously mentionned.
685 y0 = 0;
686 while(y0 < r) {
687 x0 = pow(r, 2) - pow(y0, 2);
688 x0 = sqrt(x0);
690 x1 = (x0*cos_a_ - y0*sin_a_);
691 y1 = (x0*sin_a_ + y0*cos_a_);
692 x2 = ((-x0)*cos_a_ - y0*sin_a_);
693 y2 = ((-x0)*sin_a_ + y0*cos_a_);
696 * It now parametrizes the segment : first intersection is given
697 * the value of 0 and the second is given the value of 1. The four
698 * values for each intersection of the segment and the four
699 * sides (vertical or horizontal) of the box are given by the
700 * following relations :
702 if((int) (x2 - x1) != 0) {
703 a[0] = ((-width/2) - x1) / (x2 - x1);
704 a[1] = ((width/2) - x1) / (x2 - x1);
705 } else {
706 a[0] = 0; a[1] = 1;
709 if((int) (y2 - y1) != 0) {
710 a[2] = ((-height/2) - y1) / (y2 - y1);
711 a[3] = ((height/2) - y1) / (y2 - y1);
712 } else {
713 a[2] = 0; a[3] = 1;
716 * It now has to check which of these four values are for
717 * intersections with the sides of the box (some values may be
718 * for intersections out of the box). This is made by a min/max
719 * function.
721 if(a[0] < a[1]) {
722 min1 = a[0]; max1 = a[1];
723 } else {
724 min1 = a[1]; max1 = a[0];
727 if(a[2] < a[3]) {
728 min2 = a[2]; max2 = a[3];
729 } else {
730 min2 = a[3]; max2 = a[2];
733 amin = (min1 < min2) ? min2 : min1;
734 amin = (amin < 0) ? 0 : amin;
736 amax = (max1 < max2) ? max1 : max2;
737 amax = (amax < 1) ? amax : 1;
740 * If the segment really go through the box it draws the line.
741 * It also take the opportunity of the symetry in the box in
742 * relation to its center to draw the second line at the same time.
744 * If there is no intersection of the segment with any of the sides,
745 * then there is no need to continue : there would be no more
746 * segment in the box to draw.
749 if((amax > amin) && (amax != 1) && (amin != 0)) {
750 /* There is intersection between the line and the box edges */
751 x3 = (int) (x1 + amin*(x2 - x1));
752 y3 = (int) (y1 + amin*(y2 - y1));
754 x4 = (int) (x1 + amax*(x2 - x1));
755 y4 = (int) (y1 + amax*(y2 - y1));
757 gdk_draw_line(w, gc, x3 + (x + width/2),
758 (y + height/2) - y3, x4 + (x + width/2),
759 (y + height/2) - y4);
761 gdk_draw_line(w, gc, -x3 + (x + width/2),
762 +y3 + (y + height/2), -x4 + (x + width/2),
763 +y4 + (y + height/2));
765 } else {
766 break;
769 y0 = y0 + pitch1;
774 /*! \brief Fill inside of box with mesh pattern.
775 * \par Function Description
776 * This function fills the inside of the box with a pattern made of two
777 * sets of parallel lines in two directions. The first set is drawn inside
778 * the box with an angle <B>angle1</B> from the horizontal. The distance
779 * between two of these lines is given by <B>pitch1</B>.
780 * The second set is drawn inside the box with an angle <B>angle2</B> from
781 * the horizontal. The distance between two of these lines is given
782 * by <B>pitch2</B>.
783 * Every lines have the same width given be <B>fill_width</B>.
785 * This function simply makes two successive calls to the function
786 * #o_box_fill_hatch() respectively with <B>angle1</B>, <B>pitch1</B> and
787 * <B>angle2</B>, <B>pitch2</B> for parameters.
788 * \param [in] w GdkDrawable to draw in.
789 * \param [in] gc GdkGC graphics context to draw on.
790 * \param [in] color Box fill color.
791 * \param [in] x Upper x coordinate of BOX.
792 * \param [in] y Upper y coordinate of BOX.
793 * \param [in] width Width of BOX.
794 * \param [in] height Height of BOX.
795 * \param [in] fill_width BOX pattern fill width.
796 * \param [in] angle1 1st angle for pattern.
797 * \param [in] pitch1 1st pitch for pattern.
798 * \param [in] angle2 2nd angle for pattern.
799 * \param [in] pitch2 2nd pitch for pattern.
801 void o_box_fill_mesh(GdkDrawable *w, GdkGC *gc, GdkColor *color,
802 gint x, gint y,
803 gint width, gint height,
804 gint fill_width,
805 gint angle1, gint pitch1,
806 gint angle2, gint pitch2)
808 o_box_fill_hatch(w, gc, color, x, y, width, height,
809 fill_width, angle1, pitch1, -1, -1);
810 o_box_fill_hatch(w, gc, color, x, y, width, height,
811 fill_width, angle2, pitch2, -1, -1);
815 /*! \brief Erase a box described by OBJECT.
816 * \par Function Description
817 * This function erases a box, described in a <B>OBJECT</B> structure pointed
818 * by <B>o_current</B>.
820 * It makes a call to the function #o_box_draw() after setting the special
821 * color. Therefore a box is drawn with background color over the previous
822 * one.
824 * \param [in] w_current The TOPLEVEL object.
825 * \param [in] o_current Box OBJECT to erase.
827 void o_box_erase(TOPLEVEL *w_current, OBJECT *o_current)
829 w_current->override_color = w_current->background_color;
830 o_box_draw(w_current, o_current);
831 w_current->override_color = -1;
834 /*! \todo Finish function documentation!!!
835 * \brief
836 * \par Function Description
838 * \note
839 * used in button cancel code in x_events.c
841 void o_box_eraserubber(TOPLEVEL *w_current)
843 o_box_rubberbox_xor(w_current);
846 /*! \brief Draw a box described by OBJECT with translation
847 * \par Function Description
848 * This function daws the box object described by <B>*o_current</B> translated
849 * by the vector (<B>dx</B>,<B>dy</B>) with an xor-function over the current sheet.
850 * The translation vector is in screen unit.
852 * The box is displayed with the color of the object.
854 * \param [in] w_current The TOPLEVEL object.
855 * \param [in] dx Delta x coordinate for box.
856 * \param [in] dy Delta y coordinate for box.
857 * \param [in] o_current Box OBJECT to draw.
859 void o_box_draw_xor(TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
861 int screen_x1, screen_y1;
862 int screen_x2, screen_y2;
863 int color;
865 if (o_current->box == NULL) {
866 return;
869 WORLDtoSCREEN( w_current, o_current->box->upper_x, o_current->box->upper_y,
870 &screen_x1, &screen_y1 );
871 WORLDtoSCREEN( w_current, o_current->box->lower_x, o_current->box->lower_y,
872 &screen_x2, &screen_y2 );
874 if (o_current->saved_color != -1) {
875 color = o_current->saved_color;
876 } else {
877 color = o_current->color;
880 gdk_gc_set_foreground(w_current->outline_xor_gc,
881 x_get_darkcolor(color));
882 gdk_draw_rectangle(w_current->window,
883 w_current->outline_xor_gc, FALSE,
884 screen_x1 + dx,
885 screen_y1 + dy,
886 abs(screen_x2 - screen_x1),
887 abs(screen_y2 - screen_y1));
890 /*! \brief Start process to input a new box.
891 * \par Function Description
892 * This function starts the process to input a new box. Parameters for this
893 * box are put into/extracted from the <B>w_current</B> toplevel structure.
894 * <B>x</B> and <B>y</B> are current coordinates of the pointer in screen
895 * coordinates.
897 * The first step is to input one corner of the box. This corner is
898 * (<B>x</B>,<B>y</B>) snapped to the grid and saved in <B>w_current->start_x</B>
899 * and <B>w_current->start_y</B>.
901 * The other corner will be saved in (<B>w_current->last_x</B>,
902 * <B>w_current->last_y</B>).
904 * \param [in] w_current The TOPLEVEL object.
905 * \param [in] x Current x coordinate of pointer in screen units.
906 * \param [in] y Current y coordinate of pointer in screen units.
908 void o_box_start(TOPLEVEL *w_current, int x, int y)
910 /* init start_[x|y], last_[x|y] to describe box */
911 w_current->last_x = w_current->start_x = fix_x(w_current, x);
912 w_current->last_y = w_current->start_y = fix_y(w_current, y);
914 /* start to draw the box */
915 o_box_rubberbox_xor(w_current);
919 /*! \brief End the input of a box.
920 * \par Function Description
921 * This function ends the input of the second corner of a box.
922 * The (<B>x</B>,<B>y</B>) point is set to be this second corner. The box is
923 * then defined by (<B>w_current->start_x</B>,<B>w_current->start_y</B> and
924 * (<B>w_current->last_x</B>,<B>w_current->last_y</B> that is a snapped version
925 * of (<B>x</B>,<B>y</B>).
926 * <B>x</B> and <B>y</B> are in screen unit.
928 * The temporary box is erased ; a new box object is allocated, initialized
929 * and linked to the object list ; The object is finally drawn on the
930 * current sheet.
932 * \param [in] w_current The TOPLEVEL object.
933 * \param [in] x Current x coordinate of pointer in screen units.
934 * \param [in] y Current y coordinate of pointer in screen units.
936 void o_box_end(TOPLEVEL *w_current, int x, int y)
938 int x1, y1;
939 int x2, y2;
940 int box_width, box_height;
941 int box_left, box_top;
943 if (w_current->inside_action == 0) {
944 o_redraw(w_current, w_current->page_current->object_head, TRUE);
945 return;
948 /* get the last coords of the pointer */
949 w_current->last_x = fix_x(w_current, x);
950 w_current->last_y = fix_y(w_current, y);
952 /* erase the temporary box */
953 o_box_rubberbox_xor(w_current);
955 box_width = GET_BOX_WIDTH (w_current);
956 box_height = GET_BOX_HEIGHT(w_current);
957 box_left = GET_BOX_LEFT (w_current);
958 box_top = GET_BOX_TOP (w_current);
960 /* boxes with null width and height are not allowed */
961 if ((box_width == 0) && (box_height == 0)) {
962 /* cancel the object creation */
963 w_current->start_x = (-1);
964 w_current->start_y = (-1);
965 w_current->last_x = (-1);
966 w_current->last_y = (-1);
967 return;
970 /* calculate the world coords of the upper left and lower right corners */
971 SCREENtoWORLD(w_current, box_left, box_top, &x1, &y1);
972 SCREENtoWORLD(w_current,
973 box_left + box_width, box_top + box_height, &x2, &y2);
974 x1 = snap_grid(w_current, x1);
975 y1 = snap_grid(w_current, y1);
976 x2 = snap_grid(w_current, x2);
977 y2 = snap_grid(w_current, y2);
979 /* create the object */
980 w_current->page_current->object_tail =
981 o_box_add(w_current,
982 w_current->page_current->object_tail,
983 OBJ_BOX, w_current->graphic_color, x1, y1, x2, y2);
985 /* draw it */
986 o_redraw_single(w_current, w_current->page_current->object_tail);
988 #if DEBUG
989 printf("coords: %d %d %d %d\n", x1, y2, x2, y2);
990 #endif
992 w_current->start_x = (-1);
993 w_current->start_y = (-1);
994 w_current->last_x = (-1);
995 w_current->last_y = (-1);
997 w_current->page_current->CHANGED = 1;
999 o_undo_savestate(w_current, UNDO_ALL);
1002 /*! \brief Draw temporary box while dragging edge.
1003 * \par Function Description
1004 * This function is used to draw the box while dragging one of its edge or
1005 * angle. It erases the previous temporary box drawn before, and draws a new
1006 * updated one. <B>x</B> and <B>y</B> are the new position of the mobile point,
1007 * ie the mouse.
1009 * The old values are inside the <B>w_current</B> pointed structure. Old width,
1010 * height and left and top values are recomputed by the corresponding macros.
1011 * The box is then erased by performing a xor-drawing over the box.
1013 * \param [in] w_current The TOPLEVEL object.
1014 * \param [in] x Current x coordinate of pointer in screen units.
1015 * \param [in] y Current y coordinate of pointer in screen units.
1017 void o_box_rubberbox(TOPLEVEL *w_current, int x, int y)
1019 if (w_current->inside_action == 0) {
1020 o_redraw(w_current, w_current->page_current->object_head, TRUE);
1021 return;
1024 /* erase the previous temporary box */
1025 o_box_rubberbox_xor(w_current);
1028 * New values are fixed according to the <B>x</B> and <B>y</B> parameters.
1029 * These are saved in <B>w_current</B> pointed structure as new temporary
1030 * values. The new box is then drawn.
1033 /* update the coords of the corner */
1034 w_current->last_x = fix_x(w_current, x);
1035 w_current->last_y = fix_y(w_current, y);
1037 /* draw the new temporary box */
1038 o_box_rubberbox_xor(w_current);
1042 /*! \brief Draw box from TOPLEVEL object.
1043 * \par Function Description
1044 * This function draws the box from the variables in the toplevel
1045 * structure <B>*w_current</B>.
1046 * One corner of the box is at (<B>w_current->start_x</B>,
1047 * <B>w_current->start_y</B>) and the second corner is at
1048 * (<B>w_current->last_x</B>,<B>w_current->last_y</B>.
1050 * The box is drawn with a xor-function over the current sheet with the
1051 * selection color.
1053 * \param [in] w_current The TOPLEVEL object.
1055 void o_box_rubberbox_xor(TOPLEVEL *w_current)
1057 int box_width, box_height, box_left, box_top;
1059 /* get the width/height and the upper left corner of the box */
1060 box_width = GET_BOX_WIDTH (w_current);
1061 box_height = GET_BOX_HEIGHT(w_current);
1062 box_left = GET_BOX_LEFT (w_current);
1063 box_top = GET_BOX_TOP (w_current);
1065 /* draw the box from the previous variables */
1066 gdk_gc_set_foreground(w_current->xor_gc,
1067 x_get_darkcolor(w_current->select_color));
1068 gdk_gc_set_line_attributes(w_current->xor_gc, 0,
1069 GDK_LINE_SOLID, GDK_CAP_NOT_LAST,
1070 GDK_JOIN_MITER);
1071 gdk_draw_rectangle(w_current->window, w_current->xor_gc,
1072 FALSE, box_left, box_top, box_width, box_height);
1076 /*! \brief Draw grip marks on box.
1077 * \par Function Description
1078 * This function draws four grips on the corners of the box described
1079 * by <B>*o_current</B>.
1081 * \param [in] w_current The TOPLEVEL object.
1082 * \param [in] o_current Box OBJECT to draw grip points on.
1084 * \par Author's note
1085 * p20011003 - modified the prototype : removed parameter 'GdkWindow *w'
1087 void o_box_draw_grips(TOPLEVEL *w_current, OBJECT *o_current)
1089 int s_upper_x, s_upper_y, s_lower_x, s_lower_y;
1091 if (w_current->draw_grips == FALSE)
1092 return;
1094 WORLDtoSCREEN( w_current, o_current->box->upper_x, o_current->box->upper_y,
1095 &s_upper_x, &s_upper_y );
1096 WORLDtoSCREEN( w_current, o_current->box->lower_x, o_current->box->lower_y,
1097 &s_lower_x, &s_lower_y );
1099 /* grip on upper left corner (whichone = BOX_UPPER_LEFT) */
1100 o_grips_draw(w_current, s_upper_x, s_upper_y);
1102 /* grip on upper right corner (whichone = BOX_UPPER_RIGHT) */
1103 o_grips_draw(w_current, s_lower_x, s_upper_y);
1105 /* grip on lower left corner (whichone = BOX_LOWER_LEFT) */
1106 o_grips_draw(w_current, s_upper_x, s_lower_y);
1108 /* grip on lower right corner (whichone = BOX_LOWER_RIGHT) */
1109 o_grips_draw(w_current, s_lower_x, s_lower_y);
1113 /*! \brief Erase grip marks from box.
1114 * \par Function Description
1115 * This function erases the four grips displayed on the <B>*o_current</B>
1116 * box object. These grips are on each of the corner.
1118 * \param [in] w_current The TOPLEVEL object.
1119 * \param [in] o_current Box OBJECT to erase grip marks from.
1121 void o_box_erase_grips(TOPLEVEL *w_current, OBJECT *o_current)
1123 int s_upper_x, s_upper_y, s_lower_x, s_lower_y;
1125 if (w_current->draw_grips == FALSE)
1126 return;
1128 WORLDtoSCREEN( w_current, o_current->box->upper_x, o_current->box->upper_y,
1129 &s_upper_x, &s_upper_y );
1130 WORLDtoSCREEN( w_current, o_current->box->lower_x, o_current->box->lower_y,
1131 &s_lower_x, &s_lower_y );
1133 /* grip on upper left corner (whichone = BOX_UPPER_LEFT) */
1134 o_grips_erase(w_current, s_upper_x, s_upper_y);
1136 /* grip on upper right corner (whichone = BOX_UPPER_RIGHT) */
1137 o_grips_erase(w_current, s_lower_x, s_upper_y);
1139 /* grip on lower left corner (whichone = BOX_LOWER_LEFT) */
1140 o_grips_erase(w_current, s_upper_x, s_lower_y);
1142 /* grip on lower right corner (whichone = BOX_LOWER_RIGHT) */
1143 o_grips_erase(w_current, s_lower_x, s_lower_y);