gboolean gimp_warp_tool_undo (GimpTool *tool, GimpDisplay *display) { GimpWarpTool *wt = GIMP_WARP_TOOL (tool); GeglNode *to_delete; GeglNode *previous; const gchar *type; if (! wt->render_node) return FALSE; to_delete = gegl_node_get_producer (wt->render_node, "aux", NULL); type = gegl_node_get_operation (to_delete); if (strcmp (type, "gegl:warp")) return FALSE; previous = gegl_node_get_producer (to_delete, "input", NULL); gegl_node_disconnect (to_delete, "input"); gegl_node_connect_to (previous, "output", wt->render_node, "aux"); wt->redo_stack = g_list_prepend (wt->redo_stack, g_object_ref (to_delete)); gegl_node_remove_child (wt->graph, to_delete); gimp_warp_tool_update_stroke (wt, to_delete); return TRUE; }
static void gimp_warp_tool_remove_op (GimpWarpTool *wt, GeglNode *op) { GeglNode *previous; g_return_if_fail (GEGL_IS_NODE (wt->render_node)); previous = gegl_node_get_producer (op, "input", NULL); gegl_node_disconnect (op, "input"); gegl_node_connect_to (previous, "output", wt->render_node, "aux"); gegl_node_remove_child (wt->graph, op); }
static void gimp_warp_tool_add_op (GimpWarpTool *wt, GeglNode *new_op) { GeglNode *last_op; g_return_if_fail (GEGL_IS_NODE (wt->render_node)); gegl_node_add_child (wt->graph, new_op); last_op = gegl_node_get_producer (wt->render_node, "aux", NULL); gegl_node_disconnect (wt->render_node, "aux"); gegl_node_connect_to (last_op, "output", new_op, "input"); gegl_node_connect_to (new_op, "output", wt->render_node, "aux"); }
const gchar * gimp_warp_tool_get_undo_desc (GimpTool *tool, GimpDisplay *display) { GimpWarpTool *wt = GIMP_WARP_TOOL (tool); GeglNode *to_delete; const gchar *type; if (! wt->render_node) return NULL; to_delete = gegl_node_get_producer (wt->render_node, "aux", NULL); type = gegl_node_get_operation (to_delete); if (strcmp (type, "gegl:warp")) return NULL; return _("Warp Tool Stroke"); }
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); }