示例#1
0
static void
write_xml_textbox (Textbox *textbox, parseXmlContext *ctxt)
{
	xmlNodePtr node_textbox;
	gchar *str;
	Coords pos;

	g_return_if_fail (textbox != NULL);
	if (!IS_TEXTBOX (textbox))
		return;

	// Create a node for the textbox.
	node_textbox = xmlNewChild (ctxt->node_textboxes, ctxt->ns,
		BAD_CAST "textbox", NULL);
	if (!node_textbox) {
		g_warning ("Failed during save of text box.\n");
		return;
	}

	item_data_get_pos (ITEM_DATA (textbox), &pos);

	str = g_strdup_printf ("(%g %g)", pos.x, pos.y);
	xmlNewChild (node_textbox, ctxt->ns, BAD_CAST "position", BAD_CAST str);
	g_free (str);

	str = textbox_get_text (textbox);
	xmlNewChild (node_textbox, ctxt->ns, BAD_CAST "text", BAD_CAST str);
}
示例#2
0
文件: wire.c 项目: neuroidss/oregano
void wire_dbg_print (Wire *w)
{
    Coords pos;
    item_data_get_pos (ITEM_DATA (w), &pos);
    NG_DEBUG ("Wire %p is defined by (%lf,%lf) + lambda * (%lf,%lf)\n", w, pos.x, pos.y,
              w->priv->length.x, w->priv->length.y);
}
示例#3
0
int
node_store_is_pin_at_pos (NodeStore *store, SheetPos pos)
{
	int num_pins;
	SheetPos part_pos;
	GList *p;
	Part *part;
	Pin *pins;
	int i;
	gdouble x, y;

	for (p = store->parts; p; p = p->next) {
		part = PART (p->data);

		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++) {
			x = part_pos.x + pins[i].offset.x;
			y = part_pos.y + pins[i].offset.y;

			if ((x == pos.x) && (y == pos.y)) {
				return 1;
			}
		}
	}
	g_list_free_full (p, g_object_unref);
	return 0;
}
示例#4
0
// Retrieves the bounding box. We use a caching scheme for this
// since it's too expensive to calculate it every time we need it.
inline static void get_cached_bounds (TextboxItem *item, Coords *p1, Coords *p2)
{
	PangoFontDescription *font;
	Coords pos;

	TextboxItemPriv *priv;
	priv = item->priv;

	if (!priv->cache_valid) {
		Coords start_pos, end_pos;

		font = pango_font_description_from_string (TEXTBOX_FONT);

		item_data_get_pos (sheet_item_get_data (SHEET_ITEM (item)), &pos);

		start_pos.x = pos.x;
		start_pos.y = pos.y - 5; // - font->ascent;
		end_pos.x = pos.x + 5;   // + rbearing;
		end_pos.y = pos.y + 5;   // + font->descent;

		priv->bbox_start = start_pos;
		priv->bbox_end = end_pos;
		priv->cache_valid = TRUE;
		pango_font_description_free (font);
	}

	memcpy (p1, &priv->bbox_start, sizeof(Coords));
	memcpy (p2, &priv->bbox_end, sizeof(Coords));
}
示例#5
0
gboolean node_store_is_pin_at_pos (NodeStore *store, Coords pos)
{
	int num_pins;
	Coords part_pos;
	GList *p;
	Part *part;
	Pin *pins;
	int i;
	gdouble x, y;

	for (p = store->parts; p; p = p->next) {
		part = PART (p->data);

		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++) {
			x = part_pos.x + pins[i].offset.x;
			y = part_pos.y + pins[i].offset.y;

			if (fabs (x - pos.x) < NODE_EPSILON && fabs (y - pos.y) < NODE_EPSILON)
				return TRUE;
		}
	}
	return FALSE;
}
示例#6
0
文件: wire.c 项目: neuroidss/oregano
void wire_get_start_pos (Wire *wire, Coords *pos)
{
    g_return_if_fail (wire != NULL);
    g_return_if_fail (IS_WIRE (wire));
    g_return_if_fail (pos != NULL);

    item_data_get_pos (ITEM_DATA (wire), pos);
}
示例#7
0
static GSList *
wire_intersect_parts (NodeStore *store, Wire *wire)
{
	GList *list;
	GSList *ip_list;
	Node *node;
	SheetPos lookup_pos;
	SheetPos part_pos, wire_pos, wire_length;
	Part *part;
	double x, y, wire_x1, wire_y1, wire_x2, wire_y2;
	int i, num_pins;

	g_return_val_if_fail (store != NULL, FALSE);
	g_return_val_if_fail (IS_NODE_STORE (store), FALSE);
	g_return_val_if_fail (wire != NULL, FALSE);
	g_return_val_if_fail (IS_WIRE (wire), FALSE);

	ip_list = NULL;

	wire_get_pos_and_length (wire, &wire_pos, &wire_length);

	wire_x1 = wire_pos.x;
	wire_x2 = wire_pos.x + wire_length.x;
	wire_y1 = wire_pos.y;
	wire_y2 = wire_pos.y + wire_length.y;

	// Go through all the parts and see which of their
	// pins that intersect the wire.
	for (list = store->parts; list; list = list->next) {
		part = list->data;

		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;

			lookup_pos.x = x;
			lookup_pos.y = y;

			// If there is a wire at this pin's position,
			// add it to the return list.
			if (is_wire_at_pos (wire_x1, wire_y1, wire_x2, wire_y2, lookup_pos)) {
				node = node_store_get_node (store, lookup_pos);

				if (node != NULL)
					ip_list = g_slist_prepend (ip_list, node);
			}
		}
	}
	g_list_free_full (list, g_object_unref);

	return ip_list;
}
示例#8
0
文件: wire.c 项目: neuroidss/oregano
static void wire_changed (ItemData *data)
{
    Coords loc;
    g_return_if_fail (IS_WIRE (data));

    item_data_get_pos (data, &loc);
    g_signal_emit_by_name ((GObject *)data, "moved", &loc);
    g_signal_emit_by_name ((GObject *)data, "changed");
}
示例#9
0
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;
}
示例#10
0
文件: wire.c 项目: neuroidss/oregano
void wire_get_pos_and_length (Wire *wire, Coords *pos, Coords *length)
{
    WirePriv *priv;

    g_return_if_fail (wire != NULL);
    g_return_if_fail (IS_WIRE (wire));
    g_return_if_fail (pos != NULL);

    priv = wire->priv;

    item_data_get_pos (ITEM_DATA (wire), pos);
    *length = priv->length;
}
示例#11
0
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;
}
示例#12
0
文件: wire.c 项目: neuroidss/oregano
void wire_get_start_and_end_pos (Wire *wire, Coords *start, Coords *end)
{
    WirePriv *priv;

    g_return_if_fail (wire != NULL);
    g_return_if_fail (IS_WIRE (wire));
    g_return_if_fail (start != NULL);
    g_return_if_fail (end != NULL);

    priv = wire->priv;

    item_data_get_pos (ITEM_DATA (wire), start);
    *end = coords_sum (start, &(priv->length));
}
示例#13
0
文件: wire.c 项目: neuroidss/oregano
void wire_get_end_pos (Wire *wire, Coords *pos)
{
    WirePriv *priv;

    g_return_if_fail (wire != NULL);
    g_return_if_fail (IS_WIRE (wire));
    g_return_if_fail (pos != NULL);

    priv = wire->priv;

    item_data_get_pos (ITEM_DATA (wire), pos);

    pos->x += priv->length.x;
    pos->y += priv->length.y;
}
示例#14
0
文件: textbox.c 项目: Miuler/oregano
static void
textbox_flip (ItemData *data, gboolean horizontal, SheetPos *center)
{
	double affine[6];
	ArtPoint src, dst;
	Textbox *textbox;
	TextboxPriv *priv;
	SheetPos b1, b2;
	SheetPos textbox_center, delta;

	g_return_if_fail (data != NULL);
	g_return_if_fail (IS_TEXTBOX (data));

	textbox = TEXTBOX (data);

	if (center) {
		item_data_get_absolute_bbox (ITEM_DATA (textbox), &b1, &b2);
		textbox_center.x = b1.x + (b2.x - b1.x) / 2;
		textbox_center.y = b1.y + (b2.y - b1.y) / 2;
	}

	priv = textbox->priv;

	if (horizontal)
		art_affine_scale (affine, -1, 1);
	else
		art_affine_scale (affine, 1, -1);

	/*
	 * Let the views (canvas items) know about the rotation.
	 */
	g_signal_emit_by_name(G_OBJECT (textbox), "flipped", horizontal);

	if (center) {
		SheetPos textbox_pos;

		item_data_get_pos (ITEM_DATA (textbox), &textbox_pos);

		src.x = textbox_center.x - center->x;
		src.y = textbox_center.y - center->y;
		art_affine_point (&dst, &src, affine);

		delta.x = -src.x + dst.x;
		delta.y = -src.y + dst.y;

		item_data_move (ITEM_DATA (textbox), &delta);
	}
}
示例#15
0
/**
 * 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;
}
示例#16
0
TextboxItem *textbox_item_new (Sheet *sheet, Textbox *textbox)
{
	GooCanvasItem *item;
	TextboxItem *textbox_item;
	TextboxItemPriv *priv;
	Coords pos;
	ItemData *item_data;

	g_return_val_if_fail (sheet != NULL, NULL);
	g_return_val_if_fail (IS_SHEET (sheet), NULL);

	item_data_get_pos (ITEM_DATA (textbox), &pos);

	item = g_object_new (TYPE_TEXTBOX_ITEM, NULL);

	g_object_set (item, "parent", sheet->object_group, NULL);

	textbox_item = TEXTBOX_ITEM (item);
	g_object_set (textbox_item, "data", textbox, NULL);

	priv = textbox_item->priv;

	priv->text_canvas_item = goo_canvas_text_new (
	    GOO_CANVAS_ITEM (textbox_item), textbox_get_text (textbox), 0.0, 0.0, -1,
	    GOO_CANVAS_ANCHOR_SW, "font", TEXTBOX_FONT, "fill-color", NORMAL_COLOR, NULL);

	item_data = ITEM_DATA (textbox);

	item_data->rotated_handler_id =
	    g_signal_connect_object (G_OBJECT (textbox), "rotated",
	                             G_CALLBACK (textbox_rotated_callback), G_OBJECT (textbox_item), 0);
	item_data->flipped_handler_id =
	    g_signal_connect_object (G_OBJECT (textbox), "flipped",
	                             G_CALLBACK (textbox_flipped_callback), G_OBJECT (textbox_item), 0);
	item_data->moved_handler_id =
	    g_signal_connect_object (G_OBJECT (textbox), "moved", G_CALLBACK (textbox_moved_callback),
	                             G_OBJECT (textbox_item), 0);
	textbox->text_changed_handler_id = g_signal_connect_object (
	    G_OBJECT (textbox), "text_changed", G_CALLBACK (textbox_text_changed_callback),
	    G_OBJECT (textbox_item), 0);

	textbox_update_bbox (textbox);

	return textbox_item;
}
示例#17
0
/**
 * 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;
}
示例#18
0
static void
sheet_item_set_property (GObject *object, guint prop_id, const GValue *value,
						 GParamSpec *spec)
{
	GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
	SheetItem *sheet_item; 
	Coords pos;

	sheet_item = SHEET_ITEM (object);
		
	switch (prop_id) {
		case ARG_X:
			sheet_item->x = g_value_get_double (value);
			break;
		case ARG_Y:
			sheet_item->y = g_value_get_double (value);
		break;
		case ARG_WIDTH:
			sheet_item->width = g_value_get_double (value);
		break;
		case ARG_HEIGHT:
			sheet_item->height = g_value_get_double (value);
			break;
		case ARG_DATA:
			if (sheet_item->priv->data) {
				g_warning (_("Cannot set SheetItem after creation."));
				break;
			}
			sheet_item->priv->data = g_value_get_pointer (value);
			item_data_get_pos (sheet_item->priv->data, &pos);
			sheet_item->x = pos.x;
			sheet_item->y = pos.y;
			break;
		case ARG_ACTION_GROUP:
			sheet_item->priv->action_group = g_value_get_pointer (value);
			gtk_ui_manager_insert_action_group (sheet_item->priv->ui_manager, 
		                                    sheet_item->priv->action_group, 0);
			break;
		default:
			break;
	}
	goo_canvas_item_simple_changed (simple, TRUE);
}
示例#19
0
static void
flip_items (Sheet *sheet, GList *items, IDFlip direction)
{
	GList *iter, *item_data_list;
	Coords center, b1, b2;
	Coords after;

	item_data_list = NULL;
	for (iter = items; iter; iter = iter->next) {
		item_data_list = g_list_prepend (item_data_list,
					sheet_item_get_data (iter->data));
	}

	item_data_list_get_absolute_bbox (item_data_list, &b1, &b2);

	// FIXME center is currently not used by item_data_flip (part.c implentation)
	center.x = (b2.x + b1.x) / 2;
	center.y = (b2.y + b1.y) / 2;

	// FIXME - registering an item after flipping it still creates an offset as the position is still 0
	for (iter = item_data_list; iter; iter = iter->next) {
		ItemData *item_data = iter->data;

		if (sheet->state == SHEET_STATE_NONE)
			item_data_unregister (item_data);

		item_data_flip (item_data, direction, &center);

		// Make sure we snap to grid.
		item_data_get_pos (item_data, &after);

		snap_to_grid (sheet->grid, &after.x, &after.y);

		item_data_set_pos (item_data, &after);

		if (sheet->state == SHEET_STATE_NONE)
			item_data_register (item_data);
	}

	g_list_free (item_data_list);
}
示例#20
0
static void
flip_items (Sheet *sheet, GList *items, gboolean horizontal)
{
	GList *list, *item_data_list;
	SheetPos center, b1, b2;
	SheetPos after;

	item_data_list = NULL;
	for (list = items; list; list = list->next) {
		item_data_list = g_list_prepend (item_data_list,
					sheet_item_get_data (list->data));
	}

	item_data_list_get_absolute_bbox (item_data_list, &b1, &b2);

	center.x = (b2.x + b1.x) / 2;
	center.y = (b2.y + b1.y) / 2;

	for (list = item_data_list; list; list = list->next) {
		ItemData *item_data = list->data;

		if (sheet->state == SHEET_STATE_NONE)
			item_data_unregister (item_data);

		item_data_flip (item_data, horizontal, &center);

		// Make sure we snap to grid.
		item_data_get_pos (item_data, &after);

		snap_to_grid (sheet->grid, &after.x, &after.y);

		item_data_move (item_data, &after);

		if (sheet->state == SHEET_STATE_NONE)
			item_data_register (item_data);
	}

	g_list_free (item_data_list);
	g_list_free_full (list, g_object_unref);
}
示例#21
0
文件: part.c 项目: rodolforg/oregano
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");
}
示例#22
0
/**
 * whenever the model changes, this one gets called to update the view representation
 * @attention this recalculates the matrix every time, this makes sure no errors stack up
 * @attention further reading on matrix manipulations
 * @attention http://www.cairographics.org/matrix_transform/
 * @param data the model item, a bare C struct derived from ItemData
 * @param sheet_item the view item, derived from goo_canvas_group/item
 */
static void
part_changed_callback (ItemData *data, SheetItem *sheet_item)
{
	//TODO add static vars in order to skip the redraw if nothing changed
	//TODO may happen once in a while and the check is really cheap
	GSList *iter;
	GooCanvasAnchorType anchor;
	GooCanvasGroup *group;
	GooCanvasItem *canvas_item;
	PartItem *item;
	PartItemPriv *priv;
	Part *part;
	int index = 0;
	Coords pos;
	double scale_h, scale_v;


	// states
	int rotation;
	IDFlip flip;

	g_return_if_fail (sheet_item != NULL);
	g_return_if_fail (IS_PART_ITEM (sheet_item));

	item = PART_ITEM (sheet_item);
	group = GOO_CANVAS_GROUP (item);
	part = PART (data);

	priv = item->priv;

	// init the states

	flip = part_get_flip (part);
	rotation = part_get_rotation (part);

	DEGSANITY (rotation);

	scale_h = (flip & ID_FLIP_HORIZ) ? -1. : 1.;
	scale_v = (flip & ID_FLIP_VERT) ? -1. : 1.;


	item_data_get_pos (data, &pos);
	// Move the canvas item and invalidate the bbox cache.
	goo_canvas_item_set_simple_transform (GOO_CANVAS_ITEM (sheet_item),
	                                      pos.x,
	                                      pos.y,
	                                      1.0,
	                                      0.0);

	cairo_matrix_t morph, inv;
	cairo_status_t done;

	cairo_matrix_init_rotate (&morph, DEG2RAD (rotation));
	cairo_matrix_scale (&morph, scale_h, scale_v);

	inv = morph;
	done = cairo_matrix_invert (&inv);
	if (done != CAIRO_STATUS_SUCCESS) {
		g_warning ("Failed to invert matrix. This should never happen. Never!");
		return;
	}

	// rotate all items in the canvas group
	for (index = 0; index < group->items->len; index++) {
		canvas_item = GOO_CANVAS_ITEM (group->items->pdata[index]);
		goo_canvas_item_set_transform (GOO_CANVAS_ITEM (canvas_item), &morph);
	}

	// revert the rotation of all labels and change their anchor to not overlap too badly
	// this assures that the text is always horizontal and properly aligned
	anchor = angle_to_anchor (rotation);

	for (iter = priv->label_items; iter; iter = iter->next) {
		g_object_set (iter->data,
		              "anchor", anchor,
		              NULL);

		goo_canvas_item_set_transform (iter->data, &inv);

	}
	// same for label nodes
	for (iter = priv->label_nodes; iter; iter = iter->next) {
		g_object_set (iter->data,
		              "anchor", anchor, 
		              NULL);

		goo_canvas_item_set_transform (iter->data, &inv);
	}


	// Invalidate the bounding box cache.
	priv->cache_valid = FALSE;
}
示例#23
0
/**
 * 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;
}
示例#24
0
static void
write_xml_part (Part *part, parseXmlContext *ctxt)
{
	PartPriv *priv;
	xmlNodePtr node_part;
	gchar *str;
	Coords pos;

	priv = part->priv;

	// Create a node for the part.
	node_part = xmlNewChild (ctxt->node_parts, ctxt->ns, BAD_CAST "part", NULL);
	if (!node_part) {
		g_warning ("Failed during save of part %s.\n", priv->name);
		return;
	}

	str = g_strdup_printf ("%d", priv->rotation);
	xmlNewChild (node_part, ctxt->ns, BAD_CAST "rotation",
		xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST str));
	g_free (str);

	if (priv->flip & ID_FLIP_HORIZ)
		xmlNewChild (node_part, ctxt->ns, BAD_CAST "flip",
			xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST "horizontal"));

	if (priv->flip & ID_FLIP_VERT)
		xmlNewChild (node_part, ctxt->ns, BAD_CAST "flip",
			xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST "vertical"));

	// Store the name.
	xmlNewChild (node_part, ctxt->ns, BAD_CAST "name",
		xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST priv->name));

	// Store the name of the library the part resides in.
	xmlNewChild (node_part, ctxt->ns, BAD_CAST "library",
		xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST priv->library->name));

	// Which symbol to use.
	xmlNewChild (node_part, ctxt->ns, BAD_CAST "symbol",
		xmlEncodeEntitiesReentrant (ctxt->doc, BAD_CAST priv->symbol_name));

	// Position.
	item_data_get_pos (ITEM_DATA (part), &pos);
	str = g_strdup_printf ("(%g %g)", pos.x, pos.y);
	xmlNewChild (node_part, ctxt->ns, BAD_CAST "position", BAD_CAST str);
	g_free (str);

	// Create a node for the properties.
	ctxt->node_props = xmlNewChild (node_part, ctxt->ns, BAD_CAST "properties",
		NULL);
	if (!ctxt->node_props) {
		g_warning ("Failed during save of part %s.\n", priv->name);
		return;
	}
	else{
		g_slist_foreach (priv->properties, (GFunc) write_xml_property,
			ctxt);
	}

	// Create a node for the labels.
	ctxt->node_labels = xmlNewChild (node_part, ctxt->ns, BAD_CAST "labels", NULL);
	if (!ctxt->node_labels) {
		g_warning ("Failed during save of part %s.\n", priv->name);
		return;
	}
	else{
		g_slist_foreach (priv->labels, (GFunc) write_xml_label, ctxt);
	}
}
示例#25
0
/**
 * \brief rotate an item by an @angle increment (may be negative)
 *
 * @angle the increment the item will be rotated (usually 90° steps)
 * @center_pos if rotated as part of a group, this is the center to rotate
 *around
 */
static void part_rotate (ItemData *data, int angle, Coords *center_pos)
{
	g_return_if_fail (data);
	g_return_if_fail (IS_PART (data));

	cairo_matrix_t morph, morph_rot, local_rot;
	Part *part;
	PartPriv *priv;
	gboolean handler_connected;
	// Coords b1, b2;

	part = PART (data);

	priv = part->priv;

	// FIXME store vanilla coords, apply the morph
	// FIXME to these and store the result in the
	// FIXME instance then everything will be fine
	// XXX also prevents rounding yiggle up downs

	angle /= 90;
	angle *= 90;

	cairo_matrix_init_rotate (&local_rot, (double)angle * M_PI / 180.);

	cairo_matrix_multiply (item_data_get_rotate (data), item_data_get_rotate (data), &local_rot);

	morph_rot = *(item_data_get_rotate (data));

	cairo_matrix_multiply (&morph, &morph_rot, item_data_get_translate (data));

	Coords delta_to_center, delta_to_center_transformed;
	Coords delta_to_apply, delta_bbox;
	Coords bbox_center, bbox_center_transformed;
	Coords item_pos;

// get bbox
#if 0 // this causes #115 to reappear
	item_data_get_relative_bbox (ITEM_DATA (part), &b1, &b2);
	bbox_center = coords_average (&b1, &b2);
#endif
	item_data_get_pos (ITEM_DATA (part), &item_pos);

	Coords rotation_center;

	if (center_pos == NULL) {
		rotation_center = coords_sum (&bbox_center, &item_pos);
	} else {
		rotation_center = *center_pos;
	}

	delta_to_center_transformed = delta_to_center = coords_sub (&rotation_center, &item_pos);
	cairo_matrix_transform_point (&local_rot, &(delta_to_center_transformed.x),
	                              &(delta_to_center_transformed.y));

	delta_to_apply = coords_sub (&delta_to_center, &delta_to_center_transformed);

#define DEBUG_THIS 0
	// use the cairo matrix funcs to transform the pin
	// positions relative to the item center
	// this is only indirectly related to displayin
	// HINT: we need to modify the actual pins to make the
	// pin tests work being used to detect connections

	gint i;
	gdouble x, y;
	// Rotate the pins.
	for (i = 0; i < priv->num_pins; i++) {
		x = priv->pins_orig[i].offset.x;
		y = priv->pins_orig[i].offset.y;
		cairo_matrix_transform_point (&morph_rot, &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_move (data, &delta_to_apply);

	handler_connected = g_signal_handler_is_connected (G_OBJECT (data), data->changed_handler_id);
	if (handler_connected) {
		g_signal_emit_by_name (G_OBJECT (data), "changed");
	} else {
		NG_DEBUG ("handler not yet registerd.");
	}
	NG_DEBUG ("\n\n");
}
示例#26
0
文件: part.c 项目: rodolforg/oregano
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);
}
示例#27
0
文件: part.c 项目: rodolforg/oregano
/**
 * 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");
	}

}