/*! \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); } }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * */ gint x_event_button_released (GschemPageView *page_view, GdkEventButton *event, GschemToplevel *w_current) { PAGE *page = gschem_page_view_get_page (page_view); int unsnapped_wx, unsnapped_wy; int w_x, w_y; g_return_val_if_fail ((page_view != NULL), 0); g_return_val_if_fail ((w_current != NULL), 0); if (page == NULL) { return TRUE; /* terminate event */ } #if DEBUG printf("released! %d \n", w_current->event_state); #endif w_current->SHIFTKEY = (event->state & GDK_SHIFT_MASK ) ? 1 : 0; w_current->CONTROLKEY = (event->state & GDK_CONTROL_MASK) ? 1 : 0; w_current->ALTKEY = (event->state & GDK_MOD1_MASK) ? 1 : 0; gschem_page_view_SCREENtoWORLD (page_view, (int) event->x, (int) event->y, &unsnapped_wx, &unsnapped_wy); w_x = snap_grid (w_current, unsnapped_wx); w_y = snap_grid (w_current, unsnapped_wy); /* Huge switch statement to evaluate state transitions. Jump to * end_button_released label to escape the state evaluation rather * than returning from the function directly. */ scm_dynwind_begin ((scm_t_dynwind_flags) 0); g_dynwind_window (w_current); if (event->button == 1) { if (w_current->inside_action) { if (page->place_list != NULL) { switch(w_current->event_state) { case (COPYMODE) : case (MCOPYMODE) : o_copy_end(w_current); break; case (MOVEMODE) : o_move_end(w_current); break; default: break; } } else { switch(w_current->event_state) { case (GRIPS) : o_grips_end(w_current); break; case (PATHMODE) : o_path_end (w_current, w_x, w_y); break; case (SBOX) : o_select_box_end(w_current, unsnapped_wx, unsnapped_wy); break; case (SELECT) : o_select_end(w_current, unsnapped_wx, unsnapped_wy); break; case (ZOOMBOX) : a_zoom_box_end(w_current, unsnapped_wx, unsnapped_wy); break; default: break; } } } } else if (event->button == 2) { if (w_current->inside_action) { if (w_current->event_state == COMPMODE|| w_current->event_state == TEXTMODE|| w_current->event_state == MOVEMODE|| w_current->event_state == COPYMODE || w_current->event_state == MCOPYMODE || w_current->event_state == PASTEMODE ) { if (w_current->event_state == MOVEMODE) { o_move_invalidate_rubber (w_current, FALSE); } else { o_place_invalidate_rubber (w_current, FALSE); } w_current->rubber_visible = 0; o_place_rotate(w_current); if (w_current->event_state == COMPMODE) { o_complex_place_changed_run_hook (w_current); } if (w_current->event_state == MOVEMODE) { o_move_invalidate_rubber (w_current, TRUE); } else { o_place_invalidate_rubber (w_current, TRUE); } w_current->rubber_visible = 1; goto end_button_released; } } switch(w_current->middle_button) { case(ACTION): if (w_current->inside_action && (page->place_list != NULL)) { switch(w_current->event_state) { case (COPYMODE): o_copy_end(w_current); break; case (MOVEMODE): o_move_end(w_current); break; } } break; #ifdef HAVE_LIBSTROKE case(STROKE): DOING_STROKE = FALSE; x_stroke_translate_and_execute (w_current); break; #endif /* HAVE_LIBSTROKE */ case(MID_MOUSEPAN_ENABLED): if (gschem_page_view_pan_end (page_view) && w_current->undo_panzoom) { o_undo_savestate_old(w_current, UNDO_VIEWPORT_ONLY); } break; } } else if (event->button == 3) { /* just for ending a mouse pan */ if (gschem_page_view_pan_end (page_view) && w_current->undo_panzoom) { o_undo_savestate_old(w_current, UNDO_VIEWPORT_ONLY); } } end_button_released: scm_dynwind_end (); return(0); }
/*! \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); }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * */ void o_move_motion (GschemToplevel *w_current, int w_x, int w_y) { GList *selection, *s_current; OBJECT *object; gint object_x, object_y; gboolean resnap = FALSE; SNAP_STATE snap_mode; 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); g_return_if_fail (page->place_list != NULL); snap_mode = gschem_options_get_snap_mode (w_current->options); selection = geda_list_get_glist (page->selection_list); /* realign the object if we are in resnap mode */ if ((selection != NULL) && (snap_mode == SNAP_RESNAP)) { if (g_list_length(selection) > 1) { /* find an object that is not attached to any other object */ for (s_current = selection; s_current != NULL; s_current = g_list_next(s_current)) { if (((OBJECT *) s_current->data)->attached_to == NULL) { object = (OBJECT *) s_current->data; resnap = TRUE; break; } } /* Only resnap single elements. This is also the case if the selection contains one object and all other object elements are attributes of the object element.*/ for (s_current = selection; s_current != NULL && resnap == TRUE; s_current = g_list_next(s_current)) { if (!(object == (OBJECT *) s_current->data) && !o_attrib_is_attached(page->toplevel, (OBJECT *) s_current->data, object)) { resnap = FALSE; } } } else { /* single object */ resnap = TRUE; object = (OBJECT *) selection->data; } /* manipulate w_x and w_y in a way that will lead to a position of the object that is aligned with the grid */ if (resnap) { if (o_get_position(page->toplevel, &object_x, &object_y, object)) { w_x += snap_grid (w_current, object_x) - object_x; w_y += snap_grid (w_current, object_y) - object_y; } } } o_move_invalidate_rubber (w_current, FALSE); w_current->second_wx = w_x; w_current->second_wy = w_y; o_move_invalidate_rubber (w_current, TRUE); }
/*! \brief Handle motion during a move operation, resnapping if necessary * \par Function Description * Handle movement during a move operation, by updating the global * candidate transformation parameters. The \a w_x and \b w_y * parameters are the incremental translation to be handled. * * This function mostly exists to implement the "resnapping" logic, * which destructively puts objects back onto the grid during a move * operation, as long as specific criteria are met. * * \param w_current Global gschem state structure. * \param w_x X-axis translation * \param w_y Y-axis translation */ void o_move_motion (GschemToplevel *w_current, int w_x, int w_y) { GList *selection, *s_current; OBJECT *object = NULL; gint object_x, object_y; SNAP_STATE snap_mode; 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); g_return_if_fail (page->place_list != NULL); snap_mode = gschem_options_get_snap_mode (w_current->options); selection = geda_list_get_glist (page->selection_list); /* There are three posssibilities: * * 1. There is exactly one object selected, in which case it is * snapped. * * 2. There are multiple objects selected, but there is some object * O[i] such that all other selected objects O[j!=i] are attached * as attributes of O[i]. In that case, the O[i] is snapped. * * 3. Other cases, in which case no snapping occurs. */ if (NULL == selection || SNAP_RESNAP != snap_mode) { object = NULL; } else if (1 == g_list_length (selection)) { object = (OBJECT *) selection->data; } else { /* The object that things are supposed to be attached to */ OBJECT *attached = NULL; /* Scan the selection, searching for an object that's not attached * to any other object. As we go, also check whether everything * in the list that *is* attached as an attribute is attached to * the same object. */ for (s_current = selection; NULL != s_current; s_current = g_list_next (s_current)) { OBJECT *candidate = (OBJECT *) s_current->data; if (NULL == candidate->attached_to) { /* If the object is *not* attached as an attribute, then check * whether we previously found an independent object. If we * did, we can't do snapping, so give up. */ if (NULL == object) { object = candidate; } else if (candidate != object) { break; /* Give up */ } } else { /* If the object is attached as an attribute, then check if * it's attached as an attribute of the same object as * everything else is. If not, we can't do snapping, so give * up. */ if (NULL == attached) { attached = candidate->attached_to; } else if (attached != candidate->attached_to) { break; /* Give up */ } } } if (NULL == object || (NULL != attached && object != attached)) { object = NULL; } else { g_assert (NULL != object); } } /* manipulate w_x and w_y in a way that will lead to a position of the object that is aligned with the grid */ if (NULL != object) { if (geda_object_get_position (object, &object_x, &object_y)) { w_x += snap_grid (w_current, object_x) - object_x; w_y += snap_grid (w_current, object_y) - object_y; } } o_move_invalidate_rubber (w_current, FALSE); w_current->second_wx = w_x; w_current->second_wy = w_y; o_move_invalidate_rubber (w_current, TRUE); }