libgeda

o_complex_basic.c

Go to the documentation of this file.
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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines