diff --git a/ChangeLog b/ChangeLog index 7398c5274c..2e86ae4207 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +Tue Apr 13 22:17:23 BST 1999 Andy Thomas + + Changed:- + + * app/bezier_select.c + * app/bezier_select.h + * app/pathsP.h + * app/paths_dialog.c + * app/transform_core.c + * app/transform_core.h + * app/undo.c + + New:- + + * pixmap/locked.xpm + + New image. (Your welcome to improve upon it...) + + Paths can now be locked down for transformations. Click next to the + paths preview and a icon will appear. This path will "locked" during + transformations (via the transforms tool). Undo for these path + transformations is also available. + + Fixed bug when creating a path for the first time when no paths dialog + visible. + Tue Apr 13 00:01:24 PDT 1999 Manish Singh * configure.in: bumped up to 1.1.5 diff --git a/app/bezier_select.c b/app/bezier_select.c index 5274f93538..d34a93bbc4 100644 --- a/app/bezier_select.c +++ b/app/bezier_select.c @@ -1695,6 +1695,13 @@ bezier_insert_in_list (GSList * list, return orig; } +gboolean +bezier_tool_selected() +{ + return(active_tool_type == BEZIER_SELECT && + active_tool->state == ACTIVE); +} + void bezier_paste_bezierselect_to_current(GDisplay *gdisp,BezierSelect *bsel) { @@ -1798,8 +1805,8 @@ bezier_to_sel_internal(BezierSelect *bezier_sel, bezier_sel->mask, op, 0, 0); /* show selection on all views */ - bezier_sel->draw = BEZIER_DRAW_HANDLES; - draw_core_resume (bezier_sel->core, tool); + /* bezier_sel->draw = BEZIER_DRAW_HANDLES; */ + /* draw_core_resume (bezier_sel->core, tool); */ gdisplays_flush (); } diff --git a/app/bezier_select.h b/app/bezier_select.h index 9623d1e2fc..1e87b5170e 100644 --- a/app/bezier_select.h +++ b/app/bezier_select.h @@ -25,5 +25,6 @@ void bezier_select_dialog (void); Tool * tools_new_bezier_select (void); void tools_free_bezier_select (Tool *); +gboolean bezier_tool_selected(void); #endif /* __BEZIER_SELECT_H__ */ diff --git a/app/core/gimpimage-undo-push.c b/app/core/gimpimage-undo-push.c index b6e38f83ed..dcdbceb2cc 100644 --- a/app/core/gimpimage-undo-push.c +++ b/app/core/gimpimage-undo-push.c @@ -924,6 +924,8 @@ undo_pop_transform (GImage *gimage, tc = (TransformCore *) active_tool->private; tu = (TransformUndo *) tu_ptr; + paths_transform_do_undo(gimage,tu->path_undo); + /* only pop if the active tool is the tool that pushed this undo */ if (tu->tool_ID != active_tool->ID) return TRUE; @@ -962,6 +964,7 @@ undo_free_transform (int state, tu = (TransformUndo *) tu_ptr; if (tu->original) tile_manager_destroy (tu->original); + paths_transform_free_undo(tu->path_undo); g_free (tu); } diff --git a/app/gui/paths-dialog.c b/app/gui/paths-dialog.c index d08b0a3dee..1e85da8b0d 100644 --- a/app/gui/paths-dialog.c +++ b/app/gui/paths-dialog.c @@ -50,6 +50,7 @@ #include "resize.h" #include "session.h" #include "undo.h" +#include "libgimp/gimpmatrix.h" #include "libgimp/gimpintl.h" @@ -63,6 +64,7 @@ #include "pixmaps/penstroke.xpm" #include "pixmaps/toselection.xpm" #include "pixmaps/path.xbm" +#include "pixmaps/locked.xpm" #define PREVIEW_EVENT_MASK GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK @@ -82,6 +84,7 @@ typedef struct { /* pixmaps for the no preview bitmap */ GdkPixmap * pixmap_normal; GdkPixmap * pixmap_selected; + GdkPixmap * pixmap_locked; /* state information */ gint selsigid; @@ -97,12 +100,17 @@ typedef struct { static PATHSLISTP paths_dialog = NULL; typedef struct { - GdkPixmap *paths_pixmap; - GString *text; - PATHP bzp; + GdkPixmap *paths_pixmap; + GString *text; + PATHP bzp; } PATHWIDGET, *PATHWIDGETP; -static gchar * unique_name(gchar *); +typedef struct { + Tattoo tattoo; + PATHP copy_path; +} PATHUNDO; + +static gchar * unique_name(GimpImage *,gchar *); static gint path_widget_preview_events (GtkWidget *, GdkEvent *); static void paths_dialog_realized (GtkWidget *widget); @@ -272,13 +280,16 @@ GtkWidget * paths_dialog_create() GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - paths_dialog->paths_list = paths_list = gtk_clist_new (1); + paths_dialog->paths_list = paths_list = gtk_clist_new (2); gtk_signal_connect (GTK_OBJECT (vbox), "destroy", (GtkSignalFunc) paths_list_destroy, NULL); -/* gtk_clist_set_column_title(GTK_CLIST(paths_list), 0, "col1"); */ -/* gtk_clist_column_titles_show(GTK_CLIST(paths_list)); */ +/* gtk_clist_set_column_title(GTK_CLIST(paths_list), 0, _("Locked")); */ +/* gtk_clist_set_column_title(GTK_CLIST(paths_list), 1, _("Path")); */ +/* gtk_clist_column_titles_show(GTK_CLIST(paths_list)); */ + /* gtk_clist_columns_autosize(GTK_CLIST(paths_list)); */ + gtk_clist_set_column_width (GTK_CLIST(paths_list),0,30); gtk_container_add (GTK_CONTAINER (scrolled_win), paths_list); gtk_clist_set_selection_mode (GTK_CLIST (paths_list), GTK_SELECTION_BROWSE); @@ -395,7 +406,7 @@ path_dialog_new(GimpImage *gimage,gint name_seed, gpointer udata) gchar *suniq; g_string_sprintf (s, "path %d",name_seed); - suniq = unique_name(s->str); + suniq = unique_name(gimage,s->str); if(suniq) { g_string_free(s,TRUE); @@ -440,7 +451,7 @@ strip_off_cnumber(gchar *str) /* Return NULL is already unique else a unique string */ static gchar * -unique_name(gchar *cstr) +unique_name(GimpImage *gimage,gchar *cstr) { GSList *tlist; PATHIMAGELISTP plp; @@ -451,9 +462,7 @@ unique_name(gchar *cstr) gint counter = 1; /* Get bzpath structure */ - plp = paths_dialog->current_path_list; - - if(!plp) + if(!gimage || !(plp = (PATHIMAGELISTP)gimp_image_get_paths(gimage))) return NULL; tlist = plp->bz_paths; @@ -505,14 +514,17 @@ path_copy(GimpImage *gimage,PATHP p) PATHP p_copy = g_new0(PATH,1); gchar *ext; - ext = unique_name(p->name->str); + ext = unique_name(gimage,p->name->str); p_copy->name = g_string_new(ext); g_free(ext); p_copy->closed = p->closed; p_copy->state = p->state; p_copy->pathtype = p->pathtype; p_copy->path_details = pathpoints_copy(p->path_details); - p_copy->tattoo = gimp_image_get_new_tattoo(gimage); + if(gimage) + p_copy->tattoo = gimp_image_get_new_tattoo(gimage); + else + p_copy->tattoo = p->tattoo; return p_copy; } @@ -678,7 +690,8 @@ void paths_add_path(PATHP bzp,gint insrow) /* Create a new entry in the list */ PATHWIDGETP pwidget; gint row; - gchar *row_data[1]; + gchar *row_data[2]; + GdkBitmap *mask; pwidget = g_new0(PATHWIDGET,1); @@ -720,10 +733,20 @@ void paths_add_path(PATHP bzp,gint insrow) pwidget->paths_pixmap = paths_dialog->pixmap_normal; } + if(!paths_dialog->pixmap_locked) + { + paths_dialog->pixmap_locked = + gdk_pixmap_create_from_xpm_d (paths_dialog->vbox->window, + &mask, + &paths_dialog->vbox->style->fg[GTK_STATE_NORMAL], + locked_xpm); + } + gtk_clist_set_row_height(GTK_CLIST(paths_dialog->paths_list), paths_dialog->image_height + 6); row_data[0] = ""; + row_data[1] = ""; if(insrow == -1) row = gtk_clist_append(GTK_CLIST(paths_dialog->paths_list), @@ -735,7 +758,7 @@ void paths_add_path(PATHP bzp,gint insrow) gtk_clist_set_pixtext(GTK_CLIST(paths_dialog->paths_list), row, - 0, + 1, bzp->name->str, 2, pwidget->paths_pixmap, @@ -749,7 +772,7 @@ void paths_add_path(PATHP bzp,gint insrow) gtk_signal_handler_block(GTK_OBJECT(paths_dialog->paths_list),paths_dialog->selsigid); gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list), paths_dialog->current_path_list->last_selected_row, - 0); + 1); gtk_signal_handler_unblock(GTK_OBJECT(paths_dialog->paths_list),paths_dialog->selsigid); pwidget->bzp = bzp; @@ -838,22 +861,70 @@ paths_select_row(GtkWidget *widget, PATHP bzp; BezierSelect * bsel; GDisplay *gdisp; + gint last_row; pwidget = (PATHWIDGETP)gtk_clist_get_row_data(GTK_CLIST(widget),row); if(!pwidget || (paths_dialog->current_path_list->last_selected_row == row && - paths_dialog->been_selected == TRUE)) - return; + paths_dialog->been_selected == TRUE)) + { + if(column) + return; + } - paths_dialog->selected_row_num = row; - paths_dialog->current_path_list->last_selected_row = row; - paths_dialog->been_selected = TRUE; + last_row = paths_dialog->current_path_list->last_selected_row; bzp = (PATHP)g_slist_nth_data(paths_dialog->current_path_list->bz_paths,row); g_return_if_fail(bzp != NULL); + if(column == 0) + { + if(bzp->locked == 0) + { + bzp->locked = 1; + gtk_clist_set_pixmap(GTK_CLIST(paths_dialog->paths_list), + row, + 0, + paths_dialog->pixmap_locked, + NULL); + } + else + { + gint tmprow; + + bzp->locked = 0; + gtk_clist_set_text(GTK_CLIST(paths_dialog->paths_list), + row, + 0, + ""); + /* There should be an easier way of updating the preview! */ + bsel = path_to_beziersel(bzp); + tmprow = paths_dialog->current_path_list->last_selected_row; + paths_dialog->current_path_list->last_selected_row = row; + paths_update_preview(bsel); + beziersel_free(bsel); + paths_dialog->current_path_list->last_selected_row = tmprow; + paths_dialog->selected_row_num = tmprow; + } + + /* Put hightlight back on the old original selection */ + gtk_signal_handler_block(GTK_OBJECT(paths_dialog->paths_list),paths_dialog->selsigid); + + gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list), + last_row, + 1); + + gtk_signal_handler_unblock(GTK_OBJECT(paths_dialog->paths_list),paths_dialog->selsigid); + + return; + } + + paths_dialog->selected_row_num = row; + paths_dialog->current_path_list->last_selected_row = row; + paths_dialog->been_selected = TRUE; + bsel = path_to_beziersel(bzp); gdisp = gdisplays_check_valid(paths_dialog->current_path_list->gdisp, paths_dialog->gimage); @@ -981,14 +1052,12 @@ paths_dialog_update (GimpImage* gimage) paths_dialog->current_path_list->last_selected_row = tmprow; paths_dialog->selected_row_num = tmprow; - /* g_slist_foreach(plist,paths_update_paths,NULL); */ - /* select last one */ gtk_signal_handler_block(GTK_OBJECT(paths_dialog->paths_list),paths_dialog->selsigid); gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list), paths_dialog->current_path_list->last_selected_row, - 0); + 1); gtk_signal_handler_unblock(GTK_OBJECT(paths_dialog->paths_list),paths_dialog->selsigid); gtk_clist_moveto(GTK_CLIST(paths_dialog->paths_list), @@ -1010,6 +1079,13 @@ paths_update_paths(gpointer data,gint row) paths_dialog->current_path_list->last_selected_row = row; paths_update_preview(bezier_sel); beziersel_free(bezier_sel); + + if(bzp->locked) + gtk_clist_set_pixmap(GTK_CLIST(paths_dialog->paths_list), + row, + 0, + paths_dialog->pixmap_locked, + NULL); } static void @@ -1027,7 +1103,7 @@ do_rename_paths_callback(GtkWidget *widget, gpointer call_data, gpointer client_ gtk_clist_get_pixtext(GTK_CLIST(paths_dialog->paths_list), paths_dialog->selected_row_num, - 0, + 1, NULL, &spacing, &pixmap, @@ -1036,7 +1112,7 @@ do_rename_paths_callback(GtkWidget *widget, gpointer call_data, gpointer client_ gtk_clist_set_pixtext(GTK_CLIST(call_data), paths_dialog->selected_row_num, - 0, + 1, text, spacing, pixmap, @@ -1054,7 +1130,7 @@ paths_dialog_edit_path_query(GtkWidget *widget) /* Get the current name */ ret = gtk_clist_get_pixtext(GTK_CLIST(paths_dialog->paths_list), paths_dialog->selected_row_num, - 0, + 1, &text, NULL, NULL, @@ -1071,9 +1147,10 @@ static gint paths_list_events (GtkWidget *widget, GdkEvent *event) { - GdkEventKey *kevent; + GdkEventKey *kevent; GdkEventButton *bevent; - static gint last_row = -1; + static gint last_row = -1; + gint this_colunm; switch (event->type) { @@ -1082,7 +1159,7 @@ paths_list_events (GtkWidget *widget, if(!gtk_clist_get_selection_info (GTK_CLIST(paths_dialog->paths_list), bevent->x, bevent->y, - &last_row,NULL)) + &last_row,&this_colunm)) last_row = -1; else { @@ -1101,10 +1178,15 @@ paths_list_events (GtkWidget *widget, gtk_clist_get_selection_info (GTK_CLIST(paths_dialog->paths_list), bevent->x, bevent->y, - NULL,NULL)) + NULL,&this_colunm)) { - paths_dialog_edit_path_query(widget); - return TRUE; + if(this_colunm == 1) + { + paths_dialog_edit_path_query(widget); + return TRUE; + } + else + return FALSE; } else return FALSE; @@ -1278,7 +1360,7 @@ paths_dialog_path_to_sel_callback (GtkWidget * widget, gpointer udata) plp = paths_dialog->current_path_list; bzp = (PATHP)g_slist_nth_data(plp->bz_paths,row); - /* Now do the stroke....*/ + /* Now do the selection....*/ gdisp = gdisplays_check_valid(paths_dialog->current_path_list->gdisp, paths_dialog->gimage); @@ -1291,6 +1373,11 @@ paths_dialog_path_to_sel_callback (GtkWidget * widget, gpointer udata) path_free(bzpcopy,NULL); bezier_to_selection (bezier_sel, gdisp); beziersel_free(bezier_sel); + + /* Force display to show no closed curve */ + bezier_sel = path_to_beziersel(bzp); + bezier_paste_bezierselect_to_current(gdisp,bezier_sel); + beziersel_free(bezier_sel); } else { @@ -1534,7 +1621,7 @@ paths_update_preview(BezierSelect *bezier_sel) gtk_clist_set_pixtext(GTK_CLIST(paths_dialog->paths_list), row, - 0, + 1, pwidget->bzp->name->str, 2, pwidget->paths_pixmap, @@ -1823,7 +1910,7 @@ static void file_ok_callback(GtkWidget * widget, gpointer client_data) gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list), paths_dialog->current_path_list->last_selected_row, - 0); + 1); paths_ops_button_set_sensitive(DUP_PATH_BUTTON,val); paths_ops_button_set_sensitive(DEL_PATH_BUTTON,val); @@ -1931,6 +2018,215 @@ paths_dialog_export_path_callback (GtkWidget * widget, gpointer udata) path_store_callback(); } +/*************************************/ +/* Function for transforming paths */ +/*************************************/ + +/* These functions are the undo functions for the paths + * that have undergone transformations. + * + * Generally speaking paths do not belong with the undo + * structures. However when a path undergoes a transformation + * then THIS path transformation should be part of the undo. + * We do have a problem here since a point could have been + * added to the path after the transformation. This + * point will be lost if the undo stuff is performed. It would + * then appear that this point is part of the undo structure. + * I think it is fair that this happens since the user is telling + * us to restore the state before the transformation took place. + * Note tattoos are used to find which paths have been stored in the + * undo buffer. So deleted paths will not suddenly reappear. (I did say + * generally paths are not part of the undo structures). + */ + +void * +paths_transform_start_undo(GimpImage *gimage) +{ + /* Save only the locked paths away */ + PATHIMAGELISTP plp; + GSList *plist; + PATHP p; + PATHP p_copy; + GSList *undo_list = NULL; + + /* Get bzpath structure */ + plp = (PATHIMAGELISTP)gimp_image_get_paths(gimage); + + if(!plp) + return NULL; + + plist = plp->bz_paths; + + while(plist) + { + p = (PATHP)plist->data; + if(p->locked) + { + /* save away for a rainly day */ + p_copy = path_copy(NULL,p); /* NULL means dont want new tattoo */ + undo_list = g_slist_append(undo_list,p_copy); + } + plist = g_slist_next(plist); + } + return undo_list; +} + +void +paths_transform_free_undo(void *data) +{ + GSList *pundolist = data; + PATHP p; + /* free data associated with the transform path undo */ + + while(pundolist) + { + p = (PATHP)pundolist->data; + path_free(p,NULL); + pundolist = g_slist_next(pundolist); + } + + g_slist_free((GSList *)data); +} + +void +paths_transform_do_undo(GimpImage *gimage,void *data) +{ + GSList *pundolist = data; + /* Restore the paths as they were before this transform took place. */ + PATHP p_undo; + PATHP p; + BezierSelect *bezier_sel; + gint tmprow; + gint loop; + gboolean preview_update = FALSE; + PATHIMAGELISTP plp; + GSList *plist; + + /* free data associated with the transform path undo */ + + while(pundolist) + { + p_undo = (PATHP)pundolist->data; + /* Find the old path and replace it */ + p = paths_get_path_by_tattoo(gimage,p_undo->tattoo); + if(p) + { + /* Path is still around... undo the transform stuff */ + pathpoints_free(p->path_details); + p->closed = p_undo->closed; + p->state = p_undo->state; + p->pathtype = p_undo->pathtype; + p->path_details = pathpoints_copy(p_undo->path_details); + preview_update = TRUE; + } + pundolist = g_slist_next(pundolist); + } + + if(preview_update && paths_dialog) + { + /* Heck the previews need updating...*/ + plp = (PATHIMAGELISTP)gimp_image_get_paths(gimage); + plist = plp->bz_paths; + loop = 0; + + while(plist) + { + bezier_sel = path_to_beziersel(plist->data); + tmprow = paths_dialog->current_path_list->last_selected_row; + paths_dialog->current_path_list->last_selected_row = loop; + paths_update_preview(bezier_sel); + beziersel_free(bezier_sel); + paths_dialog->current_path_list->last_selected_row = tmprow; + paths_dialog->selected_row_num = tmprow; + loop++; + plist = g_slist_next(plist); + } + + /* Force selection .. it may have changed */ + if(bezier_tool_selected()) + { + gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list), + paths_dialog->current_path_list->last_selected_row, + 1); + } + } +} + +void +paths_transform_current_path(GimpImage *gimage, + GimpMatrix transform, + gboolean forpreview) +{ + PATHIMAGELISTP plp; + PATHP p; + PATHP p_copy; + GSList *points_list; + BezierSelect *bezier_sel; + GSList *plist; + gint loop; + gint tmprow; + + /* As a first off lets just translate the current path */ + + /* Get bzpath structure */ + plp = (PATHIMAGELISTP)gimp_image_get_paths(gimage); + + if(!plp) + return; + + plist = plp->bz_paths; + loop = 0; + + while(plist) + { + p = (PATHP)plist->data; + if(p->locked) + { + if(forpreview) + p_copy = path_copy(NULL,p); /* NULL means dont want new tattoo */ + else + p_copy = p; + + points_list = p_copy->path_details; + + while (points_list) + { + gdouble newx,newy; + PATHPOINTP ppoint = points_list->data; + + /* printf("[x,y] = [%g,%g]\n",ppoint->x, ppoint->y); */ + + gimp_matrix_transform_point (transform, + ppoint->x, + ppoint->y, + &newx,&newy); + + /* printf("->[x,y] = [%g,%g]\n", newx, newy); */ + + ppoint->x = newx; + ppoint->y = newy; + points_list = points_list->next; + } + + if(paths_dialog) + { + /* Now fudge the drawing....*/ + bezier_sel = path_to_beziersel(p_copy); + tmprow = paths_dialog->current_path_list->last_selected_row; + paths_dialog->current_path_list->last_selected_row = loop; + paths_update_preview(bezier_sel); + beziersel_free(bezier_sel); + paths_dialog->current_path_list->last_selected_row = tmprow; + paths_dialog->selected_row_num = tmprow; + } + + if(forpreview) + path_free(p_copy,NULL); + } + plist = g_slist_next(plist); + loop++; + } +} /*************************************/ /* PDB function aids */ @@ -1974,7 +2270,7 @@ paths_set_path(GimpImage * gimage, { gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list), row, - 0); + 1); } else { @@ -2088,7 +2384,7 @@ paths_set_path_points(GimpImage * gimage, if(paths_dialog) gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list), row, - 0); + 1); return TRUE; } else @@ -2118,7 +2414,7 @@ paths_set_path_points(GimpImage * gimage, gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list), paths_dialog->current_path_list->last_selected_row, - 0); + 1); paths_ops_button_set_sensitive(DUP_PATH_BUTTON,TRUE); paths_ops_button_set_sensitive(DEL_PATH_BUTTON,TRUE); diff --git a/app/pathsP.h b/app/pathsP.h index e17b082faf..19065b4208 100644 --- a/app/pathsP.h +++ b/app/pathsP.h @@ -18,6 +18,8 @@ #ifndef __PATHSP_H__ #define __PATHSP_H__ +#include "libgimp/gimpmatrix.h" + /* Cutdown representation of the bezier curve description */ /* Will be used to hopefully store in XCF format... */ @@ -67,6 +69,9 @@ void paths_stroke(GimpImage *,PathsList *,PATHP); gint paths_distance(PATHP ,gdouble ,gint *,gint *, gdouble *); Tattoo paths_get_tattoo(PATHP); PATHP paths_get_path_by_tattoo(GimpImage *,Tattoo); - +void * paths_transform_start_undo(GimpImage *); +void paths_transform_free_undo(void *); +void paths_transform_do_undo(GimpImage *,void *); +void paths_transform_current_path(GimpImage *,GimpMatrix,gboolean); #endif /* __PATHSP_H__ */ diff --git a/app/paths_dialog.c b/app/paths_dialog.c index d08b0a3dee..1e85da8b0d 100644 --- a/app/paths_dialog.c +++ b/app/paths_dialog.c @@ -50,6 +50,7 @@ #include "resize.h" #include "session.h" #include "undo.h" +#include "libgimp/gimpmatrix.h" #include "libgimp/gimpintl.h" @@ -63,6 +64,7 @@ #include "pixmaps/penstroke.xpm" #include "pixmaps/toselection.xpm" #include "pixmaps/path.xbm" +#include "pixmaps/locked.xpm" #define PREVIEW_EVENT_MASK GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK @@ -82,6 +84,7 @@ typedef struct { /* pixmaps for the no preview bitmap */ GdkPixmap * pixmap_normal; GdkPixmap * pixmap_selected; + GdkPixmap * pixmap_locked; /* state information */ gint selsigid; @@ -97,12 +100,17 @@ typedef struct { static PATHSLISTP paths_dialog = NULL; typedef struct { - GdkPixmap *paths_pixmap; - GString *text; - PATHP bzp; + GdkPixmap *paths_pixmap; + GString *text; + PATHP bzp; } PATHWIDGET, *PATHWIDGETP; -static gchar * unique_name(gchar *); +typedef struct { + Tattoo tattoo; + PATHP copy_path; +} PATHUNDO; + +static gchar * unique_name(GimpImage *,gchar *); static gint path_widget_preview_events (GtkWidget *, GdkEvent *); static void paths_dialog_realized (GtkWidget *widget); @@ -272,13 +280,16 @@ GtkWidget * paths_dialog_create() GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - paths_dialog->paths_list = paths_list = gtk_clist_new (1); + paths_dialog->paths_list = paths_list = gtk_clist_new (2); gtk_signal_connect (GTK_OBJECT (vbox), "destroy", (GtkSignalFunc) paths_list_destroy, NULL); -/* gtk_clist_set_column_title(GTK_CLIST(paths_list), 0, "col1"); */ -/* gtk_clist_column_titles_show(GTK_CLIST(paths_list)); */ +/* gtk_clist_set_column_title(GTK_CLIST(paths_list), 0, _("Locked")); */ +/* gtk_clist_set_column_title(GTK_CLIST(paths_list), 1, _("Path")); */ +/* gtk_clist_column_titles_show(GTK_CLIST(paths_list)); */ + /* gtk_clist_columns_autosize(GTK_CLIST(paths_list)); */ + gtk_clist_set_column_width (GTK_CLIST(paths_list),0,30); gtk_container_add (GTK_CONTAINER (scrolled_win), paths_list); gtk_clist_set_selection_mode (GTK_CLIST (paths_list), GTK_SELECTION_BROWSE); @@ -395,7 +406,7 @@ path_dialog_new(GimpImage *gimage,gint name_seed, gpointer udata) gchar *suniq; g_string_sprintf (s, "path %d",name_seed); - suniq = unique_name(s->str); + suniq = unique_name(gimage,s->str); if(suniq) { g_string_free(s,TRUE); @@ -440,7 +451,7 @@ strip_off_cnumber(gchar *str) /* Return NULL is already unique else a unique string */ static gchar * -unique_name(gchar *cstr) +unique_name(GimpImage *gimage,gchar *cstr) { GSList *tlist; PATHIMAGELISTP plp; @@ -451,9 +462,7 @@ unique_name(gchar *cstr) gint counter = 1; /* Get bzpath structure */ - plp = paths_dialog->current_path_list; - - if(!plp) + if(!gimage || !(plp = (PATHIMAGELISTP)gimp_image_get_paths(gimage))) return NULL; tlist = plp->bz_paths; @@ -505,14 +514,17 @@ path_copy(GimpImage *gimage,PATHP p) PATHP p_copy = g_new0(PATH,1); gchar *ext; - ext = unique_name(p->name->str); + ext = unique_name(gimage,p->name->str); p_copy->name = g_string_new(ext); g_free(ext); p_copy->closed = p->closed; p_copy->state = p->state; p_copy->pathtype = p->pathtype; p_copy->path_details = pathpoints_copy(p->path_details); - p_copy->tattoo = gimp_image_get_new_tattoo(gimage); + if(gimage) + p_copy->tattoo = gimp_image_get_new_tattoo(gimage); + else + p_copy->tattoo = p->tattoo; return p_copy; } @@ -678,7 +690,8 @@ void paths_add_path(PATHP bzp,gint insrow) /* Create a new entry in the list */ PATHWIDGETP pwidget; gint row; - gchar *row_data[1]; + gchar *row_data[2]; + GdkBitmap *mask; pwidget = g_new0(PATHWIDGET,1); @@ -720,10 +733,20 @@ void paths_add_path(PATHP bzp,gint insrow) pwidget->paths_pixmap = paths_dialog->pixmap_normal; } + if(!paths_dialog->pixmap_locked) + { + paths_dialog->pixmap_locked = + gdk_pixmap_create_from_xpm_d (paths_dialog->vbox->window, + &mask, + &paths_dialog->vbox->style->fg[GTK_STATE_NORMAL], + locked_xpm); + } + gtk_clist_set_row_height(GTK_CLIST(paths_dialog->paths_list), paths_dialog->image_height + 6); row_data[0] = ""; + row_data[1] = ""; if(insrow == -1) row = gtk_clist_append(GTK_CLIST(paths_dialog->paths_list), @@ -735,7 +758,7 @@ void paths_add_path(PATHP bzp,gint insrow) gtk_clist_set_pixtext(GTK_CLIST(paths_dialog->paths_list), row, - 0, + 1, bzp->name->str, 2, pwidget->paths_pixmap, @@ -749,7 +772,7 @@ void paths_add_path(PATHP bzp,gint insrow) gtk_signal_handler_block(GTK_OBJECT(paths_dialog->paths_list),paths_dialog->selsigid); gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list), paths_dialog->current_path_list->last_selected_row, - 0); + 1); gtk_signal_handler_unblock(GTK_OBJECT(paths_dialog->paths_list),paths_dialog->selsigid); pwidget->bzp = bzp; @@ -838,22 +861,70 @@ paths_select_row(GtkWidget *widget, PATHP bzp; BezierSelect * bsel; GDisplay *gdisp; + gint last_row; pwidget = (PATHWIDGETP)gtk_clist_get_row_data(GTK_CLIST(widget),row); if(!pwidget || (paths_dialog->current_path_list->last_selected_row == row && - paths_dialog->been_selected == TRUE)) - return; + paths_dialog->been_selected == TRUE)) + { + if(column) + return; + } - paths_dialog->selected_row_num = row; - paths_dialog->current_path_list->last_selected_row = row; - paths_dialog->been_selected = TRUE; + last_row = paths_dialog->current_path_list->last_selected_row; bzp = (PATHP)g_slist_nth_data(paths_dialog->current_path_list->bz_paths,row); g_return_if_fail(bzp != NULL); + if(column == 0) + { + if(bzp->locked == 0) + { + bzp->locked = 1; + gtk_clist_set_pixmap(GTK_CLIST(paths_dialog->paths_list), + row, + 0, + paths_dialog->pixmap_locked, + NULL); + } + else + { + gint tmprow; + + bzp->locked = 0; + gtk_clist_set_text(GTK_CLIST(paths_dialog->paths_list), + row, + 0, + ""); + /* There should be an easier way of updating the preview! */ + bsel = path_to_beziersel(bzp); + tmprow = paths_dialog->current_path_list->last_selected_row; + paths_dialog->current_path_list->last_selected_row = row; + paths_update_preview(bsel); + beziersel_free(bsel); + paths_dialog->current_path_list->last_selected_row = tmprow; + paths_dialog->selected_row_num = tmprow; + } + + /* Put hightlight back on the old original selection */ + gtk_signal_handler_block(GTK_OBJECT(paths_dialog->paths_list),paths_dialog->selsigid); + + gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list), + last_row, + 1); + + gtk_signal_handler_unblock(GTK_OBJECT(paths_dialog->paths_list),paths_dialog->selsigid); + + return; + } + + paths_dialog->selected_row_num = row; + paths_dialog->current_path_list->last_selected_row = row; + paths_dialog->been_selected = TRUE; + bsel = path_to_beziersel(bzp); gdisp = gdisplays_check_valid(paths_dialog->current_path_list->gdisp, paths_dialog->gimage); @@ -981,14 +1052,12 @@ paths_dialog_update (GimpImage* gimage) paths_dialog->current_path_list->last_selected_row = tmprow; paths_dialog->selected_row_num = tmprow; - /* g_slist_foreach(plist,paths_update_paths,NULL); */ - /* select last one */ gtk_signal_handler_block(GTK_OBJECT(paths_dialog->paths_list),paths_dialog->selsigid); gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list), paths_dialog->current_path_list->last_selected_row, - 0); + 1); gtk_signal_handler_unblock(GTK_OBJECT(paths_dialog->paths_list),paths_dialog->selsigid); gtk_clist_moveto(GTK_CLIST(paths_dialog->paths_list), @@ -1010,6 +1079,13 @@ paths_update_paths(gpointer data,gint row) paths_dialog->current_path_list->last_selected_row = row; paths_update_preview(bezier_sel); beziersel_free(bezier_sel); + + if(bzp->locked) + gtk_clist_set_pixmap(GTK_CLIST(paths_dialog->paths_list), + row, + 0, + paths_dialog->pixmap_locked, + NULL); } static void @@ -1027,7 +1103,7 @@ do_rename_paths_callback(GtkWidget *widget, gpointer call_data, gpointer client_ gtk_clist_get_pixtext(GTK_CLIST(paths_dialog->paths_list), paths_dialog->selected_row_num, - 0, + 1, NULL, &spacing, &pixmap, @@ -1036,7 +1112,7 @@ do_rename_paths_callback(GtkWidget *widget, gpointer call_data, gpointer client_ gtk_clist_set_pixtext(GTK_CLIST(call_data), paths_dialog->selected_row_num, - 0, + 1, text, spacing, pixmap, @@ -1054,7 +1130,7 @@ paths_dialog_edit_path_query(GtkWidget *widget) /* Get the current name */ ret = gtk_clist_get_pixtext(GTK_CLIST(paths_dialog->paths_list), paths_dialog->selected_row_num, - 0, + 1, &text, NULL, NULL, @@ -1071,9 +1147,10 @@ static gint paths_list_events (GtkWidget *widget, GdkEvent *event) { - GdkEventKey *kevent; + GdkEventKey *kevent; GdkEventButton *bevent; - static gint last_row = -1; + static gint last_row = -1; + gint this_colunm; switch (event->type) { @@ -1082,7 +1159,7 @@ paths_list_events (GtkWidget *widget, if(!gtk_clist_get_selection_info (GTK_CLIST(paths_dialog->paths_list), bevent->x, bevent->y, - &last_row,NULL)) + &last_row,&this_colunm)) last_row = -1; else { @@ -1101,10 +1178,15 @@ paths_list_events (GtkWidget *widget, gtk_clist_get_selection_info (GTK_CLIST(paths_dialog->paths_list), bevent->x, bevent->y, - NULL,NULL)) + NULL,&this_colunm)) { - paths_dialog_edit_path_query(widget); - return TRUE; + if(this_colunm == 1) + { + paths_dialog_edit_path_query(widget); + return TRUE; + } + else + return FALSE; } else return FALSE; @@ -1278,7 +1360,7 @@ paths_dialog_path_to_sel_callback (GtkWidget * widget, gpointer udata) plp = paths_dialog->current_path_list; bzp = (PATHP)g_slist_nth_data(plp->bz_paths,row); - /* Now do the stroke....*/ + /* Now do the selection....*/ gdisp = gdisplays_check_valid(paths_dialog->current_path_list->gdisp, paths_dialog->gimage); @@ -1291,6 +1373,11 @@ paths_dialog_path_to_sel_callback (GtkWidget * widget, gpointer udata) path_free(bzpcopy,NULL); bezier_to_selection (bezier_sel, gdisp); beziersel_free(bezier_sel); + + /* Force display to show no closed curve */ + bezier_sel = path_to_beziersel(bzp); + bezier_paste_bezierselect_to_current(gdisp,bezier_sel); + beziersel_free(bezier_sel); } else { @@ -1534,7 +1621,7 @@ paths_update_preview(BezierSelect *bezier_sel) gtk_clist_set_pixtext(GTK_CLIST(paths_dialog->paths_list), row, - 0, + 1, pwidget->bzp->name->str, 2, pwidget->paths_pixmap, @@ -1823,7 +1910,7 @@ static void file_ok_callback(GtkWidget * widget, gpointer client_data) gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list), paths_dialog->current_path_list->last_selected_row, - 0); + 1); paths_ops_button_set_sensitive(DUP_PATH_BUTTON,val); paths_ops_button_set_sensitive(DEL_PATH_BUTTON,val); @@ -1931,6 +2018,215 @@ paths_dialog_export_path_callback (GtkWidget * widget, gpointer udata) path_store_callback(); } +/*************************************/ +/* Function for transforming paths */ +/*************************************/ + +/* These functions are the undo functions for the paths + * that have undergone transformations. + * + * Generally speaking paths do not belong with the undo + * structures. However when a path undergoes a transformation + * then THIS path transformation should be part of the undo. + * We do have a problem here since a point could have been + * added to the path after the transformation. This + * point will be lost if the undo stuff is performed. It would + * then appear that this point is part of the undo structure. + * I think it is fair that this happens since the user is telling + * us to restore the state before the transformation took place. + * Note tattoos are used to find which paths have been stored in the + * undo buffer. So deleted paths will not suddenly reappear. (I did say + * generally paths are not part of the undo structures). + */ + +void * +paths_transform_start_undo(GimpImage *gimage) +{ + /* Save only the locked paths away */ + PATHIMAGELISTP plp; + GSList *plist; + PATHP p; + PATHP p_copy; + GSList *undo_list = NULL; + + /* Get bzpath structure */ + plp = (PATHIMAGELISTP)gimp_image_get_paths(gimage); + + if(!plp) + return NULL; + + plist = plp->bz_paths; + + while(plist) + { + p = (PATHP)plist->data; + if(p->locked) + { + /* save away for a rainly day */ + p_copy = path_copy(NULL,p); /* NULL means dont want new tattoo */ + undo_list = g_slist_append(undo_list,p_copy); + } + plist = g_slist_next(plist); + } + return undo_list; +} + +void +paths_transform_free_undo(void *data) +{ + GSList *pundolist = data; + PATHP p; + /* free data associated with the transform path undo */ + + while(pundolist) + { + p = (PATHP)pundolist->data; + path_free(p,NULL); + pundolist = g_slist_next(pundolist); + } + + g_slist_free((GSList *)data); +} + +void +paths_transform_do_undo(GimpImage *gimage,void *data) +{ + GSList *pundolist = data; + /* Restore the paths as they were before this transform took place. */ + PATHP p_undo; + PATHP p; + BezierSelect *bezier_sel; + gint tmprow; + gint loop; + gboolean preview_update = FALSE; + PATHIMAGELISTP plp; + GSList *plist; + + /* free data associated with the transform path undo */ + + while(pundolist) + { + p_undo = (PATHP)pundolist->data; + /* Find the old path and replace it */ + p = paths_get_path_by_tattoo(gimage,p_undo->tattoo); + if(p) + { + /* Path is still around... undo the transform stuff */ + pathpoints_free(p->path_details); + p->closed = p_undo->closed; + p->state = p_undo->state; + p->pathtype = p_undo->pathtype; + p->path_details = pathpoints_copy(p_undo->path_details); + preview_update = TRUE; + } + pundolist = g_slist_next(pundolist); + } + + if(preview_update && paths_dialog) + { + /* Heck the previews need updating...*/ + plp = (PATHIMAGELISTP)gimp_image_get_paths(gimage); + plist = plp->bz_paths; + loop = 0; + + while(plist) + { + bezier_sel = path_to_beziersel(plist->data); + tmprow = paths_dialog->current_path_list->last_selected_row; + paths_dialog->current_path_list->last_selected_row = loop; + paths_update_preview(bezier_sel); + beziersel_free(bezier_sel); + paths_dialog->current_path_list->last_selected_row = tmprow; + paths_dialog->selected_row_num = tmprow; + loop++; + plist = g_slist_next(plist); + } + + /* Force selection .. it may have changed */ + if(bezier_tool_selected()) + { + gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list), + paths_dialog->current_path_list->last_selected_row, + 1); + } + } +} + +void +paths_transform_current_path(GimpImage *gimage, + GimpMatrix transform, + gboolean forpreview) +{ + PATHIMAGELISTP plp; + PATHP p; + PATHP p_copy; + GSList *points_list; + BezierSelect *bezier_sel; + GSList *plist; + gint loop; + gint tmprow; + + /* As a first off lets just translate the current path */ + + /* Get bzpath structure */ + plp = (PATHIMAGELISTP)gimp_image_get_paths(gimage); + + if(!plp) + return; + + plist = plp->bz_paths; + loop = 0; + + while(plist) + { + p = (PATHP)plist->data; + if(p->locked) + { + if(forpreview) + p_copy = path_copy(NULL,p); /* NULL means dont want new tattoo */ + else + p_copy = p; + + points_list = p_copy->path_details; + + while (points_list) + { + gdouble newx,newy; + PATHPOINTP ppoint = points_list->data; + + /* printf("[x,y] = [%g,%g]\n",ppoint->x, ppoint->y); */ + + gimp_matrix_transform_point (transform, + ppoint->x, + ppoint->y, + &newx,&newy); + + /* printf("->[x,y] = [%g,%g]\n", newx, newy); */ + + ppoint->x = newx; + ppoint->y = newy; + points_list = points_list->next; + } + + if(paths_dialog) + { + /* Now fudge the drawing....*/ + bezier_sel = path_to_beziersel(p_copy); + tmprow = paths_dialog->current_path_list->last_selected_row; + paths_dialog->current_path_list->last_selected_row = loop; + paths_update_preview(bezier_sel); + beziersel_free(bezier_sel); + paths_dialog->current_path_list->last_selected_row = tmprow; + paths_dialog->selected_row_num = tmprow; + } + + if(forpreview) + path_free(p_copy,NULL); + } + plist = g_slist_next(plist); + loop++; + } +} /*************************************/ /* PDB function aids */ @@ -1974,7 +2270,7 @@ paths_set_path(GimpImage * gimage, { gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list), row, - 0); + 1); } else { @@ -2088,7 +2384,7 @@ paths_set_path_points(GimpImage * gimage, if(paths_dialog) gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list), row, - 0); + 1); return TRUE; } else @@ -2118,7 +2414,7 @@ paths_set_path_points(GimpImage * gimage, gtk_clist_select_row(GTK_CLIST(paths_dialog->paths_list), paths_dialog->current_path_list->last_selected_row, - 0); + 1); paths_ops_button_set_sensitive(DUP_PATH_BUTTON,TRUE); paths_ops_button_set_sensitive(DEL_PATH_BUTTON,TRUE); diff --git a/app/tools/bezier_select.c b/app/tools/bezier_select.c index 5274f93538..d34a93bbc4 100644 --- a/app/tools/bezier_select.c +++ b/app/tools/bezier_select.c @@ -1695,6 +1695,13 @@ bezier_insert_in_list (GSList * list, return orig; } +gboolean +bezier_tool_selected() +{ + return(active_tool_type == BEZIER_SELECT && + active_tool->state == ACTIVE); +} + void bezier_paste_bezierselect_to_current(GDisplay *gdisp,BezierSelect *bsel) { @@ -1798,8 +1805,8 @@ bezier_to_sel_internal(BezierSelect *bezier_sel, bezier_sel->mask, op, 0, 0); /* show selection on all views */ - bezier_sel->draw = BEZIER_DRAW_HANDLES; - draw_core_resume (bezier_sel->core, tool); + /* bezier_sel->draw = BEZIER_DRAW_HANDLES; */ + /* draw_core_resume (bezier_sel->core, tool); */ gdisplays_flush (); } diff --git a/app/tools/bezier_select.h b/app/tools/bezier_select.h index 9623d1e2fc..1e87b5170e 100644 --- a/app/tools/bezier_select.h +++ b/app/tools/bezier_select.h @@ -25,5 +25,6 @@ void bezier_select_dialog (void); Tool * tools_new_bezier_select (void); void tools_free_bezier_select (Tool *); +gboolean bezier_tool_selected(void); #endif /* __BEZIER_SELECT_H__ */ diff --git a/app/tools/transform_core.c b/app/tools/transform_core.c index e1e5ab1c57..6fad0bfc27 100644 --- a/app/tools/transform_core.c +++ b/app/tools/transform_core.c @@ -312,7 +312,8 @@ transform_core_button_release (tool, bevent, gdisp_ptr) } else { - /* Do nothing, keep the grid visible */ + /* Only update the paths preview */ + paths_transform_current_path(gdisp->gimage,transform_core->transform,TRUE); } } else @@ -328,6 +329,9 @@ transform_core_button_release (tool, bevent, gdisp_ptr) /* resume drawing the current tool */ draw_core_resume (transform_core->core, tool); + + /* Update the paths preview */ + paths_transform_current_path(gdisp->gimage,transform_core->transform,TRUE); } /* if this tool is non-interactive, make it inactive after use */ @@ -341,6 +345,7 @@ transform_core_doit (tool, gdisp_ptr) gpointer gdisp_ptr; { GDisplay *gdisp; + void *pundo; TransformCore *transform_core; TileManager *new_tiles; TransformUndo *tu; @@ -376,6 +381,8 @@ transform_core_doit (tool, gdisp_ptr) gimage_active_drawable (gdisp->gimage), &new_layer); + pundo = paths_transform_start_undo(gdisp->gimage); + /* Send the request for the transformation to the tool... */ new_tiles = (* transform_core->trans_func) (tool, gdisp_ptr, FINISH); @@ -399,6 +406,7 @@ transform_core_doit (tool, gdisp_ptr) for (i = 0; i < TRAN_INFO_SIZE; i++) tu->trans_info[i] = old_trans_info[i]; tu->original = NULL; + tu->path_undo = pundo; /* Make a note of the new current drawable (since we may have a floating selection, etc now. */ @@ -755,6 +763,7 @@ transform_bounding_box (tool) TransformCore * transform_core; int i, k; int gci; + GDisplay * gdisp; transform_core = (TransformCore *) tool->private; @@ -791,6 +800,8 @@ transform_bounding_box (tool) gci += 2; } } + + gdisp = (GDisplay *) tool->gdisp_ptr; } void @@ -1036,6 +1047,8 @@ transform_core_do (gimage, drawable, float_tiles, interpolation, matrix, gimp_matrix_invert (matrix, m); } + paths_transform_current_path(gimage,matrix,FALSE); + x1 = float_tiles->x; y1 = float_tiles->y; x2 = x1 + float_tiles->width; diff --git a/app/tools/transform_core.h b/app/tools/transform_core.h index deececcdb5..bf7e39f445 100644 --- a/app/tools/transform_core.h +++ b/app/tools/transform_core.h @@ -115,6 +115,7 @@ struct _transform_undo int tool_type; TranInfo trans_info; TileManager * original; + void * path_undo; }; diff --git a/app/transform_core.c b/app/transform_core.c index e1e5ab1c57..6fad0bfc27 100644 --- a/app/transform_core.c +++ b/app/transform_core.c @@ -312,7 +312,8 @@ transform_core_button_release (tool, bevent, gdisp_ptr) } else { - /* Do nothing, keep the grid visible */ + /* Only update the paths preview */ + paths_transform_current_path(gdisp->gimage,transform_core->transform,TRUE); } } else @@ -328,6 +329,9 @@ transform_core_button_release (tool, bevent, gdisp_ptr) /* resume drawing the current tool */ draw_core_resume (transform_core->core, tool); + + /* Update the paths preview */ + paths_transform_current_path(gdisp->gimage,transform_core->transform,TRUE); } /* if this tool is non-interactive, make it inactive after use */ @@ -341,6 +345,7 @@ transform_core_doit (tool, gdisp_ptr) gpointer gdisp_ptr; { GDisplay *gdisp; + void *pundo; TransformCore *transform_core; TileManager *new_tiles; TransformUndo *tu; @@ -376,6 +381,8 @@ transform_core_doit (tool, gdisp_ptr) gimage_active_drawable (gdisp->gimage), &new_layer); + pundo = paths_transform_start_undo(gdisp->gimage); + /* Send the request for the transformation to the tool... */ new_tiles = (* transform_core->trans_func) (tool, gdisp_ptr, FINISH); @@ -399,6 +406,7 @@ transform_core_doit (tool, gdisp_ptr) for (i = 0; i < TRAN_INFO_SIZE; i++) tu->trans_info[i] = old_trans_info[i]; tu->original = NULL; + tu->path_undo = pundo; /* Make a note of the new current drawable (since we may have a floating selection, etc now. */ @@ -755,6 +763,7 @@ transform_bounding_box (tool) TransformCore * transform_core; int i, k; int gci; + GDisplay * gdisp; transform_core = (TransformCore *) tool->private; @@ -791,6 +800,8 @@ transform_bounding_box (tool) gci += 2; } } + + gdisp = (GDisplay *) tool->gdisp_ptr; } void @@ -1036,6 +1047,8 @@ transform_core_do (gimage, drawable, float_tiles, interpolation, matrix, gimp_matrix_invert (matrix, m); } + paths_transform_current_path(gimage,matrix,FALSE); + x1 = float_tiles->x; y1 = float_tiles->y; x2 = x1 + float_tiles->width; diff --git a/app/transform_core.h b/app/transform_core.h index deececcdb5..bf7e39f445 100644 --- a/app/transform_core.h +++ b/app/transform_core.h @@ -115,6 +115,7 @@ struct _transform_undo int tool_type; TranInfo trans_info; TileManager * original; + void * path_undo; }; diff --git a/app/undo.c b/app/undo.c index b6e38f83ed..dcdbceb2cc 100644 --- a/app/undo.c +++ b/app/undo.c @@ -924,6 +924,8 @@ undo_pop_transform (GImage *gimage, tc = (TransformCore *) active_tool->private; tu = (TransformUndo *) tu_ptr; + paths_transform_do_undo(gimage,tu->path_undo); + /* only pop if the active tool is the tool that pushed this undo */ if (tu->tool_ID != active_tool->ID) return TRUE; @@ -962,6 +964,7 @@ undo_free_transform (int state, tu = (TransformUndo *) tu_ptr; if (tu->original) tile_manager_destroy (tu->original); + paths_transform_free_undo(tu->path_undo); g_free (tu); } diff --git a/pixmaps/locked.xpm b/pixmaps/locked.xpm new file mode 100644 index 0000000000..7890ab6452 --- /dev/null +++ b/pixmaps/locked.xpm @@ -0,0 +1,228 @@ +/* XPM */ +static char * locked_xpm[] = { +"28 32 193 2", +" c None", +". c #FFFFFF", +"+ c #FDFDFD", +"@ c #FAFAFA", +"# c #F8F8F8", +"$ c #F7F7F7", +"% c #F9F9F9", +"& c #FBFBFB", +"* c #FEFEFE", +"= c #FCFCFC", +"- c #E3E3E3", +"; c #C1C1C1", +"> c #A1A1A1", +", c #9D9D9D", +"' c #B1B1B1", +") c #D2D2D2", +"! c #F4F4F4", +"~ c #F3F3F2", +"{ c #D8D8D8", +"] c #989898", +"^ c #666666", +"/ c #4D4D4D", +"( c #404040", +"_ c #444444", +": c #464646", +"< c #565656", +"[ c #7A7A7A", +"} c #B4B4B4", +"| c #F6F6F6", +"1 c #F6F6F5", +"2 c #F2F2F0", +"3 c #C6C6C6", +"4 c #6D6D6D", +"5 c #4B4B4B", +"6 c #707070", +"7 c #9E9E9E", +"8 c #ABABAB", +"9 c #858585", +"0 c #5A5A5A", +"a c #434343", +"b c #545454", +"c c #949494", +"d c #F3F3F3", +"e c #D1D1D1", +"f c #696969", +"g c #505050", +"h c #747474", +"i c #9C9C9C", +"j c #575757", +"k c #F7F7F6", +"l c #8A8A8A", +"m c #494949", +"n c #777777", +"o c #E6E6E6", +"p c #AEAEAE", +"q c #585858", +"r c #F9F9F8", +"s c #CBCBCB", +"t c #535353", +"u c #5D5D5D", +"v c #C9C9C9", +"w c #808080", +"x c #474747", +"y c #8B8B8B", +"z c #FDFDFB", +"A c #B0B0B0", +"B c #3E3E3E", +"C c #767676", +"D c #BFBFBF", +"E c #5F5F5F", +"F c #EEEEEE", +"G c #9B9B9B", +"H c #525252", +"I c #959595", +"J c #5B5B5B", +"K c #DEDEDF", +"L c #FFFFFE", +"M c #E0E0E0", +"N c #797979", +"O c #4C4C4C", +"P c #848484", +"Q c #E1E1E1", +"R c #DDDDDD", +"S c #DCDCDC", +"T c #DEDEDE", +"U c #EAEAEA", +"V c #D0D0D0", +"W c #4F4F4F", +"X c #B9B9BA", +"Y c #6E6E6E", +"Z c #2F2F2F", +"` c #373737", +" . c #343434", +".. c #252525", +"+. c #2E2E2E", +"@. c #3D3D3D", +"#. c #262626", +"$. c #2D2D2D", +"%. c #363636", +"&. c #313131", +"*. c #3B3B3B", +"=. c #3A3A3A", +"-. c #B5B5B4", +";. c #EFEFED", +">. c #818181", +",. c #909090", +"'. c #757575", +"). c #7C7C7C", +"!. c #B8B8B8", +"~. c #939393", +"{. c #787878", +"]. c #A7A7A7", +"^. c #B6B6B6", +"/. c #EEEEEC", +"(. c #6A6A6A", +"_. c #6B6B6B", +":. c #000000", +"<. c #A0A0A0", +"[. c #B5B5B3", +"}. c #7E7E7E", +"|. c #898989", +"1. c #6F6F6F", +"2. c #515151", +"3. c #606060", +"4. c #8F8F8F", +"5. c #747475", +"6. c #7F7F7F", +"7. c #8D8D8D", +"8. c #595959", +"9. c #969696", +"0. c #E2E2E2", +"a. c #686868", +"b. c #5E5E5E", +"c. c #757576", +"d. c #4A4A4A", +"e. c #868686", +"f. c #F2F2F2", +"g. c #7D7D7D", +"h. c #555555", +"i. c #353535", +"j. c #E9E9E9", +"k. c #7B7B7B", +"l. c #717171", +"m. c #B5B5B2", +"n. c #9A9A9A", +"o. c #AFAFAF", +"p. c #DADADA", +"q. c #888888", +"r. c #7B7B7C", +"s. c #383838", +"t. c #838383", +"u. c #2A2A2A", +"v. c #D9D9D9", +"w. c #707071", +"x. c #828282", +"y. c #9F9F9F", +"z. c #B2B2B2", +"A. c #ADADAD", +"B. c #E4E4E4", +"C. c #919191", +"D. c #B6B6B3", +"E. c #A3A3A3", +"F. c #D5D5D5", +"G. c #6F6F70", +"H. c #676767", +"I. c #626262", +"J. c #959596", +"K. c #545455", +"L. c #B9B9B6", +"M. c #BEBEBD", +"N. c #9D9D9C", +"O. c #A6A6A5", +"P. c #A5A5A5", +"Q. c #A5A5A6", +"R. c #A4A4A4", +"S. c #A0A0A1", +"T. c #A0A09F", +"U. c #9C9C9D", +"V. c #9B9B9C", +"W. c #9E9E9D", +"X. c #A3A3A2", +"Y. c #A4A4A5", +"Z. c #A4A4A3", +"`. c #A4A4A6", +" + c #DCDCDA", +".+ c #F0F0EE", +"++ c #C2C2C1", +"@+ c #A7A7A6", +"#+ c #A6A6A6", +"$+ c #AAAAA9", +"%+ c #AAAAAA", +"&+ c #A9A9A8", +"*+ c #D6D6D4", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . + @ # $ % & * . . . . . . = . . . ", +". . . . . . . . . . * - ; > , ' ) ! . . . . . = ~ . . . ", +". . . . . . . . . { ] ^ / ( _ : < [ } | . . . 1 2 . . . ", +". . . . . . . . 3 4 5 5 6 7 8 9 0 a b c d . . 1 2 . . . ", +". . . . . . . e f g h 3 # . . . - i j b i & . k 2 . . . ", +". . . . . . ! l m n o . . . . . . . p q 0 3 . r 2 . . . ", +". . . . . . s t u v . . . . . . . . . w x y = z 2 . . . ", +". . . . . . A B C . . . . . . . . . . D t E F . 2 . . . ", +". . . . . & G H I . . . . . . . . . . $ ^ J K L 2 . . . ", +". . . . . M N O P | - Q M R S T M Q U V q W X r 2 . . . ", +". . . . % Y Z ` Z ...+.m t H b @.#.$.%.&.*.=.-.;.. . . ", +". . . * & >.] ,.C '.).!.. . . . @ ~.h n {.].[ ^./.. . . ", +". . . * @ w c P (._.c U . :.:.:.. s '._._.<.{.[./.. . . ", +". . . * @ }.|.1.2.2.I . . :.. :.# - 3.H H 4.5.[./.. . . ", +". . . * @ 6.7.{.u 8.9.. . :.:.:.. 0.a.u b.c c.[./.. . . ", +". . . * @ >.7 G P >.' . . d.:.e.. f.|.P 9 ' ).[./.. . . ", +". . . * @ g.}.h. .i.g.. j.:.. :.R { _ .%.k.l.m./.. . . ", +". . . * @ w G n.9 w o.. Q 5 . :.p.! q.9 9 A r.[./.. . . ", +". . . * @ g.>.q ` s.t.. . u.o (.! v.d.` =.}.w.m./.. . . ", +". . . * @ x.y.7 q.|.z.. . ].{.A.. B.C.|.|.z.g.D./.. . . ", +". . . * @ ).x.4 W W E E.+ . F . F.k.t 2.g q.G.} /.. . . ", +". . . . @ N 8.H.b.b.< I.l c c J.c.h.J E u 4 K.L.;.. . . ", +". . . . . M.N.O.P.Q.R.S.T.U.V.W.> X.Q.Q.Y.Z.`. +.+. . . ", +". . . . f.++O.@+#+#+#+].$+%+%+$+&+@+#+#+#+@+p *+.+. . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . ", +". . . . . . . . . . . . . . . . . . . . . . . . . . . . "};