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 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 }