static gboolean gegl_can_process(GeglNode *render_node) { GeglRectangle roi; roi = gegl_node_get_bounding_box (geglGraph->node_pixbuf); g_print("GeglRectangle: height:%i, width:%i\n",roi.height,roi.width); return TRUE; }
static GeglNode * photos_base_item_load (PhotosBaseItem *self, GCancellable *cancellable, GError **error) { PhotosBaseItemPrivate *priv = self->priv; GeglNode *ret_val = NULL; gchar *path = NULL; if (priv->graph == NULL) { path = photos_base_item_download (self, cancellable, error); if (path == NULL) goto out; priv->graph = gegl_node_new (); priv->node = gegl_node_new_child (priv->graph, "operation", "gegl:load", "path", path, NULL); } gegl_node_process (priv->node); priv->bbox = gegl_node_get_bounding_box (priv->node); ret_val = g_object_ref (priv->node); out: g_free (path); return ret_val; }
static void prepare (GeglOperation *operation) { GeglProperties *o = GEGL_PROPERTIES (operation); GeglNode *gegl, *input, *output; GError *error = NULL; gegl = operation->node; if (!o->user_data || !g_str_equal (o->user_data, o->string)) { g_free (o->user_data); o->user_data = g_strdup (o->string); input = gegl_node_get_input_proxy (gegl, "input"); output = gegl_node_get_output_proxy (gegl, "output"); gegl_node_link_many (input, output, NULL); { gchar cwd[81920]; // XXX: should do better getcwd (cwd, sizeof(cwd)); gegl_create_chain (o->string, input, output, 0.0, gegl_node_get_bounding_box (input).height, cwd, &error); } if (error) { gegl_node_set (gegl, "error", error->message, NULL); g_clear_error (&error); } else g_object_set (operation, "error", "", NULL); } }
static gdouble photos_print_setup_get_max_percentage (PhotosPrintSetup *self) { PhotosPrintSetupPrivate *priv = self->priv; GeglRectangle bbox; gdouble height; gdouble page_height; gdouble page_width; gdouble width; gdouble perc; page_width = gtk_page_setup_get_page_width (priv->page_setup, GTK_UNIT_INCH); page_height = gtk_page_setup_get_page_height (priv->page_setup, GTK_UNIT_INCH); bbox = gegl_node_get_bounding_box (priv->node); width = (gdouble) bbox.width / FACTOR_INCH_TO_PIXEL; height = (gdouble) bbox.height / FACTOR_INCH_TO_PIXEL; if (page_width > width && page_height > height) perc = 1.0; else perc = MIN (page_width / width, page_height / height); return perc; }
static void update_autoscale(ViewHelper *self) { GdkRectangle viewport = self->widget_allocation; GeglRectangle bbox = gegl_node_get_bounding_box(self->node); model_rect_to_view_rect(self, &bbox); if (!self->node || viewport.width < 0 || viewport.height < 0 || bbox.width < 0 || bbox.height < 0) return; if (self->autoscale_policy == GEGL_GTK_VIEW_AUTOSCALE_WIDGET) { /* Request widget size change */ /* XXX: Should we reset scale/x/y here? */ g_signal_emit(self, view_helper_signals[SIGNAL_SIZE_CHANGED], 0, &bbox, NULL); } else if (self->autoscale_policy == GEGL_GTK_VIEW_AUTOSCALE_CONTENT) { /* Calculate and set scaling factor to make the content fit inside */ float width_ratio = bbox.width / (float)viewport.width; float height_ratio = bbox.height / (float)viewport.height; float max_ratio = width_ratio >= height_ratio ? width_ratio : height_ratio; float current_scale = view_helper_get_scale(self); view_helper_set_scale(self, current_scale * (1.0 / max_ratio)); } }
void view_helper_set_node(ViewHelper *self, GeglNode *node) { if (self->node == node) return; if (self->node) g_object_unref(self->node); if (node) { g_object_ref(node); self->node = node; g_signal_connect_object(self->node, "computed", G_CALLBACK(computed_event), self, 0); g_signal_connect_object(self->node, "invalidated", G_CALLBACK(invalidated_event), self, 0); if (self->processor) g_object_unref(self->processor); GeglRectangle bbox = gegl_node_get_bounding_box(self->node); self->processor = gegl_node_new_processor(self->node, &bbox); update_autoscale(self); trigger_processing(self, bbox); } else self->node = NULL; }
GeglRectangle * gegl_node_introspectable_get_bounding_box (GeglNode *node) { GeglRectangle bbox = gegl_node_get_bounding_box (node); GeglRectangle *result = g_new (GeglRectangle, 1); *result = bbox; return result; }
static GeglNode * photos_operation_insta_hefe_detect (GeglOperation *operation, gint x, gint y) { PhotosOperationInstaHefe *self = PHOTOS_OPERATION_INSTA_HEFE (operation); GeglRectangle bounds; bounds = gegl_node_get_bounding_box (self->output); if (x >= bounds.x && y >= bounds.y && x < bounds.x + bounds.width && y < bounds.y + bounds.height) return operation->node; return NULL; }
static void photos_operation_insta_hefe_prepare (GeglOperation *operation) { PhotosOperationInstaHefe *self = PHOTOS_OPERATION_INSTA_HEFE (operation); GeglRectangle bbox; bbox = gegl_node_get_bounding_box (self->input); if (!gegl_rectangle_equal (&self->bbox, &bbox)) { self->bbox = bbox; photos_operation_insta_hefe_setup (self); } }
static void photos_image_view_update (PhotosImageView *self) { GdkRectangle viewport; GeglRectangle bbox; float zoom_scaled = 1.0; gint scale_factor; gint viewport_height_real; gint viewport_width_real; if (self->node == NULL) return; gtk_widget_get_allocation (GTK_WIDGET (self), &viewport); if (viewport.width < 0 || viewport.height < 0) return; bbox = gegl_node_get_bounding_box (self->node); if (bbox.width < 0 || bbox.height < 0) return; scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (self)); viewport_height_real = viewport.height * scale_factor; viewport_width_real = viewport.width * scale_factor; if (bbox.height > viewport_height_real || bbox.width > viewport_width_real) { gfloat height_ratio = bbox.height / (gfloat) viewport_height_real; gfloat width_ratio = bbox.width / (gfloat) viewport_width_real; gfloat max_ratio = MAX (height_ratio, width_ratio); zoom_scaled = 1.0 / max_ratio; bbox.width = (gint) (zoom_scaled * bbox.width + 0.5); bbox.height = (gint) (zoom_scaled * bbox.height + 0.5); bbox.x = (gint) (zoom_scaled * bbox.x + 0.5); bbox.y = (gint) (zoom_scaled * bbox.y + 0.5); } self->zoom_scaled = zoom_scaled; self->zoom = self->zoom_scaled / (gfloat) scale_factor; /* At this point, viewport is definitely bigger than bbox. */ self->x_scaled = (bbox.width - viewport_width_real) / 2.0 + bbox.x; self->y_scaled = (bbox.height - viewport_height_real) / 2.0 + bbox.y; self->x = self->x_scaled / (gfloat) scale_factor; self->y = self->y_scaled / (gfloat) scale_factor; }
static void photos_print_setup_set_initial_values (PhotosPrintSetup *self) { PhotosPrintSetupPrivate *priv = self->priv; GeglRectangle bbox; gdouble page_height; gdouble page_width; gdouble factor; gdouble height; gdouble max_perc; gdouble width; factor = get_scale_to_px_factor (self); bbox = gegl_node_get_bounding_box (priv->node); width = (gdouble) bbox.width/factor; height = (gdouble) bbox.height/factor; max_perc = photos_print_setup_get_max_percentage (self); width *= max_perc; height *= max_perc; gtk_range_set_range (GTK_RANGE (priv->scaling), 1, 100 * max_perc); gtk_range_set_increments (GTK_RANGE (priv->scaling), max_perc, 10 * max_perc); gtk_range_set_value (GTK_RANGE (priv->scaling), 100 * max_perc); photos_print_preview_set_scale (PHOTOS_PRINT_PREVIEW (priv->preview), max_perc); gtk_spin_button_set_range (GTK_SPIN_BUTTON (priv->width), 0, width); gtk_spin_button_set_range (GTK_SPIN_BUTTON (priv->height), 0, height); gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->width), width); gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->height), height); gtk_combo_box_set_active (GTK_COMBO_BOX (priv->center), CENTER_BOTH); photos_print_setup_center (gtk_page_setup_get_page_width (priv->page_setup, priv->current_unit), gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->width)), GTK_SPIN_BUTTON (priv->left), GTK_SPIN_BUTTON (priv->right)); photos_print_setup_center (gtk_page_setup_get_page_height (priv->page_setup, priv->current_unit), gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->height)), GTK_SPIN_BUTTON (priv->top), GTK_SPIN_BUTTON (priv->bottom)); page_width = gtk_page_setup_get_page_width (priv->page_setup, priv->current_unit); page_height = gtk_page_setup_get_page_height (priv->page_setup, priv->current_unit); update_image_pos_ranges (self, page_width, page_height, width, height); }
static void on_scale_changed (GtkRange *range, gpointer user_data) { PhotosPrintSetup *self = PHOTOS_PRINT_SETUP (user_data); PhotosPrintSetupPrivate *priv = self->priv; GeglRectangle bbox; gdouble height; gdouble scale; gdouble width; gdouble left, right, top, bottom; gdouble page_width, page_height; gdouble factor; gtk_combo_box_set_active (GTK_COMBO_BOX (priv->center), CENTER_NONE); bbox = gegl_node_get_bounding_box (priv->node); factor = get_scale_to_px_factor (self); width = (gdouble) bbox.width / factor; height = (gdouble) bbox.height / factor; left = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->left)); top = gtk_spin_button_get_value (GTK_SPIN_BUTTON (priv->top)); scale = CLAMP (0.01 * gtk_range_get_value (range), 0, photos_print_setup_get_max_percentage (self)); photos_print_preview_set_scale (PHOTOS_PRINT_PREVIEW (priv->preview), scale); width *= scale; height *= scale; page_width = gtk_page_setup_get_page_width (priv->page_setup, priv->current_unit); page_height = gtk_page_setup_get_page_height (priv->page_setup, priv->current_unit); update_image_pos_ranges (self, page_width, page_height, width, height); right = page_width - left - width; bottom = page_height - top - height; gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->width), width); gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->height), height); gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->right), right); gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->bottom), bottom); }
static void photos_print_operation_constructed (GObject *object) { PhotosPrintOperation *self = PHOTOS_PRINT_OPERATION (object); GeglRectangle bbox; GtkPageSetup *page_setup; gchar *name; G_OBJECT_CLASS (photos_print_operation_parent_class)->constructed (object); page_setup = gtk_page_setup_new (); gtk_print_operation_set_default_page_setup (GTK_PRINT_OPERATION (self), page_setup); bbox = gegl_node_get_bounding_box (self->node); if (bbox.height >= bbox.width) gtk_page_setup_set_orientation (page_setup, GTK_PAGE_ORIENTATION_PORTRAIT); else gtk_page_setup_set_orientation (page_setup, GTK_PAGE_ORIENTATION_LANDSCAPE); g_object_unref (page_setup); name = g_strdup (photos_base_item_get_name (self->item)); if (name == NULL || name[0] == '\0') { GFile *file; const gchar *uri; gchar *basename; uri = photos_base_item_get_uri (self->item); file = g_file_new_for_uri (uri); basename = g_file_get_basename (file); if (g_utf8_validate (basename, -1, NULL)) name = g_strdup (basename); else name = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL); g_free (basename); g_object_unref (file); } gtk_print_operation_set_job_name (GTK_PRINT_OPERATION (self), name); g_free (name); }
void refresh_images(GeglEditorLayer* self) { return; GSList* pair = self->pairs; for(;pair != NULL; pair = pair->next) { node_id_pair *data = pair->data; /* if(node->image != NULL) cairo_surface_destroy(node->image); //TODO: only destory if it has changed*/ const Babl *cairo_argb32 = babl_format("cairo-ARGB32"); const GeglRectangle roi = gegl_node_get_bounding_box(GEGL_NODE(data->node)); g_print("Rect: %dx%d\n", roi.x, roi.y); if(roi.width == 0 || roi.height == 0) { g_print("Empty rectangle: %s\n", gegl_node_get_operation(GEGL_NODE(data->node))); continue; //skip } gegl_editor_show_node_image(self->editor, data->id); gint stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, roi.width); guchar* buf = malloc(stride*roi.height); //make buffer in memory gegl_node_blit(GEGL_NODE(data->node), 1.0, &roi, cairo_argb32, buf, GEGL_AUTO_ROWSTRIDE, GEGL_BLIT_CACHE); cairo_surface_t* image = cairo_image_surface_create_for_data(buf, CAIRO_FORMAT_ARGB32, roi.width, roi.height, stride); // free(buf); gegl_editor_set_node_image(self->editor, data->id, image); } }
static void photos_print_setup_size_changed (PhotosPrintSetup *self, GtkWidget *w_size_x, GtkWidget *w_size_y, GtkWidget *w_margin_x_1, GtkWidget *w_margin_x_2, GtkWidget *w_margin_y_1, GtkWidget *w_margin_y_2, gdouble page_size_x, gdouble page_size_y, gint change) { PhotosPrintSetupPrivate *priv = self->priv; GeglRectangle bbox; gdouble margin_x_1, margin_x_2; gdouble margin_y_1, margin_y_2; gdouble orig_size_x = -1, orig_size_y = -1, scale; gdouble size_x, size_y; gdouble factor; size_x = gtk_spin_button_get_value (GTK_SPIN_BUTTON (w_size_x)); margin_x_1 = gtk_spin_button_get_value (GTK_SPIN_BUTTON (w_margin_x_1)); margin_y_1 = gtk_spin_button_get_value (GTK_SPIN_BUTTON (w_margin_y_1)); bbox = gegl_node_get_bounding_box (priv->node); factor = get_scale_to_px_factor (self); switch (change) { case CHANGE_HORIZ: orig_size_x = (gdouble) bbox.width / factor; orig_size_y = (gdouble) bbox.height / factor; break; case CHANGE_VERT: orig_size_y = (gdouble) bbox.width / factor; orig_size_x = (gdouble) bbox.height / factor; break; default: g_assert_not_reached (); break; } scale = CLAMP (size_x / orig_size_x, 0, 1); size_y = scale * orig_size_y; margin_x_2 = page_size_x - margin_x_1 - size_x; margin_y_2 = page_size_y - margin_y_1 - size_y; photos_print_preview_set_scale (PHOTOS_PRINT_PREVIEW (priv->preview), scale); switch (change) { case CHANGE_HORIZ: update_image_pos_ranges (self, page_size_x, page_size_y, size_x, size_y); break; case CHANGE_VERT: update_image_pos_ranges (self, page_size_y, page_size_x, size_y, size_x); break; default: g_assert_not_reached (); break; } gtk_range_set_value (GTK_RANGE (priv->scaling), 100*scale); gtk_spin_button_set_value (GTK_SPIN_BUTTON (w_margin_x_2), margin_x_2); gtk_spin_button_set_value (GTK_SPIN_BUTTON (w_size_y), size_y); gtk_spin_button_set_value (GTK_SPIN_BUTTON (w_margin_y_2), margin_y_2); gtk_combo_box_set_active (GTK_COMBO_BOX (priv->center), CENTER_NONE); }
static gboolean test_operation (const gchar *op_name, const gchar *image, gchar *output_path) { gchar *ref_path; GeglNode *img, *ref_img, *gegl; GeglRectangle ref_bounds, comp_bounds; gint ref_pixels; gboolean result = TRUE; gegl = gegl_node_new (); ref_path = g_build_path (G_DIR_SEPARATOR_S, reference_dir, image, NULL); ref_img = gegl_node_new_child (gegl, "operation", "gegl:load", "path", ref_path, NULL); g_free (ref_path); img = gegl_node_new_child (gegl, "operation", "gegl:load", "path", output_path, NULL); ref_bounds = gegl_node_get_bounding_box (ref_img); comp_bounds = gegl_node_get_bounding_box (img); ref_pixels = ref_bounds.width * ref_bounds.height; if (ref_bounds.width != comp_bounds.width || ref_bounds.height != comp_bounds.height) { g_printf ("FAIL\n Reference and composition differ in size\n"); result = FALSE; } else { GeglNode *comparison; gdouble max_diff; comparison = gegl_node_create_child (gegl, "gegl:image-compare"); gegl_node_link (img, comparison); gegl_node_connect_to (ref_img, "output", comparison, "aux"); gegl_node_process (comparison); gegl_node_get (comparison, "max diff", &max_diff, NULL); if (max_diff < 1.0) { g_printf ("PASS\n"); result = TRUE; } else { GeglNode *output; gchar *diff_path; gdouble avg_diff_wrong, avg_diff_total; gint wrong_pixels; gegl_node_get (comparison, "avg_diff_wrong", &avg_diff_wrong, "avg_diff_total", &avg_diff_total, "wrong_pixels", &wrong_pixels, NULL); g_printf ("FAIL\n Reference image and composition differ\n" " wrong pixels : %i/%i (%2.2f%%)\n" " max Δe : %2.3f\n" " avg Δe : %2.3f (wrong) %2.3f (total)\n", wrong_pixels, ref_pixels, (wrong_pixels * 100.0 / ref_pixels), max_diff, avg_diff_wrong, avg_diff_total); diff_path = operation_to_path (op_name, TRUE); output = gegl_node_new_child (gegl, "operation", "gegl:png-save", "path", diff_path, NULL); gegl_node_link (comparison, output); gegl_node_process (output); g_free (diff_path); result = FALSE; } } g_object_unref (gegl); return result; }
gint main (gint argc, gchar **argv) { GeglNode *gegl, *imgA, *imgB, *comparison; GeglRectangle boundsA, boundsB; gdouble max_diff, avg_diff_wrong, avg_diff_total; gint wrong_pixels, total_pixels; gegl_init (&argc, &argv); if (argc != 3) { g_print ("This is simple image difference detection tool for use in regression testing.\n" "Exit code is non zero if images are different, if they are equal" "the output will contain the string identical.\n"); g_print ("Usage: %s <imageA> <imageB>\n", argv[0]); return ERROR_WRONG_ARGUMENTS; } gegl = gegl_node_new (); imgA = gegl_node_new_child (gegl, "operation", "gegl:load", "path", argv[1], NULL); imgB = gegl_node_new_child (gegl, "operation", "gegl:load", "path", argv[2], NULL); boundsA = gegl_node_get_bounding_box (imgA); boundsB = gegl_node_get_bounding_box (imgB); total_pixels = boundsA.width * boundsA.height; if (boundsA.width != boundsB.width || boundsA.height != boundsB.height) { g_printerr ("%s and %s differ in size\n", argv[1], argv[2]); g_printerr (" %ix%i vs %ix%i\n", boundsA.width, boundsA.height, boundsB.width, boundsB.height); return ERROR_WRONG_SIZE; } comparison = gegl_node_create_child (gegl, "gegl:image-compare"); gegl_node_link (imgA, comparison); gegl_node_connect_to (imgB, "output", comparison, "aux"); gegl_node_process (comparison); gegl_node_get (comparison, "max diff", &max_diff, "avg-diff-wrong", &avg_diff_wrong, "avg-diff-total", &avg_diff_total, "wrong-pixels", &wrong_pixels, NULL); if (max_diff >= 0.1) { g_printerr ("%s and %s differ\n" " wrong pixels : %i/%i (%2.2f%%)\n" " max Δe : %2.3f\n" " avg Δe (wrong) : %2.3f(wrong) %2.3f(total)\n", argv[1], argv[2], wrong_pixels, total_pixels, (wrong_pixels*100.0/total_pixels), max_diff, avg_diff_wrong, avg_diff_total); if (!strstr (argv[2], "broken")) { GeglNode *save; gchar *debug_path = g_malloc (strlen (argv[2])+16); memcpy (debug_path, argv[2], strlen (argv[2])+1); memcpy (debug_path + strlen(argv[2])-4, "-diff.png", 11); save = gegl_node_new_child (gegl, "operation", "gegl:png-save", "path", debug_path, NULL); gegl_node_link (comparison, save); gegl_node_process (save); /*gegl_graph (sink=gegl_node ("gegl:png-save", "path", debug_path, NULL, gegl_node ("gegl:buffer-source", "buffer", debug_buf, NULL)));*/ if (max_diff > 1.5) return ERROR_PIXELS_DIFFERENT; } if (strstr (argv[2], "broken")) g_print ("because the test is expected to fail "); else g_print ("because the error is small "); g_print ("we'll say "); } g_print ("%s and %s are identical\n", argv[1], argv[2]); g_object_unref (gegl); gegl_exit (); return SUCCESS; }
static void photos_print_operation_draw_page (GtkPrintOperation *operation, GtkPrintContext *context, gint page_nr) { PhotosPrintOperation *self = PHOTOS_PRINT_OPERATION (operation); GeglRectangle bbox; GdkPixbuf *pixbuf = NULL; GtkPageSetup *page_setup; cairo_t *cr; gdouble dpi_x; gdouble dpi_y; gdouble page_height; gdouble page_width; gdouble scale_factor_n; gdouble x0; gdouble y0; scale_factor_n = self->scale_factor / 100.0; bbox = gegl_node_get_bounding_box (self->node); dpi_x = gtk_print_context_get_dpi_x (context); dpi_y = gtk_print_context_get_dpi_x (context); switch (self->unit) { case GTK_UNIT_INCH: x0 = self->left_margin * dpi_x; y0 = self->top_margin * dpi_y; break; case GTK_UNIT_MM: x0 = self->left_margin * dpi_x / 25.4; y0 = self->top_margin * dpi_y / 25.4; break; case GTK_UNIT_NONE: case GTK_UNIT_POINTS: default: g_assert_not_reached (); } cr = gtk_print_context_get_cairo_context (context); cairo_translate (cr, x0, y0); page_setup = gtk_print_context_get_page_setup (context); page_width = gtk_page_setup_get_page_width (page_setup, GTK_UNIT_POINTS); page_height = gtk_page_setup_get_page_height (page_setup, GTK_UNIT_POINTS); /* This is both a workaround for a bug in cairo's PDF backend, and * a way to ensure we are not printing outside the page margins. */ cairo_rectangle (cr, 0, 0, MIN (bbox.width * scale_factor_n, page_width), MIN (bbox.height * scale_factor_n, page_height)); cairo_clip (cr); cairo_scale (cr, scale_factor_n, scale_factor_n); pixbuf = photos_utils_create_pixbuf_from_node (self->node); if (pixbuf == NULL) goto out; gdk_cairo_set_source_pixbuf (cr, pixbuf, 0.0, 0.0); cairo_paint (cr); out: g_clear_object (&pixbuf); }
gint layer_node_selected (gpointer host, GeglEditor* editor, gint node_id) { GeglEditorLayer* self = (GeglEditorLayer*)host; GeglNode* node = NULL; GSList* pair = self->pairs; for(;pair != NULL; pair = pair->next) { node_id_pair* data = pair->data; if(data->id == node_id) { node = data->node; break; } } g_assert(node != NULL); GeglNode** nodes; const gchar** pads; gint num = gegl_node_get_consumers(node, "output", &nodes, &pads); int i; g_print("%s: %d consumer(s)\n", gegl_node_get_operation(node), num); for(i = 0; i < num; i++) { g_print("Connection: (%s to %s)\n", gegl_node_get_operation(node), gegl_node_get_operation(nodes[0]), pads[0]); } g_print("Input from: %s\n", gegl_node_get_operation(gegl_node_get_producer(node, "input", NULL))); // g_print("selected: %s\n", gegl_node_get_operation(node)); guint n_props; GParamSpec** properties = gegl_operation_list_properties(gegl_node_get_operation(node), &n_props); //TODO: only create enough columns for the properties which will actually be included (i.e. ignoring GeglBuffer props) GtkTable *prop_table = GTK_TABLE(gtk_table_new(2, n_props, FALSE)); int d; for(d = 0, i = 0; i < n_props; i++, d++) { GParamSpec* prop = properties[i]; GType type = prop->value_type; const gchar* name = prop->name; GtkWidget* name_label = gtk_label_new(name); gtk_misc_set_alignment(GTK_MISC(name_label), 0, 0.5); GtkWidget* value_entry = gtk_entry_new(); gchar buf[256] = "*"; //can probably be smaller; In fact, can probably do this without sprintf and a buffer. TODO: look at g_string gint i_value; gdouble d_value; gchar* str_value; gboolean skip = FALSE; switch(type) { case G_TYPE_INT: gegl_node_get(node, name, &i_value, NULL); sprintf(buf, "%d", i_value); break; case G_TYPE_DOUBLE: gegl_node_get(node, name, &d_value, NULL); sprintf(buf, "%.3f", d_value); break; case G_TYPE_STRING: gegl_node_get(node, name, &str_value, NULL); sprintf(buf, "%s", str_value); break; } if(type == GEGL_TYPE_BUFFER) { skip = TRUE; d--; } else if( type == GEGL_TYPE_COLOR) { skip = TRUE; GtkWidget *color_button = gtk_button_new_with_label("Select"); select_color_info* info = malloc(sizeof(select_color_info)); info->node = node; info->property = name; info->layer = self; g_signal_connect(color_button, "clicked", (GCallback)select_color, info); gtk_table_attach(prop_table, name_label, 0, 1, d, d+1, GTK_FILL, GTK_FILL, 1, 1); gtk_table_attach(prop_table, color_button, 1, 2, d, d+1, GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_FILL, 1, 1); } if(!skip) { gtk_entry_set_text(GTK_ENTRY(value_entry), buf); gtk_entry_set_width_chars(GTK_ENTRY(value_entry), 2); struct text_prop_data *data = malloc(sizeof(struct text_prop_data)); //TODO store this in a list and free it when the node is deselected data->node = node; data->property = name; data->prop_type = type; data->layer = self; g_signal_connect(value_entry, "activate", G_CALLBACK(text_property_changed), data); gtk_table_attach(prop_table, name_label, 0, 1, d, d+1, GTK_FILL, GTK_FILL, 1, 1); gtk_table_attach(prop_table, value_entry, 1, 2, d, d+1, GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_FILL, 1, 1); } } // gegl_node_process(node); GeglGtkView *gtk_view = gegl_gtk_view_new_for_node(node); GeglRectangle rect = gegl_node_get_bounding_box(node); if(gegl_rectangle_is_infinite_plane(&rect)) { gegl_gtk_view_set_autoscale_policy(gtk_view, GEGL_GTK_VIEW_AUTOSCALE_DISABLED); gegl_gtk_view_set_scale(gtk_view, 1.0); g_print("Disable autoscale: scale=%f, x=%f, y=%f\n", gegl_gtk_view_get_scale(gtk_view), gegl_gtk_view_get_x(gtk_view), gegl_gtk_view_get_y(gtk_view)); } gtk_widget_show(GTK_WIDGET(gtk_view)); //TODO: draw checkerboard under preview to indicate transparency gtk_box_pack_start(GTK_BOX(self->prop_box), GTK_WIDGET(prop_table), FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(self->prop_box), GTK_WIDGET(gtk_view), TRUE, TRUE, 10); GtkWidget* label = gtk_label_new("Click the image\nto open in a\nnew window"); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); gtk_box_pack_start(GTK_BOX(self->prop_box), label, FALSE, TRUE, 10); gtk_widget_show_all(self->prop_box); }