/*! \brief Delete text object * * Delete the text object pointed to by text_object. This function * was shamelessly stolen from gschem/src/o_delete.c and hacked * for gattrib by SDB. * \param toplevel TOPLEVEL to be operated on * \param test_object text object to be deleted */ void s_object_delete_text_object_in_object (TOPLEVEL *toplevel, OBJECT * text_object) { s_page_remove (toplevel, toplevel->page_current, text_object); s_delete_object (toplevel, text_object); toplevel->page_current->CHANGED = 1; }
/*! \brief Free a gEDA smob. * \par Function Description * Finalizes a gEDA smob for deletion, removing the weak reference. * * Used internally to Guile. */ static size_t smob_free (SCM smob) { void *data; /* If the weak reference has already been cleared, do nothing */ if (!EDASCM_SMOB_VALIDP(smob)) return 0; data = (void *) SCM_SMOB_DATA (smob); /* Otherwise, clear the weak reference */ switch (EDASCM_SMOB_TYPE (smob)) { case GEDA_SMOB_TOPLEVEL: s_toplevel_weak_unref ((TOPLEVEL *) data, smob_weakref_notify, smob); break; case GEDA_SMOB_PAGE: s_page_weak_unref ((PAGE *) data, smob_weakref_notify, smob); break; case GEDA_SMOB_OBJECT: /* See edascm_from_object() for an explanation of why OBJECT * smobs store a TOPLEVEL in the second data word */ s_object_weak_unref ((OBJECT *) data, smob_weakref_notify, smob); s_toplevel_weak_unref ((TOPLEVEL *) SCM_SMOB_DATA_2 (smob), smob_weakref2_notify, smob); break; default: /* This should REALLY definitely never be run */ g_critical ("%s: received bad smob flags.", __FUNCTION__); } /* If the smob is marked as garbage-collectable, destroy its * contents. * * Because PAGEs and TOPLEVELs should never be garbage collected, * emit critical warnings if the GC tries to free them. */ if (EDASCM_SMOB_GCP (smob)) { switch (EDASCM_SMOB_TYPE (smob)) { case GEDA_SMOB_TOPLEVEL: g_critical ("%s: Blocked garbage-collection of TOPLEVEL %p", __FUNCTION__, data); break; case GEDA_SMOB_PAGE: g_critical ("%s: Blocked garbage-collection of PAGE %p", __FUNCTION__, data); break; case GEDA_SMOB_OBJECT: /* See edascm_from_object() for an explanation of why OBJECT * smobs store a TOPLEVEL in the second data word */ s_delete_object ((TOPLEVEL *) SCM_SMOB_DATA_2 (smob), (OBJECT *) data); break; default: /* This should REALLY definitely never be run */ g_critical ("%s: received bad smob flags.", __FUNCTION__); } } return 0; }
/*! \brief Delete an object. * \par Function Description * This function erases the object \a object before deleting it. It * deals with connection and object connected to it. * * \param [in] w_current The GschemToplevel object. * \param [in] object The object to delete. */ void o_delete (GschemToplevel *w_current, OBJECT *object) { TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current); g_return_if_fail (object != NULL); o_selection_remove (toplevel, toplevel->page_current->selection_list, object); s_page_remove (toplevel, toplevel->page_current, object); g_run_hook_object (w_current, "%remove-objects-hook", object); s_delete_object (toplevel, object); gschem_toplevel_page_content_changed (w_current, toplevel->page_current); }
/* deletes everything include the GList */ void s_delete_object_glist(TOPLEVEL *toplevel, GList *list) { OBJECT *o_current=NULL; GList *ptr; ptr = g_list_last(list); /* do the delete backwards */ while(ptr != NULL) { o_current = (OBJECT *) ptr->data; s_delete_object(toplevel, o_current); ptr = g_list_previous (ptr); } g_list_free(list); }
/*! \brief Delete or hide promotable from the passed OBJECT * * \par Function Description * Deletes or hides promotable attributes from the passed OBJECT. * This is used when loading symbols during the load of a schematic from * disk. The schematic will already contain local copies of symbol's * promotable objects, so we delete or hide the symbol's copies. * * Deletion / hiding is dependant on the setting of * toplevel->keep_invisible. If true, attributes eligible for * promotion are kept in memory but flagged as invisible. * * \param [in] toplevel The toplevel environment. * \param [in] object The complex object being altered. */ static void o_complex_remove_promotable_attribs (TOPLEVEL *toplevel, OBJECT *object) { GList *promotable, *iter; promotable = o_complex_get_promotable (toplevel, object, FALSE); if (promotable == NULL) return; for (iter = promotable; iter != NULL; iter = g_list_next (iter)) { OBJECT *a_object = iter->data; if (toplevel->keep_invisible == TRUE) { /* Hide promotable attributes */ o_set_visibility (toplevel, a_object, INVISIBLE); } else { /* Delete promotable attributes */ object->complex->prim_objs = g_list_remove (object->complex->prim_objs, a_object); s_delete_object (toplevel, a_object); } } o_bounds_invalidate (toplevel, object); g_list_free (promotable); }
/*! \brief try to consolidate a net object * \par Function Description * This function tries to consolidate a net with any other object * that is connected to the current \a object. * * \param toplevel The TOPLEVEL object * \param object The object to consolidate * \return 0 if no consolidation was possible, -1 otherwise * */ static int o_net_consolidate_segments (TOPLEVEL *toplevel, OBJECT *object) { int object_orient; int other_orient; GList *c_current; CONN *conn; OBJECT *other_object; PAGE *page; int changed = 0; g_return_val_if_fail ((toplevel != NULL), 0); g_return_val_if_fail ((object != NULL), 0); g_return_val_if_fail ((object->type == OBJ_NET), 0); /* It's meaningless to do anything here if the object isn't in a page. */ page = o_get_page (toplevel, object); g_return_val_if_fail ((page != NULL), 0); object_orient = o_net_orientation(object); c_current = object->conn_list; while(c_current != NULL) { conn = (CONN *) c_current->data; other_object = conn->other_object; /* only look at end points which have a valid end on the other side */ if (other_object != NULL && conn->type == CONN_ENDPOINT && conn->other_whichone != -1 && conn->whichone != -1 && o_net_consolidate_nomidpoint(object, conn->x, conn->y) ) { if (other_object->type == OBJ_NET) { other_orient = o_net_orientation(other_object); /* - both objects have the same orientation (either vert or horiz) */ /* - it's not the same object */ if (object_orient == other_orient && object->sid != other_object->sid && other_orient != NEITHER) { #if DEBUG printf("consolidating %s to %s\n", object->name, other_object->name); #endif o_net_consolidate_lowlevel(object, other_object, other_orient); changed++; if (other_object->selected == TRUE ) { o_selection_remove (toplevel, page->selection_list, other_object); /* If we're consolidating with a selected object, * ensure we select the resulting object. */ if (object->selected == FALSE) { o_selection_add (toplevel, page->selection_list, object); } } s_delete_object (toplevel, other_object); o_net_recalc(toplevel, object); s_tile_update_object(toplevel, object); s_conn_update_object (toplevel, object); return(-1); } } } c_current = g_list_next (c_current); } return(0); }
/*! \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 GSCHEM_TOPLEVEL object. * \param [in,out] o_current The OBJECT to be updated. * * \return the new OBJECT that replaces \a o_current. */ OBJECT * o_update_component (GSCHEM_TOPLEVEL *w_current, OBJECT *o_current) { TOPLEVEL *toplevel = w_current->toplevel; 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); /* This should be replaced with API to invalidate only the specific * symbol name we want to update */ s_clib_flush_symbol_cache (); clib = s_clib_get_symbol_by_name (o_current->complex_basename); 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 */ toplevel->page_current->CHANGED = 1; o_undo_savestate (w_current, UNDO_ALL); return o_new; }
/*! \brief Free a gEDA smob. * \par Function Description * Finalizes a gEDA smob for deletion, removing the weak reference. * * Used internally to Guile. */ static size_t smob_free (SCM smob) { void *data; /* If the weak reference has already been cleared, do nothing */ if (!EDASCM_SMOB_VALIDP(smob)) return 0; data = (void *) SCM_SMOB_DATA (smob); /* If the smob is being finalized, it must not be in the cache! */ g_warn_if_fail (!smob_cache_contains (data)); /* Otherwise, clear the weak reference */ switch (EDASCM_SMOB_TYPE (smob)) { case GEDA_SMOB_TOPLEVEL: s_toplevel_weak_unref ((TOPLEVEL *) data, smob_weakref_notify, unpack_as_pointer (smob)); break; case GEDA_SMOB_PAGE: s_page_weak_unref ((PAGE *) data, smob_weakref_notify, unpack_as_pointer (smob)); break; case GEDA_SMOB_OBJECT: /* See edascm_from_object() for an explanation of why OBJECT * smobs store a TOPLEVEL in the second data word */ s_object_weak_unref ((OBJECT *) data, smob_weakref2_notify, unpack_as_pointer (smob)); break; case GEDA_SMOB_CONFIG: g_object_unref (G_OBJECT (data)); break; case GEDA_SMOB_CLOSURE: break; default: /* This should REALLY definitely never be run */ g_critical ("%s: received bad smob flags.", __FUNCTION__); } /* If the smob is marked as garbage-collectable, destroy its * contents. * * Because PAGEs and TOPLEVELs should never be garbage collected, * emit critical warnings if the GC tries to free them. */ if (EDASCM_SMOB_GCP (smob)) { switch (EDASCM_SMOB_TYPE (smob)) { case GEDA_SMOB_TOPLEVEL: g_critical ("%s: Blocked garbage-collection of TOPLEVEL %p", __FUNCTION__, data); break; case GEDA_SMOB_PAGE: g_critical ("%s: Blocked garbage-collection of PAGE %p", __FUNCTION__, data); break; case GEDA_SMOB_OBJECT: /* See edascm_from_object() for an explanation of why OBJECT * smobs store a TOPLEVEL in the second data word */ s_delete_object ((TOPLEVEL *) SCM_SMOB_DATA_2 (smob), (OBJECT *) data); break; case GEDA_SMOB_CONFIG: /* These are reference counted, so the structure will have * already been destroyed above if appropriate. */ break; case GEDA_SMOB_CLOSURE: break; default: /* This should REALLY definitely never be run */ g_critical ("%s: received bad smob flags.", __FUNCTION__); } } return 0; }
/*! \brief try to consolidate a net object * \par Function Description * This function tries to consolidate a net with any other object * that is connected to the current \a object. * * \param toplevel The TOPLEVEL object * \param object The object to consolidate * \return 0 if no consolidation was possible, -1 otherwise * */ int o_net_consolidate_segments(TOPLEVEL *toplevel, OBJECT *object) { int object_orient; int other_orient; GList *c_current; CONN *conn; OBJECT *other_object; int changed = 0; int reselect_new=FALSE; if (object == NULL) { return(0); } if (object->type != OBJ_NET) { return(0); } object_orient = o_net_orientation(object); c_current = object->conn_list; while(c_current != NULL) { conn = (CONN *) c_current->data; other_object = conn->other_object; /* only look at end points which have a valid end on the other side */ if (other_object != NULL && conn->type == CONN_ENDPOINT && conn->other_whichone != -1 && conn->whichone != -1 && o_net_consolidate_nomidpoint(object, conn->x, conn->y) ) { if (other_object->type == OBJ_NET) { other_orient = o_net_orientation(other_object); /* - both objects have the same orientation (either vert or horiz) */ /* - it's not the same object */ if (object_orient == other_orient && object->sid != other_object->sid && other_orient != NEITHER) { #if DEBUG printf("consolidating %s to %s\n", object->name, other_object->name); #endif o_net_consolidate_lowlevel(object, other_object, other_orient); changed++; if (other_object->selected == TRUE ) { o_selection_remove( toplevel->page_current->selection_list, other_object ); reselect_new=TRUE; } if (reselect_new == TRUE) { o_selection_remove( toplevel->page_current->selection_list, object ); o_selection_add( toplevel->page_current->selection_list, object ); } s_conn_remove_object (toplevel, other_object); s_page_remove (toplevel->page_current, other_object); s_delete_object (toplevel, other_object); o_net_recalc(toplevel, object); s_tile_update_object(toplevel, object); s_conn_update_object (toplevel, object); return(-1); } } } c_current = g_list_next (c_current); } return(0); }
/*! \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); }