gschem
|
00001 /* gEDA - GPL Electronic Design Automation 00002 * gschem - gEDA Schematic Capture 00003 * Copyright (C) 1998-2010 Ales Hvezda 00004 * Copyright (C) 1998-2011 gEDA Contributors (see ChangeLog for details) 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 #include <config.h> 00021 #include <math.h> 00022 #include <stdio.h> 00023 00024 #include "gschem.h" 00025 00026 #ifdef HAVE_LIBDMALLOC 00027 #include <dmalloc.h> 00028 #endif 00029 00030 #define GET_BOX_WIDTH(w) \ 00031 abs((w)->second_wx - (w)->first_wx) 00032 #define GET_BOX_HEIGHT(w) \ 00033 abs((w)->second_wy - (w)->first_wy) 00034 #define GET_BOX_LEFT(w) \ 00035 min((w)->first_wx, (w)->second_wx) 00036 #define GET_BOX_TOP(w) \ 00037 max((w)->first_wy, (w)->second_wy) 00038 00039 typedef void (*FILL_FUNC) (GSCHEM_TOPLEVEL *w_current, 00040 COLOR *color, BOX *box, 00041 gint fill_width, 00042 gint angle1, gint pitch1, 00043 gint angle2, gint pitch2); 00044 00060 static void 00061 o_box_fill_hollow (GSCHEM_TOPLEVEL *w_current, 00062 COLOR *color, BOX *box, 00063 gint fill_width, 00064 gint angle1, gint pitch1, 00065 gint angle2, gint pitch2) 00066 { 00067 } 00068 00090 static void 00091 o_box_fill_fill (GSCHEM_TOPLEVEL *w_current, 00092 COLOR *color, BOX *box, 00093 gint fill_width, 00094 gint angle1, gint pitch1, 00095 gint angle2, gint pitch2) 00096 { 00097 /* NOP: We'll fill it when we do the stroking */ 00098 } 00099 00126 static void 00127 o_box_fill_hatch (GSCHEM_TOPLEVEL *w_current, 00128 COLOR *color, BOX *box, 00129 gint fill_width, 00130 gint angle1, gint pitch1, 00131 gint angle2, gint pitch2) 00132 { 00133 int i; 00134 GArray *lines; 00135 00136 gschem_cairo_set_source_color (w_current, color); 00137 00138 lines = g_array_new (FALSE, FALSE, sizeof (LINE)); 00139 m_hatch_box (box, angle1, pitch1, lines); 00140 00141 for (i=0; i < lines->len; i++) { 00142 LINE *line = &g_array_index (lines, LINE, i); 00143 00144 gschem_cairo_line (w_current, END_NONE, fill_width, line->x[0], line->y[0], 00145 line->x[1], line->y[1]); 00146 } 00147 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, fill_width, -1, -1); 00148 00149 g_array_free (lines, TRUE); 00150 } 00151 00175 static void 00176 o_box_fill_mesh (GSCHEM_TOPLEVEL *w_current, 00177 COLOR *color, BOX *box, 00178 gint fill_width, 00179 gint angle1, gint pitch1, 00180 gint angle2, gint pitch2) 00181 { 00182 o_box_fill_hatch (w_current, color, box, fill_width, angle1, pitch1, -1, -1); 00183 o_box_fill_hatch (w_current, color, box, fill_width, angle2, pitch2, -1, -1); 00184 } 00185 00186 00200 void o_box_draw(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current) 00201 { 00202 int angle1, pitch1, angle2, pitch2; 00203 FILL_FUNC fill_func; 00204 00205 if (o_current->box == NULL) { 00206 return; 00207 } 00208 00209 /* 00210 * The drawing of the box is divided in two steps : first step is to 00211 * draw the outline, the second is to draw the filling pattern inside 00212 * (if any). Finally the function takes care of the grips. 00213 */ 00214 /* 00215 * The values describing the line type are extracted from the <B>o_current</B> 00216 * pointed structure. These are the width of the line, the field called 00217 * length and the field called space and the desired end type for the line. 00218 * 00219 * Depending on the type of the line that has to be used to draw the box 00220 * the appropriate function is called. Values of space and length are 00221 * adapted to the type of line. The possible functions are the following : 00222 * #o_box_draw_solid(), #o_box_draw_dotted(), #o_box_draw_dashed() and 00223 * #o_box_draw_phantom(). 00224 * 00225 * The combination <B>length</B> == 0 and <B>space</B> == 0 is avoided as it 00226 * lead to an endless loop in function called after. If such a case is 00227 * encountered the box is drawn as a solid box independently of its 00228 * initial type. 00229 */ 00230 00231 /* 00232 * The values needed for the fill operation are taken from the 00233 * <B>o_current</B> pointed OBJECT. It include the type of fill required, 00234 * the width of the lines (if the fill use line) and angles and pitchs 00235 * for hatch based filling. 00236 * 00237 * Once again the width of the line is important as if it is equal to 00238 * 0 it may not be displayed. That is definetely not what we are looking for. 00239 * 00240 * Depending on the type of fill that has to be used inside the box the 00241 * appropriate function is called. Values of <B>angle1</B>, 00242 * <B>angle2</B>, <B>pitch1</B> and <B>pitch2</B> are adapted to the type of 00243 * filling. The possible functions are the following : 00244 * #o_box_fill_hollow(), #o_box_fill_fill(), #o_box_fill_mesh() and 00245 * #o_box_fill_hatch(). 00246 * 00247 * The combination <B>pitch1</B> <= 0 and <B>pitch2</B> <= 0 is avoided as 00248 * it lead to an endless loop in function called after. It happens when 00249 * the zoom factor is too small for two lines separated by the pitch 00250 * to be distinct. If such a case is encountered the circle is filled 00251 * hollow (e.q. not filled). 00252 */ 00253 00254 angle1 = o_current->fill_angle1; 00255 pitch1 = o_current->fill_pitch1; 00256 angle2 = o_current->fill_angle2; 00257 pitch2 = o_current->fill_pitch2; 00258 00259 switch (o_current->fill_type) { 00260 case FILLING_HOLLOW: 00261 angle1 = -1; angle2 = -1; 00262 pitch1 = 1; pitch2 = 1; 00263 /* this function is empty ! however if it do not use it we have to add 00264 * a test before the call. Simply putting a return here instead is not 00265 * possible as it would prevent any hollow box from having its grips 00266 * drawn 00267 */ 00268 fill_func = o_box_fill_hollow; 00269 break; 00270 00271 case FILLING_FILL: 00272 angle1 = -1; angle2 = -1; 00273 pitch1 = 1; pitch2 = 1; 00274 fill_func = o_box_fill_fill; 00275 break; 00276 00277 case FILLING_MESH: 00278 fill_func = o_box_fill_mesh; 00279 break; 00280 00281 case FILLING_HATCH: 00282 angle2 = -1; 00283 pitch2 = 1; 00284 fill_func = o_box_fill_hatch; 00285 break; 00286 00287 case FILLING_VOID: 00288 default: 00289 angle1 = -1; angle2 = -1; 00290 pitch1 = 1; pitch2 = 1; 00291 fill_func = o_box_fill_hollow; 00292 fprintf (stderr, _("Unknown type for box (fill)!\n")); 00293 } 00294 00295 if ((pitch1 <= 0) || (pitch2 <= 0)) 00296 fill_func = o_box_fill_fill; 00297 00298 (*fill_func) (w_current, o_drawing_color (w_current, o_current), 00299 o_current->box, o_current->fill_width, 00300 angle1, pitch1, angle2, pitch2); 00301 00302 gschem_cairo_set_source_color (w_current, 00303 o_drawing_color (w_current, o_current)); 00304 gschem_cairo_box (w_current, o_current->line_width, 00305 o_current->box->lower_x, o_current->box->lower_y, 00306 o_current->box->upper_x, o_current->box->upper_y); 00307 00308 if (o_current->fill_type == FILLING_FILL) 00309 cairo_fill_preserve (w_current->cr); 00310 00311 gschem_cairo_stroke (w_current, o_current->line_type, 00312 o_current->line_end, 00313 o_current->line_width, 00314 o_current->line_length, 00315 o_current->line_space); 00316 00317 if (o_current->selected && w_current->draw_grips) 00318 o_box_draw_grips (w_current, o_current); 00319 } 00320 00321 00327 void o_box_invalidate_rubber (GSCHEM_TOPLEVEL *w_current) 00328 { 00329 int x1, y1, x2, y2; 00330 00331 WORLDtoSCREEN (w_current, w_current->first_wx, w_current->first_wy, &x1, &y1); 00332 WORLDtoSCREEN (w_current, w_current->second_wx, w_current->second_wy, &x2, &y2); 00333 00334 o_invalidate_rect (w_current, x1, y1, x2, y1); 00335 o_invalidate_rect (w_current, x1, y1, x1, y2); 00336 o_invalidate_rect (w_current, x2, y1, x2, y2); 00337 o_invalidate_rect (w_current, x1, y2, x2, y2); 00338 } 00339 00353 void o_box_draw_place (GSCHEM_TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current) 00354 { 00355 if (o_current->box == NULL) { 00356 return; 00357 } 00358 00359 gschem_cairo_box (w_current, 0, o_current->box->upper_x + dx, 00360 o_current->box->upper_y + dy, 00361 o_current->box->lower_x + dx, 00362 o_current->box->lower_y + dy); 00363 gschem_cairo_set_source_color (w_current, 00364 x_color_lookup_dark (o_current->color)); 00365 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 1, -1, -1); 00366 } 00367 00386 void o_box_start(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y) 00387 { 00388 /* init first_w[x|y], second_w[x|y] to describe box */ 00389 w_current->first_wx = w_current->second_wx = w_x; 00390 w_current->first_wy = w_current->second_wy = w_y; 00391 00392 /* start to draw the box */ 00393 o_box_invalidate_rubber (w_current); 00394 } 00395 00412 void o_box_end(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y) 00413 { 00414 TOPLEVEL *toplevel = w_current->toplevel; 00415 OBJECT *new_obj; 00416 int box_width, box_height; 00417 int box_left, box_top; 00418 00419 g_assert( w_current->inside_action != 0 ); 00420 00421 /* get the last coords of the pointer */ 00422 w_current->second_wx = w_x; 00423 w_current->second_wy = w_y; 00424 00425 /* erase the temporary box */ 00426 /* o_box_invalidate_rubber (w_current); */ 00427 w_current->rubber_visible = 0; 00428 00429 box_width = GET_BOX_WIDTH (w_current); 00430 box_height = GET_BOX_HEIGHT(w_current); 00431 box_left = GET_BOX_LEFT (w_current); 00432 box_top = GET_BOX_TOP (w_current); 00433 00434 /* boxes with null width or height are not allowed */ 00435 if ((box_width == 0) || (box_height == 0)) { 00436 /* cancel the object creation */ 00437 w_current->first_wx = (-1); 00438 w_current->first_wy = (-1); 00439 w_current->second_wx = (-1); 00440 w_current->second_wy = (-1); 00441 return; 00442 } 00443 00444 /* create the object */ 00445 new_obj = o_box_new (toplevel, OBJ_BOX, GRAPHIC_COLOR, 00446 box_left, box_top, 00447 box_left + box_width, box_top - box_height); 00448 s_page_append (toplevel, toplevel->page_current, new_obj); 00449 00450 #if DEBUG 00451 printf("coords: %d %d %d %d\n", box_left, box_top, box_width, box_height); 00452 #endif 00453 00454 w_current->first_wx = (-1); 00455 w_current->first_wy = (-1); 00456 w_current->second_wx = (-1); 00457 w_current->second_wy = (-1); 00458 00459 /* Call add-objects-hook */ 00460 g_run_hook_object (w_current, "%add-objects-hook", new_obj); 00461 00462 toplevel->page_current->CHANGED = 1; 00463 00464 o_undo_savestate(w_current, UNDO_ALL); 00465 } 00466 00481 void o_box_motion (GSCHEM_TOPLEVEL *w_current, int w_x, int w_y) 00482 { 00483 00484 g_assert( w_current->inside_action != 0 ); 00485 00486 /* erase the previous temporary box if it is visible */ 00487 if (w_current->rubber_visible) 00488 o_box_invalidate_rubber (w_current); 00489 00490 /* 00491 * New values are fixed according to the <B>w_x</B> and <B>w_y</B> parameters. 00492 * These are saved in <B>w_current</B> pointed structure as new temporary 00493 * values. The new box is then drawn. 00494 */ 00495 00496 /* update the coords of the corner */ 00497 w_current->second_wx = w_x; 00498 w_current->second_wy = w_y; 00499 00500 /* draw the new temporary box */ 00501 o_box_invalidate_rubber (w_current); 00502 w_current->rubber_visible = 1; 00503 } 00504 00515 void o_box_draw_rubber (GSCHEM_TOPLEVEL *w_current) 00516 { 00517 gschem_cairo_box (w_current, 0, w_current->first_wx, w_current->first_wy, 00518 w_current->second_wx, w_current->second_wy); 00519 gschem_cairo_set_source_color (w_current, 00520 x_color_lookup_dark (SELECT_COLOR)); 00521 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1); 00522 } 00523 00532 void o_box_draw_grips(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current) 00533 { 00534 if (w_current->draw_grips == FALSE) 00535 return; 00536 00537 /* grip on upper left corner (whichone = BOX_UPPER_LEFT) */ 00538 o_grips_draw (w_current, o_current->box->upper_x, o_current->box->upper_y); 00539 00540 /* grip on upper right corner (whichone = BOX_UPPER_RIGHT) */ 00541 o_grips_draw (w_current, o_current->box->lower_x, o_current->box->upper_y); 00542 00543 /* grip on lower left corner (whichone = BOX_LOWER_LEFT) */ 00544 o_grips_draw (w_current, o_current->box->upper_x, o_current->box->lower_y); 00545 00546 /* grip on lower right corner (whichone = BOX_LOWER_RIGHT) */ 00547 o_grips_draw (w_current, o_current->box->lower_x, o_current->box->lower_y); 00548 }