libgeda
|
00001 /* gEDA - GPL Electronic Design Automation 00002 * libgeda - gEDA's library 00003 * Copyright (C) 1998-2010 Ales Hvezda 00004 * Copyright (C) 1998-2010 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 00027 #include <config.h> 00028 00029 #include <stdio.h> 00030 #include <math.h> 00031 #ifdef HAVE_STRING_H 00032 #include <string.h> 00033 #endif 00034 #ifdef HAVE_UNISTD_H 00035 #include <unistd.h> 00036 #endif 00037 00038 #include "libgeda_priv.h" 00039 00040 #ifdef HAVE_LIBDMALLOC 00041 #include <dmalloc.h> 00042 #endif 00043 00044 00057 int world_get_single_object_bounds(TOPLEVEL *toplevel, OBJECT *o_current, 00058 int *rleft, int *rtop, int *rright, int *rbottom) 00059 { 00060 if (o_current != NULL) { 00061 switch(o_current->type) { 00062 case(OBJ_TEXT): 00063 /* only do bounding boxes for visible or doing show_hidden_text*/ 00064 /* you might lose some attrs though */ 00065 if (! (o_is_visible (toplevel, o_current) || 00066 toplevel->show_hidden_text)) { 00067 return 0; 00068 } 00069 /* This case falls through intentionally */ 00070 case(OBJ_LINE): 00071 case(OBJ_NET): 00072 case(OBJ_BUS): 00073 case(OBJ_BOX): 00074 case(OBJ_PICTURE): 00075 case(OBJ_CIRCLE): 00076 case(OBJ_PATH): 00077 case(OBJ_PIN): 00078 case(OBJ_ARC): 00079 case(OBJ_COMPLEX): 00080 case(OBJ_PLACEHOLDER): 00081 if (!o_current->w_bounds_valid) { 00082 o_recalc_single_object (toplevel, o_current); 00083 if (!o_current->w_bounds_valid) { 00084 return 0; 00085 } 00086 } 00087 *rleft = o_current->w_left; 00088 *rtop = o_current->w_top; 00089 *rright = o_current->w_right; 00090 *rbottom = o_current->w_bottom; 00091 return 1; 00092 00093 default: 00094 break; 00095 } 00096 } 00097 return 0; 00098 } 00099 00100 00113 int world_get_object_glist_bounds(TOPLEVEL *toplevel, const GList *head, 00114 int *left, int *top, int *right, int *bottom) 00115 { 00116 const GList *s_current=NULL; 00117 OBJECT *o_current=NULL; 00118 int rleft, rtop, rright, rbottom; 00119 int found = 0; 00120 00121 s_current = head; 00122 00123 /* Find the first object with bounds, and set the bounds variables, then expand as necessary */ 00124 while ( s_current != NULL ) { 00125 o_current = (OBJECT *) s_current->data; 00126 00127 /* Sanity check */ 00128 g_return_val_if_fail ((o_current != NULL), found); 00129 00130 if ( world_get_single_object_bounds( toplevel, o_current, &rleft, &rtop, &rright, &rbottom) ) { 00131 if ( found ) { 00132 *left = min( *left, rleft ); 00133 *top = min( *top, rtop ); 00134 *right = max( *right, rright ); 00135 *bottom = max( *bottom, rbottom ); 00136 } else { 00137 *left = rleft; 00138 *top = rtop; 00139 *right = rright; 00140 *bottom = rbottom; 00141 found = 1; 00142 } 00143 } 00144 s_current = g_list_next (s_current); 00145 } 00146 return found; 00147 } 00148 00165 void world_get_complex_bounds(TOPLEVEL *toplevel, OBJECT *complex, 00166 int *left, int *top, int *right, int *bottom) 00167 { 00168 g_return_if_fail (complex != NULL && 00169 (complex->type == OBJ_COMPLEX || 00170 complex->type == OBJ_PLACEHOLDER) && 00171 complex->complex != NULL); 00172 00173 world_get_object_glist_bounds (toplevel, complex->complex->prim_objs, 00174 left, top, right, bottom); 00175 } 00176 00187 gboolean o_complex_get_position (TOPLEVEL *toplevel, gint *x, gint *y, 00188 OBJECT *object) 00189 { 00190 *x = object->complex->x; 00191 *y = object->complex->y; 00192 return TRUE; 00193 } 00194 00205 static int o_complex_is_eligible_attribute (TOPLEVEL *toplevel, OBJECT *object) 00206 { 00207 char *name = NULL; 00208 int promotableAttribute = FALSE; 00209 00210 /* always promote symversion= attribute, even if it is invisible */ 00211 if (strncmp(object->text->string, "symversion=", 11) == 0) 00212 return TRUE; 00213 00214 /* check list against attributes which can be promoted */ 00215 if (toplevel->always_promote_attributes != NULL) { 00216 if (o_attrib_get_name_value (object, &name, NULL)) { 00217 if (g_list_find_custom(toplevel->always_promote_attributes, 00218 name, (GCompareFunc) strcmp) != NULL) { 00219 /* Name of the attribute was in the always promote attributes list */ 00220 promotableAttribute = TRUE; 00221 } 00222 00223 g_free(name); 00224 if (promotableAttribute) 00225 return TRUE; 00226 } 00227 } 00228 00229 /* object is invisible and we do not want to promote invisible text */ 00230 if ((!o_is_visible (toplevel, object)) && 00231 (toplevel->promote_invisible == FALSE)) 00232 return FALSE; /* attribute not eligible for promotion */ 00233 00234 /* yup, attribute can be promoted */ 00235 return TRUE; 00236 } 00237 00245 int o_complex_is_embedded(OBJECT *o_current) 00246 { 00247 g_return_val_if_fail(o_current != NULL, 0); 00248 00249 if(o_current->complex == NULL) 00250 return 0; 00251 00252 if (o_current->complex_embedded) { 00253 return 1; 00254 } else { 00255 return 0; 00256 } 00257 } 00258 00259 00275 GList *o_complex_get_promotable (TOPLEVEL *toplevel, OBJECT *object, int detach) 00276 { 00277 GList *promoted = NULL; 00278 GList *attribs; 00279 GList *iter; 00280 OBJECT *tmp; 00281 00282 if (!toplevel->attribute_promotion) /* controlled through rc file */ 00283 return NULL; 00284 00285 attribs = o_attrib_find_floating_attribs (object->complex->prim_objs); 00286 00287 for (iter = attribs; iter != NULL; iter = g_list_next (iter)) { 00288 tmp = iter->data; 00289 00290 /* Is it an attribute we want to promote? */ 00291 if (!o_complex_is_eligible_attribute(toplevel, tmp)) 00292 continue; 00293 00294 if (detach) { 00295 tmp->parent = NULL; 00296 object->complex->prim_objs = 00297 g_list_remove (object->complex->prim_objs, tmp); 00298 } 00299 00300 promoted = g_list_prepend (promoted, tmp); 00301 } 00302 00303 g_list_free (attribs); 00304 00305 promoted = g_list_reverse (promoted); 00306 return promoted; 00307 } 00308 00309 00319 GList *o_complex_promote_attribs (TOPLEVEL *toplevel, OBJECT *object) 00320 { 00321 GList *promoted = NULL; 00322 GList *promotable = NULL; 00323 GList *iter = NULL; 00324 00325 promotable = o_complex_get_promotable (toplevel, object, FALSE); 00326 00327 /* Run through the attributes deciding if we want to keep them (in 00328 * which case we copy them and make them invisible) or if we want to 00329 * remove them. */ 00330 if (toplevel->keep_invisible) { 00331 for (iter = promotable; iter != NULL; iter = g_list_next (iter)) { 00332 OBJECT *o_kept = (OBJECT *) iter->data; 00333 OBJECT *o_copy = o_object_copy (toplevel, o_kept); 00334 o_set_visibility (toplevel, o_kept, INVISIBLE); 00335 o_copy->parent = NULL; 00336 promoted = g_list_prepend (promoted, o_copy); 00337 } 00338 promoted = g_list_reverse (promoted); 00339 } else { 00340 for (iter = promotable; iter != NULL; iter = g_list_next (iter)) { 00341 OBJECT *o_removed = (OBJECT *) iter->data; 00342 o_removed->parent = NULL; 00343 object->complex->prim_objs = 00344 g_list_remove (object->complex->prim_objs, o_removed); 00345 } 00346 promoted = promotable; 00347 /* Invalidate the object's bounds since we may have 00348 * stolen objects from inside it. */ 00349 o_bounds_invalidate (toplevel, object); 00350 } 00351 00352 /* Attach promoted attributes to the original complex object */ 00353 o_attrib_attach_list (toplevel, promoted, object, TRUE); 00354 00355 return promoted; 00356 } 00357 00358 00374 static void o_complex_remove_promotable_attribs (TOPLEVEL *toplevel, OBJECT *object) 00375 { 00376 GList *promotable, *iter; 00377 00378 promotable = o_complex_get_promotable (toplevel, object, FALSE); 00379 00380 if (promotable == NULL) 00381 return; 00382 00383 for (iter = promotable; iter != NULL; iter = g_list_next (iter)) { 00384 OBJECT *a_object = iter->data; 00385 if (toplevel->keep_invisible == TRUE) { /* Hide promotable attributes */ 00386 o_set_visibility (toplevel, a_object, INVISIBLE); 00387 } else { /* Delete promotable attributes */ 00388 object->complex->prim_objs = 00389 g_list_remove (object->complex->prim_objs, a_object); 00390 s_delete_object (toplevel, a_object); 00391 } 00392 } 00393 00394 o_bounds_invalidate (toplevel, object); 00395 g_list_free (promotable); 00396 } 00397 00398 static void create_placeholder(TOPLEVEL * toplevel, OBJECT * new_node, int x, int y) 00399 { 00400 OBJECT *new_prim_obj; 00401 char *not_found_text = NULL; 00402 int left, right, top, bottom; 00403 int x_offset, y_offset; 00404 00405 /* Put placeholder into object list. Changed by SDB on 00406 * 1.19.2005 to fix problem that symbols were silently 00407 * deleted by gattrib when RC files were messed up. */ 00408 new_node->type = OBJ_PLACEHOLDER; 00409 00410 /* Mark the origin of the missing component */ 00411 new_prim_obj = o_line_new(toplevel, OBJ_LINE, 00412 DETACHED_ATTRIBUTE_COLOR, 00413 x - 50, y, x + 50, y); 00414 new_node->complex->prim_objs = g_list_prepend (new_node->complex->prim_objs, new_prim_obj); 00415 new_prim_obj = o_line_new(toplevel, OBJ_LINE, 00416 DETACHED_ATTRIBUTE_COLOR, 00417 x, y + 50, x, y - 50); 00418 new_node->complex->prim_objs = g_list_prepend (new_node->complex->prim_objs, new_prim_obj); 00419 00420 /* Add some useful text */ 00421 not_found_text = 00422 g_strdup_printf (_("Component not found:\n %s"), 00423 new_node->complex_basename); 00424 new_prim_obj = o_text_new(toplevel, 00425 OBJ_TEXT, DETACHED_ATTRIBUTE_COLOR, 00426 x + NOT_FOUND_TEXT_X, 00427 y + NOT_FOUND_TEXT_Y, LOWER_LEFT, 0, 00428 not_found_text, 8, 00429 VISIBLE, SHOW_NAME_VALUE); 00430 new_node->complex->prim_objs = g_list_prepend (new_node->complex->prim_objs, new_prim_obj); 00431 g_free(not_found_text); 00432 00433 /* figure out where to put the hazard triangle */ 00434 world_get_text_bounds (toplevel, new_prim_obj, &left, &top, &right, &bottom); 00435 x_offset = (right - left) / 4; 00436 y_offset = bottom - top + 100; /* 100 is just an additional offset */ 00437 00438 /* add hazard triangle */ 00439 new_prim_obj = o_line_new(toplevel, OBJ_LINE, 00440 DETACHED_ATTRIBUTE_COLOR, 00441 x + NOT_FOUND_TEXT_X + x_offset, 00442 y + NOT_FOUND_TEXT_Y + y_offset, 00443 x + NOT_FOUND_TEXT_X + x_offset + 600, 00444 y + NOT_FOUND_TEXT_Y + y_offset); 00445 o_set_line_options(toplevel, new_prim_obj, END_ROUND, TYPE_SOLID, 00446 50, -1, -1); 00447 new_node->complex->prim_objs = g_list_prepend (new_node->complex->prim_objs, new_prim_obj); 00448 new_prim_obj = o_line_new(toplevel, OBJ_LINE, 00449 DETACHED_ATTRIBUTE_COLOR, 00450 x + NOT_FOUND_TEXT_X + x_offset, 00451 y + NOT_FOUND_TEXT_Y + y_offset, 00452 x + NOT_FOUND_TEXT_X + x_offset + 300, 00453 y + NOT_FOUND_TEXT_Y + y_offset + 500); 00454 o_set_line_options(toplevel, new_prim_obj, END_ROUND, TYPE_SOLID, 00455 50, -1, -1); 00456 new_node->complex->prim_objs = g_list_prepend (new_node->complex->prim_objs, new_prim_obj); 00457 new_prim_obj = o_line_new(toplevel, OBJ_LINE, 00458 DETACHED_ATTRIBUTE_COLOR, 00459 x + NOT_FOUND_TEXT_X + x_offset + 300, 00460 y + NOT_FOUND_TEXT_Y + y_offset + 500, 00461 x + NOT_FOUND_TEXT_X + x_offset + 600, 00462 y + NOT_FOUND_TEXT_Y + y_offset); 00463 o_set_line_options(toplevel, new_prim_obj, END_ROUND, TYPE_SOLID, 00464 50, -1, -1); 00465 new_node->complex->prim_objs = g_list_prepend (new_node->complex->prim_objs, new_prim_obj); 00466 new_prim_obj = o_text_new(toplevel, 00467 OBJ_TEXT, DETACHED_ATTRIBUTE_COLOR, 00468 x + NOT_FOUND_TEXT_X + x_offset + 270, 00469 y + NOT_FOUND_TEXT_Y + y_offset + 90, 00470 LOWER_LEFT, 0, "!", 18, 00471 VISIBLE, SHOW_NAME_VALUE); 00472 new_node->complex->prim_objs = g_list_prepend (new_node->complex->prim_objs, new_prim_obj); 00473 new_node->complex->prim_objs = g_list_reverse(new_node->complex->prim_objs); 00474 } 00475 00476 /* Done */ 00481 OBJECT *o_complex_new(TOPLEVEL *toplevel, 00482 char type, 00483 int color, int x, int y, int angle, 00484 int mirror, const CLibSymbol *clib, 00485 const gchar *basename, 00486 int selectable) 00487 { 00488 OBJECT *new_node=NULL; 00489 GList *iter; 00490 gchar *buffer = NULL; 00491 00492 new_node = s_basic_new_object(type, "complex"); 00493 00494 if (clib != NULL) { 00495 new_node->complex_basename = g_strdup (s_clib_symbol_get_name (clib)); 00496 } else { 00497 new_node->complex_basename = g_strdup (basename); 00498 } 00499 00500 00501 new_node->complex_embedded = FALSE; 00502 new_node->color = color; 00503 new_node->selectable = selectable; 00504 00505 new_node->complex = (COMPLEX *) g_malloc(sizeof(COMPLEX)); 00506 new_node->complex->prim_objs = NULL; 00507 new_node->complex->angle = angle; 00508 new_node->complex->mirror = mirror; 00509 new_node->complex->x = x; 00510 new_node->complex->y = y; 00511 00512 /* get the symbol data */ 00513 if (clib != NULL) { 00514 buffer = s_clib_symbol_get_data (clib); 00515 } 00516 00517 if (clib == NULL || buffer == NULL) 00518 create_placeholder(toplevel, new_node, x, y); 00519 else { 00520 GError * err = NULL; 00521 00522 /* add connections till translated */ 00523 new_node->complex->prim_objs = o_read_buffer (toplevel, NULL, buffer, -1, new_node->complex_basename, &err); 00524 if (err) { 00525 g_error_free(err); 00526 /* If reading fails, replace with placeholder object */ 00527 create_placeholder(toplevel, new_node, x, y); 00528 } 00529 else { 00530 if (mirror) { 00531 o_glist_mirror_world (toplevel, 0, 0, new_node->complex->prim_objs); 00532 } 00533 00534 o_glist_rotate_world (toplevel, 0, 0, angle, new_node->complex->prim_objs); 00535 o_glist_translate_world (toplevel, x, y, new_node->complex->prim_objs); 00536 } 00537 00538 g_free (buffer); 00539 00540 } 00541 00542 /* set the parent field now */ 00543 for (iter = new_node->complex->prim_objs; iter != NULL; iter = g_list_next (iter)) { 00544 OBJECT *tmp = iter->data; 00545 tmp->parent = new_node; 00546 } 00547 00548 o_complex_recalc(toplevel, new_node); 00549 00550 return new_node; 00551 } 00552 00568 OBJECT *o_complex_new_embedded(TOPLEVEL *toplevel, 00569 char type, int color, int x, int y, int angle, int mirror, 00570 const gchar *basename, int selectable) 00571 { 00572 OBJECT *new_node=NULL; 00573 00574 new_node = s_basic_new_object(type, "complex"); 00575 00576 new_node->complex = (COMPLEX *) g_malloc(sizeof(COMPLEX)); 00577 new_node->complex->x = x; 00578 new_node->complex->y = y; 00579 00580 new_node->complex->angle = angle; 00581 new_node->complex->mirror = mirror; 00582 00583 new_node->complex_basename = g_strdup(basename); 00584 00585 new_node->complex_embedded = TRUE; 00586 00587 new_node->color = color; 00588 new_node->selectable = selectable; 00589 00590 new_node->complex->prim_objs = NULL; 00591 00592 /* don't have to translate/rotate/mirror here at all since the */ 00593 /* object is in place */ 00594 return new_node; 00595 } 00596 00604 void o_complex_recalc(TOPLEVEL *toplevel, OBJECT *o_current) 00605 { 00606 int left, right, top, bottom; 00607 00608 /* realc routine Add this somewhere */ 00609 /* libhack */ 00610 /* o_recalc(toplevel, o_current->complex);*/ 00611 00612 if ((!o_current) || (o_current->type != OBJ_COMPLEX && o_current->type != OBJ_PLACEHOLDER)) 00613 return; 00614 00615 if (o_current->complex->prim_objs == NULL) 00616 return; 00617 00618 world_get_complex_bounds(toplevel, o_current, &left, &top, &right, &bottom); 00619 o_current->w_left = left; 00620 o_current->w_top = top; 00621 o_current->w_right = right; 00622 o_current->w_bottom = bottom; 00623 o_current->w_bounds_valid = TRUE; 00624 } 00625 00638 OBJECT *o_complex_read (TOPLEVEL *toplevel, 00639 const char buf[], unsigned int release_ver, 00640 unsigned int fileformat_ver, GError **err) 00641 { 00642 OBJECT *new_obj; 00643 char type; 00644 int x1, y1; 00645 int angle; 00646 00647 char *basename = g_malloc (1 + strlen (buf)); 00648 00649 int selectable; 00650 int mirror; 00651 00652 if (sscanf(buf, "%c %d %d %d %d %d %s\n", 00653 &type, &x1, &y1, &selectable, &angle, &mirror, basename) != 7) { 00654 g_set_error(err, EDA_ERROR, EDA_ERROR_PARSE, _("Failed to parse complex object")); 00655 return NULL; 00656 } 00657 00658 switch(angle) { 00659 00660 case(0): 00661 case(90): 00662 case(180): 00663 case(270): 00664 break; 00665 00666 default: 00667 s_log_message(_("Found a component with an invalid rotation [ %c %d %d %d %d %d %s ]\n"), type, x1, y1, selectable, angle, mirror, basename); 00668 s_log_message (_("Setting angle to 0\n")); 00669 angle = 0; 00670 } 00671 00672 switch(mirror) { 00673 00674 case(0): 00675 case(1): 00676 00677 break; 00678 00679 default: 00680 s_log_message(_("Found a component with an invalid mirror flag [ %c %d %d %d %d %d %s ]\n"), type, x1, y1, selectable, angle, mirror, basename); 00681 s_log_message (_("Setting mirror to 0\n")); 00682 mirror = 0; 00683 } 00684 if (strncmp(basename, "EMBEDDED", 8) == 0) { 00685 00686 new_obj = o_complex_new_embedded(toplevel, type, 00687 DEFAULT_COLOR, x1, y1, angle, mirror, 00688 basename + 8, 00689 selectable); 00690 } else { 00691 00692 const CLibSymbol *clib = s_clib_get_symbol_by_name (basename); 00693 00694 new_obj = o_complex_new(toplevel, type, 00695 DEFAULT_COLOR, 00696 x1, y1, 00697 angle, mirror, clib, 00698 basename, selectable); 00699 /* Delete or hide attributes eligible for promotion inside the complex */ 00700 if (new_obj) 00701 o_complex_remove_promotable_attribs (toplevel, new_obj); 00702 } 00703 00704 g_free (basename); 00705 00706 return new_obj; 00707 } 00708 00718 char *o_complex_save(TOPLEVEL *toplevel, OBJECT *object) 00719 { 00720 int selectable; 00721 char *buf = NULL; 00722 char *basename; 00723 00724 g_return_val_if_fail (object != NULL, NULL); 00725 00726 selectable = (object->selectable) ? 1 : 0; 00727 00728 if ((object->type == OBJ_COMPLEX) || (object->type == OBJ_PLACEHOLDER)) { 00729 basename = g_strdup_printf ("%s%s", 00730 object->complex_embedded ? "EMBEDDED" : "", 00731 object->complex_basename); 00732 /* We force the object type to be output as OBJ_COMPLEX for both 00733 * these object types. */ 00734 buf = g_strdup_printf("%c %d %d %d %d %d %s", OBJ_COMPLEX, 00735 object->complex->x, object->complex->y, 00736 selectable, object->complex->angle, 00737 object->complex->mirror, basename); 00738 g_free (basename); 00739 } 00740 00741 return(buf); 00742 } 00743 00753 void o_complex_translate_world(TOPLEVEL *toplevel, int dx, int dy, 00754 OBJECT *object) 00755 { 00756 g_return_if_fail (object != NULL && 00757 (object->type == OBJ_COMPLEX || 00758 object->type == OBJ_PLACEHOLDER)); 00759 00760 object->complex->x = object->complex->x + dx; 00761 object->complex->y = object->complex->y + dy; 00762 00763 o_glist_translate_world (toplevel, dx, dy, object->complex->prim_objs); 00764 00765 o_complex_recalc (toplevel, object); 00766 } 00767 00776 OBJECT *o_complex_copy(TOPLEVEL *toplevel, OBJECT *o_current) 00777 { 00778 OBJECT *o_new; 00779 GList *iter; 00780 00781 g_return_val_if_fail(o_current != NULL, NULL); 00782 00783 o_new = s_basic_new_object(o_current->type, "complex"); 00784 o_new->color = o_current->color; 00785 o_new->selectable = o_current->selectable; 00786 o_new->complex_basename = g_strdup(o_current->complex_basename); 00787 o_new->complex_embedded = o_current->complex_embedded; 00788 00789 o_new->complex = g_malloc0(sizeof(COMPLEX)); 00790 o_new->complex->x = o_current->complex->x; 00791 o_new->complex->y = o_current->complex->y; 00792 o_new->complex->angle = o_current->complex->angle; 00793 o_new->complex->mirror = o_current->complex->mirror; 00794 00795 /* Copy contents and set the parent pointers on the copied objects. */ 00796 o_new->complex->prim_objs = 00797 o_glist_copy_all (toplevel, o_current->complex->prim_objs, 00798 NULL); 00799 00800 for (iter = o_new->complex->prim_objs; 00801 iter != NULL; 00802 iter = g_list_next (iter)) { 00803 ((OBJECT*) iter->data)->parent = o_new; 00804 } 00805 00806 /* Recalculate bounds */ 00807 o_complex_recalc(toplevel, o_new); 00808 00809 /* Delete or hide attributes eligible for promotion inside the complex */ 00810 o_complex_remove_promotable_attribs (toplevel, o_new); 00811 00812 s_slot_update_object (toplevel, o_new); 00813 00814 /* deal with stuff that has changed */ 00815 00816 /* here you need to create a list of attributes which need to be 00817 * connected to the new list, probably make an attribute list and 00818 * fill it with sid's of the attributes */ 00819 00820 return o_new; 00821 } 00822 00823 00829 void o_complex_rotate_world(TOPLEVEL *toplevel, 00830 int centerx, int centery, 00831 int angle, OBJECT *object) 00832 { 00833 int x, y; 00834 int newx, newy; 00835 00836 g_return_if_fail (object!=NULL); 00837 g_return_if_fail ((object->type == OBJ_COMPLEX) || 00838 (object->type == OBJ_PLACEHOLDER)); 00839 00840 x = object->complex->x + (-centerx); 00841 y = object->complex->y + (-centery); 00842 00843 rotate_point_90(x, y, angle, &newx, &newy); 00844 00845 x = newx + (centerx); 00846 y = newy + (centery); 00847 00848 o_complex_translate_world(toplevel, 00849 -object->complex->x, 00850 -object->complex->y, object); 00851 o_glist_rotate_world (toplevel, 0, 0, angle, object->complex->prim_objs); 00852 00853 object->complex->x = 0; 00854 object->complex->y = 0; 00855 00856 o_complex_translate_world(toplevel, x, y, object); 00857 00858 object->complex->angle = ( object->complex->angle + angle ) % 360; 00859 } 00860 00861 00867 void o_complex_mirror_world(TOPLEVEL *toplevel, 00868 int world_centerx, int world_centery, 00869 OBJECT *object) 00870 { 00871 int x, y; 00872 00873 g_return_if_fail( object != NULL ); 00874 g_return_if_fail( (object->type == OBJ_COMPLEX || 00875 object->type == OBJ_PLACEHOLDER) ); 00876 g_return_if_fail( object->complex != NULL ); 00877 00878 x = 2 * world_centerx - object->complex->x; 00879 y = object->complex->y; 00880 00881 o_complex_translate_world(toplevel, 00882 -object->complex->x, 00883 -object->complex->y, object); 00884 00885 o_glist_mirror_world (toplevel, 0, 0, object->complex->prim_objs); 00886 00887 switch(object->complex->angle) { 00888 case(90): 00889 object->complex->angle = 270; 00890 break; 00891 00892 case(270): 00893 object->complex->angle = 90; 00894 break; 00895 00896 } 00897 00898 object->complex->mirror = !object->complex->mirror; 00899 00900 o_complex_translate_world(toplevel, x, y, object); 00901 } 00902 00903 00914 OBJECT *o_complex_find_pin_by_attribute (OBJECT *object, char *name, char *wanted_value) 00915 { 00916 GList *iter; 00917 OBJECT *o_current; 00918 char *value; 00919 int found; 00920 00921 g_return_val_if_fail (object != NULL, NULL); 00922 g_return_val_if_fail (object->type == OBJ_COMPLEX || 00923 object->type == OBJ_PLACEHOLDER, NULL); 00924 00925 for (iter = object->complex->prim_objs; iter != NULL; 00926 iter = g_list_next (iter)) { 00927 o_current = iter->data; 00928 00929 if (o_current->type != OBJ_PIN) 00930 continue; 00931 00932 value = o_attrib_search_object_attribs_by_name (o_current, name, 0); 00933 found = (value != NULL && strcmp (value, wanted_value) == 0); 00934 g_free (value); 00935 00936 if (found) 00937 return o_current; 00938 } 00939 00940 return NULL; 00941 } 00942 00943 00955 void 00956 o_complex_check_symversion(TOPLEVEL* toplevel, OBJECT* object) 00957 { 00958 char *inside = NULL; 00959 char *outside = NULL; 00960 char *refdes = NULL; 00961 double inside_value = -1.0; 00962 double outside_value = -1.0; 00963 char *err_check = NULL; 00964 int inside_present = FALSE; 00965 int outside_present = FALSE; 00966 double inside_major, inside_minor; 00967 double outside_major, outside_minor; 00968 00969 g_return_if_fail (object != NULL); 00970 g_return_if_fail ((object->type == OBJ_COMPLEX || 00971 object->type == OBJ_PLACEHOLDER)); 00972 g_return_if_fail (object->complex != NULL); 00973 00974 /* first look on the inside for the symversion= attribute */ 00975 inside = o_attrib_search_inherited_attribs_by_name (object, "symversion", 0); 00976 00977 /* now look for the symversion= attached to object */ 00978 outside = o_attrib_search_attached_attribs_by_name (object, "symversion", 0); 00979 00980 /* get the uref for future use */ 00981 refdes = o_attrib_search_object_attribs_by_name(object, "refdes", 0); 00982 if (!refdes) 00983 { 00984 refdes = g_strdup ("unknown"); 00985 } 00986 00987 if (inside) 00988 { 00989 inside_value = strtod(inside, &err_check); 00990 if (inside_value == 0 && inside == err_check) 00991 { 00992 if (inside) 00993 { 00994 s_log_message(_("WARNING: Symbol version parse error on refdes %s:\n" 00995 "\tCould not parse symbol file symversion=%s\n"), 00996 refdes, inside); 00997 } else { 00998 s_log_message(_("WARNING: Symbol version parse error on refdes %s:\n" 00999 "\tCould not parse symbol file symversion=\n"), 01000 refdes); 01001 } 01002 goto done; 01003 } 01004 inside_present = TRUE; 01005 } else { 01006 inside_present = FALSE; /* attribute not inside */ 01007 } 01008 01009 if (outside) 01010 { 01011 outside_value = strtod(outside, &err_check); 01012 if (outside_value == 0 && outside == err_check) 01013 { 01014 s_log_message(_("WARNING: Symbol version parse error on refdes %s:\n" 01015 "\tCould not parse attached symversion=%s\n"), 01016 refdes, outside); 01017 goto done; 01018 } 01019 outside_present = TRUE; 01020 } else { 01021 outside_present = FALSE; /* attribute not outside */ 01022 } 01023 01024 #if DEBUG 01025 printf("%s:\n\tinside: %.1f outside: %.1f\n\n", object->name, 01026 inside_value, outside_value); 01027 #endif 01028 01029 /* symversion= is not present anywhere */ 01030 if (!inside_present && !outside_present) 01031 { 01032 /* symbol is legacy and versioned okay */ 01033 goto done; 01034 } 01035 01036 /* No symversion inside, but a version is outside, this is a weird case */ 01037 if (!inside_present && outside_present) 01038 { 01039 s_log_message(_("WARNING: Symbol version oddity on refdes %s:\n" 01040 "\tsymversion=%s attached to instantiated symbol, " 01041 "but no symversion= inside symbol file\n"), 01042 refdes, outside); 01043 goto done; 01044 } 01045 01046 /* inside & not outside is a valid case, means symbol in library is newer */ 01047 /* also if inside_value is greater than outside_value, then symbol in */ 01048 /* library is newer */ 01049 if ((inside_present && !outside_present) || 01050 ((inside_present && outside_present) && (inside_value > outside_value))) 01051 { 01052 01053 s_log_message(_("WARNING: Symbol version mismatch on refdes %s (%s):\n" 01054 "\tSymbol in library is newer than " 01055 "instantiated symbol\n"), 01056 refdes, object->complex_basename); 01057 01058 /* break up the version values into major.minor numbers */ 01059 inside_major = floor(inside_value); 01060 inside_minor = inside_value - inside_major; 01061 01062 if (outside_present) 01063 { 01064 outside_major = floor(outside_value); 01065 outside_minor = outside_value - outside_major; 01066 } else { 01067 /* symversion was not attached to the symbol, set all to zero */ 01068 outside_major = 0.0; 01069 outside_minor = 0.0; 01070 outside_value = 0.0; 01071 } 01072 01073 #if DEBUG 01074 printf("i: %f %f %f\n", inside_value, inside_major, inside_minor); 01075 printf("o: %f %f %f\n", outside_value, outside_major, outside_minor); 01076 #endif 01077 01078 if (inside_major > outside_major) 01079 { 01080 char* refdes_copy; 01081 s_log_message(_("\tMAJOR VERSION CHANGE (file %.3f, " 01082 "instantiated %.3f, %s)!\n"), 01083 inside_value, outside_value, refdes); 01084 01085 /* add the refdes to the major_changed_refdes GList */ 01086 /* make sure refdes_copy is freed somewhere */ 01087 refdes_copy = g_strconcat (refdes, " (", 01088 object->complex_basename, 01089 ")", NULL); 01090 toplevel->major_changed_refdes = 01091 g_list_append(toplevel->major_changed_refdes, refdes_copy); 01092 01093 /* don't bother checking minor changes if there are major ones*/ 01094 goto done; 01095 } 01096 01097 if (inside_minor > outside_minor) 01098 { 01099 s_log_message(_("\tMinor version change (file %.3f, " 01100 "instantiated %.3f)\n"), 01101 inside_value, outside_value); 01102 } 01103 01104 goto done; 01105 } 01106 01107 /* outside value is greater than inside value, this is weird case */ 01108 if ((inside_present && outside_present) && (outside_value > inside_value)) 01109 { 01110 s_log_message(_("WARNING: Symbol version oddity on refdes %s:\n" 01111 "\tInstantiated symbol is newer than " 01112 "symbol in library\n"), 01113 refdes); 01114 goto done; 01115 } 01116 01117 /* if inside_value and outside_value match, then symbol versions are okay */ 01118 01119 done: 01120 g_free(inside); 01121 g_free(outside); 01122 g_free(refdes); 01123 } 01124 01141 double o_complex_shortest_distance (OBJECT *object, int x, int y, 01142 int force_solid) 01143 { 01144 double shortest_distance = G_MAXDOUBLE; 01145 double distance; 01146 int found_line_bounds = 0; 01147 BOX line_bounds; 01148 GList *iter; 01149 01150 g_return_val_if_fail (object->complex != NULL, G_MAXDOUBLE); 01151 01152 for (iter = object->complex->prim_objs; 01153 iter != NULL; iter= g_list_next (iter)) { 01154 OBJECT *obj = iter->data; 01155 01156 /* Collect the bounds of any lines and arcs in the symbol */ 01157 if ((obj->type == OBJ_LINE || obj->type == OBJ_ARC) && 01158 obj->w_bounds_valid) { 01159 01160 if (found_line_bounds) { 01161 line_bounds.lower_x = min (line_bounds.lower_x, obj->w_left); 01162 line_bounds.lower_y = min (line_bounds.lower_y, obj->w_top); 01163 line_bounds.upper_x = max (line_bounds.upper_x, obj->w_right); 01164 line_bounds.upper_y = max (line_bounds.upper_y, obj->w_bottom); 01165 } else { 01166 line_bounds.lower_x = obj->w_left; 01167 line_bounds.lower_y = obj->w_top; 01168 line_bounds.upper_x = obj->w_right; 01169 line_bounds.upper_y = obj->w_bottom; 01170 found_line_bounds = 1; 01171 } 01172 } else { 01173 distance = o_shortest_distance_full (obj, x, y, TRUE); 01174 shortest_distance = min (shortest_distance, distance); 01175 } 01176 01177 if (shortest_distance == 0.0) 01178 return shortest_distance; 01179 } 01180 01181 if (found_line_bounds) { 01182 distance = m_box_shortest_distance (&line_bounds, x, y, TRUE); 01183 shortest_distance = min (shortest_distance, distance); 01184 } 01185 01186 return shortest_distance; 01187 }