/*! \brief Get an object's parent PAGE. * * \par Function Description * Returns the PAGE structure which owns \a object. If \a object is * not currently associated with a PAGE, returns NULL. If \a object is * part of a compound object, recurses upward. * * \param [in] toplevel The TOPLEVEL structure. * \param [in] object The OBJECT for which to retrieve the parent PAGE. * \return The PAGE which owns \a object or NULL. * * \sa s_page_append_object() s_page_append() s_page_remove() */ PAGE * o_get_page (TOPLEVEL *toplevel, OBJECT *object) { if (object->parent != NULL) { return o_get_page (toplevel, object->parent); } return object->page; }
/*! \brief Get an object's parent PAGE, or fall back to global current page. * * \par Function Description * If set, returns the PAGE structure which owns \a object. If \a * object does not have a parent page set, returns the global current * page from \a toplevel. If the object parent page is inconsistent * with the global current page, a critical-level error message is * emitted. * * \warning This function is primarily intended to assist in the * migration of code from using the TOPLEVEL current page to using the * o_get_page(). It should not be used in new code. * * \deprecated Use o_get_page() in new code. * * \param [in] toplevel The TOPLEVEL structure. * \param [in] object The OBJECT for which to retrieve the parent PAGE. * \return The PAGE which owns \a object, the global current PAGE, or NULL. */ PAGE * o_get_page_compat (TOPLEVEL *toplevel, OBJECT *object) { PAGE *page = o_get_page (toplevel, object); if (page != toplevel->page_current) { g_critical ("o_get_page_compat: OBJECT.page = %p, TOPLEVEL.page_current = %p", page, toplevel->page_current); return toplevel->page_current; } else { return page; } }
/*! \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 add a line object to the tiles * \par Function Description * This function takes a single line object and adds it to * every tile that is touched by the line. * It also adds all tiles that are touched by the object to * the objects tile list. * \param toplevel The TOPLEVEL structure * \param object The line OBJECT to add */ static void s_tile_add_line_object (TOPLEVEL *toplevel, OBJECT *object) { TILE *t_current; PAGE *p_current; GList *found; int i, j; int v, w; double x1, y1, x2, y2; double bottom; double m, b; double x_size, y_size; double x, y; int start, end; #if DEBUG printf("name: %s\n", object->name); #endif g_return_if_fail (object != NULL); g_return_if_fail (object->line != NULL); p_current = o_get_page (toplevel, object); if (p_current == NULL) { return; } x_size = (double) toplevel->init_right / (double) MAX_TILES_X; y_size = (double) toplevel->init_bottom / (double) MAX_TILES_Y; x1 = (int) (object->line->x[0] / x_size); x2 = (int) (object->line->x[1] / x_size); y1 = (int) (object->line->y[0] / y_size); y2 = (int) (object->line->y[1] / y_size); bottom = x2 - x1; if (bottom != 0.0) { m = (double) (y2 - y1) / bottom; b = y1 - m * x1; start = min((int) x1, (int) x2); end = max((int) x1, (int) x2); for (i = start; i <= end; i++) { x = i; y = m * x + b; if (floor(y) != ceil(y)) { v = (int) x; w = (int) floor(y); if (v < 0 || w < 0 || v > MAX_TILES_X-1 || w > MAX_TILES_Y-1) { return; } /* g_assert(v < MAX_TILES_X && w < MAX_TILES_Y && v >= 0 && w >= 0); */ t_current = &p_current->world_tiles[v][w]; found = g_list_find(t_current->objects, object); if (!found) { /*printf("%d %d\n", v, w);*/ t_current->objects = g_list_append(t_current->objects, object); object->tiles = g_list_append(object->tiles, t_current); } v = (int) x; w = (int) ceil(y); if (v < 0 || w < 0 || v > MAX_TILES_X-1 || w > MAX_TILES_Y-1) { return; } /*g_assert(v < MAX_TILES_X && w < MAX_TILES_Y && v >= 0 && w >= 0);*/ t_current = &p_current->world_tiles[v][w]; found = g_list_find(t_current->objects, object); if (!found) { /*printf("%d %d\n", v, w);*/ t_current->objects = g_list_append(t_current->objects, object); object->tiles = g_list_append(object->tiles, t_current); } } else { v = (int) x; w = (int) floor(y); if (v < 0 || w < 0 || v > MAX_TILES_X-1 || w > MAX_TILES_Y-1) { return; } /*g_assert(v < MAX_TILES_X && w < MAX_TILES_Y && v >= 0 && w >= 0);*/ t_current = &p_current->world_tiles[v][w]; found = g_list_find(t_current->objects, object); if (!found) { /*printf("%d %d\n", v, w);*/ t_current->objects = g_list_append(t_current->objects, object); object->tiles = g_list_append(object->tiles, t_current); } } } if (m != 0.0) { start = min((int) y1, (int) y2); end = max((int) y1, (int) y2); for (j = start; j <= end; j++) { y = j; x = (y - b) / m; if (floor(x) != ceil(x)) { w = (int) y; v = (int) floor(x); if (v < 0 || w < 0 || v > MAX_TILES_X-1 || w > MAX_TILES_Y-1) { return; } /*g_assert(v < MAX_TILES_X && w < MAX_TILES_Y && v >= 0 && w >= 0);*/ t_current = &p_current->world_tiles[v][w]; found = g_list_find(t_current->objects, object); if (!found) { /*printf("%d %d\n", v, w);*/ t_current->objects = g_list_append(t_current->objects, object); object->tiles = g_list_append(object->tiles, t_current); } w = (int) y; v = (int) ceil(x); if (v < 0 || w < 0 || v > MAX_TILES_X-1 || w > MAX_TILES_Y-1) { return; } /* g_assert(v < MAX_TILES_X && w < MAX_TILES_Y && v >= 0 && w >= 0);*/ t_current = &p_current->world_tiles[v][w]; found = g_list_find(t_current->objects, object); if (!found) { /*printf("%d %d\n", v, w);*/ t_current->objects = g_list_append(t_current->objects, object); object->tiles = g_list_append(object->tiles, t_current); } } else { w = (int) y; v = (int) floor(x); if (v < 0 || w < 0 || v > MAX_TILES_X-1 || w > MAX_TILES_Y-1) { return; } /*g_assert(v < MAX_TILES_X && w < MAX_TILES_Y && v >= 0 && w >= 0);*/ t_current = &p_current->world_tiles[v][w]; found = g_list_find(t_current->objects, object); if (!found) { /*printf("%d %d\n", v, w);*/ t_current->objects = g_list_append(t_current->objects, object); object->tiles = g_list_append(object->tiles, t_current); } } } } } else { start = min((int) y1, (int) y2); end = max((int) y1, (int) y2); for (j = start; j <= end; j++) { y = j; x = x1; v = (int) x; w = (int) y; if (v < 0 || w < 0 || v > MAX_TILES_X-1 || w > MAX_TILES_Y-1) { return; } /*g_assert(v < MAX_TILES_X && w < MAX_TILES_Y && v >= 0 && w >= 0);*/ t_current = &p_current->world_tiles[v][w]; found = g_list_find(t_current->objects, object); if (!found) { /*printf("%d %d\n", v, w);*/ t_current->objects = g_list_append(t_current->objects, object); object->tiles = g_list_append(object->tiles, t_current); } } } }