/* this cannot be called recursively */ void o_unlock(GschemToplevel *w_current) { OBJECT *object = NULL; GList *s_current = NULL; s_current = geda_list_get_glist( w_current->toplevel->page_current->selection_list ); while(s_current != NULL) { object = (OBJECT *) s_current->data; if (object) { /* only unlock if the object is locked */ if (object->selectable == FALSE) { object->selectable = TRUE; object->color = object->locked_color; object->locked_color = -1; gschem_toplevel_page_content_changed (w_current, w_current->toplevel->page_current); } else { s_log_message(_("Object already unlocked\n")); } } s_current = g_list_next(s_current); } o_undo_savestate_old(w_current, UNDO_ALL); }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * */ void o_edit_show_specific_text (GschemToplevel *w_current, const GList *o_list, const char *stext) { TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current); OBJECT *o_current; const GList *iter; iter = o_list; while (iter != NULL) { o_current = (OBJECT *)iter->data; if (o_current->type == OBJ_TEXT) { const gchar *str = o_text_get_string (w_current->toplevel, o_current); if (!strncmp (stext, str, strlen (stext))) { if (!o_is_visible (toplevel, o_current)) { o_set_visibility (toplevel, o_current, VISIBLE); o_text_recreate(toplevel, o_current); gschem_toplevel_page_content_changed (w_current, toplevel->page_current); } } } iter = g_list_next (iter); } o_undo_savestate_old(w_current, UNDO_ALL); }
/* This locks the entire selected list. It does lock components, but does NOT * change the color (of primatives of the components) though * this cannot be called recursively */ void o_lock(GschemToplevel *w_current) { OBJECT *object = NULL; GList *s_current = NULL; /* skip over head */ s_current = geda_list_get_glist( w_current->toplevel->page_current->selection_list ); while(s_current != NULL) { object = (OBJECT *) s_current->data; if (object) { /* check to see if locked_color is already being used */ if (object->locked_color == -1) { object->selectable = FALSE; object->locked_color = object->color; object->color = LOCK_COLOR; gschem_toplevel_page_content_changed (w_current, w_current->toplevel->page_current); } else { s_log_message(_("Object already locked\n")); } } s_current = g_list_next(s_current); } if (!w_current->SHIFTKEY) o_select_unselect_all(w_current); o_undo_savestate_old(w_current, UNDO_ALL); i_update_menus(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); } }
/*! \brief Allow the undo manager to process changes * * \param [in] w_current */ static void handle_undo (GschemToplevel *w_current) { TOPLEVEL *toplevel; g_return_if_fail (w_current != NULL); toplevel = gschem_toplevel_get_toplevel (w_current); g_return_if_fail (toplevel != NULL); gschem_toplevel_page_content_changed (w_current, toplevel->page_current); o_undo_savestate_old (w_current, UNDO_ALL); }
/*! \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 second corner of a picture. * The picture is 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>. * * The temporary picture frame is erased ; a new picture 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 (unused) * \param [in] w_y (unused) */ void o_picture_end(GschemToplevel *w_current, int w_x, int w_y) { TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current); OBJECT *new_obj; int picture_width, picture_height; int picture_left, picture_top; g_assert( w_current->inside_action != 0 ); /* erase the temporary picture */ /* o_picture_draw_rubber(w_current); */ w_current->rubber_visible = 0; picture_width = GET_PICTURE_WIDTH (w_current); picture_height = GET_PICTURE_HEIGHT(w_current); picture_left = GET_PICTURE_LEFT (w_current); picture_top = GET_PICTURE_TOP (w_current); /* pictures with null width and height are not allowed */ if ((picture_width == 0) && (picture_height == 0)) { /* cancel the object creation */ return; } /* create the object */ new_obj = o_picture_new(toplevel, NULL, 0, w_current->pixbuf_filename, OBJ_PICTURE, picture_left, picture_top, picture_left + picture_width, picture_top - picture_height, 0, FALSE, FALSE); s_page_append (toplevel, toplevel->page_current, new_obj); /* Run %add-objects-hook */ g_run_hook_object (w_current, "%add-objects-hook", new_obj); gschem_toplevel_page_content_changed (w_current, toplevel->page_current); o_undo_savestate_old(w_current, UNDO_ALL); }
/*! \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 * * \param [in] widget The GschemPageView with the scroll event. * \param [in] event * \param [in] w_current */ gint x_event_scroll (GtkWidget *widget, GdkEventScroll *event, GschemToplevel *w_current) { GtkAdjustment *adj; gboolean pan_xaxis = FALSE; gboolean pan_yaxis = FALSE; gboolean zoom = FALSE; int pan_direction = 1; int zoom_direction = ZOOM_IN; GschemPageView *view = NULL; PAGE *page = NULL; g_return_val_if_fail ((w_current != NULL), 0); view = GSCHEM_PAGE_VIEW (widget); g_return_val_if_fail ((view != NULL), 0); page = gschem_page_view_get_page (view); if (page == NULL) { return FALSE; /* we cannot zoom page if it doesn't exist :) */ } /* update the state of the modifiers */ 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; if (w_current->scroll_wheel == SCROLL_WHEEL_CLASSIC) { /* Classic gschem behaviour */ zoom = !w_current->CONTROLKEY && !w_current->SHIFTKEY; pan_yaxis = !w_current->CONTROLKEY && w_current->SHIFTKEY; pan_xaxis = w_current->CONTROLKEY && !w_current->SHIFTKEY; } else { /* GTK style behaviour */ zoom = w_current->CONTROLKEY && !w_current->SHIFTKEY; pan_yaxis = !w_current->CONTROLKEY && !w_current->SHIFTKEY; pan_xaxis = !w_current->CONTROLKEY && w_current->SHIFTKEY; } /* If the user has a left/right scroll wheel, always scroll the y-axis */ if (event->direction == GDK_SCROLL_LEFT || event->direction == GDK_SCROLL_RIGHT) { zoom = FALSE; pan_yaxis = FALSE; pan_xaxis = TRUE; } /* You must have scrollbars enabled if you want to use the scroll wheel to pan */ if (!w_current->scrollbars_flag) { pan_xaxis = FALSE; pan_yaxis = FALSE; } switch (event->direction) { case GDK_SCROLL_UP: case GDK_SCROLL_LEFT: pan_direction = -1; zoom_direction = ZOOM_IN; break; case GDK_SCROLL_DOWN: case GDK_SCROLL_RIGHT: pan_direction = 1; zoom_direction = ZOOM_OUT; break; } if (zoom) { /*! \todo Change "HOTKEY" TO new "MOUSE" specifier? */ a_zoom(w_current, GSCHEM_PAGE_VIEW (widget), zoom_direction, HOTKEY); } if (pan_xaxis) { adj = gschem_page_view_get_hadjustment (GSCHEM_PAGE_VIEW (widget)); g_return_val_if_fail (adj != NULL, TRUE); gtk_adjustment_set_value(adj, MIN(adj->value + pan_direction * (adj->page_increment / w_current->scrollpan_steps), adj->upper - adj->page_size)); } if (pan_yaxis) { adj = gschem_page_view_get_vadjustment (GSCHEM_PAGE_VIEW (widget)); g_return_val_if_fail (adj != NULL, TRUE); gtk_adjustment_set_value(adj, MIN(adj->value + pan_direction * (adj->page_increment / w_current->scrollpan_steps), adj->upper - adj->page_size)); } if (w_current->undo_panzoom && (zoom || pan_xaxis || pan_yaxis)) { o_undo_savestate_old(w_current, UNDO_VIEWPORT_ONLY); } x_event_faked_motion (view, NULL); /* Stop further processing of this signal */ return 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); }
/*! \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. */ void o_net_end(GschemToplevel *w_current, int w_x, int w_y) { int primary_zero_length, secondary_zero_length; int found_primary_connection = FALSE; int save_wx, save_wy; GList *prev_conn_objects; OBJECT *new_net = NULL; /* Save a list of added objects to run the %add-objects-hook later */ GList *added_objects = 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); 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 ) { o_net_reset(w_current); return; } save_wx = w_current->third_wx; save_wy = w_current->third_wy; 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(page->toplevel, OBJ_NET, NET_COLOR, w_current->first_wx, w_current->first_wy, w_current->second_wx, w_current->second_wy); s_page_append (page->toplevel, page, new_net); added_objects = g_list_prepend (added_objects, new_net); /* conn stuff */ /* LEAK CHECK 1 */ prev_conn_objects = s_conn_return_others (NULL, new_net); o_net_add_busrippers (w_current, new_net, prev_conn_objects); g_list_free (prev_conn_objects); #if DEBUG printf("primary:\n"); s_conn_print(new_net->conn_list); #endif /* 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; } } /* 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(page->toplevel, OBJ_NET, NET_COLOR, w_current->second_wx, w_current->second_wy, w_current->third_wx, w_current->third_wy); s_page_append (page->toplevel, page, new_net); added_objects = g_list_prepend (added_objects, new_net); /* conn stuff */ /* LEAK CHECK 2 */ prev_conn_objects = s_conn_return_others (NULL, new_net); o_net_add_busrippers (w_current, new_net, prev_conn_objects); g_list_free (prev_conn_objects); #if DEBUG s_conn_print(new_net->conn_list); #endif } /* Call add-objects-hook */ if (added_objects != NULL) { g_run_hook_object_list (w_current, "%add-objects-hook", added_objects); g_list_free (added_objects); } w_current->first_wx = save_wx; w_current->first_wy = save_wy; gschem_toplevel_page_content_changed (w_current, page); o_undo_savestate_old(w_current, UNDO_ALL); /* Continue net drawing */ o_net_start(w_current, w_current->first_wx, w_current->first_wy); }
/*! \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); }
/*! \brief Handles all the options of the autonumber text dialog * \par Function Description * This function is the master of all autonumber code. It receives the options of * the the autonumber text dialog in an <B>AUTONUMBER_TEXT</B> structure. * First it collects all pages of a hierarchical schematic. * Second it gets all matching text elements for the searchtext. * Then it renumbers all text elements of all schematic pages. The renumbering * follows the rules of the parameters given in the autonumber text dialog. */ void autonumber_text_autonumber(AUTONUMBER_TEXT *autotext) { GList *pages; GList *searchtext_list=NULL; GList *text_item, *obj_item, *page_item; OBJECT *o_current; GschemToplevel *w_current; gchar *searchtext; gchar *scope_text; gchar *new_searchtext; gint i, number, slot; GList *o_list = NULL; const GList *iter; w_current = autotext->w_current; autotext->current_searchtext = NULL; autotext->root_page = 1; autotext->used_numbers = NULL; autotext->free_slots = NULL; autotext->used_slots = NULL; scope_text = g_list_first(autotext->scope_text)->data; /* Step1: get all pages of the hierarchy */ pages = s_hierarchy_traversepages (w_current->toplevel, w_current->toplevel->page_current, HIERARCHY_NODUPS); /* g_list_foreach(pages, (GFunc) s_hierarchy_print_page, NULL); */ /* Step2: if searchtext has an asterisk at the end we have to find all matching searchtextes. Example: "refdes=*" will match each text that starts with "refdes=" and has a trailing "?" or a trailing number if the "all"-option is set. We get a list of possible prefixes: refdes=R, refdes=C. If there is only one search pattern, it becomes a single item in the searchtext list */ if (strlen(scope_text) == 0) { s_log_message(_("No searchstring given in autonumber text.\n")); return; /* error */ } else if (g_str_has_suffix(scope_text,"?") == TRUE) { /* single searchtext, strip of the "?" */ searchtext = g_strndup(scope_text, strlen(scope_text)-1); searchtext_list=g_list_append (searchtext_list, searchtext); } else if (g_str_has_suffix(scope_text,"*") == TRUE) { /* strip of the "*" */ searchtext = g_strndup(scope_text, strlen(scope_text)-1); /* collect all the possible searchtexts in all pages of the hierarchy */ for (page_item = pages; page_item != NULL; page_item = g_list_next(page_item)) { s_page_goto(w_current->toplevel, page_item->data); gschem_toplevel_page_changed (w_current); /* iterate over all objects an look for matching searchtext's */ for (iter = s_page_objects (w_current->toplevel->page_current); iter != NULL; iter = g_list_next (iter)) { o_current = iter->data; if (o_current->type == OBJ_TEXT) { if (autotext->scope_number == SCOPE_HIERARCHY || autotext->scope_number == SCOPE_PAGE || ((autotext->scope_number == SCOPE_SELECTED) && (o_current->selected))) { const gchar *str = o_text_get_string (w_current->toplevel, o_current); if (g_str_has_prefix (str, searchtext)) { /* the beginnig of the current text matches with the searchtext now */ /* strip of the trailing [0-9?] chars and add it too the searchtext */ for (i = strlen (str)-1; (i >= strlen(searchtext)) && (str[i] == '?' || isdigit( (int) (str[i]) )); i--) ; /* void */ new_searchtext = g_strndup (str, i+1); if (g_list_find_custom(searchtext_list, new_searchtext, (GCompareFunc) strcmp) == NULL ) { searchtext_list = g_list_append(searchtext_list, new_searchtext); } else { g_free(new_searchtext); } } } } } if (autotext->scope_number == SCOPE_SELECTED || autotext->scope_number == SCOPE_PAGE) break; /* search only in the first page */ } g_free(searchtext); } else { s_log_message(_("No '*' or '?' given at the end of the autonumber text.\n")); return; } /* Step3: iterate over the search items in the list */ for (text_item=searchtext_list; text_item !=NULL; text_item=g_list_next(text_item)) { autotext->current_searchtext = text_item->data; /* printf("autonumber_text_autonumber: searchtext %s\n", autotext->current_searchtext); */ /* decide whether to renumber page by page or get a global used-list */ if (autotext->scope_skip == SCOPE_HIERARCHY) { /* whole hierarchy database */ /* renumbering all means that no db is required */ if (!(autotext->scope_number == SCOPE_HIERARCHY && autotext->scope_overwrite)) { for (page_item = pages; page_item != NULL; page_item = g_list_next(page_item)) { autotext->root_page = (pages->data == page_item->data); s_page_goto(w_current->toplevel, page_item->data); gschem_toplevel_page_changed (w_current); autonumber_get_used(w_current, autotext); } } } /* renumber the elements */ for (page_item = pages; page_item != NULL; page_item = g_list_next(page_item)) { s_page_goto(w_current->toplevel, page_item->data); gschem_toplevel_page_changed (w_current); autotext->root_page = (pages->data == page_item->data); /* build a page database if we're numbering pagebypage or selection only*/ if (autotext->scope_skip == SCOPE_PAGE || autotext->scope_skip == SCOPE_SELECTED) { autonumber_get_used(w_current, autotext); } /* RENUMBER CODE FOR ONE PAGE AND ONE SEARCHTEXT*/ /* 1. get objects to renumber */ for (iter = s_page_objects (w_current->toplevel->page_current); iter != NULL; iter = g_list_next (iter)) { o_current = iter->data; if (autonumber_match(autotext, o_current, &number) == AUTONUMBER_RENUMBER) { /* put number into the used list */ o_list = g_list_append(o_list, o_current); } } /* 2. sort object list */ switch (autotext->order) { case AUTONUMBER_SORT_YX: o_list=g_list_sort(o_list, autonumber_sort_yx); break; case AUTONUMBER_SORT_YX_REV: o_list=g_list_sort(o_list, autonumber_sort_yx_rev); break; case AUTONUMBER_SORT_XY: o_list=g_list_sort(o_list, autonumber_sort_xy); break; case AUTONUMBER_SORT_XY_REV: o_list=g_list_sort(o_list, autonumber_sort_xy_rev); break; case AUTONUMBER_SORT_DIAGONAL: o_list=g_list_sort(o_list, autonumber_sort_diagonal); break; default: ; /* unsorted file order */ } /* 3. renumber/reslot the objects */ for(obj_item=o_list; obj_item != NULL; obj_item=g_list_next(obj_item)) { o_current= obj_item->data; if(autotext->removenum) { autonumber_remove_number(autotext, o_current); } else { /* get valid numbers from the database */ autonumber_get_new_numbers(autotext, o_current, &number, &slot); /* and apply it. TODO: join these two functions */ autonumber_apply_new_text(autotext, o_current, number, slot); } } g_list_free(o_list); o_list = NULL; /* destroy the page database */ if (autotext->scope_skip == SCOPE_PAGE || autotext->scope_skip == SCOPE_SELECTED) autonumber_clear_database(autotext); if (autotext->scope_number == SCOPE_SELECTED || autotext->scope_number == SCOPE_PAGE) break; /* only renumber the parent page (the first page) */ } autonumber_clear_database(autotext); /* cleanup */ } /* cleanup and redraw all*/ g_list_foreach(searchtext_list, (GFunc) g_free, NULL); g_list_free(searchtext_list); s_page_goto(w_current->toplevel, pages->data); /* go back to the root page */ gschem_toplevel_page_changed (w_current); gschem_page_view_invalidate_all (gschem_toplevel_get_current_page_view (w_current)); g_list_free(pages); o_undo_savestate_old(w_current, UNDO_ALL); }
/*! \brief Update a component. * * \par Function Description * Updates \a o_current to the latest version of the symbol available * in the symbol library, while preserving any attributes set in the * current schematic. On success, returns the new OBJECT which * replaces \a o_current on the page; \a o_current is deleted. On * failure, returns NULL, and \a o_current is left unchanged. * * \param [in] w_current The GschemToplevel object. * \param [in,out] o_current The OBJECT to be updated. * * \return the new OBJECT that replaces \a o_current. */ OBJECT * o_update_component (GschemToplevel *w_current, OBJECT *o_current) { TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current); OBJECT *o_new; PAGE *page; GList *new_attribs; GList *old_attribs; GList *iter; const CLibSymbol *clib; g_return_val_if_fail (o_current != NULL, NULL); g_return_val_if_fail (o_current->type == OBJ_COMPLEX, NULL); g_return_val_if_fail (o_current->complex_basename != NULL, NULL); page = o_get_page (toplevel, o_current); /* Force symbol data to be reloaded from source */ clib = s_clib_get_symbol_by_name (o_current->complex_basename); s_clib_symbol_invalidate_data (clib); if (clib == NULL) { s_log_message (_("Could not find symbol [%s] in library. Update failed.\n"), o_current->complex_basename); return NULL; } /* Unselect the old object. */ o_selection_remove (toplevel, page->selection_list, o_current); /* Create new object and set embedded */ o_new = o_complex_new (toplevel, OBJ_COMPLEX, DEFAULT_COLOR, o_current->complex->x, o_current->complex->y, o_current->complex->angle, o_current->complex->mirror, clib, o_current->complex_basename, 1); if (o_complex_is_embedded (o_current)) { o_embed (toplevel, o_new); } new_attribs = o_complex_promote_attribs (toplevel, o_new); /* Cull any attributes from new COMPLEX that are already attached to * old COMPLEX. Note that the new_attribs list is kept consistent by * setting GList data pointers to NULL if their OBJECTs are * culled. At the end, the new_attribs list is updated by removing * all list items with NULL data. This is slightly magic, but * works. */ for (iter = new_attribs; iter != NULL; iter = g_list_next (iter)) { OBJECT *attr_new = iter->data; gchar *name; gchar *value; g_assert (attr_new->type == OBJ_TEXT); o_attrib_get_name_value (attr_new, &name, NULL); value = o_attrib_search_attached_attribs_by_name (o_current, name, 0); if (value != NULL) { o_attrib_remove (toplevel, &o_new->attribs, attr_new); s_delete_object (toplevel, attr_new); iter->data = NULL; } g_free (name); g_free (value); } new_attribs = g_list_remove_all (new_attribs, NULL); /* Detach attributes from old OBJECT and attach to new OBJECT */ old_attribs = g_list_copy (o_current->attribs); o_attrib_detach_all (toplevel, o_current); o_attrib_attach_list (toplevel, old_attribs, o_new, 1); g_list_free (old_attribs); /* Add new attributes to page */ s_page_append_list (toplevel, page, new_attribs); /* Update pinnumbers for current slot */ s_slot_update_object (toplevel, o_new); /* Replace old OBJECT with new OBJECT */ s_page_replace (toplevel, page, o_current, o_new); s_delete_object (toplevel, o_current); /* Select new OBJECT */ o_selection_add (toplevel, page->selection_list, o_new); /* mark the page as modified */ gschem_toplevel_page_content_changed (w_current, toplevel->page_current); o_undo_savestate_old (w_current, UNDO_ALL); return o_new; }
/*! \brief Delete objects from the selection. * \par Function Description * This function deletes the objects selected on the current page of * toplevel \a w_current. * * \param [in] w_current The GschemToplevel object. */ void o_delete_selected (GschemToplevel *w_current) { TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current); SELECTION *selection = toplevel->page_current->selection_list; GList *to_remove; GList *iter; OBJECT *obj; unsigned int locked_num = 0; g_return_if_fail (o_select_selected (w_current)); to_remove = g_list_copy (geda_list_get_glist (selection)); for (iter = to_remove; iter != NULL; iter = g_list_next (iter)) { obj = (OBJECT *) iter->data; if (obj->selectable == FALSE) locked_num++; } if (locked_num > 0) { GList *non_locked = NULL; gint resp; GtkWidget *dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, ngettext ("Delete locked object?", "Delete %u locked objects?", locked_num), locked_num); gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_YES, GTK_RESPONSE_YES, GTK_STOCK_NO, GTK_RESPONSE_NO, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_NO); resp = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); switch (resp) { case GTK_RESPONSE_YES: /* Remove all */ break; case GTK_RESPONSE_NO: /* Remove non locked */ for (iter = to_remove; iter != NULL; iter = g_list_next (iter)) { obj = (OBJECT *) iter->data; if (obj->selectable == TRUE) non_locked = g_list_append (non_locked, iter->data); } g_list_free (to_remove); to_remove = non_locked; break; default: /* Cancel */ g_list_free (to_remove); return; } } for (iter = to_remove; iter != NULL; iter = g_list_next (iter)) { obj = (OBJECT *) iter->data; o_selection_remove (toplevel, selection, obj); s_page_remove (toplevel, toplevel->page_current, obj); } g_run_hook_object_list (w_current, "%remove-objects-hook", to_remove); for (iter = to_remove; iter != NULL; iter = g_list_next (iter)) { obj = (OBJECT *) iter->data; s_delete_object (toplevel, obj); } g_list_free (to_remove); gschem_toplevel_page_content_changed (w_current, toplevel->page_current); w_current->inside_action = 0; o_undo_savestate_old (w_current, UNDO_ALL); i_update_menus (w_current); }