/*! \brief Rotate all objects in list. * \par Function Description * Given an object <B>list</B>, and the center of rotation * (<B>centerx</B>,<B>centery</B>, this function traverses all the selection * list, rotating each object through angle <B>angle</B>. * The list contains a given object and all its attributes * (refdes, pinname, pinlabel, ...). * There is a second pass to run the rotate hooks of non-simple objects, * like pin or complex objects, for example. * * \param [in] w_current The GschemToplevel object. * \param [in] centerx Center x coordinate of rotation. * \param [in] centery Center y coordinate of rotation. * \param [in] angle Angle to rotate the objects through. * \param [in] list The list of objects to rotate. */ void o_rotate_world_update(GschemToplevel *w_current, int centerx, int centery, int angle, GList *list) { TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current); OBJECT *o_current; GList *o_iter; /* this is okay if you just hit rotate and have nothing selected */ if (list == NULL) { i_action_stop (w_current); i_set_state(w_current, SELECT); return; } o_invalidate_glist (w_current, list); /* Find connected objects, removing each object in turn from the * connection list. We only _really_ want those objects connected * to the selection, not those within in it. */ for (o_iter = list; o_iter != NULL; o_iter = g_list_next (o_iter)) { o_current = o_iter->data; s_conn_remove_object_connections (toplevel, o_current); } o_glist_rotate_world( toplevel, centerx, centery, angle, list ); /* Find connected objects, adding each object in turn back to the * connection list. We only _really_ want those objects connected * to the selection, not those within in it. */ for (o_iter = list; o_iter != NULL; o_iter = g_list_next (o_iter)) { o_current = o_iter->data; s_conn_update_object (o_current->page, o_current); } o_invalidate_glist (w_current, list); /* Run rotate-objects-hook */ g_run_hook_object_list (w_current, "%rotate-objects-hook", list); /* Don't save the undo state if we are inside an action */ /* This is useful when rotating the selection while moving, for example */ gschem_toplevel_page_content_changed (w_current, toplevel->page_current); if (!w_current->inside_action) { o_undo_savestate_old(w_current, UNDO_ALL); } if (w_current->event_state == ROTATEMODE) { i_set_state(w_current, SELECT); } }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * */ void o_mirror_world_update(GschemToplevel *w_current, int centerx, int centery, GList *list) { TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current); OBJECT *o_current; GList *o_iter; if (list == NULL) { i_action_stop (w_current); i_set_state(w_current, SELECT); return; } o_invalidate_glist (w_current, list); /* Find connected objects, removing each object in turn from the * connection list. We only _really_ want those objects connected * to the selection, not those within in it. */ for (o_iter = list; o_iter != NULL; o_iter = g_list_next (o_iter)) { o_current = o_iter->data; s_conn_remove_object_connections (toplevel, o_current); } o_glist_mirror_world( toplevel, centerx, centery, list ); /* Find connected objects, adding each object in turn back to the * connection list. We only _really_ want those objects connected * to the selection, not those within in it. */ for (o_iter = list; o_iter != NULL; o_iter = g_list_next (o_iter)) { o_current = o_iter->data; s_conn_update_object (o_current->page, o_current); } o_invalidate_glist (w_current, list); /* Run mirror-objects-hook */ g_run_hook_object_list (w_current, "%mirror-objects-hook", list); gschem_toplevel_page_content_changed (w_current, toplevel->page_current); o_undo_savestate_old(w_current, UNDO_ALL); if (w_current->event_state == MIRRORMODE) { i_set_state(w_current, SELECT); } }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * */ void o_mirror_world_update(GSCHEM_TOPLEVEL *w_current, int centerx, int centery, GList *list) { TOPLEVEL *toplevel = w_current->toplevel; OBJECT *o_current; GList *o_iter; if (list == NULL) { w_current->inside_action = 0; i_set_state(w_current, SELECT); return; } o_invalidate_glist (w_current, list); /* Find connected objects, removing each object in turn from the * connection list. We only _really_ want those objects connected * to the selection, not those within in it. */ for (o_iter = list; o_iter != NULL; o_iter = g_list_next (o_iter)) { o_current = o_iter->data; s_conn_remove_object (toplevel, o_current); } o_glist_mirror_world( toplevel, centerx, centery, list ); /* Find connected objects, adding each object in turn back to the * connection list. We only _really_ want those objects connected * to the selection, not those within in it. */ for (o_iter = list; o_iter != NULL; o_iter = g_list_next (o_iter)) { o_current = o_iter->data; s_conn_update_object (toplevel, o_current); } o_invalidate_glist (w_current, list); /* Run mirror-objects-hook */ g_run_hook_object_list ("%mirror-objects-hook", list); toplevel->page_current->CHANGED=1; o_undo_savestate(w_current, UNDO_ALL); }
/*! \brief finish a bus drawing action * \par Function Description * This function finishes a net drawing action. The function draws * a bus from the point (<B>first_wx</B>,<B>first_wy</B>) to * (<B>second_wx</B>,<B>second_wy</B>). Both points are taken from * the <B>GschemToplevel</B> structure. * * The function returns TRUE if a bus object has been created and * FALSE if no bus object has been created. * * \param [in] w_current The GschemToplevel object. * \param [in] w_x (unused) * \param [in] w_y (unused) */ void o_bus_end(GschemToplevel *w_current, int w_x, int w_y) { OBJECT *new_obj; GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current); g_return_if_fail (page_view != NULL); g_assert( w_current->inside_action != 0 ); PAGE *page = gschem_page_view_get_page (page_view); g_return_if_fail (page != NULL); TOPLEVEL *toplevel = page->toplevel; g_return_if_fail (toplevel != NULL); GList *prev_conn_objects = NULL; /* erase the rubberbus */ /* o_bus_invalidate_rubber (w_current); */ w_current->rubber_visible = 0; /* don't allow zero length bus */ /* this ends the bus drawing behavior we want this? hack */ if ( (w_current->first_wx != w_current->second_wx) || (w_current->first_wy != w_current->second_wy) ) { new_obj = geda_bus_object_new (toplevel, BUS_COLOR, w_current->first_wx, w_current->first_wy, w_current->second_wx, w_current->second_wy, 0); s_page_append (toplevel, page, new_obj); /* connect the new bus to the other busses */ prev_conn_objects = s_conn_return_others (prev_conn_objects, new_obj); o_invalidate_glist (w_current, prev_conn_objects); g_list_free (prev_conn_objects); /* Call add-objects-hook */ g_run_hook_object (w_current, "%add-objects-hook", new_obj); w_current->first_wx = w_current->second_wx; w_current->first_wy = w_current->second_wy; gschem_toplevel_page_content_changed (w_current, page); o_undo_savestate(w_current, page, UNDO_ALL); } /* Don't reset w_current->inside_action here since we want to continue drawing */ }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * */ void o_move_start(GschemToplevel *w_current, int w_x, int w_y) { GList *s_iter; g_return_if_fail (w_current != NULL); GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current); g_return_if_fail (page_view != NULL); PAGE *page = gschem_page_view_get_page (page_view); g_return_if_fail (page != NULL); g_return_if_fail (w_current->stretch_list == NULL); if (o_select_selected (w_current)) { i_set_state (w_current, MOVEMODE); gboolean net_rubber_band_mode; net_rubber_band_mode = gschem_options_get_net_rubber_band_mode (w_current->options); w_current->last_drawb_mode = LAST_DRAWB_MODE_NONE; w_current->first_wx = w_current->second_wx = w_x; w_current->first_wy = w_current->second_wy = w_y; o_invalidate_glist (w_current, geda_list_get_glist (page->selection_list)); if (net_rubber_band_mode) { o_move_prep_rubberband(w_current); /* Set the dont_redraw flag on rubberbanded objects and invalidate them. * This ensures that they are not drawn (in their un-stretched position) * during screen updates. */ for (s_iter = w_current->stretch_list; s_iter != NULL; s_iter = g_list_next (s_iter)) { STRETCH *stretch = s_iter->data; stretch->object->dont_redraw = TRUE; o_invalidate (w_current, stretch->object); } } o_select_move_to_place_list(w_current); i_action_start (w_current); o_move_invalidate_rubber (w_current, TRUE); } }
/*! \brief End placement action * * \par Function Description * This function finishes the current placement action by adding * objects to the current page at the given new world coordinates * and redrawing them on the canvas. It also saves the current * state in the undo list and updates the menus. * * If \a continue_placing is TRUE, a copy of the placement list * is saved to start a new place action. * * \param [in] w_current GschemToplevel which we're drawing for. * \param [in] w_x The current world X coordinate. * \param [in] w_y The current world Y coordinate. * \param [in] hook_name The hook to run after adding the objects. */ void o_place_end (GschemToplevel *w_current, int w_x, int w_y, int continue_placing, const char* hook_name) { int w_diff_x, w_diff_y; OBJECT *o_current; GList *temp_dest_list = NULL; GList *connected_objects = NULL; GList *iter; g_return_if_fail (w_current != NULL); g_assert (w_current->inside_action != 0); GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current); g_return_if_fail (page_view != NULL); PAGE *page = gschem_page_view_get_page (page_view); g_return_if_fail (page != NULL); /* erase old image */ /* o_place_invalidate_rubber (w_current, FALSE); */ w_current->rubber_visible = 0; /* Calc final object positions */ w_current->second_wx = w_x; w_current->second_wy = w_y; w_diff_x = w_current->second_wx - w_current->first_wx; w_diff_y = w_current->second_wy - w_current->first_wy; if (continue_placing) { /* Make a copy of the place list if we want to keep it afterwards */ temp_dest_list = o_glist_copy_all (page->toplevel, page->place_list, temp_dest_list); } else { /* Otherwise just take it */ temp_dest_list = page->place_list; page->place_list = NULL; } geda_object_list_translate (temp_dest_list, w_diff_x, w_diff_y); /* Attach each item back onto the page's object list. Update object * connectivity and add the new objects to the selection list.*/ for (iter = temp_dest_list; iter != NULL; iter = g_list_next (iter)) { o_current = (OBJECT*) iter->data; s_page_append (page->toplevel, page, o_current); /* Update object connectivity */ s_conn_update_object (page, o_current); connected_objects = s_conn_return_others (connected_objects, o_current); } if (hook_name != NULL) { g_run_hook_object_list (w_current, hook_name, temp_dest_list); } o_invalidate_glist (w_current, connected_objects); g_list_free (connected_objects); connected_objects = NULL; gschem_toplevel_page_content_changed (w_current, page); o_invalidate_glist (w_current, temp_dest_list); /* only redraw new objects */ g_list_free (temp_dest_list); o_undo_savestate_old (w_current, UNDO_ALL); i_update_menus (w_current); if (!continue_placing) { i_set_state(w_current, SELECT); i_action_stop (w_current); } }
/*! \brief finish a net drawing action * \par Function Description * This function finishes the drawing of a net. If we have a visible * magnetic marker, we use that instead of the current cursor * position. * * The rubber nets are removed, the nets and cues are drawn and the * net is added to the TOPLEVEL structure. * * The function returns TRUE if it has drawn a net, FALSE otherwise. */ int o_net_end(GSCHEM_TOPLEVEL *w_current, int w_x, int w_y) { TOPLEVEL *toplevel = w_current->toplevel; int color; int primary_zero_length, secondary_zero_length; int found_primary_connection = FALSE; int save_wx, save_wy; GList *prev_conn_objects = NULL; OBJECT *new_net = NULL; g_assert( w_current->inside_action != 0 ); o_net_invalidate_rubber (w_current); if (w_current->magnetic_wx != -1 && w_current->magnetic_wy != -1) o_net_finishmagnetic(w_current); w_current->rubber_visible = 0; /* See if either of the nets are zero length. We'll only add */ /* the non-zero ones */ primary_zero_length = (w_current->first_wx == w_current->second_wx) && (w_current->first_wy == w_current->second_wy); secondary_zero_length = (w_current->second_wx == w_current->third_wx) && (w_current->second_wy == w_current->third_wy); /* If both nets are zero length... */ /* this ends the net drawing behavior */ if ( primary_zero_length && secondary_zero_length ) { return FALSE; } save_wx = w_current->third_wx; save_wy = w_current->third_wy; if (toplevel->override_net_color == -1) { color = NET_COLOR; } else { color = toplevel->override_net_color; } if (w_current->third_wx != snap_grid (w_current, w_current->third_wx) || w_current->third_wy != snap_grid (w_current, w_current->third_wy)) s_log_message(_("Warning: Ending net at off grid coordinate\n")); if (!primary_zero_length ) { /* create primary net */ new_net = o_net_new(toplevel, OBJ_NET, color, w_current->first_wx, w_current->first_wy, w_current->second_wx, w_current->second_wy); s_page_append (toplevel->page_current, new_net); /* conn stuff */ /* LEAK CHECK 1 */ prev_conn_objects = s_conn_return_others (prev_conn_objects, new_net); if (o_net_add_busrippers (w_current, new_net, prev_conn_objects)) { g_list_free (prev_conn_objects); prev_conn_objects = NULL; prev_conn_objects = s_conn_return_others (prev_conn_objects, new_net); } #if DEBUG printf("primary:\n"); s_conn_print(new_net->conn_list); #endif o_invalidate (w_current, new_net); o_invalidate_glist (w_current, prev_conn_objects); g_list_free (prev_conn_objects); prev_conn_objects = NULL; /* Go off and search for valid connection on this newly created net */ found_primary_connection = s_conn_net_search(new_net, 1, new_net->conn_list); if (found_primary_connection) { /* if a net connection is found, reset start point of next net */ save_wx = w_current->second_wx; save_wy = w_current->second_wy; } /* you don't want to consolidate nets which are drawn non-ortho */ if (toplevel->net_consolidate == TRUE && !w_current->CONTROLKEY) { /* CAUTION: Object list will change when nets are consolidated, don't * keep pointers to other objects than new_net after this. */ o_net_consolidate_segments(toplevel, new_net); } } /* If the second net is not zero length, add it as well */ /* Also, a valid net connection from the primary net was not found */ if (!secondary_zero_length && !found_primary_connection) { /* Add secondary net */ new_net = o_net_new(toplevel, OBJ_NET, color, w_current->second_wx, w_current->second_wy, w_current->third_wx, w_current->third_wy); s_page_append (toplevel->page_current, new_net); /* conn stuff */ /* LEAK CHECK 2 */ prev_conn_objects = s_conn_return_others (prev_conn_objects, new_net); if (o_net_add_busrippers (w_current, new_net, prev_conn_objects)) { g_list_free (prev_conn_objects); prev_conn_objects = NULL; prev_conn_objects = s_conn_return_others (prev_conn_objects, new_net); } #if DEBUG s_conn_print(new_net->conn_list); #endif o_invalidate (w_current, new_net); o_invalidate_glist (w_current, prev_conn_objects); g_list_free (prev_conn_objects); prev_conn_objects = NULL; /* you don't want to consolidate nets which are drawn non-ortho */ if (toplevel->net_consolidate == TRUE && !w_current->CONTROLKEY) { /* CAUTION: Object list will change when nets are consolidated, don't * keep pointers to other objects than new_net after this. */ o_net_consolidate_segments(toplevel, new_net); } } toplevel->page_current->CHANGED = 1; w_current->first_wx = save_wx; w_current->first_wy = save_wy; o_undo_savestate(w_current, UNDO_ALL); return (TRUE); }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * */ void o_place_end (GSCHEM_TOPLEVEL *w_current, int w_x, int w_y, int continue_placing, GList **ret_new_objects, const char* hook_name) { TOPLEVEL *toplevel = w_current->toplevel; int w_diff_x, w_diff_y; OBJECT *o_current; PAGE *p_current; GList *temp_dest_list = NULL; GList *connected_objects = NULL; GList *iter; /* erase old image */ /* o_place_invaidate_rubber (w_current, FALSE); */ w_current->rubber_visible = 0; /* Calc final object positions */ w_current->second_wx = w_x; w_current->second_wy = w_y; w_diff_x = w_current->second_wx - w_current->first_wx; w_diff_y = w_current->second_wy - w_current->first_wy; if (continue_placing) { /* Make a copy of the place list if we want to keep it afterwards */ temp_dest_list = o_glist_copy_all (toplevel, toplevel->page_current->place_list, temp_dest_list); } else { /* Otherwise just take it */ temp_dest_list = toplevel->page_current->place_list; toplevel->page_current->place_list = NULL; } if (ret_new_objects != NULL) { *ret_new_objects = g_list_copy (temp_dest_list); } o_glist_translate_world(toplevel, w_diff_x, w_diff_y, temp_dest_list); /* Attach each item back onto the page's object list. Update object * connectivity and add the new objects to the selection list.*/ p_current = toplevel->page_current; for (iter = temp_dest_list; iter != NULL; iter = g_list_next (iter)) { o_current = iter->data; s_page_append (toplevel, p_current, o_current); /* Update object connectivity */ s_conn_update_object (toplevel, o_current); connected_objects = s_conn_return_others (connected_objects, o_current); } if (hook_name != NULL) { g_run_hook_object_list (hook_name, temp_dest_list); } o_invalidate_glist (w_current, connected_objects); g_list_free (connected_objects); connected_objects = NULL; toplevel->page_current->CHANGED = 1; o_invalidate_glist (w_current, temp_dest_list); /* only redraw new objects */ g_list_free (temp_dest_list); o_undo_savestate (w_current, UNDO_ALL); i_update_menus (w_current); }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * */ void o_move_end(GschemToplevel *w_current) { GschemPageView *page_view = gschem_toplevel_get_current_page_view (w_current); g_return_if_fail (page_view != NULL); PAGE *page = gschem_page_view_get_page (page_view); g_return_if_fail (page != NULL); GList *s_current = NULL; OBJECT *object; int diff_x, diff_y; GList *s_iter; GList *rubbernet_objects = NULL; gboolean net_rubber_band_mode; g_return_if_fail (w_current != NULL); g_return_if_fail (page != NULL); g_assert (w_current->inside_action != 0); object = o_select_return_first_object(w_current); if (!object) { /* actually this is an error condition hack */ i_action_stop (w_current); i_set_state(w_current, SELECT); return; } diff_x = w_current->second_wx - w_current->first_wx; diff_y = w_current->second_wy - w_current->first_wy; o_move_invalidate_rubber (w_current, FALSE); w_current->rubber_visible = 0; net_rubber_band_mode = gschem_options_get_net_rubber_band_mode (w_current->options); if (net_rubber_band_mode) { o_move_end_rubberband (w_current, diff_x, diff_y, &rubbernet_objects); } /* Unset the dont_redraw flag on rubberbanded objects. * We set this above, in o_move_start(). */ for (s_iter = w_current->stretch_list; s_iter != NULL; s_iter = g_list_next (s_iter)) { STRETCH *stretch = s_iter->data; stretch->object->dont_redraw = FALSE; } s_current = geda_list_get_glist( page->selection_list ); while (s_current != NULL) { object = (OBJECT *) s_current->data; if (object == NULL) { fprintf(stderr, _("ERROR: NULL object in o_move_end!\n")); exit(-1); } switch (object->type) { case (OBJ_COMPLEX): case (OBJ_PLACEHOLDER): /* TODO: Fix so we can just pass the complex to o_move_end_lowlevel, * IE.. by falling through the bottom of this case statement. */ /* this next section of code is from */ /* o_complex_world_translate_world */ object->complex->x = object->complex->x + diff_x; object->complex->y = object->complex->y + diff_y; o_move_end_lowlevel_glist (w_current, object->complex->prim_objs, diff_x, diff_y); object->w_bounds_valid_for = NULL; break; default: o_move_end_lowlevel (w_current, object, diff_x, diff_y); break; } s_current = g_list_next(s_current); } /* Draw the objects that were moved */ o_invalidate_glist (w_current, geda_list_get_glist (page->selection_list)); /* Draw the connected nets/buses that were also changed */ o_invalidate_glist (w_current, rubbernet_objects); /* Call move-objects-hook for moved objects and changed connected * nets/buses */ GList *moved_list = g_list_concat (page->place_list, rubbernet_objects); page->place_list = NULL; rubbernet_objects = NULL; g_run_hook_object_list (w_current, "%move-objects-hook", moved_list); g_list_free (moved_list); gschem_toplevel_page_content_changed (w_current, page); o_undo_savestate_old(w_current, UNDO_ALL); s_stretch_destroy_all (w_current->stretch_list); w_current->stretch_list = NULL; i_set_state(w_current, SELECT); i_action_stop (w_current); }