gschem
|
00001 /* gEDA - GPL Electronic Design Automation 00002 * gschem - gEDA Schematic Capture 00003 * Copyright (C) 1998-2010 Ales Hvezda 00004 * Copyright (C) 1998-2011 gEDA Contributors (see ChangeLog for details) 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 #include <config.h> 00021 00022 #include <stdio.h> 00023 00024 #include "gschem.h" 00025 00026 #ifdef HAVE_LIBDMALLOC 00027 #include <dmalloc.h> 00028 #endif 00029 00035 void o_move_start(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y) 00036 { 00037 TOPLEVEL *toplevel = w_current->toplevel; 00038 GList *s_iter; 00039 00040 g_return_if_fail (w_current->stretch_list == NULL); 00041 00042 if (o_select_selected (w_current)) { 00043 00044 /* Save the current state. When rotating the selection when moving, 00045 we have to come back to here */ 00046 o_undo_savestate(w_current, UNDO_ALL); 00047 w_current->last_drawb_mode = LAST_DRAWB_MODE_NONE; 00048 w_current->event_state = MOVE; 00049 00050 w_current->first_wx = w_current->second_wx = w_x; 00051 w_current->first_wy = w_current->second_wy = w_y; 00052 00053 o_invalidate_glist (w_current, 00054 geda_list_get_glist (toplevel->page_current->selection_list)); 00055 00056 if (w_current->netconn_rubberband) { 00057 o_move_prep_rubberband(w_current); 00058 00059 /* Set the dont_redraw flag on rubberbanded objects and invalidate them. 00060 * This ensures that they are not drawn (in their un-stretched position) 00061 * during screen updates. */ 00062 for (s_iter = w_current->stretch_list; 00063 s_iter != NULL; s_iter = g_list_next (s_iter)) { 00064 STRETCH *stretch = s_iter->data; 00065 stretch->object->dont_redraw = TRUE; 00066 o_invalidate (w_current, stretch->object); 00067 } 00068 } 00069 00070 o_select_move_to_place_list(w_current); 00071 w_current->inside_action = 1; 00072 00073 o_move_invalidate_rubber (w_current, TRUE); 00074 } 00075 } 00076 00082 static void o_move_end_lowlevel_glist (GSCHEM_TOPLEVEL *w_current, 00083 GList *list, 00084 int diff_x, int diff_y) 00085 { 00086 OBJECT *object; 00087 GList *iter; 00088 00089 iter = list; 00090 while (iter != NULL) { 00091 object = (OBJECT *)iter->data; 00092 o_move_end_lowlevel (w_current, object, diff_x, diff_y); 00093 iter = g_list_next (iter); 00094 } 00095 } 00096 00097 00103 void o_move_end_lowlevel (GSCHEM_TOPLEVEL *w_current, 00104 OBJECT *object, 00105 int diff_x, int diff_y) 00106 { 00107 TOPLEVEL *toplevel = w_current->toplevel; 00108 00109 switch (object->type) { 00110 00111 case (OBJ_NET): 00112 case (OBJ_BUS): 00113 case (OBJ_PIN): 00114 s_conn_remove_object (toplevel, object); 00115 o_translate_world (toplevel, diff_x, diff_y, object); 00116 s_conn_update_object (toplevel, object); 00117 break; 00118 00119 default: 00120 o_translate_world (toplevel, diff_x, diff_y, object); 00121 break; 00122 } 00123 } 00124 00130 void o_move_end(GSCHEM_TOPLEVEL *w_current) 00131 { 00132 TOPLEVEL *toplevel = w_current->toplevel; 00133 GList *s_current = NULL; 00134 OBJECT *object; 00135 int diff_x, diff_y; 00136 int left, top, right, bottom; 00137 GList *s_iter; 00138 GList *rubbernet_objects = NULL; 00139 00140 object = o_select_return_first_object(w_current); 00141 00142 if (!object) { 00143 /* actually this is an error condition hack */ 00144 w_current->inside_action = 0; 00145 i_set_state(w_current, SELECT); 00146 return; 00147 } 00148 00149 diff_x = w_current->second_wx - w_current->first_wx; 00150 diff_y = w_current->second_wy - w_current->first_wy; 00151 00152 o_move_invalidate_rubber (w_current, FALSE); 00153 w_current->rubber_visible = 0; 00154 00155 if (w_current->netconn_rubberband) { 00156 o_move_end_rubberband (w_current, diff_x, diff_y, &rubbernet_objects); 00157 } 00158 00159 /* Unset the dont_redraw flag on rubberbanded objects. 00160 * We set this above, in o_move_start(). */ 00161 for (s_iter = w_current->stretch_list; 00162 s_iter != NULL; s_iter = g_list_next (s_iter)) { 00163 STRETCH *stretch = s_iter->data; 00164 stretch->object->dont_redraw = FALSE; 00165 } 00166 00167 s_current = geda_list_get_glist( toplevel->page_current->selection_list ); 00168 00169 while (s_current != NULL) { 00170 00171 object = (OBJECT *) s_current->data; 00172 00173 if (object == NULL) { 00174 fprintf(stderr, _("ERROR: NULL object in o_move_end!\n")); 00175 exit(-1); 00176 } 00177 00178 00179 switch (object->type) { 00180 case (OBJ_COMPLEX): 00181 case (OBJ_PLACEHOLDER): 00182 00183 /* TODO: Fix so we can just pass the complex to o_move_end_lowlevel, 00184 * IE.. by falling through the bottom of this case statement. */ 00185 00186 /* this next section of code is from */ 00187 /* o_complex_world_translate_world */ 00188 object->complex->x = object->complex->x + diff_x; 00189 object->complex->y = object->complex->y + diff_y; 00190 00191 o_move_end_lowlevel_glist (w_current, object->complex->prim_objs, 00192 diff_x, diff_y); 00193 00194 00195 world_get_object_glist_bounds (toplevel, object->complex->prim_objs, 00196 &left, &top, &right, &bottom); 00197 00198 object->w_left = left; 00199 object->w_top = top; 00200 object->w_right = right; 00201 object->w_bottom = bottom; 00202 00203 break; 00204 00205 default: 00206 o_move_end_lowlevel (w_current, object, diff_x, diff_y); 00207 break; 00208 } 00209 00210 s_current = g_list_next(s_current); 00211 } 00212 00213 /* Remove the undo saved in o_move_start */ 00214 o_undo_remove_last_undo(w_current); 00215 00216 /* Draw the objects that were moved */ 00217 o_invalidate_glist (w_current, 00218 geda_list_get_glist (toplevel->page_current->selection_list)); 00219 00220 /* Draw the connected nets/buses that were also changed */ 00221 o_invalidate_glist (w_current, rubbernet_objects); 00222 00223 /* Call move-objects-hook for moved objects and changed connected 00224 * nets/buses */ 00225 GList *moved_list = g_list_concat (toplevel->page_current->place_list, 00226 rubbernet_objects); 00227 toplevel->page_current->place_list = NULL; 00228 rubbernet_objects = NULL; 00229 g_run_hook_object_list (w_current, "%move-objects-hook", moved_list); 00230 g_list_free (moved_list); 00231 00232 toplevel->page_current->CHANGED = 1; 00233 o_undo_savestate(w_current, UNDO_ALL); 00234 00235 s_stretch_destroy_all (w_current->stretch_list); 00236 w_current->stretch_list = NULL; 00237 } 00238 00239 00245 void o_move_cancel (GSCHEM_TOPLEVEL *w_current) 00246 { 00247 GList *s_iter; 00248 00249 /* Unset the dont_redraw flag on rubberbanded objects. 00250 * We set this above, in o_move_start(). */ 00251 for (s_iter = w_current->stretch_list; 00252 s_iter != NULL; s_iter = g_list_next (s_iter)) { 00253 STRETCH *stretch = s_iter->data; 00254 stretch->object->dont_redraw = FALSE; 00255 } 00256 g_list_free(w_current->toplevel->page_current->place_list); 00257 w_current->toplevel->page_current->place_list = NULL; 00258 00259 s_stretch_destroy_all (w_current->stretch_list); 00260 w_current->stretch_list = NULL; 00261 00262 w_current->inside_action = 0; 00263 i_set_state (w_current, SELECT); 00264 00265 o_undo_callback(w_current, UNDO_ACTION); 00266 } 00267 00268 00274 void o_move_motion (GSCHEM_TOPLEVEL *w_current, int w_x, int w_y) 00275 { 00276 TOPLEVEL *toplevel = w_current->toplevel; 00277 GList *selection, *s_current; 00278 OBJECT *object; 00279 gint object_x, object_y; 00280 gboolean resnap = FALSE; 00281 00282 selection = geda_list_get_glist( toplevel->page_current->selection_list ); 00283 00284 /* realign the object if we are in resnap mode */ 00285 if (selection != NULL 00286 && w_current->snap == SNAP_RESNAP) { 00287 00288 if (g_list_length(selection) > 1) { 00289 /* find an object that is not attached to any other object */ 00290 for (s_current = selection; 00291 s_current != NULL; 00292 s_current = g_list_next(s_current)) { 00293 if (((OBJECT *) s_current->data)->attached_to == NULL) { 00294 object = (OBJECT *) s_current->data; 00295 resnap = TRUE; 00296 break; 00297 } 00298 } 00299 00300 /* Only resnap single elements. This is also the case if 00301 the selection contains one object and all other object 00302 elements are attributes of the object element.*/ 00303 for (s_current = selection; 00304 s_current != NULL && resnap == TRUE; 00305 s_current = g_list_next(s_current)) { 00306 if (!(object == (OBJECT *) s_current->data) 00307 && !o_attrib_is_attached(toplevel, 00308 (OBJECT *) s_current->data, object)) { 00309 resnap = FALSE; 00310 } 00311 } 00312 } else { /* single object */ 00313 resnap = TRUE; 00314 object = (OBJECT *) selection->data; 00315 } 00316 00317 /* manipulate w_x and w_y in a way that will lead to a position 00318 of the object that is aligned with the grid */ 00319 if (resnap) { 00320 if (o_get_position(toplevel, &object_x, &object_y, object)) { 00321 w_x += snap_grid (w_current, object_x) - object_x; 00322 w_y += snap_grid (w_current, object_y) - object_y; 00323 } 00324 } 00325 } 00326 00327 o_move_invalidate_rubber (w_current, FALSE); 00328 w_current->second_wx = w_x; 00329 w_current->second_wy = w_y; 00330 o_move_invalidate_rubber (w_current, TRUE); 00331 } 00332 00333 00339 void o_move_invalidate_rubber (GSCHEM_TOPLEVEL *w_current, int drawing) 00340 { 00341 GList *s_iter; 00342 int dx1, dx2, dy1, dy2; 00343 int x1, y1, x2, y2; 00344 00345 o_place_invalidate_rubber (w_current, drawing); 00346 if (w_current->netconn_rubberband) { 00347 00348 for (s_iter = w_current->stretch_list; 00349 s_iter != NULL; s_iter = g_list_next (s_iter)) { 00350 STRETCH *s_current = s_iter->data; 00351 OBJECT *object = s_current->object; 00352 00353 switch (object->type) { 00354 case (OBJ_NET): 00355 case (OBJ_BUS): 00356 if (s_current->whichone == 0) { 00357 dx1 = w_current->second_wx - w_current->first_wx; 00358 dy1 = w_current->second_wy - w_current->first_wy; 00359 dx2 = dy2 = 0; 00360 } else { 00361 dx1 = dy1 = 0; 00362 dx2 = w_current->second_wx - w_current->first_wx; 00363 dy2 = w_current->second_wy - w_current->first_wy; 00364 } 00365 00366 WORLDtoSCREEN (w_current, object->line->x[0] + dx1, 00367 object->line->y[0] + dy1, &x1, &y1); 00368 WORLDtoSCREEN (w_current, object->line->x[1] + dx2, 00369 object->line->y[1] + dy2, &x2, &y2); 00370 00371 o_invalidate_rect (w_current, x1, y1, x2, y2); 00372 } 00373 } 00374 } 00375 } 00376 00377 00383 void o_move_draw_rubber (GSCHEM_TOPLEVEL *w_current, int drawing) 00384 { 00385 GList *s_iter; 00386 int diff_x, diff_y; 00387 00388 o_place_draw_rubber (w_current, drawing); 00389 00390 if (!w_current->netconn_rubberband) 00391 return; 00392 00393 diff_x = w_current->second_wx - w_current->first_wx; 00394 diff_y = w_current->second_wy - w_current->first_wy; 00395 00396 for (s_iter = w_current->stretch_list; 00397 s_iter != NULL; s_iter = g_list_next (s_iter)) { 00398 STRETCH *s_current = s_iter->data; 00399 OBJECT *object = s_current->object; 00400 int whichone = s_current->whichone; 00401 00402 switch (object->type) { 00403 case (OBJ_NET): 00404 o_net_draw_stretch (w_current, diff_x, diff_y, whichone, object); 00405 break; 00406 00407 case (OBJ_BUS): 00408 o_bus_draw_stretch (w_current, diff_x, diff_y, whichone, object); 00409 break; 00410 } 00411 } 00412 } 00413 00414 00420 int o_move_return_whichone(OBJECT * object, int x, int y) 00421 { 00422 if (object->line->x[0] == x && object->line->y[0] == y) { 00423 return (0); 00424 } 00425 00426 if (object->line->x[1] == x && object->line->y[1] == y) { 00427 return (1); 00428 } 00429 00430 fprintf(stderr, 00431 _("DOH! tried to find the whichone, but didn't find it!\n")); 00432 return (-1); 00433 } 00434 00440 void o_move_check_endpoint(GSCHEM_TOPLEVEL *w_current, OBJECT * object) 00441 { 00442 TOPLEVEL *toplevel = w_current->toplevel; 00443 GList *cl_current; 00444 CONN *c_current; 00445 OBJECT *other; 00446 int whichone; 00447 00448 if (!object) 00449 return; 00450 00451 if (object->type != OBJ_NET && object->type != OBJ_PIN && 00452 object->type != OBJ_BUS) { 00453 fprintf(stderr, _("Got a non line object in o_move_check_endpoint\n")); 00454 return; 00455 } 00456 00457 for (cl_current = object->conn_list; 00458 cl_current != NULL; 00459 cl_current = g_list_next(cl_current)) { 00460 00461 c_current = (CONN *) cl_current->data; 00462 other = c_current->other_object; 00463 00464 if (other == NULL) 00465 continue; 00466 00467 /* really make sure that the object is not selected */ 00468 if (other->selected) 00469 continue; 00470 00471 /* Catch pins, whos parent object is selected. */ 00472 if (other->parent != NULL && other->parent->selected) 00473 continue; 00474 00475 if (c_current->type != CONN_ENDPOINT && 00476 (c_current->type != CONN_MIDPOINT || 00477 c_current->other_whichone == -1)) 00478 continue; 00479 00480 if (/* (net)pin to (net)pin contact */ 00481 (object->type == OBJ_PIN && object->pin_type == PIN_TYPE_NET && 00482 other->type == OBJ_PIN && other->pin_type == PIN_TYPE_NET)) { 00483 00484 /* net to (net)pin contact */ 00485 /* (object->type == OBJ_NET && 00486 other->type == OBJ_PIN && other->pin_type == PIN_TYPE_NET) */ 00487 00488 OBJECT *new_net; 00489 /* other object is a pin, insert a net */ 00490 new_net = o_net_new (toplevel, OBJ_NET, NET_COLOR, 00491 c_current->x, c_current->y, 00492 c_current->x, c_current->y); 00493 s_page_append (toplevel, toplevel->page_current, new_net); 00494 /* This new net object is only picked up for stretching later, 00495 * somewhat of a kludge. If the move operation is cancelled, these 00496 * new 0 length nets are removed by the "undo" operation invoked. 00497 */ 00498 } 00499 00500 /* Only attempt to stretch nets and buses */ 00501 if (other->type != OBJ_NET && other->type != OBJ_BUS) 00502 continue; 00503 00504 whichone = o_move_return_whichone (other, c_current->x, c_current->y); 00505 00506 #if DEBUG 00507 printf ("FOUND: %s type: %d, whichone: %d, x,y: %d %d\n", 00508 other->name, c_current->type, 00509 whichone, c_current->x, c_current->y); 00510 00511 printf("other x,y: %d %d\n", c_current->x, c_current->y); 00512 printf("type: %d return: %d real: [ %d %d ]\n", 00513 c_current->type, whichone, c_current->whichone, 00514 c_current->other_whichone); 00515 #endif 00516 00517 if (whichone >= 0 && whichone <= 1) { 00518 w_current->stretch_list = s_stretch_add (w_current->stretch_list, 00519 other, whichone); 00520 } 00521 } 00522 00523 } 00524 00530 void o_move_prep_rubberband(GSCHEM_TOPLEVEL *w_current) 00531 { 00532 TOPLEVEL *toplevel = w_current->toplevel; 00533 GList *s_current; 00534 OBJECT *object; 00535 OBJECT *o_current; 00536 GList *iter; 00537 00538 for (s_current = geda_list_get_glist (toplevel->page_current->selection_list); 00539 s_current != NULL; s_current = g_list_next (s_current)) { 00540 object = s_current->data; 00541 00542 if (object == NULL) 00543 continue; 00544 00545 switch (object->type) { 00546 case (OBJ_NET): 00547 case (OBJ_PIN): 00548 case (OBJ_BUS): 00549 o_move_check_endpoint (w_current, object); 00550 break; 00551 00552 case (OBJ_COMPLEX): 00553 case (OBJ_PLACEHOLDER): 00554 for (iter = object->complex->prim_objs; 00555 iter != NULL; iter = g_list_next (iter)) { 00556 o_current = iter->data; 00557 00558 if (o_current->type == OBJ_PIN) { 00559 o_move_check_endpoint (w_current, o_current); 00560 } 00561 } 00562 break; 00563 } 00564 } 00565 } 00566 00572 int o_move_zero_length(OBJECT * object) 00573 { 00574 #if DEBUG 00575 printf("x: %d %d y: %d %d\n", 00576 object->line->x[0], object->line->x[1], 00577 object->line->y[0], object->line->y[1]); 00578 #endif 00579 00580 if (object->line->x[0] == object->line->x[1] && 00581 object->line->y[0] == object->line->y[1]) { 00582 return TRUE; 00583 } else { 00584 return FALSE; 00585 } 00586 } 00587 00593 void o_move_end_rubberband (GSCHEM_TOPLEVEL *w_current, 00594 int w_dx, int w_dy, 00595 GList** objects) 00596 { 00597 TOPLEVEL *toplevel = w_current->toplevel; 00598 GList *s_iter, *s_iter_next; 00599 00600 for (s_iter = w_current->stretch_list; 00601 s_iter != NULL; s_iter = s_iter_next) { 00602 STRETCH *s_current = s_iter->data; 00603 OBJECT *object = s_current->object; 00604 int whichone = s_current->whichone; 00605 00606 /* Store this now, since we may delete the current item */ 00607 s_iter_next = g_list_next (s_iter); 00608 00609 if (object->type == OBJ_NET || 00610 object->type == OBJ_BUS) { 00611 00612 /* remove the object's connections */ 00613 s_conn_remove_object (toplevel, object); 00614 00615 object->line->x[whichone] += w_dx; 00616 object->line->y[whichone] += w_dy; 00617 00618 if (o_move_zero_length (object)) { 00619 w_current->stretch_list = 00620 s_stretch_remove (w_current->stretch_list, object); 00621 o_delete (w_current, object); 00622 continue; 00623 } 00624 00625 o_recalc_single_object (toplevel, object); 00626 s_tile_update_object (toplevel, object); 00627 s_conn_update_object (toplevel, object); 00628 *objects = g_list_append (*objects, object); 00629 } 00630 } 00631 }