libgeda

o_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 
00045 #include <config.h>
00046 
00047 #include <stdio.h>
00048 
00049 /* instrumentation code */
00050 #if 0
00051 #include <sys/time.h>
00052 #include <unistd.h>
00053 #endif
00054 
00055 #include "libgeda_priv.h"
00056 
00057 #ifdef HAVE_LIBDMALLOC
00058 #include <dmalloc.h>
00059 #endif
00060 
00061 
00075 int inside_region(int xmin, int ymin, int xmax, int ymax, int x, int y)
00076 {
00077   return ((x >= xmin && x <= xmax && y >= ymin && y <= ymax) ? 1 : 0);
00078 }
00079 
00089 void o_recalc_single_object(TOPLEVEL *toplevel, OBJECT *o_current)
00090 {
00091   if (o_current != NULL) {
00092     switch(o_current->type) {
00093 
00094       case(OBJ_LINE):
00095         o_line_recalc(toplevel, o_current);
00096         break;
00097 
00098       case(OBJ_NET):
00099         o_net_recalc(toplevel, o_current);
00100         break;
00101 
00102       case(OBJ_BUS):
00103         o_bus_recalc(toplevel, o_current);
00104         break;
00105 
00106       case(OBJ_BOX):
00107         o_box_recalc(toplevel, o_current);
00108         break;
00109 
00110       case(OBJ_PATH):
00111         o_path_recalc(toplevel, o_current);
00112         break;
00113 
00114       case(OBJ_PICTURE):
00115         o_picture_recalc(toplevel, o_current);
00116         break;
00117 
00118       case(OBJ_CIRCLE):
00119         o_circle_recalc(toplevel, o_current);
00120         break;
00121 
00122       case(OBJ_COMPLEX):
00123       case(OBJ_PLACEHOLDER):
00124         o_complex_recalc(toplevel, o_current);
00125         break;
00126 
00127       case(OBJ_PIN):
00128         o_pin_recalc(toplevel, o_current);
00129         break;
00130 
00131       case(OBJ_ARC):
00132         o_arc_recalc(toplevel, o_current);
00133         break;
00134 
00135       case(OBJ_TEXT):
00136         o_text_recalc(toplevel, o_current);
00137         break;
00138     }
00139   }
00140 }
00141 
00142 
00152 void
00153 o_recalc_object_glist(TOPLEVEL *toplevel, GList *object_glist)
00154 {
00155   GList *list = object_glist;
00156   OBJECT *o_current;
00157 
00158   while (list != NULL) {
00159     o_current = (OBJECT *) list->data;
00160     o_recalc_single_object(toplevel, o_current);
00161    list = g_list_next(list);
00162   }
00163 }
00164 
00165 
00183 void o_set_line_options(TOPLEVEL *toplevel, OBJECT *o_current,
00184             OBJECT_END end, OBJECT_TYPE type,
00185             int width, int length, int space) 
00186 {
00187   if(o_current == NULL) {
00188     return;
00189   }
00190 
00191   /* do some error checking / correcting */
00192   switch(type) {
00193     case(TYPE_DOTTED):
00194     if (space < 1) {
00195       space = 100;
00196       s_log_message (_("Invalid space specified, setting to 100\n"));
00197     }
00198     break;
00199     case(TYPE_DASHED):
00200     case(TYPE_CENTER):
00201     case(TYPE_PHANTOM):
00202     if (length < 1) {
00203       length = 100;
00204       s_log_message (_("Invalid length specified, setting to 100\n"));
00205     }
00206     if (space < 1) {
00207       space = 100;
00208       s_log_message (_("Invalid space specified, setting to 100\n"));
00209     }
00210     break;
00211     default:
00212     
00213     break;
00214   }
00215   
00216   o_emit_pre_change_notify (toplevel, o_current);
00217 
00218   o_current->line_width = width;
00219   o_current->line_end   = end;
00220   o_current->line_type  = type;
00221 
00222   o_current->line_length = length;
00223   o_current->line_space  = space;
00224 
00225   /* Recalculate the object's bounding box */
00226   o_recalc_single_object( toplevel, o_current );
00227   o_emit_change_notify (toplevel, o_current);
00228 
00229 }
00230 
00246 gboolean o_get_line_options(OBJECT *object,
00247                             OBJECT_END *end, OBJECT_TYPE *type,
00248                             int *width, int *length, int *space)
00249 {
00250   if (object->type != OBJ_LINE
00251       && object->type != OBJ_ARC
00252       && object->type != OBJ_BOX
00253       && object->type != OBJ_CIRCLE
00254       && object->type != OBJ_PATH)
00255     return FALSE;
00256 
00257   *end = object->line_end;
00258   *type = object->line_type;
00259   *width = object->line_width;
00260   *length = object->line_length;
00261   *space = object->line_space;
00262 
00263   return TRUE;
00264 }
00265 
00281 void o_set_fill_options(TOPLEVEL *toplevel, OBJECT *o_current,
00282             OBJECT_FILLING type, int width,
00283             int pitch1, int angle1,
00284             int pitch2, int angle2) 
00285 {
00286   if(o_current == NULL) {
00287     return;
00288   }
00289 
00290   o_emit_pre_change_notify (toplevel, o_current);
00291 
00292   o_current->fill_type = type;
00293   o_current->fill_width = width;
00294 
00295   o_current->fill_pitch1 = pitch1;
00296   o_current->fill_angle1 = angle1;
00297 
00298   o_current->fill_pitch2 = pitch2;
00299   o_current->fill_angle2 = angle2;
00300 
00301   o_emit_change_notify (toplevel, o_current);
00302 }
00303 
00319 gboolean o_get_fill_options(OBJECT *object,
00320                             OBJECT_FILLING *type, int *width,
00321                             int *pitch1, int *angle1,
00322                             int *pitch2, int *angle2)
00323 {
00324   if (object->type != OBJ_BOX
00325       && object->type != OBJ_CIRCLE
00326       && object->type != OBJ_PATH)
00327     return FALSE;
00328 
00329   *type = object->fill_type;
00330   *width = object->fill_width;
00331   *pitch1 = object->fill_pitch1;
00332   *angle1 = object->fill_angle1;
00333   *pitch2 = object->fill_pitch2;
00334   *angle2 = object->fill_angle2;
00335 
00336   return TRUE;
00337 }
00338 
00349 gboolean o_get_position (TOPLEVEL *toplevel, gint *x, gint *y, OBJECT *object)
00350 {
00351   gboolean (*func) (TOPLEVEL*, int*, int*, OBJECT*) = NULL;
00352 
00353   switch (object->type) {
00354       case OBJ_LINE:    func = o_line_get_position;    break;
00355       case OBJ_NET:     func = o_net_get_position;     break;
00356       case OBJ_BUS:     func = o_bus_get_position;     break;
00357       case OBJ_BOX:     func = o_box_get_position;     break;
00358       case OBJ_PICTURE: func = o_picture_get_position; break;
00359       case OBJ_CIRCLE:  func = o_circle_get_position;  break;
00360       case OBJ_PLACEHOLDER:
00361       case OBJ_COMPLEX: func = o_complex_get_position; break;
00362       case OBJ_TEXT:    func = o_text_get_position;    break;
00363       case OBJ_PATH:    func = o_path_get_position;    break;
00364       case OBJ_PIN:     func = o_pin_get_position;     break;
00365       case OBJ_ARC:     func = o_arc_get_position;     break;
00366       default:
00367         g_critical ("o_get_position: object %p has bad type '%c'\n",
00368                     object, object->type);
00369   }
00370 
00371   if (func != NULL) {
00372     return (*func) (toplevel, x, y, object);
00373   }
00374   return FALSE;
00375 }
00376 
00377 
00388 void o_translate_world (TOPLEVEL *toplevel, gint dx, gint dy, OBJECT *object)
00389 {
00390   void (*func) (TOPLEVEL*, int, int, OBJECT*) = NULL;
00391 
00392   switch (object->type) {
00393       case OBJ_LINE:    func = o_line_translate_world;    break;
00394       case OBJ_NET:     func = o_net_translate_world;     break;
00395       case OBJ_BUS:     func = o_bus_translate_world;     break;
00396       case OBJ_BOX:     func = o_box_translate_world;     break;
00397       case OBJ_PICTURE: func = o_picture_translate_world; break;
00398       case OBJ_CIRCLE:  func = o_circle_translate_world;  break;
00399       case OBJ_PLACEHOLDER:
00400       case OBJ_COMPLEX: func = o_complex_translate_world; break;
00401       case OBJ_TEXT:    func = o_text_translate_world;    break;
00402       case OBJ_PATH:    func = o_path_translate_world;    break;
00403       case OBJ_PIN:     func = o_pin_translate_world;     break;
00404       case OBJ_ARC:     func = o_arc_translate_world;     break;
00405       default:
00406         g_critical ("o_translate_world: object %p has bad type '%c'\n",
00407                     object, object->type);
00408   }
00409 
00410   if (func != NULL) {
00411     (*func) (toplevel, dx, dy, object);
00412   }
00413 }
00414 
00415 
00427 void o_rotate_world (TOPLEVEL *toplevel, int world_centerx, int world_centery, int angle, OBJECT *object)
00428 {
00429   void (*func) (TOPLEVEL*, int, int, int, OBJECT*) = NULL;
00430 
00431   switch (object->type) {
00432       case OBJ_LINE:    func = o_line_rotate_world;       break;
00433       case OBJ_NET:     func = o_net_rotate_world;        break;
00434       case OBJ_BUS:     func = o_bus_rotate_world;        break;
00435       case OBJ_BOX:     func = o_box_rotate_world;        break;
00436       case OBJ_PICTURE: func = o_picture_rotate_world;    break;
00437       case OBJ_CIRCLE:  func = o_circle_rotate_world;     break;
00438       case OBJ_PLACEHOLDER:
00439       case OBJ_COMPLEX: func = o_complex_rotate_world;    break;
00440       case OBJ_TEXT:    func = o_text_rotate_world;       break;
00441       case OBJ_PATH:    func = o_path_rotate_world;       break;
00442       case OBJ_PIN:     func = o_pin_rotate_world;        break;
00443       case OBJ_ARC:     func = o_arc_rotate_world;        break;
00444       default:
00445         g_critical ("o_rotate_world: object %p has bad type '%c'\n",
00446                     object, object->type);
00447   }
00448 
00449   if (func != NULL) {
00450     (*func) (toplevel, world_centerx, world_centery, angle, object);
00451   }
00452 }
00453 
00454 
00465 void o_mirror_world (TOPLEVEL *toplevel, int world_centerx, int world_centery, OBJECT *object)
00466 {
00467   void (*func) (TOPLEVEL*, int, int, OBJECT*) = NULL;
00468 
00469   switch (object->type) {
00470       case OBJ_LINE:    func = o_line_mirror_world;       break;
00471       case OBJ_NET:     func = o_net_mirror_world;        break;
00472       case OBJ_BUS:     func = o_bus_mirror_world;        break;
00473       case OBJ_BOX:     func = o_box_mirror_world;        break;
00474       case OBJ_PICTURE: func = o_picture_mirror_world;    break;
00475       case OBJ_CIRCLE:  func = o_circle_mirror_world;     break;
00476       case OBJ_PLACEHOLDER:
00477       case OBJ_COMPLEX: func = o_complex_mirror_world;    break;
00478       case OBJ_TEXT:    func = o_text_mirror_world;       break;
00479       case OBJ_PATH:    func = o_path_mirror_world;       break;
00480       case OBJ_PIN:     func = o_pin_mirror_world;        break;
00481       case OBJ_ARC:     func = o_arc_mirror_world;        break;
00482       default:
00483         g_critical ("o_mirror_world: object %p has bad type '%c'\n",
00484                     object, object->type);
00485   }
00486 
00487   if (func != NULL) {
00488     (*func) (toplevel, world_centerx, world_centery, object);
00489   }
00490 }
00491 
00492 
00504 double o_shortest_distance (OBJECT *object, int x, int y)
00505 {
00506   return o_shortest_distance_full (object, x, y, FALSE);
00507 }
00508 
00521 double o_shortest_distance_full (OBJECT *object, int x, int y, int force_solid)
00522 {
00523   double shortest_distance = G_MAXDOUBLE;
00524   double (*func) (OBJECT *, int, int, int) = NULL;
00525 
00526   g_return_val_if_fail (object != NULL, G_MAXDOUBLE);
00527 
00528   switch(object->type) {
00529     case OBJ_BUS:
00530     case OBJ_NET:
00531     case OBJ_PIN:
00532     case OBJ_LINE:        func = o_line_shortest_distance;     break;
00533     case OBJ_BOX:         func = o_box_shortest_distance;      break;
00534     case OBJ_PICTURE:     func = o_picture_shortest_distance;  break;
00535     case OBJ_CIRCLE:      func = o_circle_shortest_distance;   break;
00536     case OBJ_PLACEHOLDER:
00537     case OBJ_COMPLEX:     func = o_complex_shortest_distance;  break;
00538     case OBJ_TEXT:        func = o_text_shortest_distance;     break;
00539     case OBJ_PATH:        func = o_path_shortest_distance;     break;
00540     case OBJ_ARC:         func = o_arc_shortest_distance;      break;
00541     default:
00542       g_critical ("o_shortest_distance: object %p has bad type '%c'\n",
00543                   object, object->type);
00544   }
00545 
00546   if (func != NULL) {
00547     shortest_distance = (*func) (object, x, y, force_solid);
00548   }
00549 
00550   return shortest_distance;
00551 }
00552 
00564 void o_bounds_invalidate(TOPLEVEL *toplevel, OBJECT *obj)
00565 {
00566   do {
00567       obj->w_bounds_valid = FALSE;
00568   } while ((obj = obj->parent) != NULL);
00569 }
00570 
00571 
00581 void o_set_color (TOPLEVEL *toplevel, OBJECT *object, int color)
00582 {
00583   g_return_if_fail (object != NULL);
00584 
00585   object->color = color;
00586 
00587   if (object->type == OBJ_COMPLEX ||
00588       object->type == OBJ_PLACEHOLDER)
00589     o_glist_set_color (toplevel, object->complex->prim_objs, color);
00590 }
00591 
00592 
00606 PAGE *
00607 o_get_page (TOPLEVEL *toplevel, OBJECT *object)
00608 {
00609   if (object->parent != NULL) {
00610     return o_get_page (toplevel, object->parent);
00611   }
00612   return object->page;
00613 }
00614 
00634 PAGE *
00635 o_get_page_compat (TOPLEVEL *toplevel, OBJECT *object) {
00636   PAGE *page = o_get_page (toplevel, object);
00637   if (page != toplevel->page_current) {
00638     g_critical ("o_get_page_compat: OBJECT.page = %p, TOPLEVEL.page_current = %p",
00639                 page, toplevel->page_current);
00640     return toplevel->page_current;
00641   } else {
00642     return page;
00643   }
00644 }
00645 
00656 OBJECT *
00657 o_get_parent (TOPLEVEL *toplevel, OBJECT *object)
00658 {
00659   g_return_val_if_fail ((object != NULL), NULL);
00660 
00661   if (object->parent != NULL) {
00662     return object->parent;
00663   }
00664   return NULL;
00665 }
00666 
00667 /* Structure for each entry in a TOPLEVEL's list of registered change
00668  * notification handlers */
00669 struct change_notify_entry {
00670   ChangeNotifyFunc pre_change_func;
00671   ChangeNotifyFunc change_func;
00672   void *user_data;
00673 };
00674 
00687 void
00688 o_add_change_notify (TOPLEVEL *toplevel,
00689                      ChangeNotifyFunc pre_change_func,
00690                      ChangeNotifyFunc change_func,
00691                      void *user_data)
00692 {
00693   struct change_notify_entry *entry = g_new0 (struct change_notify_entry, 1);
00694   entry->pre_change_func = pre_change_func;
00695   entry->change_func = change_func;
00696   entry->user_data = user_data;
00697   toplevel->change_notify_funcs =
00698     g_list_prepend (toplevel->change_notify_funcs, entry);
00699 }
00700 
00715 void
00716 o_remove_change_notify (TOPLEVEL *toplevel,
00717                         ChangeNotifyFunc pre_change_func,
00718                         ChangeNotifyFunc change_func,
00719                         void *user_data)
00720 {
00721   GList *iter;
00722   for (iter = toplevel->change_notify_funcs;
00723        iter != NULL; iter = g_list_next (iter)) {
00724 
00725     struct change_notify_entry *entry =
00726       (struct change_notify_entry *) iter->data;
00727 
00728     if ((entry != NULL)
00729         && (entry->pre_change_func == pre_change_func)
00730         && (entry->change_func == change_func)
00731         && (entry->user_data == user_data)) {
00732       g_free (entry);
00733       iter->data = NULL;
00734     }
00735   }
00736   toplevel->change_notify_funcs =
00737     g_list_remove_all (toplevel->change_notify_funcs, NULL);
00738 }
00739 
00750 void
00751 o_emit_pre_change_notify (TOPLEVEL *toplevel, OBJECT *object)
00752 {
00753   GList *iter;
00754   for (iter = toplevel->change_notify_funcs;
00755        iter != NULL; iter = g_list_next (iter)) {
00756 
00757     struct change_notify_entry *entry =
00758       (struct change_notify_entry *) iter->data;
00759 
00760     if ((entry != NULL) && (entry->pre_change_func != NULL)) {
00761       entry->pre_change_func (entry->user_data, object);
00762     }
00763   }
00764 }
00765 
00776 void
00777 o_emit_change_notify (TOPLEVEL *toplevel, OBJECT *object)
00778 {
00779   GList *iter;
00780   for (iter = toplevel->change_notify_funcs;
00781        iter != NULL; iter = g_list_next (iter)) {
00782 
00783     struct change_notify_entry *entry =
00784       (struct change_notify_entry *) iter->data;
00785 
00786     if ((entry != NULL) && (entry->change_func != NULL)) {
00787       entry->change_func (entry->user_data, object);
00788     }
00789   }
00790 }
00791 
00800 gboolean
00801 o_is_visible (TOPLEVEL *toplevel, OBJECT *object)
00802 {
00803   g_return_val_if_fail (object != NULL, FALSE);
00804   return object->visibility == VISIBLE;
00805 }
00806 
00816 void
00817 o_set_visibility (TOPLEVEL *toplevel, OBJECT *object, int visibility)
00818 {
00819   g_return_if_fail (object != NULL);
00820   if (object->visibility != visibility) {
00821     object->visibility = visibility;
00822     o_bounds_invalidate (toplevel, object);
00823   }
00824 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines