gschem

o_move.c

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