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
24 #include <libgeda/libgeda.h>
26 #include "../include/globals.h"
27 #include "../include/prototype.h"
29 #ifdef HAVE_LIBDMALLOC
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
;
74 DRAW_FUNC draw_func
= NULL
;
77 if (o_current
->box
== NULL
) {
81 /* Get read to check for visibility of this line by using it's
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
)) ) {
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
));
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
);
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
132 line_width
= SCREENabs( w_current
, o_current
->line_width
);
133 if(line_width
<= 0) {
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
;
146 length
= SCREENabs( w_current
, o_current
->line_length
);
147 space
= SCREENabs( w_current
, o_current
->line_space
);
149 switch(o_current
->line_type
) {
153 draw_func
= o_box_draw_solid
;
157 length
= -1; /* ..._draw_dotted only space is used */
158 draw_func
= o_box_draw_dotted
;
162 draw_func
= o_box_draw_dashed
;
166 draw_func
= o_box_draw_center
;
170 draw_func
= o_box_draw_phantom
;
179 line_width
= 0; /* just to be careful */
180 draw_func
= o_box_draw_solid
;
181 fprintf(stderr
, _("Unknown type for box !\n"));
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
,
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
,
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) {
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
) {
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
247 fill_func
= o_box_fill_hollow
;
251 angle1
= -1; angle2
= -1;
252 pitch1
= 1; pitch2
= 1;
253 fill_func
= o_box_fill_fill
;
257 fill_func
= o_box_fill_mesh
;
263 fill_func
= o_box_fill_hatch
;
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
);
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
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
,
340 o_line_draw_solid(w
, gc
, color
, cap
,
341 x
+ width
, y
+ height
, x
, y
+ height
, line_width
,
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
,
563 gint width
, gint height
,
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
,
602 gint width
, gint height
,
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
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
,
646 gint width
, gint height
,
648 gint angle1
, gint pitch1
, gint angle2
, gint pitch2
)
651 double cos_a_
, sin_a_
;
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
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.
687 x0
= pow(r
, 2) - pow(y0
, 2);
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
);
709 if((int) (y2
- y1
) != 0) {
710 a
[2] = ((-height
/2) - y1
) / (y2
- y1
);
711 a
[3] = ((height
/2) - y1
) / (y2
- y1
);
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
722 min1
= a
[0]; max1
= a
[1];
724 min1
= a
[1]; max1
= a
[0];
728 min2
= a
[2]; max2
= a
[3];
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));
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
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
,
803 gint width
, gint height
,
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
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!!!
836 * \par Function Description
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
;
865 if (o_current
->box
== NULL
) {
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
;
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
,
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
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
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
)
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
);
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);
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
=
982 w_current
->page_current
->object_tail
,
983 OBJ_BOX
, w_current
->graphic_color
, x1
, y1
, x2
, y2
);
986 o_redraw_single(w_current
, w_current
->page_current
->object_tail
);
989 printf("coords: %d %d %d %d\n", x1
, y2
, x2
, y2
);
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,
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
);
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
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
,
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
)
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
)
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
);