// Cancel the placement of floating items and remove them. void sheet_item_cancel_floating (Sheet *sheet) { GooCanvasGroup *group; GList *list; g_return_if_fail (sheet != NULL); g_return_if_fail (IS_SHEET (sheet)); group = GOO_CANVAS_GROUP (sheet->priv->floating_group); if (group == NULL) return; if (sheet->state != SHEET_STATE_FLOAT && sheet->state != SHEET_STATE_FLOAT_START) return; if (g_signal_handler_is_connected (sheet, sheet->priv->float_handler_id)) g_signal_handler_disconnect (sheet, sheet->priv->float_handler_id); // TODO verfiy that the following has no nasty sideffects for (list = sheet->priv->floating_objects; list; list = list->next) { goo_canvas_item_remove (list->data); // remove from canvas and free } g_list_free (sheet->priv->floating_objects); sheet->priv->floating_objects = NULL; goo_canvas_item_remove (GOO_CANVAS_ITEM (group)); // Create a new empty group to prepare next floating group sheet->priv->floating_group = GOO_CANVAS_GROUP ( goo_canvas_group_new (GOO_CANVAS_ITEM (sheet->object_group), "x", 0.0, "y", 0.0, NULL)); // sheet_clear_ghosts (sheet); sheet->priv->float_handler_id = 0; sheet->state = SHEET_STATE_NONE; }
static int select_idle_callback (PartItem *item) { GooCanvasItem *canvas_item = NULL; int index; g_return_val_if_fail (item != NULL, FALSE); for (index = 0; index < GOO_CANVAS_GROUP (item)->items->len; index++) { canvas_item = GOO_CANVAS_ITEM (GOO_CANVAS_GROUP (item)->items->pdata[index]); g_object_set (canvas_item, "stroke-color", SELECTED_COLOR, NULL); } g_object_unref (G_OBJECT (item)); return FALSE; }
static int deselect_idle_callback (PartItem *item) { GooCanvasItem *canvas_item = NULL; int index; for (index = 0; index < GOO_CANVAS_GROUP (item)->items->len; index++) { canvas_item = GOO_CANVAS_ITEM (GOO_CANVAS_GROUP (item)->items->pdata[index]); if (GOO_IS_CANVAS_TEXT (canvas_item)) { g_object_set (canvas_item, "stroke-color", LABEL_COLOR, NULL); } else { g_object_set (canvas_item, "stroke-color", NORMAL_COLOR, NULL); } } g_object_unref (G_OBJECT (item)); return FALSE; }
PartItem * part_item_new (Sheet *sheet, Part *part) { Library *library; LibraryPart *library_part; PartPriv *priv; PartItem *item; priv = part->priv; library = priv->library; library_part = library_get_part (library, priv->name); // Create the PartItem canvas item item = part_item_canvas_new (sheet, part); create_canvas_items (GOO_CANVAS_GROUP (item), library_part); create_canvas_labels (item, part); create_canvas_label_nodes (item, part); goo_canvas_item_ensure_updated (GOO_CANVAS_ITEM (item)); return item; }
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 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); }
// This function defines the drawing sheet on which schematic will be drawn GtkWidget * sheet_new (int width, int height) { GooCanvas *sheet_canvas; GooCanvasGroup *sheet_group; GooCanvasPoints *points; Sheet *sheet; GtkWidget *sheet_widget; GooCanvasItem *root; // Creation of the Canvas sheet = SHEET (g_object_new (TYPE_SHEET, NULL)); sheet_canvas = GOO_CANVAS (sheet); g_object_set (G_OBJECT (sheet_canvas), "bounds-from-origin", FALSE, "bounds-padding", 4.0, "background-color-rgb", 0xFFFFFF, NULL); root = goo_canvas_get_root_item (sheet_canvas); sheet_group = GOO_CANVAS_GROUP (goo_canvas_group_new ( root, NULL)); sheet_widget = GTK_WIDGET (sheet); goo_canvas_set_bounds (GOO_CANVAS (sheet_canvas), 0, 0, width + 20, height + 20); // Define vicinity around GooCanvasItem //sheet_canvas->close_enough = 6.0; sheet->priv->width = width; sheet->priv->height = height; // Create the dot grid. sheet->grid = grid_create (GOO_CANVAS_ITEM (sheet_group), width, height); // Everything outside the sheet should be gray. // top // goo_canvas_rect_new (GOO_CANVAS_ITEM (sheet_group), 0.0, 0.0, (double) width + 20.0, 20.0, "fill_color", "gray", "line-width", 0.0, NULL); goo_canvas_rect_new (GOO_CANVAS_ITEM (sheet_group), 0.0, (double) height, (double) width + 20.0, (double) height + 20.0, "fill_color", "gray", "line-width", 0.0, NULL); // right // goo_canvas_rect_new (GOO_CANVAS_ITEM (sheet_group), 0.0, 0.0, 20.0, (double) height + 20.0, "fill_color", "gray", "line-width", 0.0, NULL); goo_canvas_rect_new (GOO_CANVAS_ITEM (sheet_group), (double) width, 0.0, (double) width + 20.0, (double) height + 20.0, "fill_color", "gray", "line-width", 0.0, NULL); // Draw a thin black border around the sheet. points = goo_canvas_points_new (5); points->coords[0] = 20.0; points->coords[1] = 20.0; points->coords[2] = width; points->coords[3] = 20.0; points->coords[4] = width; points->coords[5] = height; points->coords[6] = 20.0; points->coords[7] = height; points->coords[8] = 20.0; points->coords[9] = 20.0; goo_canvas_polyline_new (GOO_CANVAS_ITEM (sheet_group), FALSE, 0, "line-width", 1.0, "points", points, NULL); goo_canvas_points_unref (points); // Finally, create the object group that holds all objects. sheet->object_group = GOO_CANVAS_GROUP (goo_canvas_group_new ( root, "x", 0.0, "y", 0.0, NULL)); NG_DEBUG ("root group %p", sheet->object_group); sheet->priv->selected_group = GOO_CANVAS_GROUP (goo_canvas_group_new ( GOO_CANVAS_ITEM (sheet->object_group), "x", 0.0, "y", 0.0, NULL)); NG_DEBUG ("selected group %p", sheet->priv->selected_group); sheet->priv->floating_group = GOO_CANVAS_GROUP (goo_canvas_group_new ( GOO_CANVAS_ITEM (sheet->object_group), "x", 0.0, "y", 0.0, NULL)); NG_DEBUG ("floating group %p", sheet->priv->floating_group); // Hash table that keeps maps coordinate to a specific dot. sheet->priv->node_dots = g_hash_table_new_full (dot_hash, dot_equal, g_free, NULL); //this requires object_group to be setup properly sheet->priv->rubberband_info = rubberband_info_new (sheet); sheet->priv->create_wire_info = create_wire_info_new (sheet); return sheet_widget; }
/** * 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; }