Пример #1
0
static void
update_tux(gint direction)
{
  gint rotation = 0;
  GooCanvasBounds bounds;
  gdouble scale;

  /* Our svg image of tux is faced south */
  switch(direction)
    {
    case EAST:
      rotation = -90;
      break;
    case WEST:
      rotation = 90;
      break;
    case NORTH:
      rotation = 180;
      break;
    case SOUTH:
      rotation = 0;
      break;
    }

  goo_canvas_item_set_transform(tuxitem, NULL);

  goo_canvas_item_get_bounds(tuxitem, &bounds);

  scale = (gdouble) cellsize / (bounds.x2 - bounds.x1);
  goo_canvas_item_scale(tuxitem, scale, scale);

  goo_canvas_item_rotate( tuxitem, rotation,
			  (bounds.x2-bounds.x1)/2,
			  (bounds.y2-bounds.y1)/2);


  // update the running shoes
  if(run_fast_possible && run_fast) {
	  goo_canvas_item_set_transform(tuxshoes, NULL);

	  scale = (gdouble) cellsize / (bounds.x2 - bounds.x1);
	  goo_canvas_item_scale(tuxshoes, scale, scale);

	  goo_canvas_item_rotate( tuxshoes, rotation,
				  (bounds.x2-bounds.x1)/2,
				  (bounds.y2-bounds.y1)/2);
  }
}
Пример #2
0
/*
 * Same as draw rect but for an image
 */
static void move_image(GooCanvasItem *group,
		       int x, int y, GooCanvasItem *item)
{
  int x1,y1;
  y1=cellsize*(y)-hoogte + board_border_y;
  x1=cellsize*(x)-breedte + board_border_x;

  goo_canvas_item_set_transform(item, NULL);
  goo_canvas_item_translate(item,
  			    x1, y1);

  goo_canvas_item_raise(item, NULL);
}
Пример #3
0
/** Setting the bar location
 * @param[in] x the bar x coordinate, -1 to set the default
 * @param[in] y the bar y coordinate, -1 to set the default
 * @param[in] zoom the bar zoom factor, -1 to set the default
 */
static void
bar_location (int x, int y, double zoom)
{
  // Make the y coord be assigned at its bottom
  int ny = (y == -1 ? _default_y : y);
  ny += BARHEIGHT - (zoom == -1 ? _default_zoom : zoom) * BARHEIGHT;

  goo_canvas_item_set_transform(rootitem, NULL);

  GooCanvasBounds bounds;
  goo_canvas_item_get_bounds(rootitem, &bounds);
  int nx = (x == -1 ? (BOARDWIDTH - (bounds.x2 - bounds.x1))/2 : x);
  goo_canvas_item_translate(rootitem, nx, ny);
  goo_canvas_item_scale(rootitem,
			(zoom == -1 ? _default_zoom : zoom),
			(zoom == -1 ? _default_zoom : zoom));
  //#endif
}
Пример #4
0
static void
update_preview (Browser *br)
{
	LibraryPart *library_part;
	gdouble new_x, new_y, x1, y1, x2, y2;
	gdouble text_width;
	gdouble width, height;
	GooCanvasBounds bounds;
	gdouble scale; 
	cairo_matrix_t transf, affine;
	gchar *part_name;
	char *description;
	GtkTreeModel *model;
	GtkTreeIter iter;
	GtkTreeSelection *selection;

	// Get the current selected row
	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (br->list));
	model = gtk_tree_view_get_model (GTK_TREE_VIEW (br->list));

	if (!GTK_IS_TREE_SELECTION (selection)) return;
	
	if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
		return;
	}

	gtk_tree_model_get (model, &iter, 0, &part_name, -1);

	library_part = library_get_part (br->library, part_name);
	
	// If there is already a preview part-item, destroy its group and create a
	// new one.
	if (br->preview != NULL) {
		goo_canvas_item_remove (GOO_CANVAS_ITEM (br->preview));
	}
	
	br->preview = GOO_CANVAS_GROUP (goo_canvas_group_new (
	    goo_canvas_get_root_item (GOO_CANVAS (br->canvas)),
	    NULL));

	goo_canvas_set_bounds (GOO_CANVAS (br->canvas), 0.0, 0.0, 250.0, 110.0);

	g_object_get (br->preview, 
	              "width", &width, 
	              "height", &height, 
	              NULL);
	
	if (!library_part)
		return;

	part_item_create_canvas_items_for_preview (br->preview, library_part);

	// Unconstraint the canvas width & height to adjust for the part description
	g_object_set (br->preview,
	              "width", -1.0,
	              "height", -1.0,
	              NULL);
	
	// Get the coordonates */
	goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (br->preview), &bounds);
	x1 = bounds.x1;
	x2 = bounds.x2;
	y1 = bounds.y1;
	y2 = bounds.y2;

	// Translate in such a way that the canvas centre remains in (0, 0) 
	cairo_matrix_init_translate (&transf, -(x2 + x1) / 2.0f + PREVIEW_WIDTH / 2,
	                             -(y2 + y1) / 2.0f + PREVIEW_HEIGHT / 2);

	// Compute the scale of the widget 
	if ((x2 - x1 != 0) || (y2 - y1 != 0)) {
		if ((x2 - x1) < (y2 - y1))
			scale = 0.60f * PREVIEW_HEIGHT / (y2 - y1);
		else
			scale = 0.60f * PREVIEW_WIDTH / (x2 - x1);
	} 
	else
		scale = 5;

	cairo_matrix_init_scale (&affine, scale, scale);
	cairo_matrix_multiply (&transf, &transf, &affine);

	// Apply the transformation 
	goo_canvas_item_set_transform (GOO_CANVAS_ITEM (br->preview), &transf);
	
	// Compute the motion to centre the Preview widget 
	new_x = 100 + (PREVIEW_WIDTH - x1 - x2) / 2;
	new_y = (PREVIEW_HEIGHT - y1 - y2) / 2 - 10;

	// Apply the transformation 
	if (scale > 5.0) scale = 3.0;
	goo_canvas_item_set_simple_transform (GOO_CANVAS_ITEM (br->preview), 
	                                      new_x,
	                                      new_y,
	                                      scale,
	                                      0.0);
    	
	description = g_strdup (library_part->description);
	wrap_string (description, 20);
	g_object_set (br->description,
	              "text", description, 
	              NULL);
	g_free (description);

	g_object_get (G_OBJECT (br->description),
	              "width", &text_width, 
	              NULL);
	
	goo_canvas_item_set_simple_transform (GOO_CANVAS_ITEM (br->description), 
	                                      50.0, 
	                                      -20.0,
	                                      1.0,
	                                      0.0);
	g_free (part_name);
}
Пример #5
0
/* Setting list of available icons in the control bar */
static void
bar_set (const GComprisBarFlags flags)
{
  // Always reset the zoom factor or the calculation
  // will be wrong
  goo_canvas_item_set_transform(rootitem, NULL);

  _hidden = FALSE;
  goo_canvas_item_raise(rootitem, NULL);

  /* Non yet initialized : Something Wrong */
  if(get_item(GC_BAR_LEVEL) == NULL)
    {
      g_message("in bar_set_level, level_item uninitialized : should not happen\n");
      return;
    }

  current_flags = flags;

  if(gc_help_has_board(gc_board_get_current()))
    current_flags |= GC_BAR_HELP;

  if(flags&GC_BAR_ABOUT)
    current_flags |= GC_BAR_ABOUT;

  if(flags&GC_BAR_CONFIG)
    current_flags |= GC_BAR_CONFIG;

  if(flags&GC_BAR_REPEAT_ICON)
    current_flags |= GC_BAR_REPEAT_ICON;

  if(flags&GC_BAR_REPEAT)
    current_flags |= GC_BAR_REPEAT;

  update_exit_button();

  GSList *list;
  double x = 0;
  for (list = buttons; list != NULL; list = list->next)
    {
      GooCanvasItem *item = (GooCanvasItem *)list->data;
      GComprisBarFlags flag =
        GPOINTER_TO_UINT(g_object_get_data(G_OBJECT (item), "flag"));

      if (flag & current_flags)
        {
          GooCanvasBounds bounds;
	  SET_ITEM_LOCATION(item, x, -20);
          goo_canvas_item_get_bounds(item, &bounds);
          gc_item_focus_init(item, NULL);
          x += bounds.x2 - bounds.x1 + BAR_GAP;

          g_object_set (item,
                        "visibility", GOO_CANVAS_ITEM_VISIBLE,
                        NULL);
        }
      else
          g_object_set (item,
                        "visibility", GOO_CANVAS_ITEM_INVISIBLE,
                        NULL);

    }

  /* Scale the bar back to fit the buttons, no more */
  SET_ITEM_LOCATION(bar_item, 0, 0);
  GooCanvasBounds bounds;
  goo_canvas_item_get_bounds(bar_item, &bounds);
  goo_canvas_item_scale(bar_item,
                        x / (bounds.x2 - bounds.x1),
                        1);

  // Always center the bar with its new bounds
  //SET_ITEM_LOCATION(rootitem, 0, _default_y);
  bar_location (-1, -1, -1);
}
Пример #6
0
// Event handler for a SheetItem
gboolean
sheet_item_event (GooCanvasItem *sheet_item,
		 GooCanvasItem *sheet_target_item,
		 GdkEvent *event, Sheet *sheet)
{
	// Remember the last position of the mouse cursor.
	static double last_x, last_y;
	GooCanvas *canvas;
	SheetPriv *priv;
	GList *list;
	// Mouse cursor position in window coordinates, snapped to the grid spacing.
	double snapped_x, snapped_y;
	// Move the selected item(s) by this movement.
	double dx, dy;
	
	
	g_return_val_if_fail (sheet_item != NULL, FALSE);
	g_return_val_if_fail (sheet != NULL, FALSE);

	priv = sheet->priv;

	canvas = GOO_CANVAS (sheet);
	
	switch (event->type) {
	case GDK_BUTTON_PRESS:
		// Grab focus to sheet for correct use of events
		gtk_widget_grab_focus (GTK_WIDGET (sheet));
		switch (event->button.button) {
		case 1:
			g_signal_stop_emission_by_name (sheet_item, "button_press_event");
			sheet->state = SHEET_STATE_DRAG_START;
			sheet_get_pointer (sheet, &last_x, &last_y);
			break;
		case 3:
			g_signal_stop_emission_by_name (sheet_item, "button_press_event");

			if (sheet->state != SHEET_STATE_NONE)
				return TRUE;

			// Bring up a context menu for right button clicks.
			if (!SHEET_ITEM (sheet_item)->priv->selected &&
				!((event->button.state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK))
					sheet_select_all (sheet, FALSE);

			sheet_item_select (SHEET_ITEM (sheet_item), TRUE);

			sheet_item_run_menu (SHEET_ITEM (sheet_item), sheet, 
			                     (GdkEventButton *) event);
			break;
		default:
			return FALSE;
		}
		break;

	case GDK_2BUTTON_PRESS:
		// Do not interfere with object dragging.
		if (sheet->state == SHEET_STATE_DRAG)
			return FALSE;

		switch (event->button.button) {
		case 1:
			if (sheet->state == SHEET_STATE_DRAG_START)
				sheet->state = SHEET_STATE_NONE;
			g_signal_stop_emission_by_name (sheet_item, "button_press_event");
			g_signal_emit_by_name (sheet_item, "double_clicked");
			break;

		default:
			return FALSE;
		}
		break;

	case GDK_3BUTTON_PRESS:
		g_signal_stop_emission_by_name (sheet_item, "button_press_event");
		return TRUE;

	case GDK_BUTTON_RELEASE:
		switch (event->button.button) {
		case 1:
			if (sheet->state != SHEET_STATE_DRAG &&
				sheet->state != SHEET_STATE_DRAG_START)
				return TRUE;

			g_signal_stop_emission_by_name (sheet_item, "button-release-event");

			if (sheet->state == SHEET_STATE_DRAG_START) {
				sheet->state = SHEET_STATE_NONE;

				if (!(event->button.state & GDK_SHIFT_MASK))
					sheet_select_all (sheet, FALSE);

				if (IS_SHEET_ITEM (sheet_item))
					sheet_item_select (SHEET_ITEM (sheet_item), TRUE);

				return TRUE;
			}

			// Get the mouse motion
			sheet_get_pointer (sheet, &snapped_x, &snapped_y);
			snapped_x -= last_x;
			snapped_y -= last_y;

			sheet->state = SHEET_STATE_NONE;
			goo_canvas_pointer_ungrab (canvas, GOO_CANVAS_ITEM (sheet_item),
			                           event->button.time);

			// Reparent the selected objects to the normal group
			// to have correct behaviour
			for (list = priv->selected_objects; list; list = list->next) {
            	sheet_item_reparent (SHEET_ITEM (list->data), 
	                                 sheet->object_group);
            }

			for (list = priv->selected_objects; list; list = list->next) {
            	ItemData *item_data;
				Coords pos;

                item_data = SHEET_ITEM (list->data)->priv->data;
				pos.x = snapped_x;
				pos.y = snapped_y;
				item_data_move (item_data, &pos);
                item_data_register (item_data);
            }
			g_list_free_full (list, g_object_unref);
				
			break;
		}
			
	case GDK_KEY_PRESS:
		switch (event->key.keyval) {
			case GDK_KEY_r:
				sheet_rotate_selection (sheet);
				{
					gdouble x, y;
					GooCanvasBounds bounds;
					
					sheet_get_pointer (sheet, &x, &y);

                    // Center the objects around the mouse pointer.
					goo_canvas_item_get_bounds (
						GOO_CANVAS_ITEM (priv->floating_group), &bounds);

					dx = x - (bounds.x1 + bounds.x2) / 2;
					dy = y - (bounds.y1 + bounds.y2) / 2;
                    snap_to_grid (sheet->grid, &dx, &dy);

					goo_canvas_item_translate (
						GOO_CANVAS_ITEM (priv->floating_group), dx, dy);

                    last_x = snapped_x;
                    last_y = snapped_y;
				}
				break;
			default:
				return FALSE;
		}
		return TRUE;

	case GDK_MOTION_NOTIFY:
		if (sheet->state != SHEET_STATE_DRAG &&
			sheet->state != SHEET_STATE_DRAG_START)
			return FALSE;

		if (sheet->state == SHEET_STATE_DRAG_START) {
			sheet->state = SHEET_STATE_DRAG;
			
			// Update the selection if needed. 
			if (IS_SHEET_ITEM (sheet_item)					&&
	    		(!SHEET_ITEM (sheet_item)->priv->selected))	{
				if (!(event->button.state & GDK_SHIFT_MASK)) {
					sheet_select_all (sheet, FALSE);
				}
				sheet_item_select (SHEET_ITEM (sheet_item), TRUE);
			}

			// Reparent the selected objects so that we can move them 
			// efficiently.
			for (list = priv->selected_objects; list; list = list->next) {
				ItemData *item_data;

				item_data = SHEET_ITEM (list->data)->priv->data;
				item_data_unregister (item_data);
				sheet_item_reparent (SHEET_ITEM (list->data), 
                                     priv->selected_group);
			}
			
			goo_canvas_pointer_grab (canvas, GOO_CANVAS_ITEM (sheet_item),
	    		GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
	    		NULL, 
	    		event->button.time);
		}

		// Set last_x & last_y to the pointer position
		sheet_get_pointer (sheet, &snapped_x, &snapped_y);

		dx = snapped_x - last_x;
		dy = snapped_y - last_y;
		
		// Check that we don't move outside the sheet... 
		// Horizontally: 
		/*
		if (cx1 <= 0) {  // leftmost edge 
			dx = dx - x1;
			snap_to_grid (sheet->grid, &dx, NULL);
			snapped_x = last_x + dx;
		} 
		else if (cx2 >= sheet_width) {  // rightmost edge 
			dx = dx - (x2 - sheet_width / priv->zoom);
			snap_to_grid (sheet->grid, &dx, NULL);
			snapped_x = last_x + dx;
		}

		// And vertically:
		if (cy1 <= 0) {  // upper edge
			dy = dy - y1;
			snap_to_grid (sheet->grid, NULL, &dy);
			snapped_y = last_y + dy;
		} 
		else if (cy2 >= sheet_height) {  // lower edge 
			dy = dy - (y2 - sheet_height / priv->zoom);
			snap_to_grid (sheet->grid, NULL, &dy);
			snapped_y = last_y + dy;
		}
		//last_x = snapped_x;
		//last_y = snapped_y;
		*/

		goo_canvas_item_set_transform (GOO_CANVAS_ITEM (priv->selected_group), 
		                               NULL);
		goo_canvas_item_translate (GOO_CANVAS_ITEM (priv->selected_group), 
			                       dx, dy);
		return TRUE;
	
	default:
		return FALSE;
	}
	return TRUE;
}
Пример #7
0
// Event handler for a "floating" group of objects.
int sheet_item_floating_event (Sheet *sheet, const GdkEvent *event)
{
	SheetPriv *priv;
	GList *list;
	static gboolean keep = FALSE;

	// Remember the start position of the mouse cursor.
	static Coords last = {0., 0.};

	// Mouse cursor position in window coordinates, snapped to the grid spacing.
	static Coords snapped = {0., 0.};

	// Move the selected item(s) by this movement.
	Coords delta = {0., 0.};

	g_return_val_if_fail (sheet != NULL, FALSE);
	g_return_val_if_fail (IS_SHEET (sheet), FALSE);
	g_return_val_if_fail (sheet->priv->floating_objects != NULL, FALSE);

	priv = sheet->priv;

	switch (event->type) {
	case GDK_BUTTON_RELEASE:
		g_signal_stop_emission_by_name (sheet, "event");
		break;

	case GDK_BUTTON_PRESS:
		if (sheet->state != SHEET_STATE_FLOAT)
			return TRUE;

		switch (event->button.button) {
		case 2:
		case 4:
		case 5:
			return FALSE;

		case 1:
			// do not free the floating items, but use them like a stamp
			keep = event->button.state & GDK_CONTROL_MASK;

			// Continue adding if CTRL is pressed
			if (!keep) {
				sheet->state = SHEET_STATE_NONE;
				g_signal_stop_emission_by_name (sheet, "event");
				if (g_signal_handler_is_connected (sheet, sheet->priv->float_handler_id))
					g_signal_handler_disconnect (sheet, sheet->priv->float_handler_id);

				sheet->priv->float_handler_id = 0;
			}
			// FIXME assert that `Coords current` has been set by now!
			for (list = priv->floating_objects; list; list = list->next) {
				SheetItem *floating_item;
				ItemData *floating_data;

				// Create a real item.
				floating_item = list->data;
				if (!keep) {
					floating_data = sheet_item_get_data (floating_item);
					g_object_set (floating_item, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
				} else {
					// FIXME the bounding box of the clone is wrong
					floating_data = item_data_clone (sheet_item_get_data (floating_item));
				}
				g_object_ref (G_OBJECT (floating_data));

				NG_DEBUG ("Item Data Pos will be %lf %lf", snapped.x, snapped.y)

				item_data_set_pos (floating_data, &snapped);
				item_data_snap (floating_data, sheet->grid);

				schematic_add_item (schematic_view_get_schematic_from_sheet (sheet), floating_data);

				if (!keep)
					g_object_unref (G_OBJECT (floating_item));
			}

			if (keep) {
				g_object_set (G_OBJECT (priv->floating_group), "x", snapped.x, "y", snapped.y,
				              NULL);
			} else {
				g_list_free (priv->floating_objects);
				priv->floating_objects = NULL;
			}
			break;

		case 3:
			// Cancel the "float-placement" for button-3 clicks.
			g_signal_stop_emission_by_name (sheet, "event");
			sheet_item_cancel_floating (sheet);
			break;
		}
		break;

	case GDK_2BUTTON_PRESS:
	case GDK_3BUTTON_PRESS:
		g_signal_stop_emission_by_name (sheet, "event");
		return TRUE;

	case GDK_MOTION_NOTIFY:
// keep track of the position, as `sheet_get_pointer*()` does not work
// in other events than MOTION_NOTIFY
#if 0
		{
			Coords tmp;
			last = current;
			if (sheet_get_pointer (sheet, &tmp.x, &tmp.y)) {
				snapped_current = current = tmp;
				snap_to_grid (sheet->grid, &snapped_current.x, &snapped_current.y);
			}
		}
#endif
		if (sheet->state != SHEET_STATE_FLOAT && sheet->state != SHEET_STATE_FLOAT_START)
			return FALSE;

		g_signal_stop_emission_by_name (sheet, "event");

		// Get pointer position independantly of the zoom

		if (sheet->state == SHEET_STATE_FLOAT_START) {
			sheet->state = SHEET_STATE_FLOAT;
			last.x = last.y = 0.;
			// Reparent the selected objects so that we can move them
			// efficiently.
			for (list = priv->floating_objects; list; list = list->next) {
				sheet_item_reparent (SHEET_ITEM (list->data), priv->floating_group);
				// Set the floating item visible
				g_object_set (G_OBJECT (list->data), "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
			}
#if 0
			GooCanvasBounds box;
			goo_canvas_item_get_bounds (priv->floating_group, &box);
#endif
			NG_DEBUG ("\n\n\nFLOAT ### START\n\n\n\n");
		}

		sheet_get_pointer_snapped (sheet, &snapped.x, &snapped.y);

		delta = coords_sub (&snapped, &last);
		NG_DEBUG ("drag floating current      sx=%lf sy=%lf \n", snapped.x, snapped.y);
		NG_DEBUG ("drag floating last         lx=%lf ly=%lf \n", last.x, last.y);
		NG_DEBUG ("drag floating delta     -> dx=%lf dy=%lf \n", delta.x, delta.y);

#if !FIXME_INCREMENTAL_MOVMENT_DOES_NOT_WORK
		last = snapped;
#else
		goo_canvas_item_set_transform (GOO_CANVAS_ITEM (priv->floating_group), NULL);
#endif
		goo_canvas_item_translate (GOO_CANVAS_ITEM (priv->floating_group), delta.x, delta.y);

		break;

	case GDK_KEY_PRESS:
		switch (event->key.keyval) {
		case GDK_KEY_r:
		case GDK_KEY_R: {
			Coords bbdelta;
			GooCanvasBounds bounds;

			// Center the objects around the mouse pointer.
			goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (priv->floating_group), &bounds);

			bbdelta.x = (bounds.x2 - bounds.x1) / 2.;
			bbdelta.y = (bounds.y2 - bounds.y1) / 2.;

			sheet_rotate_ghosts (sheet);

			// Center the objects around the mouse pointer.
			goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (priv->floating_group), &bounds);

			bbdelta.x -= (bounds.x2 - bounds.x1) / 2.;
			bbdelta.y -= (bounds.y2 - bounds.y1) / 2.;

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

			goo_canvas_item_translate (GOO_CANVAS_ITEM (priv->floating_group), bbdelta.x,
			                           bbdelta.y);
		} break;
		default:
			return FALSE;
		}
	default:
		return FALSE;
	}
	return TRUE;
}
Пример #8
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;
}