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 <stdio.h> 00022 #include <math.h> 00023 00024 #include "gschem.h" 00025 00026 #ifdef HAVE_LIBDMALLOC 00027 #include <dmalloc.h> 00028 #endif 00029 00030 00031 typedef void (*FILL_FUNC) (GSCHEM_TOPLEVEL *w_current, 00032 COLOR *color, CIRCLE *circle, 00033 gint fill_width, gint angle1, gint pitch1, 00034 gint angle2, gint pitch2); 00035 00036 00055 static void 00056 o_circle_fill_hollow (GSCHEM_TOPLEVEL *w_current, 00057 COLOR *color, CIRCLE *circle, 00058 gint fill_width, 00059 gint angle1, gint pitch1, 00060 gint angle2, gint pitch2) 00061 { 00062 } 00063 00087 static void 00088 o_circle_fill_fill (GSCHEM_TOPLEVEL *w_current, 00089 COLOR *color, CIRCLE *circle, 00090 gint fill_width, 00091 gint angle1, gint pitch1, 00092 gint angle2, gint pitch2) 00093 { 00094 /* NOP: We'll fill it when we do the stroking */ 00095 } 00096 00127 static void 00128 o_circle_fill_hatch (GSCHEM_TOPLEVEL *w_current, 00129 COLOR *color, CIRCLE *circle, 00130 gint fill_width, 00131 gint angle1, gint pitch1, 00132 gint angle2, gint pitch2) 00133 { 00134 int i; 00135 GArray *lines; 00136 00137 gschem_cairo_set_source_color (w_current, color); 00138 00139 lines = g_array_new (FALSE, FALSE, sizeof (LINE)); 00140 m_hatch_circle (circle, angle1, pitch1, lines); 00141 00142 for (i=0; i < lines->len; i++) { 00143 LINE *line = &g_array_index (lines, LINE, i); 00144 00145 gschem_cairo_line (w_current, END_NONE, fill_width, line->x[0], line->y[0], 00146 line->x[1], line->y[1]); 00147 } 00148 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, fill_width, -1, -1); 00149 00150 g_array_free (lines, TRUE); 00151 } 00152 00180 static void 00181 o_circle_fill_mesh (GSCHEM_TOPLEVEL *w_current, 00182 COLOR *color, CIRCLE *circle, 00183 gint fill_width, 00184 gint angle1, gint pitch1, 00185 gint angle2, gint pitch2) 00186 { 00187 o_circle_fill_hatch (w_current, color, circle, 00188 fill_width, angle1, pitch1, -1, -1); 00189 o_circle_fill_hatch (w_current, color, circle, 00190 fill_width, angle2, pitch2, -1, -1); 00191 00192 } 00193 00194 00208 void o_circle_draw(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current) 00209 { 00210 int angle1, pitch1, angle2, pitch2; 00211 FILL_FUNC fill_func; 00212 00213 if (o_current->circle == NULL) { 00214 return; 00215 } 00216 00217 /* 00218 * The draw of the circle is divided in two steps : first step is to draw 00219 * the outline, the second is to draw the filling pattern inside (if any). 00220 * 00221 * Finally the function takes care of the grips. 00222 */ 00223 00224 /* 00225 * The values needed for the fill operation are taken from the 00226 * <B>o_current</B> pointed OBJECT. It include the type of fill required, the 00227 * width of the lines (if the fill use line) and angles and pitchs for hatch 00228 * based filling. 00229 * 00230 * Once again the width of the line is important as if it is equal to 0 it 00231 * may not be displayed. That is definetely not what we are looking for. 00232 * 00233 * Depending on the type of fill that has to be used inside the circle the 00234 * right function is called. Values of <B>angle1</B>, <B>angle2</B>, 00235 * <B>pitch1</B> and <B>pitch2</B> are adapted to the type of filling. The 00236 * possible functions are the following : #o_circle_fill_hollow(), 00237 * #o_circle_fill_fill(), #o_circle_fill_mesh() and #o_circle_fill_hatch(). 00238 * 00239 * The combination <B>pitch1</B> <= 0 and <B>pitch2</B> <= 0 is avoided as it 00240 * lead to an endless loop in function called after. It happens when the 00241 * zoom factor is too small for two lines separated by the pitch to be 00242 * distinct. If such a case is encountered the circle is filled hollow 00243 * (e.q. not filled). 00244 */ 00245 00246 angle1 = o_current->fill_angle1; 00247 pitch1 = o_current->fill_pitch1; 00248 angle2 = o_current->fill_angle2; 00249 pitch2 = o_current->fill_pitch2; 00250 00251 switch(o_current->fill_type) { 00252 case FILLING_HOLLOW: 00253 angle1 = -1; angle2 = -1; 00254 pitch1 = 1; pitch2 = 1; 00255 /* 00256 * this function is empty ! however if it do not use it we have to add 00257 * a test before the call. Simply putting a return here instead is not 00258 * possible as it would prevent any hollow circle from having its grips 00259 */ 00260 fill_func = o_circle_fill_hollow; 00261 break; 00262 00263 case FILLING_FILL: 00264 angle1 = -1; angle2 = -1; 00265 pitch1 = 1; pitch2 = 1; 00266 fill_func = o_circle_fill_fill; 00267 break; 00268 00269 case FILLING_MESH: 00270 fill_func = o_circle_fill_mesh; 00271 break; 00272 00273 case FILLING_HATCH: 00274 angle2 = -1; 00275 pitch2 = 1; 00276 fill_func = o_circle_fill_hatch; 00277 break; 00278 00279 case FILLING_VOID: 00280 default: 00281 angle1 = -1; angle2 = -1; 00282 pitch1 = 1; pitch2 = 1; 00283 fill_func = o_circle_fill_hollow; 00284 fprintf (stderr, _("Unknown type for circle (fill)!\n")); 00285 } 00286 00287 if ((pitch1 <= 0) || (pitch2 <= 0)) 00288 fill_func = o_circle_fill_fill; 00289 00290 (*fill_func) (w_current, o_drawing_color (w_current, o_current), 00291 o_current->circle, o_current->fill_width, 00292 angle1, pitch1, angle2, pitch2); 00293 00294 gschem_cairo_arc (w_current, o_current->line_width, 00295 o_current->circle->center_x, 00296 o_current->circle->center_y, 00297 o_current->circle->radius, 0, 360); 00298 00299 gschem_cairo_set_source_color (w_current, 00300 o_drawing_color (w_current, o_current)); 00301 if (o_current->fill_type == FILLING_FILL) 00302 cairo_fill_preserve (w_current->cr); 00303 gschem_cairo_stroke (w_current, o_current->line_type, 00304 o_current->line_end, 00305 o_current->line_width, 00306 o_current->line_length, 00307 o_current->line_space); 00308 00309 if (o_current->selected && w_current->draw_grips) 00310 o_circle_draw_grips (w_current, o_current); 00311 } 00312 00313 00319 void o_circle_invalidate_rubber (GSCHEM_TOPLEVEL *w_current) 00320 { 00321 int cx, cy, radius; 00322 00323 WORLDtoSCREEN (w_current, w_current->first_wx, w_current->first_wy, &cx, &cy); 00324 radius = SCREENabs (w_current, w_current->distance); 00325 00326 o_invalidate_rect (w_current, cx - radius, cy - radius, 00327 cx + radius, cy + radius); 00328 } 00329 00346 void o_circle_draw_place (GSCHEM_TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current) 00347 { 00348 g_return_if_fail (o_current->circle != NULL); 00349 00350 gschem_cairo_arc (w_current, 0, o_current->circle->center_x + dx, 00351 o_current->circle->center_y + dy, 00352 o_current->circle->radius, 0, 360); 00353 00354 gschem_cairo_set_source_color (w_current, 00355 x_color_lookup_dark (o_current->color)); 00356 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1); 00357 } 00358 00374 void o_circle_start(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y) 00375 { 00376 /* center of circle */ 00377 w_current->first_wx = w_x; 00378 w_current->first_wy = w_y; 00379 00380 /* radius */ 00381 w_current->distance = 0; 00382 00383 /* first temporary circle */ 00384 o_circle_invalidate_rubber (w_current); 00385 w_current->rubber_visible = 1; 00386 } 00387 00407 void o_circle_end(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y) 00408 { 00409 TOPLEVEL *toplevel = w_current->toplevel; 00410 OBJECT *new_obj; 00411 00412 g_assert( w_current->inside_action != 0 ); 00413 00414 /* erase the temporary circle */ 00415 /* o_circle_invalidate_rubber (w_current); */ 00416 w_current->rubber_visible = 0; 00417 00418 /* circle with null radius are not allowed */ 00419 if (w_current->distance == 0) { 00420 /* cancel the object creation */ 00421 return; 00422 } 00423 00424 /* create the object */ 00425 new_obj = o_circle_new (toplevel, OBJ_CIRCLE, GRAPHIC_COLOR, 00426 w_current->first_wx, w_current->first_wy, 00427 w_current->distance); 00428 s_page_append (toplevel, toplevel->page_current, new_obj); 00429 00430 /* Call add-objects-hook */ 00431 g_run_hook_object (w_current, "%add-objects-hook", new_obj); 00432 00433 toplevel->page_current->CHANGED = 1; 00434 o_undo_savestate(w_current, UNDO_ALL); 00435 } 00436 00459 void o_circle_motion (GSCHEM_TOPLEVEL *w_current, int w_x, int w_y) 00460 { 00461 int diff_x, diff_y; 00462 00463 g_assert( w_current->inside_action != 0 ); 00464 00465 /* erase the previous temporary circle if it is visible */ 00466 if (w_current->rubber_visible) 00467 o_circle_invalidate_rubber (w_current); 00468 00469 /* 00470 * The radius is taken as the biggest distance on the x and y axis between 00471 * the center of the circle and the mouse position. 00472 */ 00473 diff_x = abs(w_current->first_wx - w_x); 00474 diff_y = abs(w_current->first_wy - w_y); 00475 w_current->distance = max(diff_x, diff_y); 00476 00477 /* draw the new temporary circle */ 00478 o_circle_invalidate_rubber (w_current); 00479 w_current->rubber_visible =1; 00480 } 00481 00494 void o_circle_draw_rubber (GSCHEM_TOPLEVEL *w_current) 00495 { 00496 gschem_cairo_arc (w_current, 0, w_current->first_wx, 00497 w_current->first_wy, 00498 w_current->distance, 0, 360); 00499 00500 gschem_cairo_line (w_current, END_NONE, 0, 00501 w_current->first_wx, 00502 w_current->first_wy, 00503 w_current->first_wx + w_current->distance, 00504 w_current->first_wy); 00505 00506 gschem_cairo_set_source_color (w_current, 00507 x_color_lookup_dark (SELECT_COLOR)); 00508 gschem_cairo_stroke (w_current, TYPE_SOLID, END_NONE, 0, -1, -1); 00509 } 00510 00518 void o_circle_draw_grips(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current) 00519 { 00520 if (w_current->draw_grips == FALSE) 00521 return; 00522 00523 /* grip on lower right corner of the square */ 00524 o_grips_draw (w_current, 00525 o_current->circle->center_x + o_current->circle->radius, 00526 o_current->circle->center_y - o_current->circle->radius); 00527 }