static void part_copy (ItemData *dest, ItemData *src) { Part *dest_part, *src_part; GSList *list; int i; g_return_if_fail (dest != NULL); g_return_if_fail (IS_PART (dest)); g_return_if_fail (src != NULL); g_return_if_fail (IS_PART (src)); if (parent_class->copy != NULL) parent_class->copy (dest, src); dest_part = PART (dest); src_part = PART (src); dest_part->priv->rotation = src_part->priv->rotation; dest_part->priv->flip = src_part->priv->flip; dest_part->priv->num_pins = src_part->priv->num_pins; dest_part->priv->library = src_part->priv->library; dest_part->priv->name = g_strdup (src_part->priv->name); dest_part->priv->symbol_name = g_strdup (src_part->priv->symbol_name); memcpy (dest_part->priv->pins, src_part->priv->pins, src_part->priv->num_pins * sizeof (Pin)); for (i = 0; i < dest_part->priv->num_pins; i++) dest_part->priv->pins[i].part = dest_part; // Copy properties and labels. dest_part->priv->properties = g_slist_copy (src_part->priv->properties); for (list = dest_part->priv->properties; list; list = list->next) { PartProperty *prop, *new_prop; new_prop = g_new0 (PartProperty, 1); prop = list->data; new_prop->name = g_strdup (prop->name); new_prop->value = g_strdup (prop->value); list->data = new_prop; } dest_part->priv->labels = g_slist_copy (src_part->priv->labels); for (list = dest_part->priv->labels; list; list = list->next) { PartLabel *label, *new_label; new_label = g_new0 (PartLabel, 1); label = list->data; new_label->name = g_strdup (label->name); new_label->text = g_strdup (label->text); new_label->pos = label->pos; list->data = new_label; } }
static int part_set_properties (Part *part, GSList *properties) { PartPriv *priv; GSList *list; g_return_val_if_fail (part != NULL, FALSE); g_return_val_if_fail (IS_PART (part), FALSE); priv = part->priv; if (priv->properties != NULL) g_warning ("Properties already set!"); // Copy the properties list to the part. for (list = properties; list; list = list->next) { PartProperty *prop_new, *prop; prop = list->data; prop_new = g_new0 (PartProperty, 1); prop_new->name = g_strdup (prop->name); prop_new->value = g_strdup (prop->value); priv->properties = g_slist_prepend (priv->properties, prop_new); } return TRUE; }
int part_set_pins (Part *part, GSList *pins) { PartPriv *priv; GSList *list; int num_pins, i; g_return_val_if_fail (part != NULL, FALSE); g_return_val_if_fail (IS_PART (part), FALSE); g_return_val_if_fail (pins != NULL, FALSE); priv = part->priv; num_pins = g_slist_length (pins); if (priv->pins) g_free (priv->pins); priv->pins = g_new0 (Pin, num_pins); priv->num_pins = num_pins; for (list = pins, i = 0; list; list = list->next, i++) { // Note that this is slightly hackish. The list contains // Connections which only have the Coords field. Pin *pin = list->data; priv->pins[i].pin_nr = i; priv->pins[i].node_nr= 0; priv->pins[i].offset.x = pin->offset.x; priv->pins[i].offset.y = pin->offset.y; priv->pins[i].part = part; } return TRUE; }
/** * @returns the rotation in degrees * @attention steps of 90 degrees only! */ gint part_get_rotation (Part *part) { ItemData *item; gdouble register a, b, c, d, sx, sy; cairo_matrix_t *t; g_return_val_if_fail (part != NULL, 0); g_return_val_if_fail (IS_PART (part), 0); item = ITEM_DATA (part); t = item_data_get_rotate (item); a = t->xx; b = t->xy; c = t->yx; d = t->yy; sx = a * a + c * c; sy = b * b + d * d; if (G_UNLIKELY (abs (sx) < 1e-10 && abs (sy) < 1e-10)) { g_warning ("Unabled to calculate rotation from matrix. Assuming 0°."); return 0; } gint register r = -1; if (abs (sx) > abs (sy)) r = 90 * (gint)(2. * acos (a / sqrt (sx)) / M_PI); else r = 90 * (gint)(2. * acos (d / sqrt (sy)) / M_PI); return r; }
static char * part_get_refdes_prefix (ItemData *data) { Part *part; char *refdes; int i, length; g_return_val_if_fail (IS_PART (data), NULL); part = PART (data); refdes = part_get_property (part, "refdes"); if (refdes == NULL) return NULL; // Get the 'prefix' i.e R for resistors. length = strlen (refdes); for (i = 0; i < length; i++) { if (isdigit (refdes[length-i -1])) { refdes[length -i -1] = '\0'; } else break; } return g_strdup (refdes); }
static void part_set_property (ItemData *data, char *property, char *value) { Part *part; PartPriv *priv; GSList *props; PartProperty *prop; part = PART (data); g_return_if_fail (part != NULL); g_return_if_fail (IS_PART (part)); g_return_if_fail (property != NULL); priv = part->priv; for (props = priv->properties; props; props = props->next) { prop = props->data; if (g_ascii_strcasecmp (prop->name, property) == 0) { g_free (prop->value); if (value != NULL) prop->value = g_strdup (value); else prop->value = NULL; break; } } }
PartItem * part_item_canvas_new (Sheet *sheet, Part *part) { PartItem *part_item; PartItemPriv *priv; GooCanvasItem *item; ItemData *item_data; g_return_val_if_fail (sheet != NULL, NULL); g_return_val_if_fail (IS_SHEET (sheet), NULL); g_return_val_if_fail (part != NULL, NULL); g_return_val_if_fail (IS_PART (part), NULL); item = g_object_new (TYPE_PART_ITEM, NULL); g_object_set (item, "parent", sheet->object_group, NULL); part_item = PART_ITEM (item); g_object_set (part_item, "data", part, NULL); priv = part_item->priv; priv->label_group = GOO_CANVAS_ITEM (goo_canvas_group_new ( GOO_CANVAS_ITEM (part_item), "width", -1.0, "height", -1.0, NULL)); g_object_unref (item); priv->node_group = GOO_CANVAS_ITEM (goo_canvas_group_new ( GOO_CANVAS_ITEM (part_item), NULL)); g_object_set (GOO_CANVAS_ITEM (priv->node_group), "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL); item_data = ITEM_DATA (part); item_data->rotated_handler_id = g_signal_connect_object (G_OBJECT (part), "rotated", G_CALLBACK (part_rotated_callback), G_OBJECT (part_item), 0); item_data->flipped_handler_id = g_signal_connect_object (G_OBJECT (part), "flipped", G_CALLBACK (part_flipped_callback), G_OBJECT (part_item), 0); item_data->moved_handler_id = g_signal_connect_object (G_OBJECT (part), "moved", G_CALLBACK (part_moved_callback), G_OBJECT (part_item), 0); item_data->changed_handler_id = g_signal_connect_object (G_OBJECT (part), "changed", G_CALLBACK (part_changed_callback), G_OBJECT (part_item), 0); return part_item; }
// Create a SheetItem from an ItemData object. This is a bit ugly. // It could be beautified by having a method that creates the item. // E.g. sheet_item->new_from_data (data); SheetItem * sheet_item_factory_create_sheet_item (Sheet *sheet, ItemData *data) { SheetItem *item; g_return_val_if_fail (data != NULL, NULL); g_return_val_if_fail (IS_ITEM_DATA (data), NULL); g_return_val_if_fail (sheet != NULL, NULL); g_return_val_if_fail (IS_SHEET (sheet), NULL); item = NULL; // Pick the right model. if (IS_PART (data)) { NG_DEBUG ("sheet_item_factory_create_sheet_item part\n\n"); item = SHEET_ITEM (part_item_new (sheet, PART (data))); } else if (IS_WIRE (data)) { NG_DEBUG ("sheet_item_factory_create_sheet_item wire\n\n"); item = SHEET_ITEM (wire_item_new (sheet, WIRE (data))); } else if (IS_TEXTBOX (data)) { NG_DEBUG ("sheet_item_factory_create_sheet_item text\n\n"); item = SHEET_ITEM (textbox_item_new (sheet, TEXTBOX (data))); } else g_warning ("Unknown Item type."); return item; }
static void part_unregister (ItemData *data) { NodeStore *store; g_return_if_fail (IS_PART (data)); store = item_data_get_store (data); node_store_remove_part (store, PART (data)); }
int node_store_add_part (NodeStore *self, Part *part) { GSList *wire_list, *list; Node *node; SheetPos lookup_key; SheetPos part_pos; gdouble x, y; int i, num_pins; g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (IS_NODE_STORE (self), FALSE); g_return_val_if_fail (part != NULL, FALSE); g_return_val_if_fail (IS_PART (part), FALSE); num_pins = part_get_num_pins (part); item_data_get_pos (ITEM_DATA (part), &part_pos); for (i = 0; i < num_pins; i++) { Pin *pins; pins = part_get_pins (part); x = part_pos.x + pins[i].offset.x; y = part_pos.y + pins[i].offset.y; //Use the position of the pin as hash key. lookup_key.x = x; lookup_key.y = y; // Retrieve a node for this position. node = node_store_get_or_create_node (self, lookup_key); // Add all the wires that intersect this pin to the node store. wire_list = wires_at_pos (self, lookup_key); for (list = wire_list; list; list = list->next) { Wire *wire = list->data; NG_DEBUG ("Add pin to wire.\n"); node_add_wire (node, wire); wire_add_node (wire, node); } g_slist_free (wire_list); node_add_pin (node, &pins[i]); } g_object_set (G_OBJECT (part), "store", self, NULL); self->parts = g_list_prepend (self->parts, part); self->items = g_list_prepend (self->items, part); return TRUE; }
Pin *part_get_pins (Part *part) { PartPriv *priv; g_return_val_if_fail (part != NULL, NULL); g_return_val_if_fail (IS_PART (part), NULL); priv = part->priv; return priv->pins; }
IDFlip part_get_flip (Part *part) { PartPriv *priv; g_return_val_if_fail (part != NULL, 0); g_return_val_if_fail (IS_PART (part), 0); priv = part->priv; return priv->flip; }
gint part_get_num_pins (Part *part) { PartPriv *priv; g_return_val_if_fail (part != NULL, 0); g_return_val_if_fail (IS_PART (part), 0); priv = part->priv; return priv->num_pins; }
static void part_item_paste (Sheet *sheet, ItemData *data) { g_return_if_fail (sheet != NULL); g_return_if_fail (IS_SHEET (sheet)); g_return_if_fail (data != NULL); g_return_if_fail (IS_PART (data)); sheet_add_ghost_item (sheet, data); }
int part_get_rotation (Part *part) { PartPriv *priv; g_return_val_if_fail (part != NULL, 0); g_return_val_if_fail (IS_PART (part), 0); priv = part->priv; return priv->rotation; }
GSList *part_get_properties (Part *part) { PartPriv *priv; g_return_val_if_fail (part != NULL, FALSE); g_return_val_if_fail (IS_PART (part), FALSE); priv = part->priv; return priv->properties; }
GSList *part_get_labels (Part *part) { PartPriv *priv; g_return_val_if_fail (part != NULL, NULL); g_return_val_if_fail (IS_PART (part), NULL); priv = part->priv; return priv->labels; }
/** * register a part to its nodestore * @param data the part * @attention the @data has to have a valid nodestore set */ static int part_register (ItemData *data) { NodeStore *store; g_return_val_if_fail (IS_PART (data), FALSE); store = item_data_get_store (data); node_store_add_part (store, PART (data)); return TRUE; }
int node_store_remove_part (NodeStore *self, Part *part) { Node *node; SheetPos lookup_key; SheetPos pos; gdouble x, y; int i, num_pins; Pin *pins; g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (IS_NODE_STORE (self), FALSE); g_return_val_if_fail (part != NULL, FALSE); g_return_val_if_fail (IS_PART (part), FALSE); self->parts = g_list_remove (self->parts, part); self->items = g_list_remove (self->items, part); num_pins = part_get_num_pins (part); item_data_get_pos (ITEM_DATA (part), &pos); pins = part_get_pins (part); for (i = 0; i < num_pins; i++) { x = pos.x + pins[i].offset.x; y = pos.y + pins[i].offset.y; // Use the position of the pin as lookup key. lookup_key.x = x; lookup_key.y = y; node = g_hash_table_lookup (self->nodes, &lookup_key); if (node) { if (!node_remove_pin (node, &pins[i])) { g_warning ("Couldn't remove pin."); return FALSE; } // If the node is empty after removing the pin, // remove the node as well. if (node_is_empty (node)) { g_hash_table_remove (self->nodes, &lookup_key); g_object_unref (G_OBJECT (node)); } } else { return FALSE; } } return TRUE; }
/** * register a part to the nodestore */ gboolean node_store_add_part (NodeStore *self, Part *part) { NG_DEBUG ("-0-"); g_return_val_if_fail (self, FALSE); g_return_val_if_fail (IS_NODE_STORE (self), FALSE); g_return_val_if_fail (part, FALSE); g_return_val_if_fail (IS_PART (part), FALSE); GSList *iter, *copy; Node *node; Coords pin_pos; Coords part_pos; int i, num_pins; Pin *pins; num_pins = part_get_num_pins (part); pins = part_get_pins (part); item_data_get_pos (ITEM_DATA (part), &part_pos); for (i = 0; i < num_pins; i++) { // Use the position of the pin as hash key. pin_pos.x = part_pos.x + pins[i].offset.x; pin_pos.y = part_pos.y + pins[i].offset.y; // Retrieve a node for this position. node = node_store_get_or_create_node (self, pin_pos); // Add all the wires that intersect this pin to the node store. copy = get_wires_at_pos (self, pin_pos); for (iter = copy; iter; iter = iter->next) { Wire *wire = copy->data; node_add_wire (node, wire); wire_add_node (wire, node); } g_slist_free (copy); node_add_pin (node, &pins[i]); } g_object_set (G_OBJECT (part), "store", self, NULL); self->parts = g_list_prepend (self->parts, part); self->items = g_list_prepend (self->items, part); return TRUE; }
/** * remove/unregister a part from the nodestore * this does _not_ free the part! */ gboolean node_store_remove_part (NodeStore *self, Part *part) { Node *node; Coords pin_pos; Coords part_pos; int i, num_pins; Pin *pins; g_return_val_if_fail (self, FALSE); g_return_val_if_fail (IS_NODE_STORE (self), FALSE); g_return_val_if_fail (part, FALSE); g_return_val_if_fail (IS_PART (part), FALSE); self->parts = g_list_remove (self->parts, part); self->items = g_list_remove (self->items, part); num_pins = part_get_num_pins (part); item_data_get_pos (ITEM_DATA (part), &part_pos); pins = part_get_pins (part); for (i = 0; i < num_pins; i++) { pin_pos.x = part_pos.x + pins[i].offset.x; pin_pos.y = part_pos.y + pins[i].offset.y; node = g_hash_table_lookup (self->nodes, &pin_pos); if (node) { if (!node_remove_pin (node, &pins[i])) { g_warning ("Could not remove pin[%i] from node %p.", i, node); return FALSE; } // If the node is empty after removing the pin, // remove the node as well. if (node_is_empty (node)) { g_hash_table_remove (self->nodes, &pin_pos); g_object_unref (G_OBJECT (node)); } } else { return FALSE; } } return TRUE; }
void part_item_update_node_label (PartItem *item) { PartItemPriv *priv; Part *part; GSList *labels; GooCanvasItem *canvas_item; Pin *pins; gint num_pins; g_return_if_fail (item != NULL); g_return_if_fail (IS_PART_ITEM (item)); priv = item->priv; part = PART (sheet_item_get_data (SHEET_ITEM (item))); g_return_if_fail (IS_PART (part) ); // Put the label of each node num_pins = part_get_num_pins (part); if (num_pins == 1) { pins = part_get_pins (part); labels = priv->label_nodes; for (labels = priv->label_nodes; labels; labels=labels->next) { char *txt; txt = g_strdup_printf ("V(%d)", pins[0].node_nr); canvas_item = labels->data; if (pins[0].node_nr != 0) g_object_set (canvas_item, "text", txt, "fill_color", LABEL_COLOR, "font", "Sans 8", NULL); else g_object_set (canvas_item, "text", "", NULL); g_free (txt); } } }
static ItemData *part_clone (ItemData *src) { Part *src_part, *new_part; ItemDataClass *id_class; g_return_val_if_fail (src != NULL, NULL); g_return_val_if_fail (IS_PART (src), NULL); id_class = ITEM_DATA_CLASS (G_OBJECT_GET_CLASS (src)); if (id_class->copy == NULL) return NULL; src_part = PART (src); new_part = g_object_new (TYPE_PART, NULL); new_part->priv->pins = g_new0 (Pin, src_part->priv->num_pins); id_class->copy (ITEM_DATA (new_part), src); return ITEM_DATA (new_part); }
/** * @returns [transfer-full] */ char *part_get_property (Part *part, char *name) { PartPriv *priv; GSList *props; PartProperty *prop; g_return_val_if_fail (part != NULL, NULL); g_return_val_if_fail (IS_PART (part), NULL); g_return_val_if_fail (name != NULL, NULL); priv = part->priv; for (props = priv->properties; props; props = props->next) { prop = props->data; if (g_ascii_strcasecmp (prop->name, name) == 0) { return g_strdup (prop->value); } } return NULL; }
static void create_canvas_labels (PartItem *item, Part *part) { GooCanvasItem *canvas_item; GSList *list, *item_list; GooCanvasGroup *group; g_return_if_fail (item != NULL); g_return_if_fail (IS_PART_ITEM (item)); g_return_if_fail (part != NULL); g_return_if_fail (IS_PART (part)); group = GOO_CANVAS_GROUP (item->priv->label_group); item_list = NULL; for (list = part_get_labels (part); list; list = list->next) { PartLabel *label = list->data; char *text; text = part_property_expand_macros (part, label->text); canvas_item = goo_canvas_text_new (GOO_CANVAS_ITEM (group), text, (double) label->pos.x, (double) label->pos.y, 0, GOO_CANVAS_ANCHOR_SOUTH_WEST, "fill_color", LABEL_COLOR, "font", "Sans 8", NULL); item_list = g_slist_prepend (item_list, canvas_item); g_free (text); } g_slist_free_full (list, g_object_unref); item_list = g_slist_reverse (item_list); part_item_set_label_items (item, item_list); }
static int part_set_labels (Part *part, GSList *labels) { PartPriv *priv; GSList *list; g_return_val_if_fail (part != NULL, FALSE); g_return_val_if_fail (IS_PART (part), FALSE); priv = part->priv; if (priv->labels != NULL) { g_warning ("Part already has labels."); for (list = priv->labels; list; list = list->next) { PartLabel *label = list->data; g_free (label->name); g_free (label->text); g_free (label); } g_slist_free (priv->labels); priv->labels = NULL; } for (list = labels; list; list = list->next) { PartLabel *label, *label_copy; label = list->data; label_copy = g_new0 (PartLabel, 1); label_copy->name = g_strdup (label->name); label_copy->text = g_strdup (label->text); label_copy->pos.x = label->pos.x; label_copy->pos.y = label->pos.y; priv->labels = g_slist_prepend (priv->labels, label_copy); } return TRUE; }
static void part_changed (ItemData *data) { Part *part; Coords loc = {0., 0.}; int angle = 0; IDFlip flip = ID_FLIP_NONE; g_return_if_fail (IS_PART (data)); part = (Part *)data; flip = part_get_flip (part); angle = part_get_rotation (part); item_data_get_pos (data, &loc); #if 0 //FIXME isn't it more sane to just emit the changed? g_signal_emit_by_name (data, "moved", &loc); g_signal_emit_by_name (data, "flipped", flip); g_signal_emit_by_name (data, "rotated", angle); #endif g_signal_emit_by_name (data, "changed"); }
/** * add/register the wire to the nodestore * * @param store * @param wire * @returns TRUE if the wire was added or merged, else FALSE */ gboolean node_store_add_wire (NodeStore *store, Wire *wire) { GList *list; Node *node; int i = 0; g_return_val_if_fail (store, FALSE); g_return_val_if_fail (IS_NODE_STORE (store), FALSE); g_return_val_if_fail (wire, FALSE); g_return_val_if_fail (IS_WIRE (wire), FALSE); // Check for intersection with other wires. for (list = store->wires; list; list = list->next) { g_assert (list->data != NULL); g_assert (IS_WIRE (list->data)); Coords where = {-77.77, -77.77}; Wire *other = list->data; if (do_wires_intersect (wire, other, &where)) { if (is_t_crossing (wire, other, &where) || is_t_crossing (other, wire, &where)) { node = node_store_get_or_create_node (store, where); node_add_wire (node, wire); node_add_wire (node, other); wire_add_node (wire, node); wire_add_node (other, node); NG_DEBUG ("Add wire %p to wire %p @ %lf,%lf.\n", wire, other, where.x, where.y); } else { // magic node removal if a x crossing is overlapped with another wire node = node_store_get_node (store, where); NG_DEBUG ("Nuke that node [ %p ] at coords inbetween", node); if (node) { Coords c[4]; wire_get_start_and_end_pos (other, c + 0, c + 1); wire_get_start_and_end_pos (wire, c + 2, c + 3); if (!coords_equal (&where, c + 0) && !coords_equal (&where, c + 1) && !coords_equal (&where, c + 2) && !coords_equal (&where, c + 3)) { wire_remove_node (wire, node); wire_remove_node (other, node); node_remove_wire (node, wire); node_remove_wire (node, other); } } } } } // Check for overlapping with other wires. do { for (list = store->wires; list; list = list->next) { g_assert (list->data != NULL); g_assert (IS_WIRE (list->data)); Wire *other = list->data; Coords so, eo; const gboolean overlap = do_wires_overlap (wire, other, &so, &eo); NG_DEBUG ("overlap [ %p] and [ %p ] -- %s", wire, other, overlap == TRUE ? "YES" : "NO"); if (overlap) { Node *sn = node_store_get_node (store, eo); Node *en = node_store_get_node (store, so); #if 1 wire = vulcanize_wire (store, wire, other, &so, &eo); node_store_remove_wire (store, g_object_ref (other)); // equiv // wire_unregister // XXX FIXME this // modifies the list // we iterate over! // delay this until idle, so all handlers like adding view // representation are completed so existing wire-items can be deleted // properly // this is not fancy nor nice but seems to work fairly nicly g_idle_add (delayed_wire_delete, other); break; NG_DEBUG ("overlapping of %p with %p ", wire, other); #else if (!sn && !en) { wire = vulcanize_wire (store, wire, other, &so, &eo); } else if (!sn) { NG_DEBUG ("do_something(TM) : %p sn==NULL ", other); } else if (!en) { NG_DEBUG ("do_something(TM) : %p en==NULL ", other); } else { NG_DEBUG ("do_something(TM) : %p else ", other); } #endif } else { NG_DEBUG ("not of %p with %p ", wire, other); } } } while (list); // Check for intersection with parts (pins). for (list = store->parts; list; list = list->next) { g_assert (list->data != NULL); g_assert (IS_PART (list->data)); Coords part_pos; gint num_pins = -1; Part *part = list->data; num_pins = part_get_num_pins (part); item_data_get_pos (ITEM_DATA (part), &part_pos); // Go through all the parts and see which of their // pins that intersect the wire. for (i = 0; i < num_pins; i++) { Pin *pins; Coords lookup_pos; pins = part_get_pins (part); lookup_pos.x = part_pos.x + pins[i].offset.x; lookup_pos.y = part_pos.y + pins[i].offset.y; // If there is a wire at this pin's position, // add it to the return list. if (is_point_on_wire (wire, &lookup_pos)) { Node *node; node = node_store_get_node (store, lookup_pos); if (node != NULL) { // Add the wire to the node (pin) that it intersected. node_add_wire (node, wire); wire_add_node (wire, node); NG_DEBUG ("Add wire %p to pin (node) %p.\n", wire, node); } else { g_warning ("Bug: Found no node at pin at (%g %g).\n", lookup_pos.x, lookup_pos.y); } } } } g_object_set (G_OBJECT (wire), "store", store, NULL); store->wires = g_list_prepend (store->wires, wire); store->items = g_list_prepend (store->items, wire); return TRUE; }
static void part_print (ItemData *data, cairo_t *cr, SchematicPrintContext *ctx) { GSList *objects, *labels; SymbolObject *object; LibrarySymbol *symbol; double x0, y0; int i, rotation; Part *part; PartPriv *priv; Coords pos; IDFlip flip; GooCanvasPoints *line; g_return_if_fail (data != NULL); g_return_if_fail (IS_PART (data)); part = PART (data); priv = part->priv; symbol = library_get_symbol (priv->symbol_name); if (symbol == NULL) { return; } item_data_get_pos (ITEM_DATA (part), &pos); x0 = pos.x; y0 = pos.y; cairo_save (cr); gdk_cairo_set_source_rgba (cr, &ctx->colors.components); rotation = part_get_rotation (part); flip = part_get_flip (part); if ((flip & ID_FLIP_HORIZ) && (flip & ID_FLIP_VERT)) rotation += 180; else if (flip == ID_FLIP_HORIZ) cairo_scale (cr, -1, 1); else if (flip == ID_FLIP_VERT) cairo_scale (cr, 1, -1); if (rotation %= 360) cairo_rotate (cr, rotation*M_PI/180); for (objects = symbol->symbol_objects; objects; objects = objects->next) { object = (SymbolObject *)(objects->data); switch (object->type) { case SYMBOL_OBJECT_LINE: line = object->u.uline.line; for (i = 0; i < line->num_points; i++) { double x, y; x = line->coords[i * 2]; y = line->coords[i * 2 + 1]; if (i == 0) cairo_move_to (cr, x0 + x, y0 + y); else cairo_line_to (cr, x0 + x, y0 + y); } break; case SYMBOL_OBJECT_ARC: { gdouble x1 = object->u.arc.x1; gdouble y1 = object->u.arc.y1; gdouble x2 = object->u.arc.x2; gdouble y2 = object->u.arc.y2; gdouble width, height, x, y; x = (x2 + x1) / 2; y = (y2 + y1) / 2; width = x2 - x1; height = y2 - y1; cairo_save (cr); cairo_translate (cr, x0 + x, y0 + y); cairo_scale (cr, width / 2.0, height / 2.0); cairo_arc (cr, 0.0, 0.0, 1.0, 0.0, 2 * M_PI); cairo_restore (cr); } break; default: g_warning ( "Print part: Part %s contains unknown object.", priv->name ); continue; } cairo_stroke (cr); } // We don't want to rotate labels text, only the (x,y) coordinate gdk_cairo_set_source_rgba (cr, &ctx->colors.labels); for (labels = part_get_labels (part); labels; labels = labels->next) { gdouble x, y; PartLabel *label = (PartLabel *)labels->data; gchar *text; /* gint text_width, text_height; */ x = label->pos.x + x0; y = label->pos.y + y0; text = part_property_expand_macros (part, label->text); /* Align the label. switch (rotation) { case 90: y += text_height*opc->scale; break; case 180: break; case 270: x -= text_width*opc->scale; break; case 0: default: break; } */ cairo_save (cr); cairo_move_to (cr, x, y); cairo_show_text (cr, text); cairo_restore (cr); g_free (text); } cairo_restore (cr); }
/** * flip a part in a given direction * @direction gives the direction the item will be flipped, end users pov! * @center the center to flip over - currently ignored FIXME */ static void part_flip (ItemData *data, IDFlip direction, Coords *center) { Part *part; PartPriv *priv; int i; cairo_matrix_t affine; double x, y; double scale_v, scale_h; gboolean handler_connected; Coords pos, trans; Coords b1, b2; Coords pos_new, pos_old, delta; //FIXME properly recenter after flipping //Coords part_center_before, part_center_after, delta; g_return_if_fail (data); g_return_if_fail (IS_PART (data)); part = PART (data); priv = part->priv; item_data_get_pos (data, &trans); // mask, just for the sake of cleanness direction &= ID_FLIP_MASK; // TODO evaluate if we really want to be able to do double flips (180* rots via flipping) g_assert (direction != ID_FLIP_MASK); // create a transformation _relativ_ to the current _state_ // reverse axis and fix the created offset by adding 2*pos.x or .y // convert the flip direction to binary, used in the matrix setup // keep in mind that we do relativ manipulations within the model // which in turn makes this valid for all rotations! scale_h = ((direction & ID_FLIP_HORIZ) != 0) ? -1. : 1.; scale_v = ((direction & ID_FLIP_VERT) != 0) ? -1. : 1.; // magic, if we are in either 270 or 90 state, we need to rotate the flip state by 90° to draw it properly // TODO maybe better put this into the rotation function if ((priv->rotation / 90) % 2 == 1) { priv->flip ^= ID_FLIP_MASK; } // toggle the direction priv->flip ^= direction; if ((priv->flip & ID_FLIP_MASK)== ID_FLIP_MASK) { priv->flip = ID_FLIP_NONE; priv->rotation += 180; priv->rotation %= 360; } cairo_matrix_init_scale (&affine, scale_h, scale_v); item_data_get_pos (data, &pos_old); pos_new = pos_old; cairo_matrix_transform_point (&affine, &pos_new.x, &pos_new.y); g_printf ("\ncenter %p [old] x=%lf,y=%lf -->", data, pos_old.x, pos_old.y); g_printf (" x=%lf, y=%lf\n", pos_new.x, pos_new.y); delta.x = - pos_new.x + pos_old.x; delta.y = - pos_new.y + pos_old.y; // flip the pins for (i = 0; i < priv->num_pins; i++) { x = priv->pins[i].offset.x; y = priv->pins[i].offset.y; cairo_matrix_transform_point (&affine, &x, &y); if (fabs (x) < 1e-2) x = 0.0; if (fabs (y) < 1e-2) y = 0.0; priv->pins[i].offset.x = x; priv->pins[i].offset.y = y; } item_data_snap (data); // tell the view handler_connected = g_signal_handler_is_connected (G_OBJECT (part), ITEM_DATA(part)->flipped_handler_id); if (handler_connected) { g_signal_emit_by_name (G_OBJECT (part), "flipped", priv->flip); // TODO - proper boundingbox center calculation item_data_get_relative_bbox (ITEM_DATA (part), &b1, &b2); // flip the bounding box. cairo_matrix_transform_point (&affine, &b1.x, &b1.y); cairo_matrix_transform_point (&affine, &b2.x, &b2.y); item_data_set_relative_bbox (ITEM_DATA (part), &b1, &b2); item_data_set_pos (ITEM_DATA (part), &pos); // FIXME - proper recenter to boundingbox center } if (g_signal_handler_is_connected (G_OBJECT (part), ITEM_DATA (part)->changed_handler_id)) { g_signal_emit_by_name (G_OBJECT (part), "changed"); } }