/*! \todo Finish function documentation!!! * \brief * \par Function Description * */ void o_move_cancel (GschemToplevel *w_current) { 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); /* 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; } g_list_free(page->place_list); page->place_list = NULL; s_stretch_destroy_all (w_current->stretch_list); w_current->stretch_list = NULL; i_action_stop (w_current); }
/*! \brief Reset all variables used for net drawing * \par Function Description * This function resets all variables from GschemToplevel that are used * for net drawing. This function should be called when escaping from * a net drawing action or before entering it. */ void o_net_reset(GschemToplevel *w_current) { o_net_invalidate_rubber (w_current); w_current->first_wx = w_current->first_wy = -1; w_current->second_wx = w_current->second_wy = -1; w_current->third_wx = w_current->third_wy = -1; w_current->magnetic_wx = w_current->magnetic_wy = -1; w_current->rubber_visible = 0; i_action_stop (w_current); }
/*! \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 a_zoom_box_end(GschemToplevel *w_current, int x, int y) { g_assert( w_current->inside_action != 0 ); a_zoom_box_invalidate_rubber (w_current); w_current->rubber_visible = 0; a_zoom_box(w_current); if (w_current->undo_panzoom) { o_undo_savestate_old(w_current, UNDO_VIEWPORT_ONLY); } i_action_stop (w_current); i_set_state(w_current, SELECT); }
/*! \brief End the input of a circle. * \par Function Description * This function ends the input of the radius of the circle. * The (<B>w_x</B>,<B>w_y</B>) point is taken as the other end of the radius * segment, i.e. on the circle. The distance between this point and the * center is the radius of the circle. * <B>w_x</B> and <B>w_y</B> are in world coords. * * The center has previously been input and saved as * (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>). * * The temporary circle drawn during the input of the radius is erased. * A new object is allocated, initialized and linked in the object list. * This new object is finally drawn. * * \param [in] w_current The GschemToplevel object. * \param [in] w_x (unused) * \param [in] w_y (unused) */ void o_circle_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); /* erase the temporary circle */ /* o_circle_invalidate_rubber (w_current); */ w_current->rubber_visible = 0; /* circle with null radius are not allowed */ if (w_current->distance == 0) { /* cancel the object creation */ return; } /* create the object */ new_obj = geda_circle_object_new (toplevel, GRAPHIC_COLOR, w_current->first_wx, w_current->first_wy, w_current->distance); s_page_append (toplevel, page, new_obj); /* Call add-objects-hook */ g_run_hook_object (w_current, "%add-objects-hook", new_obj); gschem_toplevel_page_content_changed (w_current, page); o_undo_savestate(w_current, page, UNDO_ALL); i_action_stop (w_current); }
/*! \brief End the input of an arc. * \par Function Description * This function ends the input of the radius of the arc. * The (<B>w_x</B>,<B>w_y</B>) point is taken as the other end of the radius segment. * The distance between this point and the center is the radius of the arc. * <B>w_x</B> and <B>w_y</B> are in world coords. * * At the end of this function, the center of the arc is at * (<B>w_current->first_wx</B>,<B>w_current->first_wy</B>) and its radius is * <B>w_current->distance</B>. * * The two angles needs to be input to fully define the arc. * * \param [in] w_current The GschemToplevel object. * \param [in] w_x (unused) * \param [in] w_y (unused) */ void o_arc_end1(GschemToplevel *w_current, int w_x, int w_y) { g_assert( w_current->inside_action != 0 ); /* erases the previous temporary radius segment */ /* o_arc_invalidate_rubber (w_current); */ w_current->rubber_visible = 0; /* ack! zero length radius */ if (w_current->distance != 0) { #if DEBUG printf("DIST: %d\n", w_current->distance); #endif /* open a dialog to input the start and end angle */ arc_angle_dialog(w_current, NULL); } i_action_stop (w_current); }
/*! \brief End the input of a box. * \par Function Description * This function ends the input of the second corner of a box. * The (<B>w_x</B>,<B>w_y</B>) point is set to be this second corner. The box is * then defined by (<B>w_current->first_wx</B>,<B>w_current->first_wy</B> and * (<B>w_current->second_wx</B>,<B>w_current->second_wy</B>. * <B>w_x</B> and <B>w_y</B> are in screen unit. * * The temporary box is erased ; a new box object is allocated, initialized * and linked to the object list ; The object is finally drawn on the * current sheet. * * \param [in] w_current The GschemToplevel object. * \param [in] w_x Current x coordinate of pointer in world units. * \param [in] w_y Current y coordinate of pointer in world units. */ void o_box_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); int box_width, box_height; int box_left, box_top; /* get the last coords of the pointer */ w_current->second_wx = w_x; w_current->second_wy = w_y; /* erase the temporary box */ /* o_box_invalidate_rubber (w_current); */ w_current->rubber_visible = 0; box_width = GET_BOX_WIDTH (w_current); box_height = GET_BOX_HEIGHT(w_current); box_left = GET_BOX_LEFT (w_current); box_top = GET_BOX_TOP (w_current); /* boxes with null width or height are not allowed */ if ((box_width == 0) || (box_height == 0)) { /* cancel the object creation */ w_current->first_wx = (-1); w_current->first_wy = (-1); w_current->second_wx = (-1); w_current->second_wy = (-1); } else { /* create the object */ new_obj = geda_box_object_new (toplevel, OBJ_BOX, GRAPHIC_COLOR, box_left, box_top, box_left + box_width, box_top - box_height); s_page_append (toplevel, page, new_obj); #if DEBUG printf("coords: %d %d %d %d\n", box_left, box_top, box_width, box_height); #endif w_current->first_wx = (-1); w_current->first_wy = (-1); w_current->second_wx = (-1); w_current->second_wy = (-1); /* Call add-objects-hook */ g_run_hook_object (w_current, "%add-objects-hook", new_obj); gschem_toplevel_page_content_changed (w_current, page); o_undo_savestate(w_current, page, UNDO_ALL); } i_action_stop (w_current); }
/*! \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); } }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * */ gint x_event_button_pressed(GschemPageView *page_view, GdkEventButton *event, GschemToplevel *w_current) { PAGE *page = gschem_page_view_get_page (page_view); int w_x, w_y; int unsnapped_wx, unsnapped_wy; g_return_val_if_fail ((w_current != NULL), 0); if (page == NULL) { return TRUE; /* terminate event */ } if (!gtk_widget_has_focus (GTK_WIDGET (page_view))) { gtk_widget_grab_focus (GTK_WIDGET (page_view)); } scm_dynwind_begin ((scm_t_dynwind_flags) 0); g_dynwind_window (w_current); #if DEBUG printf("pressed button %d! \n", event->button); printf("event state: %d \n", event->state); printf("w_current state: %d \n", w_current->event_state); printf("Selection is:\n"); o_selection_print_all(&(page->selection_list)); printf("\n"); #endif 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); if (event->type == GDK_2BUTTON_PRESS && w_current->event_state == SELECT) { /* Don't re-select an object (lp-912978) */ /* o_find_object(w_current, w_x, w_y, TRUE); */ /* GDK_BUTTON_EVENT is emitted before GDK_2BUTTON_EVENT, which * leads to setting of the inside_action flag. If o_edit() * brings up a modal window (e.g., the edit attribute dialog), * it intercepts the release button event and thus doesn't * allow resetting of the inside_action flag so we do it * manually here before processing the double-click event. */ i_action_stop (w_current); o_edit(w_current, geda_list_get_glist( page->selection_list )); scm_dynwind_end (); return(0); } 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; /* Huge switch statement to evaluate state transitions. Jump to * end_button_pressed label to escape the state evaluation rather than * returning from the function directly. */ if (event->button == 1) { if (w_current->inside_action) { /* End action */ if (page->place_list != NULL) { switch(w_current->event_state) { case (COMPMODE) : o_place_end(w_current, w_x, w_y, w_current->continue_component_place, "%add-objects-hook"); break; case (TEXTMODE) : o_place_end(w_current, w_x, w_y, FALSE, "%add-objects-hook"); break; case (PASTEMODE) : o_place_end(w_current, w_x, w_y, FALSE, "%paste-objects-hook"); break; default: break; } } else { switch(w_current->event_state) { case (ARCMODE) : o_arc_end1(w_current, w_x, w_y); break; case (BOXMODE) : o_box_end(w_current, w_x, w_y); break; case (BUSMODE) : o_bus_end(w_current, w_x, w_y); break; case (CIRCLEMODE) : o_circle_end(w_current, w_x, w_y); break; case (LINEMODE) : o_line_end(w_current, w_x, w_y); break; case (NETMODE) : o_net_end(w_current, w_x, w_y); break; case (PATHMODE) : o_path_continue (w_current, w_x, w_y); break; case (PICTUREMODE): o_picture_end(w_current, w_x, w_y); break; case (PINMODE) : o_pin_end (w_current, w_x, w_y); break; default: break; } } } else { /* Start action */ switch(w_current->event_state) { case (ARCMODE) : o_arc_start(w_current, w_x, w_y); break; case (BOXMODE) : o_box_start(w_current, w_x, w_y); break; case (BUSMODE) : o_bus_start(w_current, w_x, w_y); break; case (CIRCLEMODE) : o_circle_start(w_current, w_x, w_y); break; case (LINEMODE) : o_line_start(w_current, w_x, w_y); break; case (NETMODE) : o_net_start(w_current, w_x, w_y); break; case (PATHMODE) : o_path_start (w_current, w_x, w_y); break; case (PICTUREMODE): o_picture_start(w_current, w_x, w_y); break; case (PINMODE) : o_pin_start (w_current, w_x, w_y); break; case (ZOOMBOX) : a_zoom_box_start(w_current, unsnapped_wx, unsnapped_wy); break; case (SELECT) : o_select_start(w_current, w_x, w_y); break; case (COPYMODE) : case (MCOPYMODE) : o_copy_start(w_current, w_x, w_y); break; case (MOVEMODE) : o_move_start(w_current, w_x, w_y); break; default: break; } } switch(w_current->event_state) { case(ROTATEMODE): o_rotate_world_update(w_current, w_x, w_y, 90, geda_list_get_glist(page->selection_list)); break; case(MIRRORMODE): o_mirror_world_update(w_current, w_x, w_y, geda_list_get_glist(page->selection_list)); break; case(PAN): gschem_page_view_pan (page_view, w_x, w_y); i_set_state(w_current, SELECT); break; } } else if (event->button == 2) { /* try this out and see how it behaves */ 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 )) { i_callback_cancel(w_current, 0, NULL); } goto end_button_pressed; } switch(w_current->middle_button) { case(ACTION): /* don't want to search if shift */ /* key is pressed */ if (!w_current->SHIFTKEY) { o_find_object(w_current, unsnapped_wx, unsnapped_wy, TRUE); } /* make sure the list is not empty */ if (!o_select_selected(w_current)) { /* this means the above find did not * find anything */ i_action_stop (w_current); i_set_state(w_current, SELECT); goto end_button_pressed; } /* determine here if copy or move */ if (w_current->ALTKEY) { i_set_state(w_current, COPYMODE); o_copy_start(w_current, w_x, w_y); } else { o_move_start(w_current, w_x, w_y); } break; case(REPEAT): if (w_current->last_callback != NULL) { (*w_current->last_callback)(w_current, 0, NULL); } break; #ifdef HAVE_LIBSTROKE case(STROKE): DOING_STROKE=TRUE; break; #endif /* HAVE_LIBSTROKE */ case(MID_MOUSEPAN_ENABLED): gschem_page_view_pan_start (page_view, (int) event->x, (int) event->y); break; } } else if (event->button == 3) { if (!w_current->inside_action) { if (w_current->third_button == POPUP_ENABLED) { /* (third-button "popup") */ i_update_menus(w_current); /* update menus before popup */ do_popup(w_current, event); } else { /* (third-button "mousepan") */ gschem_page_view_pan_start (page_view, (int) event->x, (int) event->y); } } else { if ((w_current->third_button == MOUSEPAN_ENABLED) && (!w_current->third_button_cancel)) { gschem_page_view_pan_start (page_view, (int) event->x, (int) event->y); } else { /* this is the default cancel */ /* reset all draw and place actions */ switch (w_current->event_state) { case (ARCMODE) : o_arc_invalidate_rubber (w_current); break; case (BOXMODE) : o_box_invalidate_rubber (w_current); break; case (BUSMODE) : o_bus_invalidate_rubber (w_current); break; case (CIRCLEMODE) : o_circle_invalidate_rubber (w_current); break; case (LINEMODE) : o_line_invalidate_rubber (w_current); break; case (NETMODE) : o_net_reset (w_current); break; case (PATHMODE) : o_path_invalidate_rubber (w_current); break; case (PICTUREMODE): o_picture_invalidate_rubber (w_current); break; case (PINMODE) : o_pin_invalidate_rubber (w_current); break; default: i_callback_cancel(w_current, 0, NULL); break; } } } } end_button_pressed: 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); }