diff --git a/ChangeLog b/ChangeLog index 629ec3a9eb..6c309723f5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Mon Dec 8 16:30:29 EST 1997 Adrian Likins + + * udpdate gqbist, warp, randomize, fuse, gfig plugins + + * removed gflare-tar.gz from the plugins dir + Mon Dec 8 11:43:17 EST 1997 Adrian Likins * updated iwarp to latest version diff --git a/plug-ins/common/gqbist.c b/plug-ins/common/gqbist.c index 98a3678099..2348406b01 100644 --- a/plug-ins/common/gqbist.c +++ b/plug-ins/common/gqbist.c @@ -32,6 +32,7 @@ * 1.7 added patch from Art Haas to make it compile with HP-UX, a small clean-up * 1.8 Dscho added transform file load/save, bug-fixes * 1.9 rewrote renderloop. + * 1.9a fixed a bug. */ #include @@ -258,7 +259,6 @@ void run(char *name, int nparams, GParam *param, int *nreturn_vals, GParam **ret gint sel_x1, sel_y1, sel_x2, sel_y2; gint img_height, img_width, img_bpp, img_has_alpha; - GParam values[1]; GDrawable *drawable; GRunModeType run_mode; GStatusType status; diff --git a/plug-ins/common/randomize.c b/plug-ins/common/randomize.c index 0e50f77851..151bdeb215 100644 --- a/plug-ins/common/randomize.c +++ b/plug-ins/common/randomize.c @@ -1,13 +1,15 @@ /**************************************************************************** - * This is a plugin for the GIMP v 0.99.8 or later. + * This is a plugin for the GIMP v 0.99.8 or later. Documentation is + * available at http://www.rru.com/~meo/gimp/ . * - * Copyright (C) 1997 Miles O'Neal + * Copyright (C) 1997 Miles O'Neal http://www.rru.com/~meo/ * Blur code Copyright (C) 1995 Spencer Kimball and Peter Mattis * GUI based on GTK code from: - * plasma (Copyright (C) 1996 Stephen Norris), - * oilify (Copyright (C) 1996 Torsten Martinsen), - * ripple (Copyright (C) 1997 Brian Degenhardt) and - * whirl (Copyright (C) 1997 Federico Mena Quintero). + * alienmap (Copyright (C) 1996, 1997 Daniel Cotting) + * plasma (Copyright (C) 1996 Stephen Norris), + * oilify (Copyright (C) 1996 Torsten Martinsen), + * ripple (Copyright (C) 1997 Brian Degenhardt) and + * whirl (Copyright (C) 1997 Federico Mena Quintero). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,8 +30,19 @@ /**************************************************************************** * Randomize: * - * randomize version 0.4c (17 May 1997, MEO) + * randomize version 1.0 (19 Oct 1997, MEO) * history + * 1.1 - 30 Nov 1997 MEO + * added tooltips + * 1.0 - 19 Nov 1997 MEO + * final cleanup for 1.0 GIMP release + * - added email and URL info for author + * - added doc URL info + * - final FCS comment cleanup + * - standardized constant strings + * - restored proper behavior when repeating + * - final UI labels + * - better help text (for when GIMP help arrives) * 0.5 - 20 May 1997 MEO * added seed initialization choices (current time or user value) * added randomization type to progress label @@ -99,7 +112,8 @@ * * TODO List * - * - Add a real melt function. + * - add a real melt function + * - split into multiple files ****************************************************************************/ #include @@ -107,23 +121,25 @@ #include "libgimp/gimp.h" #include "gtk/gtk.h" +/********************************* + * + * PLUGIN-SPECIFIC CONSTANTS + * + ********************************/ + /* - * Set this to 0 for faster processing, to 1 if for some + * Set this to 1 for faster processing, to 0 if for some * reason you want all functions to be subroutines */ -#define SUBS_NOT_DEFINES 0 +#define OPTIMIZE_SUBS 0 + /* * progress meter update frequency */ #define PROG_UPDATE_TIME ((row % 10) == 0) -#define RNDM_VERSION "Randomize 0.5" - -/********************************* - * - * LOCAL DATA - * - ********************************/ +#define PLUG_IN_NAME "plug_in_randomize" +#define RNDM_VERSION "Randomize 1.1" #define RNDM_BLUR 1 #define RNDM_PICK 2 @@ -136,6 +152,12 @@ #define ENTRY_WIDTH 75 #define SCALE_WIDTH 100 +/********************************* + * + * PLUGIN-SPECIFIC STRUCTURES AND DATA + * + ********************************/ + typedef struct { gint rndm_type; /* type of randomization to apply */ gdouble rndm_pct; /* likelihood of randomization (as %age) */ @@ -185,14 +207,15 @@ GPlugInInfo PLUG_IN_INFO = { }; static void randomize(GDrawable *drawable); -#if (SUBS_NOT_DEFINES == 1) -static void randomize_prepare_row( - GPixelRgn *pixel_rgn, - guchar *data, - int x, - int y, - int w -); + +#if (OPTIMIZE_SUBS == 0) + static void randomize_prepare_row( + GPixelRgn *pixel_rgn, + guchar *data, + int x, + int y, + int w + ); #endif static gint randomize_dialog(); @@ -224,6 +247,14 @@ static void randomize_text_update( gpointer data ); +static void set_tooltip( + GtkWidget *widget, + const char *tip +); + +static void setup_tooltips(); + +/************************************ Guts ***********************************/ MAIN() @@ -250,12 +281,18 @@ query() static int nargs = sizeof(args) / sizeof (args[0]); static int nreturn_vals = 0; - gimp_install_procedure("plug_in_randomize", - "Add a random factor to the image, by blurring, picking a nearby pixel, slurring (similar to melting), or just hurling on it.", - "This function randomly ``blurs'' the specified drawable, using either a 3x3 blur, picking a nearby pixel, slurring (cheezy melting), or hurling (spewing colors). The type and percentage are user selectable. Blurring is not supported for indexed images.", - "Miles O'Neal", - "Miles O'Neal, Spencer Kimball, Peter Mattis, Torsten Martinsen, Brian Degenhardt, Federico Mena Quintero", - "1995-1997", + const char *blurb = "Add a random factor to the image, by blurring, picking a nearby pixel, slurring (similar to melting), or just hurling on it."; + const char *help = "This function randomly ``blurs'' the specified drawable, using either a 3x3 blur, picking a nearby pixel, slurring (cheezy melting), or hurling (spewing colors). The type and percentage are user selectable. Blurring is not supported for indexed images."; + const char *author = "Miles O'Neal http://www.rru.com/~meo/"; + const char *copyrights = "Miles O'Neal, Spencer Kimball, Peter Mattis, Torsten Martinsen, Brian Degenhardt, Federico Mena Quintero, Stephen Norris, Daniel Cotting"; + const char *copyright_date = "1995-1997"; + + gimp_install_procedure(PLUG_IN_NAME, + (char *) blurb, + (char *) help, + (char *) author, + (char *) copyrights, + (char *) copyright_date, "/Filters/Distorts/Randomize", "RGB*, GRAY*, INDEXED*", PROC_PLUG_IN, @@ -292,12 +329,12 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals, GParam **return_vals) { - static GParam values[1]; GDrawable *drawable; GRunModeType run_mode; GStatusType status = STATUS_SUCCESS; /* assume the best! */ char *rndm_type_str = '\0'; char prog_label[32]; + static GParam values[1]; /* * Get the specified drawable, do standard initialization. */ @@ -321,7 +358,7 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals, */ case RUN_INTERACTIVE: FIX_INDEX_BLUR(); - gimp_get_data("plug_in_randomize", &pivals); + gimp_get_data(PLUG_IN_NAME, &pivals); if (!randomize_dialog()) /* return on Cancel */ return; break; @@ -355,7 +392,7 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals, * If we're running with the last set of values, get those values. */ case RUN_WITH_LAST_VALS: - gimp_get_data("plug_in_randomize", &pivals); + gimp_get_data(PLUG_IN_NAME, &pivals); break; /* * Hopefully we never get here! @@ -376,7 +413,7 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals, gimp_progress_init(prog_label); gimp_tile_cache_ntiles(2 * (drawable->width / gimp_tile_width() + 1)); /* - * Initialie the rand() function seed + * Initialize the rand() function seed */ if (pivals.seed_type == SEED_TIME) srand(time(NULL)); @@ -394,7 +431,7 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals, * If we use the dialog popup, set the data for future use. */ if (run_mode == RUN_INTERACTIVE) { - gimp_set_data("plug_in_randomize", &pivals, sizeof(RandomizeVals)); + gimp_set_data(PLUG_IN_NAME, &pivals, sizeof(RandomizeVals)); } } else { /* @@ -420,7 +457,7 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals, * ********************************/ -#if (SUBS_NOT_DEFINES == 1) +#if (OPTIMIZE_SUBS == 0) static void randomize_prepare_row(GPixelRgn *pixel_rgn, guchar *data, int x, int y, int w) { @@ -474,7 +511,7 @@ randomize_prepare_row(GPixelRgn *pixel_rgn, guchar *data, int x, int y, int w) static void randomize(GDrawable *drawable) { - GPixelRgn srcPR, destPR; + GPixelRgn srcPR, destPR, destPR2, *sp, *dp, *tp; gint width, height; gint bytes; guchar *dest, *d; @@ -509,27 +546,32 @@ randomize(GDrawable *drawable) next_row = (guchar *) malloc((x2 - x1 + 2) * bytes); dest = (guchar *) malloc((x2 - x1) * bytes); - for (cnt = 1; cnt <= pivals.rndm_rcount; cnt++) { /* * initialize the pixel regions */ - gimp_pixel_rgn_init(&srcPR, drawable, 0, 0, width, height, FALSE, FALSE); - gimp_pixel_rgn_init(&destPR, drawable, 0, 0, width, height, TRUE, TRUE); + gimp_pixel_rgn_init(&srcPR, drawable, 0, 0, width, height, FALSE, FALSE); + gimp_pixel_rgn_init(&destPR, drawable, 0, 0, width, height, TRUE, TRUE); + gimp_pixel_rgn_init(&destPR2, drawable, 0, 0, width, height, TRUE, TRUE); + sp = &srcPR; + dp = &destPR; + tp = NULL; - pr = prev_row + bytes; - cr = cur_row + bytes; - nr = next_row + bytes; + pr = prev_row + bytes; + cr = cur_row + bytes; + nr = next_row + bytes; + + for (cnt = 1; cnt <= pivals.rndm_rcount; cnt++) { /* * prepare the first row and previous row */ - randomize_prepare_row(&srcPR, pr, x1, y1 - 1, (x2 - x1)); - randomize_prepare_row(&srcPR, cr, x1, y1, (x2 - x1)); + randomize_prepare_row(sp, pr, x1, y1 - 1, (x2 - x1)); + randomize_prepare_row(dp, cr, x1, y1, (x2 - x1)); /* * loop through the rows, applying the selected convolution */ for (row = y1; row < y2; row++) { /* prepare the next row */ - randomize_prepare_row(&srcPR, nr, x1, row + 1, (x2 - x1)); + randomize_prepare_row(sp, nr, x1, row + 1, (x2 - x1)); d = dest; for (col = 0; col < (x2 - x1) * bytes; col++) { @@ -621,7 +663,7 @@ randomize(GDrawable *drawable) * Save the modified row, shuffle the row pointers, and every * so often, update the progress meter. */ - gimp_pixel_rgn_set_row(&destPR, dest, x1, row, (x2 - x1)); + gimp_pixel_rgn_set_row(dp, dest, x1, row, (x2 - x1)); tmp = pr; pr = cr; @@ -631,6 +673,20 @@ randomize(GDrawable *drawable) if (PROG_UPDATE_TIME) gimp_progress_update((double) row / (double) (y2 - y1)); } +/* + * if we have more cycles to perform, swap the src and dest Pixel Regions + */ + if (cnt < pivals.rndm_rcount) { + if (tp != NULL) { + tp = dp; + dp = sp; + sp = tp; + } else { + tp = &srcPR; + sp = &destPR; + dp = &destPR2; + } + } } gimp_progress_update((double) 100); /* @@ -654,7 +710,7 @@ randomize(GDrawable *drawable) * ********************************/ -#define randomize_add_action_button(label, callback, dialog) \ +#define randomize_add_action_button(label, callback, dialog, tip) \ { \ GtkWidget *button; \ \ @@ -665,9 +721,10 @@ randomize(GDrawable *drawable) button, TRUE, TRUE, 0); \ gtk_widget_grab_default(button); \ gtk_widget_show(button); \ + set_tooltip(button, tip); \ } -#define randomize_add_radio_button(group, label, box, callback, value) \ +#define randomize_add_radio_button(group, label, box, callback, value, tip) \ { \ GtkWidget *toggle; \ \ @@ -679,6 +736,7 @@ randomize(GDrawable *drawable) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(toggle), *value); \ gtk_widget_show(toggle); \ gtk_widget_show(box); \ + set_tooltip(toggle, tip); \ } /********************************* @@ -723,13 +781,6 @@ randomize_dialog() gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE); gtk_signal_connect(GTK_OBJECT(dlg), "destroy", (GtkSignalFunc) randomize_close_callback, NULL); -/* - * Action area OK & Cancel buttons - */ - randomize_add_action_button("OK", - (GtkSignalFunc) randomize_ok_callback, dlg); - randomize_add_action_button("Cancel", - (GtkSignalFunc) randomize_cancel_callback, dlg); /* * Parameter settings * @@ -742,6 +793,17 @@ randomize_dialog() table = gtk_table_new(4, 2, FALSE); gtk_container_border_width(GTK_CONTAINER(table), 10); gtk_container_add(GTK_CONTAINER(frame), table); + gtk_widget_show(table); + setup_tooltips(table); +/* + * Action area OK & Cancel buttons + */ + randomize_add_action_button("OK", + (GtkSignalFunc) randomize_ok_callback, dlg, + "Accept settings and apply filter to image"); + randomize_add_action_button("Cancel", + (GtkSignalFunc) randomize_cancel_callback, dlg, + "Close plug-in without making any changes"); /* * Randomization Type - label & radio buttons */ @@ -761,22 +823,25 @@ randomize_dialog() */ if (! is_indexed_drawable) { randomize_add_radio_button(type_group, "Blur", toggle_hbox, - (GtkSignalFunc) randomize_toggle_update, &do_blur); + (GtkSignalFunc) randomize_toggle_update, &do_blur, + "Blur each pixel by averaging its value with those of its neighbors"); } /* * Hurl, Pick and Slur buttons */ randomize_add_radio_button(type_group, "Hurl", toggle_hbox, - (GtkSignalFunc) randomize_toggle_update, &do_hurl); + (GtkSignalFunc) randomize_toggle_update, &do_hurl, + "Hurl random colors onto pixels"); randomize_add_radio_button(type_group, "Pick", toggle_hbox, - (GtkSignalFunc) randomize_toggle_update, &do_pick); + (GtkSignalFunc) randomize_toggle_update, &do_pick, + "Pick at random from neighboring pixels"); randomize_add_radio_button(type_group, "Slur", toggle_hbox, - (GtkSignalFunc) randomize_toggle_update, &do_slur); - + (GtkSignalFunc) randomize_toggle_update, &do_slur, + "Simplistic melt"); /* * Randomization seed initialization controls */ - label = gtk_label_new("Seed"); + label = gtk_label_new("Randomization Seed"); gtk_misc_set_alignment(GTK_MISC (label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 5, 0); gtk_widget_show(label); @@ -791,7 +856,8 @@ randomize_dialog() * Time button */ randomize_add_radio_button(seed_group, "Current Time", seed_vbox, - (GtkSignalFunc) randomize_toggle_update, &do_time); + (GtkSignalFunc) randomize_toggle_update, &do_time, + "Seed random number generator from the current time - this guarantees a reasonable randomization"); /* * Box to hold seed user initialization controls */ @@ -801,10 +867,11 @@ randomize_dialog() /* * User button */ - randomize_add_radio_button(seed_group, "User", seed_hbox, - (GtkSignalFunc) randomize_toggle_update, &do_user); + randomize_add_radio_button(seed_group, "Other Value", seed_hbox, + (GtkSignalFunc) randomize_toggle_update, &do_user, + "Enable user-entered value for random number generator seed - this allows you to repeat a given \"random\" operation"); /* - * Randomization seed text + * Randomization seed number (text) */ entry = gtk_entry_new(); gtk_widget_set_usize(entry, ENTRY_WIDTH, 0); @@ -814,8 +881,8 @@ randomize_dialog() gtk_signal_connect(GTK_OBJECT(entry), "changed", (GtkSignalFunc) randomize_text_update, &pivals.rndm_seed); gtk_widget_show(entry); + set_tooltip(entry, "Value for seeding the random number generator"); gtk_widget_show(seed_hbox); - /* * Randomization percentage label & scale (1 to 100) */ @@ -837,6 +904,7 @@ randomize_dialog() (GtkSignalFunc) randomize_scale_update, &pivals.rndm_pct); gtk_widget_show(label); gtk_widget_show(scale); + set_tooltip(scale, "Percentage of pixels to be filtered"); /* * Repeat count label & scale (1 to 100) */ @@ -858,11 +926,11 @@ randomize_dialog() (GtkSignalFunc) randomize_scale_update, &pivals.rndm_rcount); gtk_widget_show(label); gtk_widget_show(scale); + set_tooltip(scale, "Number of times to apply filter"); /* * Display everything. */ gtk_widget_show(frame); - gtk_widget_show(table); gtk_widget_show(dlg); gtk_main(); @@ -898,28 +966,42 @@ randomize_dialog() * ********************************/ +/* + * DESTROY callback + */ static void randomize_close_callback(GtkWidget *widget, gpointer data) { gtk_main_quit(); } +/* + * OK BUTTON callback + */ static void randomize_ok_callback(GtkWidget *widget, gpointer data) { rndm_int.run = TRUE; gtk_widget_destroy(GTK_WIDGET(data)); } +/* + * CANCEL BUTTON callback + */ static void randomize_cancel_callback(GtkWidget *widget, gpointer data) { gtk_widget_destroy(GTK_WIDGET(data)); } - +/* + * SCALE UPDATE callback + */ static void randomize_scale_update(GtkAdjustment *adjustment, double *scale_val) { *scale_val = adjustment->value; } +/* + * TOGGLE UPDATE callback + */ static void randomize_toggle_update(GtkWidget *widget, gpointer data) { int *toggle_val; @@ -932,6 +1014,9 @@ randomize_toggle_update(GtkWidget *widget, gpointer data) { *toggle_val = FALSE; } +/* + * TEXT UPDATE callback + */ static void randomize_text_update(GtkWidget *widget, gpointer data) { gint *text_val; @@ -940,3 +1025,39 @@ randomize_text_update(GtkWidget *widget, gpointer data) { *text_val = atoi(gtk_entry_get_text(GTK_ENTRY(widget))); } + +/* + * TOOLTIPS ROUTINES + */ +static GtkTooltips *tips; + + +void setup_tooltips(GtkWidget *parent) +{ + static GdkColor tips_fg, tips_bg; + + tips = gtk_tooltips_new(); + + /* black as foreground: */ + + tips_fg.red = 0; + tips_fg.green = 0; + tips_fg.blue = 0; + gdk_color_alloc(gtk_widget_get_colormap(parent), &tips_fg); + + /* postit yellow (khaki) as background: */ + + tips_bg.red = 61669; + tips_bg.green = 59113; + tips_bg.blue = 35979; + gdk_color_alloc(gtk_widget_get_colormap(parent), &tips_bg); + + gtk_tooltips_set_colors(tips, &tips_bg, &tips_fg); +} + + +void set_tooltip(GtkWidget *widget, const char *tip) +{ + if (tip && tip[0]) + gtk_tooltips_set_tips(tips, widget, (char *) tip); +} diff --git a/plug-ins/fuse/fuse.c b/plug-ins/fuse/fuse.c index 8473ecf0d8..3544e21f9f 100644 --- a/plug-ins/fuse/fuse.c +++ b/plug-ins/fuse/fuse.c @@ -20,6 +20,17 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* + + revision history + + Fri Nov 28 1997 - added template image + + Sun Nov 16 1997 - listbox to select multiple inputs + +*/ + #include #include #include @@ -27,14 +38,14 @@ #include #include #include +#include #include "gtk/gtk.h" #include "libgimp/gimp.h" #include "libgimp/gimpmenu.h" -#include "libgimp/gimpwire.h" +#include "gck/gck.h" -/* Declare local functions. */ static void query(void); static void run(char *name, int nparams, @@ -65,25 +76,36 @@ int run_flag = 0; GtkWidget *dlg; +GckListBox *listbox; -#define preview_size 200 + +#define preview_size 150 GtkWidget *preview; +GDrawable *drawable; + +#define max_inputs 100 struct { - gint32 input_image_id; + int ninputs; + gint32 input_image_ids[max_inputs]; int tile_size; int overlap; int order; int acceleration; int search_time; + int use_template; + double template_weight; /* in [0,10] */ } config = { - -1, + 0, + {0}, 25, 8, 0, 0, - 10 + 10, + 0, + 0.5, }; @@ -107,7 +129,7 @@ static void query() "uhm, image dissociation", "Scott Draves", "Scott Draves", - "1997", + "Nov 1997", "/Filters/Transforms/Fuse", "RGB*", PROC_PLUG_IN, @@ -115,11 +137,11 @@ static void query() args, return_vals); } -static void run(char *name, int n_params, GParam * param, int *nreturn_vals, - GParam ** return_vals) +static void +run(char *name, int n_params, GParam * param, int *nreturn_vals, + GParam ** return_vals) { static GParam values[1]; - GDrawable *drawable; GRunModeType run_mode; GStatusType status = STATUS_SUCCESS; @@ -148,14 +170,7 @@ static void run(char *name, int n_params, GParam * param, int *nreturn_vals, if (status == STATUS_SUCCESS) { if (gimp_drawable_color(drawable->id)) { - gimp_progress_init("Fusing..."); - gimp_tile_cache_ntiles(2 * (drawable->width / gimp_tile_width() + 1)); - - doit(drawable); - - if (run_mode != RUN_NONINTERACTIVE) - gimp_displays_flush(); - gimp_set_data("plug_in_fuse", &config, sizeof(config)); + ; } else { status = STATUS_EXECUTION_ERROR; } @@ -177,19 +192,20 @@ compare(image *in, image *out) { pixel *q = out->pixels + y * out->stride; for (x = 0; x < in->width; x++) { double rr, z; - guchar *i = (guchar *) p; - guchar *o = (guchar *) q; - int d = i[0] - (int) o[0]; - z = i[3] * o[3]; + guchar *i = (guchar *) (&p[x]); + guchar *o = (guchar *) (&q[x]); + int d; if (0 == i[3] || 0 == o[3]) continue; + d = i[0] - (int) o[0]; rr = d * d; - d = i[1] - o[1]; + d = i[1] - (int) o[1]; rr += d * d; - d = i[2] - o[2]; + d = i[2] - (int) o[2]; rr += d * d; + z = i[3] * (double) o[3]; r += rr * z; - t += z; + t += z * z; /* z * 255? */ } } @@ -207,8 +223,8 @@ blit(image *dst, image *src) { pixel *p = dst->pixels + y * dst->stride; pixel *q = src->pixels + y * src->stride; for (x = 0; x < src->width; x++) { - guchar *o = (guchar *) p; - guchar *i = (guchar *) q; + guchar *o = (guchar *) (&p[x]); + guchar *i = (guchar *) (&q[x]); int s = i[3]; if (255 == s) p[x] = q[x]; @@ -221,11 +237,13 @@ blit(image *dst, image *src) { } } +/* find tile somewhere in IN that matches OUT and TEMPLATE */ void -source_match(image *in, image *out) { +source_match(image *in, image *out, image *template) { int i; double best_d = HUGE; image best_tile; + double w = exp(-0.3 * (10-config.template_weight)); if (0 == out->width || 0 == out->height) return; @@ -237,15 +255,25 @@ source_match(image *in, image *out) { tile.pixels = in->pixels + (random() % (in->width - out->width)) + in->stride * (random() % (in->height - out->height)); + tile.stride = in->stride; tile.width = out->width; tile.height = out->height; d = compare(&tile, out); if (d < 0.0) { + /* should really only happen with null overlap */ best_tile = tile; break; } + if (template) { + double e = compare(&tile, template); + if (e < 0.0) + printf("e less than zero\n"); + else + d = (d * (1.0 - w) + e * w); + } + if (d < best_d) { best_d = d; best_tile = tile; @@ -256,7 +284,7 @@ source_match(image *in, image *out) { void -do_fuse(image *in, image *out) { +do_fuse(int nin, image *ins, image *out, image *template) { int i, parity = 0; double r, rad; double bo; @@ -264,9 +292,12 @@ do_fuse(image *in, image *out) { bo = config.tile_size - config.overlap; - if (config.tile_size >= in->width || - config.tile_size >= in->height) - return; + for (i = 0; i < nin; i++) + if (config.tile_size >= ins[i].width || + config.tile_size >= ins[i].height) { + printf("input smaller than tile - bailing\n"); + return; + } rad = sqrt(out->width * out->width + out->height * out->height) / 2; @@ -286,7 +317,7 @@ do_fuse(image *in, image *out) { } parity++; for (i = 0; i < n; i++) { - image tile; + image tile, template_tile; int x, y, w, h; double theta = 2.0 * M_PI * prmute[i] / n; if (parity&1) @@ -302,18 +333,55 @@ do_fuse(image *in, image *out) { if (x > out->width - w) w = out->width - x; if (y > out->height - h) h = out->height - y; + if (w <= 0 || h <= 0) + continue; + tile.pixels = out->pixels + y * out->stride + x; tile.stride = out->stride; tile.width = w; tile.height = h; - source_match(in, &tile); - if (0) { - int y; - for (y = 0; y < preview_size; y++) + if (template) { + template_tile.pixels = template->pixels + y * template->stride + x; + template_tile.stride = template->stride; + template_tile.width = w; + template_tile.height = h; + } + + source_match(ins + (random()%nin), &tile, + template ? &template_tile : NULL); + if ((parity < 4) || ((i&7) == 0)) { + int xx, yy; + int cx, cy; + guchar *buf = (guchar *) malloc(3 * preview_size); + int p2 = preview_size/2; + if (r < p2) { + cx = out->width/2; + cy = out->height/2; + } else { + cx = x; + cy = y; + } + for (yy = cy-p2; yy < cy+p2; yy++) { + for (xx = cx-p2; xx < cx+p2; xx++) { + guchar *p = &buf[3*(xx-(cx-p2))]; + guchar *q = (guchar *)(out->pixels+yy*out->stride+xx); + if ((xx < out->width) && + (xx >= 0) && + (yy < out->height) && + (yy >= 0)) { + p[0] = q[0]; + p[1] = q[1]; + p[2] = q[2]; + } else { + p[0] = p[1] = p[2] = 0; + } + } gtk_preview_draw_row(GTK_PREVIEW (preview), - (guchar *)(out->pixels+y*out->stride), - 0, y, preview_size); + buf, 0, (yy-(cy-p2)), preview_size); + } + free(buf); + gtk_widget_draw (preview, NULL); } gimp_progress_update((1-i/(double)n) * r * r / (rad * rad) + i/(double)n * (r + bo) * (r + bo) / (rad * rad)); @@ -324,57 +392,151 @@ do_fuse(image *in, image *out) { static void doit(GDrawable * target_drawable) { - image in, out; + image *in, out, template; gint bytes; GPixelRgn pr; GDrawable *input_drawable; + int i; - in.width = gimp_image_width(config.input_image_id); - in.height = gimp_image_height(config.input_image_id); - in.stride = in.width; - - -#if 0 - if (4 == bytes) { - printf("using 4 channel image\n"); - } - if (3 != bytes && 4 != bytes) { - fprintf(stderr, "only works with three or four channels, not %d.\n", bytes); + if (0 == config.ninputs) { + printf("fuse needs at least one input\n"); return; } -#endif - /* allocate and initialize input buffer */ + in = (image *) malloc(sizeof(image) * config.ninputs); - in.pixels = (pixel *) malloc(in.width * in.height * 4); - if (in.pixels == NULL) { - fprintf(stderr, "cannot malloc %d bytes for input.\n", in.width * in.height * 4); - return; + for (i = 0; i < config.ninputs; i++) { + image *inp = &in[i]; + + inp->width = gimp_image_width(config.input_image_ids[i]); + inp->height = gimp_image_height(config.input_image_ids[i]); + inp->stride = inp->width; + + /* allocate and initialize input buffer */ + + inp->pixels = (pixel *) malloc(inp->width * inp->height * 4); + if (inp->pixels == NULL) { + fprintf(stderr, "cannot malloc %d bytes for input.\n", inp->width * inp->height * 4); + return; + } + + { + int nlayers; + gint32 *layer_ids; + layer_ids = gimp_image_get_layers (config.input_image_ids[i], &nlayers); + if ((NULL == layer_ids) || (nlayers <= 0)) { + fprintf(stderr, "fuse: error getting layer IDs\n"); + return; + } + input_drawable = gimp_drawable_get(layer_ids[nlayers-1]); + bytes = input_drawable->bpp; + + gimp_pixel_rgn_init(&pr, input_drawable, + 0, 0, inp->width, inp->height, FALSE, FALSE); + if (4 == bytes) { + printf("4 channel image, using alpha\n"); + gimp_pixel_rgn_get_rect(&pr, (guchar *)inp->pixels, 0, 0, inp->width, inp->height); + } else if (3 == bytes) { + int i; + guchar *tb = malloc (inp->width * bytes); + for (i = 0; i < inp->height; i++) { + int j; + gimp_pixel_rgn_get_rect(&pr, tb, 0, i, inp->width, 1); + for (j = 0; j < inp->width; j++) { + guchar *d = (guchar *) (inp->pixels + (inp->width * i) + j); + guchar *s = tb + j * bytes; + d[0] = s[0]; + d[1] = s[1]; + d[2] = s[2]; + d[3] = 255; + } + } + free(tb); + } else if (1 == bytes) { + int i; + guchar *tb = malloc (inp->width * bytes); + for (i = 0; i < inp->height; i++) { + int j; + gimp_pixel_rgn_get_rect(&pr, tb, 0, i, inp->width, 1); + for (j = 0; j < inp->width; j++) { + guchar *d = (guchar *) (inp->pixels + (inp->width * i) + j); + guchar *s = tb + j * bytes; + d[0] = d[1] = d[2] = s[0]; + d[3] = 255; + } + } + free(tb); + } else { + printf("cannot handle image with %d bytes per pixel\n", bytes); + } + + + if (nlayers > 1) { + input_drawable = gimp_drawable_get(layer_ids[0]); + bytes = input_drawable->bpp; + + gimp_pixel_rgn_init(&pr, input_drawable, + 0, 0, inp->width, inp->height, FALSE, FALSE); + printf("looking for alpha\n"); + if (1 == bytes) { + int i; + guchar *tb = malloc (inp->width * bytes); + printf("got alpha\n"); + for (i = 0; i < inp->height; i++) { + int j; + gimp_pixel_rgn_get_rect(&pr, tb, 0, i, inp->width, 1); + for (j = 0; j < inp->width; j++) { + guchar *d = (guchar *) (inp->pixels + (inp->width * i) + j); + guchar *s = tb + j * bytes; + d[3] = s[0]; + } + } + free(tb); + } + + } + } } { - int nlayers; - gint32 *layer_ids; - layer_ids = gimp_image_get_layers (config.input_image_id, &nlayers); - if ((NULL == layer_ids) || (nlayers <= 0)) { - fprintf(stderr, "fuse: error getting layer IDs\n"); + out.width = target_drawable->width; + out.height = target_drawable->height; + out.stride = out.width; + + out.pixels = (pixel *) malloc(out.width * out.height * 4); + if (out.pixels == NULL) { + fprintf(stderr, "cannot malloc %d bytes for output.\n", + out.width * out.height * 4); return; } - input_drawable = gimp_drawable_get(layer_ids[0]); - bytes = input_drawable->bpp; + } + + if (config.use_template) { + template.width = target_drawable->width; + template.height = target_drawable->height; + template.stride = template.width; + template.pixels = (pixel *) malloc(template.width * template.height * 4); + if (template.pixels == NULL) { + fprintf(stderr, "cannot malloc %d bytes for output.\n", + template.width * template.height * 4); + return; + } + + bytes = target_drawable->bpp; - gimp_pixel_rgn_init(&pr, input_drawable, - 0, 0, in.width, in.height, FALSE, FALSE); - if (4 == bytes) - gimp_pixel_rgn_get_rect(&pr, (guchar *)in.pixels, 0, 0, in.width, in.height); - else if (3 == bytes) { + gimp_pixel_rgn_init(&pr, target_drawable, + 0, 0, template.width, template.height, FALSE, FALSE); + if (4 == bytes) { + printf("4 channel image, using alpha\n"); + gimp_pixel_rgn_get_rect(&pr, (guchar *)template.pixels, 0, 0, template.width, template.height); + } else if (3 == bytes) { int i; - guchar *tb = malloc (in.width * bytes); - for (i = 0; i < in.height; i++) { + guchar *tb = malloc (template.width * bytes); + for (i = 0; i < template.height; i++) { int j; - gimp_pixel_rgn_get_rect(&pr, tb, 0, i, in.width, 1); - for (j = 0; j < in.width; j++) { - guchar *d = (guchar *) (in.pixels + (in.width * i) + j); + gimp_pixel_rgn_get_rect(&pr, tb, 0, i, template.width, 1); + for (j = 0; j < template.width; j++) { + guchar *d = (guchar *) (template.pixels + (template.width * i) + j); guchar *s = tb + j * bytes; d[0] = s[0]; d[1] = s[1]; @@ -383,49 +545,20 @@ doit(GDrawable * target_drawable) { } } free(tb); - } else if (1 == bytes) { - int i; - guchar *tb = malloc (in.width * bytes); - for (i = 0; i < in.height; i++) { - int j; - gimp_pixel_rgn_get_rect(&pr, tb, 0, i, in.width, 1); - for (j = 0; j < in.width; j++) { - guchar *d = (guchar *) (in.pixels + (in.width * i) + j); - guchar *s = tb + j * bytes; - d[0] = d[1] = d[2] = s[0]; - d[3] = 255; - } - } - free(tb); } } - out.width = target_drawable->width; - out.height = target_drawable->height; - out.stride = out.width; - - out.pixels = (pixel *) malloc(out.width * out.height * 4); - if (out.pixels == NULL) { - fprintf(stderr, "cannot malloc %d bytes for output.\n", - out.width * out.height * 4); - return; - } - - if (1) - do_fuse(&in, &out); - else { - int i, j; - for (i = 0; i < out.height; i++) - for (j = 0; j < out.width; j++) - out.pixels[i * out.stride + j] = random(); - } - + do_fuse(config.ninputs, in, &out, + config.use_template ? &template : NULL); gimp_pixel_rgn_init(&pr, target_drawable, 0, 0, out.width, out.height, FALSE, FALSE); + bytes = target_drawable->bpp; + + if (4 == bytes) { - gimp_pixel_rgn_set_rect(&pr, (guchar *)out.pixels, 0, 0, out.width, out.height); + gimp_pixel_rgn_set_rect(&pr, (guchar *) out.pixels, 0, 0, out.width, out.height); } else { int i; guchar *tb = malloc (out.width * bytes); @@ -448,6 +581,16 @@ doit(GDrawable * target_drawable) { */ gimp_drawable_update(target_drawable->id, 0, 0, target_drawable->width, target_drawable->height); + + + + for (i = 0; i < config.ninputs; i++) + free(in[i].pixels); + free(in); + + free(out.pixels); + if (config.use_template) + free(template.pixels); } @@ -458,8 +601,34 @@ static void close_callback(GtkWidget * widget, gpointer data) static void ok_callback(GtkWidget * widget, gpointer data) { + GList *sel; + int n; run_flag = 1; - gtk_widget_destroy(GTK_WIDGET(data)); + + if (gimp_drawable_color(drawable->id)) { + + sel = gck_listbox_get_current_selection(listbox); + + n = 0; + while (sel != NULL && n < max_inputs) { + + config.input_image_ids[n] = + ((GckListBoxItem *) sel->data)->user_data; + sel = sel->next; + n++; + } + config.ninputs = n; + + gimp_progress_init("Fusing..."); + gimp_tile_cache_ntiles(2 * (drawable->width / gimp_tile_width() + 1)); + + doit(drawable); + + gtk_widget_destroy(dlg); + + gimp_displays_flush(); + gimp_set_data("plug_in_fuse", &config, sizeof(config)); + } } static gint @@ -472,13 +641,6 @@ not_indexed_constrain (gint32 image_id, gint32 drawable_id, gpointer data) { return INDEXED != gimp_image_base_type (image_id); } - -static void -input_callback(gint32 id, gpointer data) { - config.input_image_id = id; -} - - static void overlap_callback (GtkWidget *widget, gpointer data) { @@ -505,12 +667,42 @@ search_time_callback (GtkWidget *widget, gpointer data) } +static void +toggle_callback (GtkWidget *widget, gpointer data) +{ + int *toggle_val; + + toggle_val = (int *) data; + + if (GTK_TOGGLE_BUTTON (widget)->active) + *toggle_val = TRUE; + else + *toggle_val = FALSE; +} + +static void +scale_callback (GtkAdjustment *adjustment, gpointer data) +{ + * (double *) data = adjustment->value; +} + +static char* +gimp_base_name (char *str) +{ + char *t; + + t = strrchr (str, '/'); + if (!t) + return str; + return t+1; +} + static gint dialog() { + GtkWidget *frame; GtkWidget *button; GtkWidget *table; GtkWidget *box; GtkWidget *w; - GtkWidget *frame; gchar **argv; gint argc; int row; @@ -557,29 +749,56 @@ static gint dialog() { box = GTK_DIALOG(dlg)->vbox; + { - GtkWidget *menu; - GtkWidget *menuitem; - GtkWidget *hbox; - GtkWidget *option_menu = gtk_option_menu_new (); + gint32 *images; + int i, k, nimages; + + frame = gtk_frame_new("Source Images"); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); + gtk_container_border_width(GTK_CONTAINER(frame), 10); + gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 10); + gtk_widget_show(frame); - hbox = gtk_hbox_new (FALSE, 5); - gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, FALSE, 10); - gtk_widget_show(hbox); + listbox = gck_listbox_new(frame, TRUE, TRUE, 10, 150, 150, + GTK_SELECTION_MULTIPLE, NULL, + NULL /* event_handler */); - w = gtk_label_new("Tile Source:"); - gtk_misc_set_alignment(GTK_MISC(w), 0.0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), w, TRUE, TRUE, 10); - gtk_widget_show(w); + + images = gimp_query_images (&nimages); + for (i = 0, k = 0; i < nimages; i++) { + if (not_indexed_constrain(images[i], 0, 0)) { + int j; + GckListBoxItem item; + char *filename; + filename = gimp_image_get_filename (images[i]); + item.label = g_new (char, strlen (filename) + 16); + sprintf (item.label, "%s-%d", gimp_base_name (filename), images[i]); + g_free (filename); - gtk_box_pack_start(GTK_BOX(hbox), option_menu, TRUE, TRUE, 10); - menu = gimp_image_menu_new(not_indexed_constrain, input_callback, - 0, config.input_image_id); - - gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu); - gtk_widget_show (option_menu); + item.widget = NULL; + item.user_data = (gpointer) images[i]; + item.listbox = NULL; + gck_listbox_insert_item(listbox, &item, k); + g_free(item.label); + for (j = 0; j < config.ninputs; j++) + if (images[i] == config.input_image_ids[j]) + (void) gck_listbox_select_item_by_position(listbox, k); + k++; + } + } } + frame = gtk_frame_new("Parameters"); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); + gtk_container_border_width(GTK_CONTAINER(frame), 10); + gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 10); + gtk_widget_show(frame); + + box = gtk_vbox_new (FALSE, 5); + gtk_container_add(GTK_CONTAINER(frame), box); + gtk_widget_show (box); + { GtkWidget *label; GtkWidget *entry; @@ -654,6 +873,63 @@ static gint dialog() { gtk_widget_show (hbox); } + { + GtkWidget *toggle; + toggle = gtk_check_button_new_with_label ("use target as template"); + gtk_box_pack_start(GTK_BOX(box), toggle, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) toggle_callback, + &config.use_template); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), (config.use_template)); + gtk_widget_show (toggle); + } + + { + GtkWidget *label; + GtkWidget *scale; + GtkObject *scale_data; + GtkWidget *hbox; + char buffer[20]; + hbox = gtk_hbox_new (FALSE, 5); + gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, FALSE, 0); + + label = gtk_label_new ("Template weight: "); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); + gtk_widget_show (label); + + scale_data = gtk_adjustment_new (config.template_weight, 0.0, 10.0, + 0.01, 0.01, 0.0); + scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data)); + gtk_widget_set_usize (scale, 150, 0); + gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0); + gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP); + gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED); + gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed", + (GtkSignalFunc) scale_callback, + &config.template_weight); + gtk_widget_show (scale); + + gtk_widget_show (hbox); + } + + box = GTK_DIALOG(dlg)->vbox; + + { + frame = gtk_frame_new("Preview"); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); + gtk_container_border_width(GTK_CONTAINER(frame), 10); + gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 10); + gtk_widget_show(frame); + + + preview = gtk_preview_new (GTK_PREVIEW_COLOR); + gtk_preview_size (GTK_PREVIEW (preview), preview_size, preview_size); + + gtk_container_add(GTK_CONTAINER(frame), preview); + + gtk_widget_show (preview); + } + gtk_widget_show(dlg); gtk_main(); gdk_flush(); diff --git a/plug-ins/gfig/Makefile b/plug-ins/gfig/Makefile deleted file mode 100644 index dd8f6f9350..0000000000 --- a/plug-ins/gfig/Makefile +++ /dev/null @@ -1,361 +0,0 @@ -# Generated automatically from Makefile.in by configure. -# Makefile.in generated automatically by automake 1.2c from Makefile.am - -# Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - - -SHELL = /bin/sh - -srcdir = . -top_srcdir = ../.. -prefix = /usr -exec_prefix = ${prefix} - -bindir = ${exec_prefix}/bin -sbindir = ${exec_prefix}/sbin -libexecdir = ${exec_prefix}/libexec -datadir = ${prefix}/share -sysconfdir = ${prefix}/etc -sharedstatedir = ${prefix}/com -localstatedir = ${prefix}/var -libdir = ${exec_prefix}/lib -infodir = ${prefix}/info -mandir = ${prefix}/man -includedir = ${prefix}/include -oldincludedir = /usr/include - -pkgdatadir = $(datadir)/gimp -pkglibdir = $(libdir)/gimp -pkgincludedir = $(includedir)/gimp - -top_builddir = ../.. - -ACLOCAL = aclocal -AUTOCONF = autoconf -AUTOMAKE = automake -AUTOHEADER = autoheader - -INSTALL = /usr/bin/install -c -INSTALL_PROGRAM = ${INSTALL} -INSTALL_DATA = ${INSTALL} -m 644 -INSTALL_SCRIPT = ${INSTALL_PROGRAM} -transform = s,x,x, - -NORMAL_INSTALL = true -PRE_INSTALL = true -POST_INSTALL = true -NORMAL_UNINSTALL = true -PRE_UNINSTALL = true -POST_UNINSTALL = true -host_alias = i486-pc-linux-gnu -host_triplet = i486-pc-linux-gnu -CC = gcc -CPP = gcc -E -EMACS = /usr/bin/emacs -GIMPTCL = gimptcl -JPEG = jpeg -LD = /usr/lib/gcc-lib/i386-linux/egcs-2.90.18/ld -LIBJPEG_LIB = -ljpeg -LIBMPEG_LIB = -LIBPNG_LIB = -lpng -lz -LIBTCL_LIB = -ltcl -ltk -LIBTIFF_LIB = -ltiff -LIBTOOL = $(SHELL) $(top_builddir)/libtool -LIBXDELTA_LIB = -LIBXPM_LIB = -lXpm -LN_S = ln -s -MAINT = #M# -MAKEINFO = makeinfo -MPEG = -NM = /usr/bin/nm -B -PACKAGE = gimp -PNG = png -RANLIB = ranlib -TIFF = tiff -VERSION = 0.99.15 -XD = -XPM = xpm -gimpdatadir = ${prefix}/share/gimp -gimpdir = .gimp -gimpplugindir = ${exec_prefix}/lib/gimp/0.99.15 - -pluginlibdir = $(gimpplugindir)/plug-ins - -pluginlib_PROGRAMS = gfig - -gfig_SOURCES = \ - gfig.c - -INCLUDES = \ - $(X_CFLAGS) \ - -I$(top_srcdir) \ - -I$(includedir) - -LDADD = \ - $(top_builddir)/libgimp/libgimpui.la \ - $(top_builddir)/libgimp/libgimp.la \ - $(X_LIBS) \ - -lc - -DEPS = \ - $(top_builddir)/libgimp/libgimpui.la \ - $(top_builddir)/libgimp/libgimp.la - -gfig_DEPENDENCIES = $(DEPS) -mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs -CONFIG_HEADER = ../../config.h -CONFIG_CLEAN_FILES = -PROGRAMS = $(pluginlib_PROGRAMS) - - -DEFS = -DHAVE_CONFIG_H -I. -I$(srcdir) -I../.. -CPPFLAGS = -LDFLAGS = -L/usr/X11R6/lib -lgtk -lgdk -lglib -lXext -lX11 -lm -LIBS = -X_CFLAGS = -I/usr/X11R6/include -X_LIBS = -L/usr/X11R6/lib -lgtk -lgdk -lglib -lXext -lX11 -lm -X_EXTRA_LIBS = -X_PRE_LIBS = -lSM -lICE -gfig_OBJECTS = gfig.o -gfig_LDADD = $(LDADD) -gfig_LDFLAGS = -CFLAGS = -I/usr/X11R6/include -g -O2 -Wall -COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -LINK = $(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -o $@ -DIST_COMMON = README Makefile.am Makefile.in - - -DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) - -TAR = tar -GZIP = --best -DEP_FILES = .deps/gfig.P -SOURCES = $(gfig_SOURCES) -OBJECTS = $(gfig_OBJECTS) - -default: all - -.SUFFIXES: -.SUFFIXES: .c .lo .o -$(srcdir)/Makefile.in: #M# Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) - cd $(top_srcdir) && $(AUTOMAKE) --gnu plug-ins/gfig/Makefile - -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) - cd $(top_builddir) \ - && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status - - -mostlyclean-pluginlibPROGRAMS: - -clean-pluginlibPROGRAMS: - -test -z "$(pluginlib_PROGRAMS)" || rm -f $(pluginlib_PROGRAMS) - -distclean-pluginlibPROGRAMS: - -maintainer-clean-pluginlibPROGRAMS: - -install-pluginlibPROGRAMS: $(pluginlib_PROGRAMS) - @$(NORMAL_INSTALL) - $(mkinstalldirs) $(pluginlibdir) - @list='$(pluginlib_PROGRAMS)'; for p in $$list; do \ - if test -f $$p; then \ - echo " $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(pluginlibdir)/`echo $$p|sed '$(transform)'`"; \ - $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(pluginlibdir)/`echo $$p|sed '$(transform)'`; \ - else :; fi; \ - done - -uninstall-pluginlibPROGRAMS: - $(NORMAL_UNINSTALL) - list='$(pluginlib_PROGRAMS)'; for p in $$list; do \ - rm -f $(pluginlibdir)/`echo $$p|sed '$(transform)'`; \ - done - -.c.o: - $(COMPILE) -c $< - -mostlyclean-compile: - -rm -f *.o core - -clean-compile: - -distclean-compile: - -rm -f *.tab.c - -maintainer-clean-compile: - -.c.lo: - $(LIBTOOL) --mode=compile $(COMPILE) -c $< - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs - -distclean-libtool: - -maintainer-clean-libtool: - -gfig: $(gfig_OBJECTS) $(gfig_DEPENDENCIES) - @rm -f gfig - $(LINK) $(gfig_LDFLAGS) $(gfig_OBJECTS) $(gfig_LDADD) $(LIBS) - -tags: TAGS - -ID: $(HEADERS) $(SOURCES) - here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS) - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) - tags=; \ - here=`pwd`; \ - test -z "$(ETAGS_ARGS)$(SOURCES)$(HEADERS)$$tags" \ - || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $(SOURCES) $(HEADERS) -o $$here/TAGS) - -mostlyclean-tags: - -clean-tags: - -distclean-tags: - -rm -f TAGS ID - -maintainer-clean-tags: - -distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) - -subdir = plug-ins/gfig - -distdir: $(DISTFILES) - here=`cd $(top_builddir) && pwd`; \ - top_distdir=`cd $(top_distdir) && pwd`; \ - distdir=`cd $(distdir) && pwd`; \ - cd $(top_srcdir) \ - && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu plug-ins/gfig/Makefile - @for file in $(DISTFILES); do \ - d=$(srcdir); \ - test -f $(distdir)/$$file \ - || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ - || cp -p $$d/$$file $(distdir)/$$file; \ - done - -MKDEP = $(CC) -M $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) - -DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) --include .deps/.P -.deps/.P: $(BUILT_SOURCES) - echo > $@ - --include $(DEP_FILES) - -mostlyclean-depend: - -clean-depend: - -distclean-depend: - -maintainer-clean-depend: - -rm -rf .deps - -.deps/%.P: %.c - @echo "Computing dependencies for $<..." - @o='o'; \ - test -n "$o" && o='$$o'; \ - $(MKDEP) $< >$@.tmp \ - && sed "s,^\(.*\)\.o:,\1.$$o \1.l$$o $@:," < $@.tmp > $@ \ - && rm -f $@.tmp -info: -dvi: -check: all - $(MAKE) -installcheck: -install-exec: - @$(NORMAL_INSTALL) - -install-data: install-pluginlibPROGRAMS - @$(NORMAL_INSTALL) - -install: install-exec install-data all - @: - -uninstall: uninstall-pluginlibPROGRAMS - -all: Makefile $(PROGRAMS) - -install-strip: - $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install -installdirs: - $(mkinstalldirs) $(pluginlibdir) - - -mostlyclean-generic: - -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) - -clean-generic: - -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) - -distclean-generic: - -rm -f Makefile $(DISTCLEANFILES) - -rm -f config.cache config.log stamp-h stamp-h[0-9]* - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -maintainer-clean-generic: - -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) - -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) -mostlyclean: mostlyclean-pluginlibPROGRAMS mostlyclean-compile \ - mostlyclean-libtool mostlyclean-tags mostlyclean-depend \ - mostlyclean-generic - -clean: clean-pluginlibPROGRAMS clean-compile clean-libtool clean-tags \ - clean-depend clean-generic mostlyclean - -distclean: distclean-pluginlibPROGRAMS distclean-compile \ - distclean-libtool distclean-tags distclean-depend \ - distclean-generic clean - -rm -f config.status - -rm -f libtool - -maintainer-clean: maintainer-clean-pluginlibPROGRAMS \ - maintainer-clean-compile maintainer-clean-libtool \ - maintainer-clean-tags maintainer-clean-depend \ - maintainer-clean-generic distclean - @echo "This command is intended for maintainers to use;" - @echo "it deletes files that may require special tools to rebuild." - -.PHONY: default mostlyclean-pluginlibPROGRAMS \ -distclean-pluginlibPROGRAMS clean-pluginlibPROGRAMS \ -maintainer-clean-pluginlibPROGRAMS uninstall-pluginlibPROGRAMS \ -install-pluginlibPROGRAMS mostlyclean-compile distclean-compile \ -clean-compile maintainer-clean-compile mostlyclean-libtool \ -distclean-libtool clean-libtool maintainer-clean-libtool tags \ -mostlyclean-tags distclean-tags clean-tags maintainer-clean-tags \ -distdir mostlyclean-depend distclean-depend clean-depend \ -maintainer-clean-depend info dvi installcheck install-exec install-data \ -install uninstall all installdirs mostlyclean-generic distclean-generic \ -clean-generic maintainer-clean-generic clean mostlyclean distclean \ -maintainer-clean - - -.PHONY: files - -files: - @files=`ls $(DISTFILES) 2> /dev/null`; for p in $$files; do \ - echo $$p; \ - done - @for subdir in $(SUBDIRS); do \ - files=`cd $$subdir; $(MAKE) files | grep -v "make\[[1-9]\]"`; \ - for file in $$files; do \ - echo $$subdir/$$file; \ - done; \ - done - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/plug-ins/gfig/gfig b/plug-ins/gfig/gfig deleted file mode 100755 index 6948a880d8..0000000000 --- a/plug-ins/gfig/gfig +++ /dev/null @@ -1,80 +0,0 @@ -#! /bin/sh - -# gfig - temporary wrapper script for _libs/gfig -# Generated by ltmain.sh - GNU libtool 1.0c -# -# The gfig program cannot be directly executed until all the libtool -# libraries that it depends on are installed. -# -# This wrapper script should never be moved out of `/usr/local/src/cvs/gimp/plug-ins/gfig'. -# If it is, it will not operate correctly. - -# This environment variable determines our operation mode. -if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then - # install mode needs the following variables: - link_against_libtool_libs=' ../../libgimp/libgimpui.la ../../libgimp/libgimp.la' - finalize_command="gcc -g -O2 -Wall -o _libs/gfigT gfig.o -Wl,-rpath -Wl,/usr/lib -L/usr/lib -lgimpui -Wl,-rpath -Wl,/usr/lib -L/usr/lib -lgimp -L/usr/X11R6/lib -lgtk -lgdk -lglib -lX11 -lXext -lm -lc" -else - # When we are sourced in execute mode, $file and $echo are already set. - if test "$libtool_execute_magic" = "%%%MAGIC variable%%%"; then : - else - echo='printf %s\n' - file="$0" - fi - - # Find the directory that this script lives in. - thisdir=`$echo "$file" | sed 's%/[^/]*$%%'` - test "x$thisdir" = "x$file" && thisdir=. - - # Try to get the absolute directory name. - absdir=`cd "$thisdir" && pwd` - test -n "$absdir" && thisdir="$absdir" - - progdir="$thisdir/_libs" - program='gfig' - - # If the $file dir failed (maybe due to symlink), try a hardcoded dir. - oprogdir="$progdir" - if test -f "$progdir/$program"; then : - else - thisdir='/usr/local/src/cvs/gimp/plug-ins/gfig' - progdir="$thisdir/_libs" - fi - - if test -f "$progdir/$program"; then - # Add our own library path to LD_LIBRARY_PATH - LD_LIBRARY_PATH="$thisdir/../../libgimp/_libs:$thisdir/../../libgimp/_libs:$LD_LIBRARY_PATH" - - # Some systems cannot cope with colon-terminated LD_LIBRARY_PATH - LD_LIBRARY_PATH=`$echo $LD_LIBRARY_PATH | sed -e 's/:*$//'` - - export LD_LIBRARY_PATH - - if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then - # Run the actual program with our arguments. - args= - for arg - do - # Quote arguments (to preserve shell metacharacters). - sed_quote_subst='s/\([\\"$]\)/\\\1/g' - arg=`$echo "$arg" | sed "$sed_quote_subst"` - args="$args \"$arg\"" - done - - # Export the path to the program. - PATH="$progdir:$PATH" - export PATH - - eval "exec $program $args" - - $echo "$0: cannot exec $program $args" - exit 1 - fi - else - # The program doesn't exist. - $echo "$0: error: neither $oprogdir/$program nor $progdir/$program exists" 1>&2 - $echo "This script is just a wrapper for $program." 1>&2 - $echo "See the libtool documentation for more information." 1>&2 - exit 1 - fi -fi diff --git a/plug-ins/gfig/gfig.c b/plug-ins/gfig/gfig.c index 7069cb9849..30084df6b5 100644 --- a/plug-ins/gfig/gfig.c +++ b/plug-ins/gfig/gfig.c @@ -50,7 +50,7 @@ * following #define */ -#define HAVE_PATCHED 1 +#define HAVE_PATCHED 1 #ifdef HAVE_PATCHED #define GFIG_LCC 1 @@ -61,7 +61,7 @@ /***** Magic numbers *****/ -#define PREVIEW_SIZE 256 +#define PREVIEW_SIZE 650 #define SCALE_WIDTH 120 #define ENTRY_WIDTH 28 @@ -76,6 +76,7 @@ #define MIN_UNDO 1 #define MAX_LOAD_LINE 256 #define SMALL_PREVIEW_SZ 48 +#define BRUSH_PREVIEW_SZ 32 #define GFIG_HEADER "GFIG Version 0.1\n" @@ -87,7 +88,9 @@ GDK_POINTER_MOTION_MASK | \ GDK_BUTTON_PRESS_MASK | \ GDK_BUTTON_RELEASE_MASK | \ - GDK_BUTTON_MOTION_MASK + GDK_BUTTON_MOTION_MASK | \ + GDK_KEY_PRESS_MASK | \ + GDK_KEY_RELEASE_MASK GDrawable *gfig_select_drawable; GtkWidget *gfig_preview; @@ -97,6 +100,7 @@ gint gfig_preview_exp_id; GdkPixmap *gfig_pixmap; gint32 gfig_image; gint32 gfig_drawable; +GtkWidget *brush_page_pw; static gint tile_width, tile_height; @@ -118,8 +122,9 @@ static void gfig_undo_callback (GtkWidget *widget,gpointer data); static gint gfig_preview_expose( GtkWidget *widget,GdkEvent *event ); static gint pic_preview_expose( GtkWidget *widget,GdkEvent *event ); static gint gfig_preview_events ( GtkWidget *widget,GdkEvent *event ); +static gint gfig_brush_preview_events ( GtkWidget *widget,GdkEvent *event ); static void gfig_entry_update(GtkWidget *widget, gint *value); -static void gfig_entry_update_fp(GtkWidget *widget, gdouble *value); +/*static void gfig_entry_update_fp(GtkWidget *widget, gdouble *value);*/ static void gfig_scale_update(GtkAdjustment *adjustment, gint *value); static void gfig_scale_update_fp(GtkAdjustment *adjustment, gdouble *value); static void gfig_scale_update_scale(GtkAdjustment *adjustment, gdouble *value); @@ -129,6 +134,10 @@ static gint gfig_scale_x(gint x); static gint gfig_scale_y(gint y); static gint gfig_invscale_x(gint x); static gint gfig_invscale_y(gint y); +static GdkGC * gfig_get_grid_gc(GtkWidget *w, gint gctype); +static void gfig_cancel_callback(GtkWidget *widget,gpointer data); +static void gfig_pos_enable(GtkWidget *widget, gpointer data); + static gint list_button_press(GtkWidget *widget,GdkEventButton *event,gpointer data); static gint save_button_press(GtkWidget *widget,GdkEventButton *bevent,gpointer data); @@ -149,7 +158,9 @@ static void toggle_tooltips(GtkWidget *widget,gpointer data); static void toggle_obj_type(GtkWidget *widget,gpointer data); static void draw_grid(GtkWidget *widget,gpointer data); static void gfig_new_gc(void); -static void find_grid_pos(GdkPoint *p,GdkPoint *gp); +static void find_grid_pos(GdkPoint *p,GdkPoint *gp, guint state); +static gint brush_list_button_press(GtkWidget *widget,GdkEventButton *event,gpointer data); + GPlugInInfo PLUG_IN_INFO = @@ -169,6 +180,9 @@ typedef enum DobjType { ELLIPSE, ARC, POLY, + STAR, + SPIRAL, + BEZIER, MOVE_OBJ, MOVE_POINT, COPY_OBJ, @@ -195,14 +209,43 @@ typedef enum LayersBGType { LAYER_COPY_BG, } DRAWLAYERBG; +typedef enum PaintType { + PAINT_BRUSH_TYPE = 0, + PAINT_SELECTION_TYPE, + PAINT_SELECTION_FILL_TYPE, +} PAINTTYPE; + +typedef enum BrshType { + BRUSH_BRUSH_TYPE=0, + BRUSH_PENCIL_TYPE, + BRUSH_AIRBRUSH_TYPE, + BRUSH_PATTERN_TYPE, +} BRUSH_TYPE; + + #define GRID_TYPE_MENU 1 #define GRID_RENDER_MENU 2 +#define GRID_IGNORE 0 +#define GRID_HIGHTLIGHT 1 +#define GRID_RESTORE 2 + #define GFIG_BLACK_GC -2 #define GFIG_WHITE_GC -3 #define GFIG_GREY_GC -4 #define PAINT_LAYERS_MENU 1 #define PAINT_BGS_MENU 2 +#define PAINT_TYPE_MENU 3 + +#define SELECT_TYPE_MENU 1 +#define SELECT_ARCTYPE_MENU 2 +#define SELECT_TYPE_MENU_FILL 3 +#define SELECT_TYPE_MENU_WHEN 4 + +#define OBJ_SELECT_GT 1 +#define OBJ_SELECT_LT 2 +#define OBJ_SELECT_EQ 4 + typedef struct GfigOpts { @@ -232,14 +275,18 @@ typedef struct SelectItVals GFIGOPTS opts; gint showimage; gint maxundo; + gint showpos; gdouble brushfade; + gdouble airbrushpressure; gint showtooltips; DRAWONLAYERS onlayers; DRAWLAYERBG onlayerbg; + PAINTTYPE painttype; gint reverselines; gint scaletoimage; gdouble scaletoimagefp; gint approxcircles; + BRUSH_TYPE brshtype; DOBJTYPE otype; } SelectItVals; @@ -256,23 +303,78 @@ static SelectItVals selvals = }, 0, /* show image */ MIN_UNDO + (MAX_UNDO - MIN_UNDO)/2, /* Max level of undos */ + FALSE, /* Show pos updates */ 0.0, /* Brush fade */ + 20.0, /* Air bursh pressure */ TRUE, /* show Tool tips */ ORIGINAL_LAYER, /* Draw all objects on one layer */ LAYER_TRANS_BG, /* New layers background */ + PAINT_BRUSH_TYPE, /* Default to use brushes */ FALSE, /* reverse lines */ TRUE, /* Scale to image when painting */ 1.0, /* Scale to image fp */ FALSE, /* Approx circles by drawing lines */ + BRUSH_BRUSH_TYPE, /* Default to use a brush */ LINE /* Initial object type */ }; +typedef enum Selection_Type { + ADD=0, + SUBTRACT=1, + REPLACE=2, + INTERSECT=3, +} SELECTION_TYPE; + + +typedef enum Arc_Type { + ARC_SEGMENT, + ARC_SECTOR, +} ARC_TYPE; + +typedef enum Fill_Type { + FILL_FOREGROUND = 0, + FILL_BACKGROUND = 1, + FILL_PATTERN = 2, +} FILL_TYPE; + +typedef enum Fill_When { + FILL_EACH = 0, + FILL_AFTER, +} FILL_WHEN; + +struct selection_option { + SELECTION_TYPE type; /* ADD etc .. */ + gint antia; /* Boolean for Antia */ + gint feather; /* Feather it ? */ + gdouble feather_radius; /* Radius to feather */ + ARC_TYPE as_pie; /* Arc type selection segment/sector */ + FILL_TYPE fill_type; /* Fill type for selection */ + FILL_WHEN fill_when; /* Fill on each selection or after all? */ + gdouble fill_opacity; /* You can guess this one */ +} selopt = { + ADD, /* type */ + FALSE, /* Antia */ + FALSE, /* Feather */ + 10.0, /* feather radius */ + ARC_SEGMENT, /* Arc as a segment */ + FILL_PATTERN, /* Fill as pattern */ + FILL_EACH, /* Fill after each selection */ + 100.0, /* Max opacity */ +}; + + GList *gfig_path_list = NULL; GList *gfig_list = NULL; static gint line_no; static gint poly_num_sides = 3; /* Default to three sided object */ +static gint star_num_sides = 3; /* Default to three sided object */ +static gint spiral_num_turns = 4; /* Default to 4 turns */ +static gint spiral_toggle = 0; /* 0 = clockwise -1 = anti-clockwise */ +static gint bezier_closed = 0; /* Closed curve 0 = false 1 = true */ +static gint bezier_line_frame = 0; /* Show frame = false 1 = true */ +static gint obj_show_single = -1; /* -1 all >= 0 object number */ /* Structures etc for the objects */ /* Points used to draw the object */ @@ -299,8 +401,8 @@ typedef struct Dobject { } DOBJECT; static DOBJECT *obj_creating; /* Object we are creating */ -static DOBJECT * tmp_line; /* Needed when drawing lines */ - +static DOBJECT *tmp_line; /* Needed when drawing lines */ +static DOBJECT *tmp_bezier; /* Neeed when drawing bezier curves */ typedef struct DAllObjs { struct DAllObjs * next; @@ -326,16 +428,36 @@ typedef struct DFigObj { } GFIGOBJ; +typedef struct BrushDesc { + gchar * bname; /* name of the brush */ + gint32 width; /* Width of brush */ + gint32 height; /* Height of brush */ + gchar *pv_buf; /* Buffer where brush placed */ + gint16 x_off; + gint16 y_off; + gint bpp; /* Depth - should ALWAYS be the same for all BRUSHDESC */ +} BRUSHDESC; + static GFIGOBJ *current_obj; static DOBJECT *operation_obj; static GdkPoint *move_all_pnt; /* Point moving all from */ static GFIGOBJ *pic_obj; static DALLOBJS *undo_table[MAX_UNDO]; static gint need_to_scale; +static gint32 brush_image_ID = -1; + GtkWidget * undo_widget; GtkWidget * gfig_op_menu; /* Popup menu in the list box */ GtkWidget *delete_frame_to_freeze; /* Top preview frame window */ GtkWidget *progress_widget; /* Progress widget */ +GtkWidget *fade_out_hbox; /* Fade out widget in brush page */ +GtkWidget *pressure_hbox; /* Pressure widget in brush page */ +GtkWidget *pencil_hbox; /* Dummy widget in brush page */ +GtkWidget *x_pos_label; /* X pos marker */ +GtkWidget *y_pos_label; /* Y pos marker */ +GtkWidget *obj_size_label; /* Size of object showing */ +GtkWidget *brush_page_widget; /* Widget for the brush part of notebook */ +GtkWidget *select_page_widget; /* Widget for the selection part of notebook */ static gint undo_water_mark = -1; /* Last slot filled in -1 = no undo */ static gint drawing_pic = FALSE; /* If true drawing to the small preview */ @@ -364,7 +486,7 @@ static void setup_undo(void); static void d_pnt_add_line(DOBJECT *obj, gint x, gint y, gint pos); GFIGOBJ * gfig_load (gchar *filename, gchar *name); static void free_all_objs(DALLOBJS * objs); -static void draw_objects(DALLOBJS *objs); +static void draw_objects(DALLOBJS *objs,gint show_single); DOBJECT * d_load_line(FILE *from); DOBJECT * d_load_circle(FILE *from); char * get_line(gchar *buf,gint s,FILE * from,gint init); @@ -386,6 +508,34 @@ DOBJECT * d_new_poly(gint x, gint y); void d_update_poly(GdkPoint *pnt); void d_poly_start(GdkPoint *pnt,gint shift_down); void d_poly_end(GdkPoint *pnt,gint shift_down); +void d_save_star(DOBJECT * obj, FILE *to); +DOBJECT * d_load_star(FILE *from); +static void d_draw_star(DOBJECT *obj); +static void d_paint_star(DOBJECT *obj); +DOBJECT * d_copy_star(DOBJECT * obj); +DOBJECT * d_new_star(gint x, gint y); +void d_update_star(GdkPoint *pnt); +void d_star_start(GdkPoint *pnt,gint shift_down); +void d_star_end(GdkPoint *pnt,gint shift_down); +DOBJECT * d_load_spiral(FILE *from); +static void d_draw_spiral(DOBJECT *obj); +static void d_paint_spiral(DOBJECT *obj); +DOBJECT * d_copy_spiral(DOBJECT * obj); +DOBJECT * d_new_spiral(gint x, gint y); +void d_update_spiral(GdkPoint *pnt); +void d_spiral_start(GdkPoint *pnt,gint shift_down); +void d_spiral_end(GdkPoint *pnt,gint shift_down); + +DOBJECT * d_load_bezier(FILE *from); +static void d_draw_bezier(DOBJECT *obj); +static void d_paint_bezier(DOBJECT *obj); +DOBJECT * d_copy_bezier(DOBJECT * obj); +DOBJECT * d_new_bezier(gint x, gint y); +void d_update_bezier(GdkPoint *pnt); +void d_bezier_start(GdkPoint *pnt,gint shift_down); +void d_bezier_end(GdkPoint *pnt,gint shift_down); + + static void new_obj_2edit(GFIGOBJ *obj); DOBJECT * d_new_ellipse(gint x, gint y); DOBJECT * d_load_ellipse(FILE *from); @@ -393,6 +543,9 @@ DOBJECT * d_new_arc(gint x, gint y); DOBJECT * d_load_arc(FILE *from); gint load_options(GFIGOBJ *gfig,FILE *fp); gint gfig_obj_counts(DALLOBJS * objs); +static gint about_button_press(GtkWidget *widget,GdkEventButton *event,gpointer data); +static gint reload_button_press(GtkWidget *widget,GdkEventButton *event,gpointer data); +static void gfig_brush_fill_preview_xy(GtkWidget *pw,gint x ,gint y); /* globals */ @@ -401,7 +554,7 @@ gint gfig_run; GdkGC *gfig_gc; GdkGC *grid_hightlight_drawgc; gint grid_gc_type = GTK_STATE_NORMAL; -guchar *pv_cache; +guchar *pv_cache = NULL; guchar preview_row[PREVIEW_SIZE*4]; /* Stuff for the preview bit */ @@ -954,6 +1107,18 @@ gfig_load_objs(GFIGOBJ *gfig,gint load_count,FILE *fp) { obj = d_load_poly(fp); } + else if(!strcmp(load_buf,"")) + { + obj = d_load_star(fp); + } + else if(!strcmp(load_buf,"")) + { + obj = d_load_spiral(fp); + } + else if(!strcmp(load_buf,"")) + { + obj = d_load_bezier(fp); + } else if(!strcmp(load_buf,"")) { obj = d_load_arc(fp); @@ -1441,7 +1606,7 @@ gfig_save(void) /* HACK WARNING */ void * xxx; - +void * yyy; typedef struct { @@ -1452,7 +1617,7 @@ typedef struct GdkPixmap* -gdk_pixmap_create_from_xpm_d (GdkWindow *window, +my_gdk_pixmap_create_from_xpm_d (GdkWindow *window, GdkBitmap **mask, GdkColor *transparent_color, gchar **data) @@ -1478,7 +1643,7 @@ gdk_pixmap_create_from_xpm_d (GdkWindow *window, colors = g_new(_GdkPixmapColor, num_cols); colormap = xxx; - visual = gdk_window_get_visual (window); + visual = yyy; for (cnt = 0; cnt < num_cols; cnt++) { @@ -1584,6 +1749,7 @@ gdk_pixmap_create_from_xpm_d (GdkWindow *window, /* END HACK WARNING */ + /* Cache the preview image - updates are a lot faster. */ /* The preview_cache will contain the small image */ @@ -1601,10 +1767,6 @@ cache_preview() src_rows = g_new(guchar ,sel_width*4); p = pv_cache = g_new(guchar ,preview_width*preview_height*4); - - img_width = gimp_drawable_width(gfig_select_drawable->id); - img_height = gimp_drawable_height(gfig_select_drawable->id); - real_img_bpp = gimp_drawable_bpp(gfig_select_drawable->id); has_alpha = gimp_drawable_has_alpha(gfig_select_drawable->id); @@ -1650,6 +1812,35 @@ cache_preview() g_free(src_rows); } +static void +refill_cache() +{ + GdkCursorType ctype1 = GDK_WATCH; + GdkCursorType ctype2 = GDK_TOP_LEFT_ARROW; + static GdkCursor *preview_cursor1; + static GdkCursor *preview_cursor2; + + if(!preview_cursor1) + preview_cursor1 = gdk_cursor_new(ctype1); + + if(!preview_cursor2) + preview_cursor2 = gdk_cursor_new(ctype2); + + gdk_window_set_cursor(gtk_widget_get_toplevel(GTK_WIDGET(gfig_preview))->window, + preview_cursor1); + + gdk_window_set_cursor(gfig_preview->window,preview_cursor1); + + gdk_flush(); + + cache_preview(); + + gdk_window_set_cursor(gtk_widget_get_toplevel(GTK_WIDGET(gfig_preview))->window, + preview_cursor2); + + toggle_obj_type(NULL,(gpointer)selvals.otype); + +} void gfig_set_pixmap(GFIGOBJ *obj,char **pixdata) @@ -1658,7 +1849,7 @@ gfig_set_pixmap(GFIGOBJ *obj,char **pixdata) GdkColor transparent; GdkBitmap *mask; - pixmap = gdk_pixmap_create_from_xpm_d(gfig_gtk_list->window,&mask,&transparent,pixdata); + pixmap = my_gdk_pixmap_create_from_xpm_d(gfig_gtk_list->window,&mask,&transparent,pixdata); gtk_pixmap_set(GTK_PIXMAP(obj->pixmap_widget),pixmap,mask); } @@ -1671,7 +1862,7 @@ gfig_new_pixmap(GtkWidget *list, char **pixdata) GdkColor transparent; GdkBitmap *mask; - pixmap = gdk_pixmap_create_from_xpm_d(list->window,&mask,&transparent,pixdata); + pixmap = my_gdk_pixmap_create_from_xpm_d(list->window,&mask,&transparent,pixdata); pixmap_widget = gtk_pixmap_new(pixmap,mask); gtk_widget_show(pixmap_widget); return(pixmap_widget); @@ -1745,6 +1936,87 @@ gfig_obj_modified(GFIGOBJ *obj,gint stat_type) gtk_widget_draw(GTK_WIDGET(obj->list_item),NULL); } +static gint +select_button_press(GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + gint type = (gint)data; + gint count = 0; + DALLOBJS * objs; + + if(current_obj) + { + objs = current_obj->obj_list; + + while(objs) + { + objs = objs->next; + count++; + } + } + + switch(type) + { + case OBJ_SELECT_LT: + obj_show_single--; + if(obj_show_single < 0) + obj_show_single = count - 1; + break; + case OBJ_SELECT_GT: + obj_show_single++; + if(obj_show_single >= count) + obj_show_single = 0; + break; + case OBJ_SELECT_EQ: + obj_show_single = -1; /* Reset to show all */ + break; + default: + break; + } + + draw_grid_clear(widget,data); + + return(FALSE); +} + +static GtkWidget * +obj_select_buttons(void) +{ + GtkWidget *button; + GtkWidget *hbox,*vbox; + + hbox = gtk_hbox_new(FALSE, 0); + vbox = gtk_vbox_new(FALSE, 0); + + button = gtk_button_new_with_label ("<"); + gtk_box_pack_start (GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (button), "button_press_event", + (GtkSignalFunc) select_button_press, + (gpointer) OBJ_SELECT_LT); + gtk_widget_show(button); + + button = gtk_button_new_with_label (">"); + gtk_box_pack_start (GTK_BOX(hbox), button, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (button), "button_press_event", + (GtkSignalFunc) select_button_press, + (gpointer) OBJ_SELECT_GT); + gtk_widget_show(button); + + gtk_box_pack_start (GTK_BOX(vbox), hbox, TRUE, TRUE, 0); + + button = gtk_button_new_with_label ("=="); + gtk_box_pack_start (GTK_BOX(vbox), button, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (button), "button_press_event", + (GtkSignalFunc) select_button_press, + (gpointer) OBJ_SELECT_EQ); + gtk_widget_show(button); + + gtk_widget_show(hbox); + gtk_widget_show(vbox); + return(vbox); +} + static GtkWidget * but_with_pix(char **pixdata, GSList **group, gint baction) { @@ -1836,9 +2108,14 @@ small_preview(GtkWidget * list) return(vbox); } -/* Special case for now - options on poly button */ +/* Special case for now - options on poly/star/spiral button */ + static void -poly_num_sides_dialog (void) +num_sides_dialog (gchar * d_title, + gint * num_sides, + gint * which_way, + gint adj_min, + gint adj_max) { GtkWidget *window = NULL; GtkWidget *label; @@ -1851,7 +2128,7 @@ poly_num_sides_dialog (void) window = gtk_dialog_new (); - gtk_window_set_title (GTK_WINDOW (window), "Poly number of sides"); + gtk_window_set_title (GTK_WINDOW (window), d_title); gtk_container_border_width (GTK_CONTAINER (window), 0); button = gtk_button_new_with_label ("Close"); @@ -1865,14 +2142,14 @@ poly_num_sides_dialog (void) gtk_widget_show (button); hbox = gtk_hbox_new(FALSE, 0); - label = gtk_label_new("Number of sides:-"); + label = gtk_label_new("Number of sides/points/turns:-"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_widget_show (label); gtk_misc_set_padding (GTK_MISC (label), 1, 1); - gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); - size_data = gtk_adjustment_new (poly_num_sides, 3, 200, 5, 1, 0); + size_data = gtk_adjustment_new (*num_sides, adj_min, adj_max, 5, 1, 0); slider = gtk_hscale_new (GTK_ADJUSTMENT (size_data)); gtk_widget_set_usize (slider, 100, 0); gtk_box_pack_start(GTK_BOX (hbox),slider,TRUE,TRUE,0); @@ -1881,27 +2158,106 @@ poly_num_sides_dialog (void) gtk_range_set_update_policy (GTK_RANGE (slider),GTK_UPDATE_CONTINUOUS ); gtk_signal_connect (GTK_OBJECT (size_data), "value_changed", (GtkSignalFunc) gfig_scale_update, - &poly_num_sides); + num_sides); gtk_widget_show (slider); entry = gtk_entry_new(); gtk_object_set_user_data(GTK_OBJECT(entry), size_data); gtk_object_set_user_data(size_data, entry); gtk_widget_set_usize(entry, ENTRY_WIDTH, 0); - sprintf(buf, "%d", poly_num_sides); + sprintf(buf, "%d", *num_sides); gtk_entry_set_text(GTK_ENTRY(entry), buf); gtk_signal_connect(GTK_OBJECT(entry), "changed", (GtkSignalFunc) gfig_entry_update, - &poly_num_sides); + num_sides); gtk_box_pack_start(GTK_BOX (hbox), entry, TRUE, TRUE, 0); gtk_widget_show(entry); + if(which_way) + { + GtkWidget *option_menu; + GtkWidget *menu; + GtkWidget *menuitem; + + /* Add special toggle for spiral */ + option_menu = gtk_option_menu_new (); + menu = gtk_menu_new(); + + menuitem = gtk_menu_item_new_with_label("Clockwise"); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc)gfig_toggle_update, + (gpointer)which_way); + + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label("Anti-Clockwise"); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc)gfig_toggle_update, + (gpointer)which_way); + + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu); + gtk_widget_show (option_menu); + gtk_box_pack_start (GTK_BOX (hbox), option_menu,TRUE,TRUE,0); + } + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), hbox, TRUE, TRUE, 0); gtk_widget_show (label); gtk_widget_show (hbox); gtk_widget_show (window); } +static void +bezier_dialog (void) +{ + GtkWidget *window = NULL; + GtkWidget *vbox; + GtkWidget *button; + GtkWidget *toggle; + + window = gtk_dialog_new (); + + gtk_window_set_title (GTK_WINDOW (window), "Bezier settings"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + button = gtk_button_new_with_label ("Close"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) ok_warn_window, + window); + + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + vbox = gtk_vbox_new(FALSE, 0); + + toggle = gtk_check_button_new_with_label ("Closed"); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) gfig_toggle_update, + (gpointer)&bezier_closed); + gtk_tooltips_set_tips(gfig_tooltips,toggle,"Close curve on compeletion"); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle),bezier_closed); + gtk_widget_show(toggle); + gtk_box_pack_start(GTK_BOX(vbox),toggle, TRUE, TRUE, 0); + + toggle = gtk_check_button_new_with_label ("Show line frame"); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) gfig_toggle_update, + (gpointer)&bezier_line_frame); + gtk_tooltips_set_tips(gfig_tooltips,toggle,"Draws lines between the control points. Only during curve creation"); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle),bezier_line_frame); + gtk_widget_show(toggle); + gtk_box_pack_start(GTK_BOX(vbox),toggle, TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox, TRUE, TRUE, 0); + gtk_widget_show (vbox); + gtk_widget_show (window); +} + static gint poly_button_press (GtkWidget *w, GdkEventButton *event, @@ -1909,7 +2265,40 @@ poly_button_press (GtkWidget *w, { if ((event->type == GDK_2BUTTON_PRESS) && (event->button == 1)) - poly_num_sides_dialog(); + num_sides_dialog("Regular polygon number of sides",&poly_num_sides,NULL,3,200); + return FALSE; +} + +static gint +star_button_press (GtkWidget *w, + GdkEventButton *event, + gpointer data) +{ + if ((event->type == GDK_2BUTTON_PRESS) && + (event->button == 1)) + num_sides_dialog("Star number of points",&star_num_sides,NULL,3,200); + return FALSE; +} + +static gint +spiral_button_press (GtkWidget *w, + GdkEventButton *event, + gpointer data) +{ + if ((event->type == GDK_2BUTTON_PRESS) && + (event->button == 1)) + num_sides_dialog("Spiral number of points",&spiral_num_turns,&spiral_toggle,1,20); + return FALSE; +} + +static gint +bezier_button_press (GtkWidget *w, + GdkEventButton *event, + gpointer data) +{ + if ((event->type == GDK_2BUTTON_PRESS) && + (event->button == 1)) + bezier_dialog(); return FALSE; } @@ -1927,7 +2316,7 @@ draw_buttons(GtkWidget *ww) /* Create group */ group = NULL; - vbox = gtk_vbox_new(TRUE, 0); + vbox = gtk_vbox_new(FALSE, 0); gtk_container_add (GTK_CONTAINER (frame), vbox); gtk_container_border_width(GTK_CONTAINER(vbox), 2); @@ -1959,8 +2348,32 @@ draw_buttons(GtkWidget *ww) gtk_signal_connect (GTK_OBJECT (button), "button_press_event", (GtkSignalFunc) poly_button_press, NULL); + gtk_tooltips_set_tips(gfig_tooltips,button,"Create reg polygon"); - gtk_tooltips_set_tips(gfig_tooltips,button,"Create polygon"); + button = but_with_pix(star_xpm,&group,STAR); + gtk_container_add (GTK_CONTAINER (vbox), button); + gtk_widget_show(button); + gtk_signal_connect (GTK_OBJECT (button), "button_press_event", + (GtkSignalFunc) star_button_press, + NULL); + gtk_tooltips_set_tips(gfig_tooltips,button,"Create star"); + + button = but_with_pix(spiral_xpm,&group,SPIRAL); + gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + gtk_signal_connect (GTK_OBJECT (button), "button_press_event", + (GtkSignalFunc) spiral_button_press, + NULL); + gtk_tooltips_set_tips(gfig_tooltips,button,"Create spiral"); + + button = but_with_pix(bezier_xpm,&group,BEZIER); + gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 0); + gtk_widget_show(button); + gtk_signal_connect (GTK_OBJECT (button), "button_press_event", + (GtkSignalFunc) bezier_button_press, + NULL); + + gtk_tooltips_set_tips(gfig_tooltips,button,"Create bezier curve. Shift + Button ends object creation."); button = but_with_pix(move_obj_xpm,&group,MOVE_OBJ); gtk_container_add (GTK_CONTAINER (vbox), button); @@ -1982,20 +2395,495 @@ draw_buttons(GtkWidget *ww) gtk_widget_show(button); gtk_tooltips_set_tips(gfig_tooltips,button,"Delete an object"); + button = obj_select_buttons(); + gtk_container_add (GTK_CONTAINER (vbox), button); + gtk_widget_show(button); + +#if 0 button = but_with_pix(blank_xpm,&group,NULL_OPER); gtk_container_add (GTK_CONTAINER (vbox), button); gtk_widget_set_sensitive(button,FALSE); gtk_widget_show(button); +#endif /* 0 */ gtk_widget_show(vbox); gtk_widget_show(frame); return(frame); } +/* Brush preview stuff */ +static gint +gfig_brush_preview_events ( GtkWidget *widget, + GdkEvent *event ) +{ + GdkEventButton *bevent; + GdkEventMotion *mevent; + static GdkPoint point; + static have_start = 0; + + switch (event->type) + { + case GDK_EXPOSE: + break; + + case GDK_BUTTON_PRESS: + bevent = (GdkEventButton *) event; + point.x = bevent->x; + point.y = bevent->y; + have_start = 1; + + break; + case GDK_BUTTON_RELEASE: + bevent = (GdkEventButton *) event; + have_start = 0; + + break; + case GDK_MOTION_NOTIFY: + mevent = (GdkEventMotion *) event; + + if(!have_start || !(mevent->state & GDK_BUTTON1_MASK)) + break; + + gfig_brush_fill_preview_xy(widget,point.x - mevent->x,point.y - mevent->y); + gtk_widget_draw(widget, NULL); + point.x = mevent->x; + point.y = mevent->y; + break; + default: + break; + } + return FALSE; +} + +static void +gfig_brush_update_preview(GtkWidget *widget,gpointer data) +{ + GtkWidget *pw = (GtkWidget*)data; + BRUSHDESC *bdesc; + + /* Must update the dialog area */ + /* Use the same brush as already set in the dialog */ + bdesc = gtk_object_get_user_data (GTK_OBJECT (pw)); + brush_list_button_press(NULL,NULL,bdesc); +} + +static void +gfig_brush_menu_callback(GtkWidget *widget, gpointer data) +{ + BRUSH_TYPE btype = (BRUSH_TYPE)data; + + switch(btype) + { + case BRUSH_BRUSH_TYPE: + selvals.brshtype = btype; + gtk_widget_hide(pressure_hbox); + gtk_widget_hide(pencil_hbox); + gtk_widget_show(fade_out_hbox); + break; + case BRUSH_PENCIL_TYPE: + selvals.brshtype = btype; + gtk_widget_hide(fade_out_hbox); + gtk_widget_hide(pressure_hbox); + gtk_widget_show(pencil_hbox); + break; + case BRUSH_AIRBRUSH_TYPE: + selvals.brshtype = btype; + gtk_widget_hide(fade_out_hbox); + gtk_widget_hide(pencil_hbox); + gtk_widget_show(pressure_hbox); + break; + case BRUSH_PATTERN_TYPE: + selvals.brshtype = btype; + gtk_widget_hide(fade_out_hbox); + gtk_widget_hide(pressure_hbox); + gtk_widget_show(pencil_hbox); + break; + default: + create_warn_dialog("Internal error - invalid brush type"); + break; + } + gfig_brush_update_preview(widget, + (gpointer)gtk_object_get_user_data (GTK_OBJECT (widget))); +} + + +static GtkWidget * +gfig_brush_preview(GtkWidget **pv) +{ + GtkWidget *option_menu; + GtkWidget *menu; + GtkWidget *menuitem; + GtkWidget * frame; + GtkWidget * hbox; + GtkWidget * vbox; + gint y; + /* Returns a new preview widget for a brush */ + + hbox = gtk_hbox_new(FALSE, 0); + gtk_container_border_width(GTK_CONTAINER(hbox), 4); + gtk_widget_show(hbox); + + frame = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + gtk_container_border_width (GTK_CONTAINER (frame), 0); + gtk_widget_show(frame); + + *pv = gtk_preview_new(GTK_PREVIEW_COLOR); + gtk_widget_show(*pv); + gtk_widget_set_events( GTK_WIDGET(*pv), PREVIEW_MASK); + gtk_signal_connect( GTK_OBJECT(*pv), "event", + (GtkSignalFunc) gfig_brush_preview_events, + NULL); + gtk_preview_size(GTK_PREVIEW(*pv), BRUSH_PREVIEW_SZ, BRUSH_PREVIEW_SZ); + gtk_container_add (GTK_CONTAINER (frame), *pv); + + /* Fill with white */ + for(y = 0; y < BRUSH_PREVIEW_SZ; y++) + { + guchar prow[BRUSH_PREVIEW_SZ*3]; + memset(prow,-1,BRUSH_PREVIEW_SZ*3); + gtk_preview_draw_row(GTK_PREVIEW(*pv), prow, 0, y,BRUSH_PREVIEW_SZ); + } + + /* Now the buttons */ + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_border_width(GTK_CONTAINER(vbox), 4); + gtk_widget_show(vbox); + + option_menu = gtk_option_menu_new (); + menu = gtk_menu_new(); + + menuitem = gtk_menu_item_new_with_label("Brush"); + gtk_object_set_user_data (GTK_OBJECT (menuitem), (gpointer) *pv); + + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc)gfig_brush_menu_callback, + (gpointer)BRUSH_BRUSH_TYPE); + + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + + menuitem = gtk_menu_item_new_with_label("Airbrush"); + gtk_object_set_user_data (GTK_OBJECT (menuitem), (gpointer) *pv); + + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc)gfig_brush_menu_callback, + (gpointer)BRUSH_AIRBRUSH_TYPE); + + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label("Pencil"); + gtk_object_set_user_data (GTK_OBJECT (menuitem), (gpointer) *pv); + + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc)gfig_brush_menu_callback, + (gpointer)BRUSH_PENCIL_TYPE); + + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label("Pattern"); + gtk_object_set_user_data (GTK_OBJECT (menuitem), (gpointer) *pv); + + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc)gfig_brush_menu_callback, + (gpointer)BRUSH_PATTERN_TYPE); + + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu); + gtk_widget_show (option_menu); + + gtk_container_add (GTK_CONTAINER (vbox), option_menu); + gtk_tooltips_set_tips(gfig_tooltips,option_menu,"Use the brush/pencil or the airbrush when drawing on the image. Pattern paints with currently selected brush with a pattern. Only applies to circles/ellipses if Approx. Circles/Ellipses toggle is set."); + + gtk_container_add (GTK_CONTAINER (hbox), vbox); + gtk_container_add (GTK_CONTAINER (hbox), frame); + + return(hbox); +} + +static void +gfig_brush_fill_preview_xy(GtkWidget *pw,gint x1 ,gint y1) +{ + gint row_count; + BRUSHDESC *bdesc = (BRUSHDESC*)gtk_object_get_user_data(GTK_OBJECT(pw)); + + /* Adjust start position */ + bdesc->x_off += x1; + bdesc->y_off += y1; + + if(bdesc->y_off < 0) + bdesc->y_off = 0; + if(bdesc->y_off > (bdesc->height - BRUSH_PREVIEW_SZ)) + bdesc->y_off = bdesc->height - BRUSH_PREVIEW_SZ; + + if(bdesc->x_off < 0) + bdesc->x_off = 0; + if(bdesc->x_off > (bdesc->width - BRUSH_PREVIEW_SZ)) + bdesc->x_off = bdesc->width - BRUSH_PREVIEW_SZ; + + /* Given an x and y fill preview in correctly offsetted */ + for(row_count = 0; row_count < BRUSH_PREVIEW_SZ; row_count++) + gtk_preview_draw_row(GTK_PREVIEW(pw), + &bdesc->pv_buf[bdesc->x_off*bdesc->bpp + + (bdesc->width + *bdesc->bpp + *(row_count + bdesc->y_off))], + 0, + row_count, + BRUSH_PREVIEW_SZ); +} + +static void +gfig_brush_fill_preview(GtkWidget *pw,gint32 layer_ID, BRUSHDESC * bdesc) +{ + GPixelRgn src_rgn; + GDrawable *brushdrawable; + gint bcount = 3; + + if(bdesc->pv_buf) + { + g_free(bdesc->pv_buf); /* Free old area */ + } + + brushdrawable = gimp_drawable_get(layer_ID); + + bdesc->bpp = bcount; + + /* Fill the preview with the current brush name */ + gimp_pixel_rgn_init(&src_rgn,brushdrawable,0,0,bdesc->width,bdesc->height,FALSE,FALSE); + + bdesc->pv_buf = g_new(guchar ,bdesc->width*bdesc->height*bcount); + bdesc->x_off = bdesc->y_off = 0; /* Start from top left */ + + gimp_pixel_rgn_get_rect(&src_rgn,bdesc->pv_buf,0,0,bdesc->width,bdesc->height); + + /* Dump the pv_buf into the preview area */ + gfig_brush_fill_preview_xy(pw,0,0); +} + +void +mygimp_brush_set(gchar *bname) +{ + GParam *return_vals; + int nreturn_vals; + + return_vals = gimp_run_procedure ("gimp_brushes_set_brush", + &nreturn_vals, + PARAM_STRING, bname, + PARAM_END); + + if (return_vals[0].data.d_status != STATUS_SUCCESS) + { + create_warn_dialog("Can't set brush...(1)"); + } + + gimp_destroy_params (return_vals, nreturn_vals); +} + +static gchar * +mygimp_brush_get (void) +{ + GParam *return_vals; + int nreturn_vals; + static gchar saved_bname[1024]; /* required to be static - returned from proc */ + + return_vals = gimp_run_procedure ("gimp_brushes_get_brush", + &nreturn_vals, + PARAM_END); + + if (return_vals[0].data.d_status == STATUS_SUCCESS) + { + strncpy(saved_bname,return_vals[1].data.d_string,sizeof(saved_bname)); + } + else + { + saved_bname[0] = '\0'; + } + + gimp_destroy_params (return_vals, nreturn_vals); + + return(saved_bname); +} + +static void +mygimp_brush_info(gint32 *width, + gint32 *height) +{ + GParam *return_vals; + int nreturn_vals; + + return_vals = gimp_run_procedure ("gimp_brushes_get_brush", + &nreturn_vals, + PARAM_END); + + if (return_vals[0].data.d_status == STATUS_SUCCESS) + { + *width = MAX(return_vals[2].data.d_int32,32); + *height = MAX(return_vals[3].data.d_int32,32); + } + else + { + create_warn_dialog("Failed to get brush info"); + *width = *height = 48; + } + + gimp_destroy_params (return_vals, nreturn_vals); +} + +static void +gfig_brush_img_del(void) +{ + gimp_image_delete(brush_image_ID); + brush_image_ID = -1; +} + +static gint32 +gfig_gen_brush_preview(BRUSHDESC *bdesc) +{ + /* Given the name of a brush then paint it and return the ID of the image + * the preview can be got from + */ + GParam *return_vals; + int nreturn_vals; + static gint32 layer_ID = -1; + guchar fR,fG,fB; + guchar bR,bG,bB; + gchar *saved_bname; + gint32 width,height; + gdouble line_pnts[2]; + + if(brush_image_ID == -1) + { + /* Create a new image */ + brush_image_ID = gimp_image_new(48,48,0); + if(brush_image_ID < 0) + { + create_warn_dialog("Failed to generate brush preview"); + return(-1); + } + if((layer_ID = gimp_layer_new(brush_image_ID, + "Brush preview", + 48, + 48, + 0, /* RGB type */ + 100.0, /* opacity */ + 0 /* mode */)) < 0) + { + create_warn_dialog("Error in creating layer for brush preview\n"); + return(-1); + } + gimp_image_add_layer(brush_image_ID,layer_ID,-1); + } + + /* Need this later to delete it */ + + /* Store foreground & backgroud colours set to black/white + * paint with brush + * restore colours + */ + + gimp_palette_get_foreground(&fR,&fG,&fB); + gimp_palette_get_background(&bR,&bG,&bB); + saved_bname = mygimp_brush_get(); + + gimp_palette_set_background((guchar)-1,(guchar)-1,(guchar)-1); + gimp_palette_set_foreground(0,0,0); + mygimp_brush_set(bdesc->bname); + + mygimp_brush_info(&width,&height); + bdesc->width = width; + bdesc->height = height; + line_pnts[0] = (gdouble)width/2; + line_pnts[1] = (gdouble)height/2; + + gimp_layer_resize(layer_ID,width,height,0,0); + gimp_image_resize(brush_image_ID,width,height,0,0); + + gimp_drawable_fill(layer_ID,1); /* Clear... Fill with white ... */ + + /* Blob of paint */ + + switch(selvals.brshtype) + { + case BRUSH_BRUSH_TYPE: + return_vals = gimp_run_procedure ("gimp_paintbrush", &nreturn_vals, + PARAM_IMAGE, brush_image_ID, + PARAM_DRAWABLE, layer_ID, + PARAM_FLOAT,0.0, + PARAM_INT32,2*GFIG_LCC,/* GIMP BUG should be 2!!!!*/ + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_PENCIL_TYPE: + return_vals = gimp_run_procedure ("gimp_pencil", &nreturn_vals, + PARAM_IMAGE, brush_image_ID, + PARAM_DRAWABLE, layer_ID, + PARAM_INT32,2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_AIRBRUSH_TYPE: + return_vals = gimp_run_procedure ("gimp_airbrush", &nreturn_vals, + PARAM_IMAGE, brush_image_ID, + PARAM_DRAWABLE, layer_ID, + PARAM_FLOAT,(gdouble)selvals.airbrushpressure, + PARAM_INT32,2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_PATTERN_TYPE: + return_vals = gimp_run_procedure ("gimp_clone", &nreturn_vals, + PARAM_IMAGE, brush_image_ID, + PARAM_DRAWABLE, layer_ID, + PARAM_DRAWABLE, layer_ID, + PARAM_INT32, 1, + PARAM_FLOAT,(gdouble)0.0, + PARAM_FLOAT,(gdouble)0.0, + PARAM_INT32,2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + default: + break; + } + + gimp_destroy_params (return_vals, nreturn_vals); + + gimp_palette_set_background(bR,bG,bB); + gimp_palette_set_foreground(fR,fG,fB); + mygimp_brush_set(saved_bname); + + return(layer_ID); +} + +static gint +brush_list_button_press(GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + gint32 layer_ID; + + BRUSHDESC *bdesc = (BRUSHDESC *)data; + if((layer_ID = gfig_gen_brush_preview(bdesc)) != -1) + { + gtk_object_set_user_data (GTK_OBJECT (brush_page_pw), (gpointer)bdesc); + gfig_brush_fill_preview(brush_page_pw,layer_ID,bdesc); + gtk_widget_draw(brush_page_pw, NULL); + } + + return(FALSE); +} + /* Build the dialog up. This was the hard part! */ static GtkWidget *page_menu_bg; +static GtkWidget *page_menu_layers; static void paint_menu_callback (GtkWidget *widget, gpointer data) @@ -2023,6 +2911,42 @@ paint_menu_callback (GtkWidget *widget, gpointer data) #endif /* DEBUG */ selvals.onlayerbg = (DRAWLAYERBG)gtk_object_get_user_data (GTK_OBJECT (widget)); } + else if(mtype == PAINT_TYPE_MENU) + { +#ifdef DEBUG + printf("Got type menu = %d\n",(PAINTTYPE)gtk_object_get_user_data (GTK_OBJECT (widget))); +#endif /* DEBUG */ + selvals.painttype = (PAINTTYPE)gtk_object_get_user_data (GTK_OBJECT (widget)); + switch(selvals.painttype) + { + case PAINT_BRUSH_TYPE: + gtk_widget_set_sensitive(select_page_widget,FALSE); + gtk_widget_set_sensitive(brush_page_widget,TRUE); + gtk_widget_set_sensitive(page_menu_layers,TRUE); + if(selvals.onlayers == ORIGINAL_LAYER) + gtk_widget_set_sensitive(page_menu_bg,FALSE); + else + gtk_widget_set_sensitive(page_menu_bg,TRUE); + break; + case PAINT_SELECTION_TYPE: + gtk_widget_set_sensitive(select_page_widget,TRUE); + gtk_widget_set_sensitive(brush_page_widget,FALSE); + gtk_widget_set_sensitive(page_menu_layers,FALSE); + gtk_widget_set_sensitive(page_menu_bg,FALSE); + break; + case PAINT_SELECTION_FILL_TYPE: + gtk_widget_set_sensitive(select_page_widget,TRUE); + gtk_widget_set_sensitive(brush_page_widget,FALSE); + gtk_widget_set_sensitive(page_menu_layers,TRUE); + if(selvals.onlayers == ORIGINAL_LAYER) + gtk_widget_set_sensitive(page_menu_bg,FALSE); + else + gtk_widget_set_sensitive(page_menu_bg,TRUE); + break; + default: + break; + } + } } GtkWidget * @@ -2074,6 +2998,49 @@ paint_page_menu_bgs(void) return option_menu; } + +GtkWidget * +paint_page_menu_type(void) +{ + GtkWidget *option_menu; + GtkWidget *menu; + GtkWidget *menuitem; + + option_menu = gtk_option_menu_new (); + + menu = gtk_menu_new(); + + menuitem = gtk_menu_item_new_with_label("Brush"); + gtk_object_set_user_data (GTK_OBJECT (menuitem), (gpointer) PAINT_BRUSH_TYPE); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) paint_menu_callback, + (gpointer)PAINT_TYPE_MENU); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label("Selection"); + gtk_object_set_user_data (GTK_OBJECT (menuitem), (gpointer) PAINT_SELECTION_TYPE); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) paint_menu_callback, + (gpointer)PAINT_TYPE_MENU); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label("Selection+Fill"); + gtk_object_set_user_data (GTK_OBJECT (menuitem), (gpointer) PAINT_SELECTION_FILL_TYPE); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) paint_menu_callback, + (gpointer)PAINT_TYPE_MENU); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + + gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu); + gtk_widget_show (option_menu); + + return option_menu; +} + GtkWidget * paint_page_menu_layers(void) { @@ -2124,7 +3091,7 @@ paint_page() GtkWidget *hbox; GtkWidget *label; GtkWidget *toggle; - GtkWidget *page_menu_layers; + GtkWidget *page_menu_type; GtkWidget *scale_scale; GtkObject *scale_scale_data; @@ -2138,31 +3105,41 @@ paint_page() gtk_widget_show(table); /* Put buttons in */ - - label = gtk_label_new ("Draw on:-"); + label = gtk_label_new ("Using:-"); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (label); + + page_menu_type = paint_page_menu_type(); + gtk_tooltips_set_tips(gfig_tooltips,page_menu_type,"Draw type. Either a brush or a selection. See brush page or selection page for more options"); + /* Default is original */ + gtk_table_attach(GTK_TABLE(table), page_menu_type, 1, 2, 1, 2, GTK_FILL , GTK_FILL, 0, 0); + + label = gtk_label_new ("draw on:-"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); page_menu_layers = paint_page_menu_layers(); gtk_tooltips_set_tips(gfig_tooltips,page_menu_layers,"Draw all objects on one layer (original or new) or one object per layer"); - gtk_table_attach(GTK_TABLE(table), page_menu_layers, 1, 2, 1, 2, GTK_FILL , GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), page_menu_layers, 3, 4, 1, 2, GTK_FILL , GTK_FILL, 0, 0); if(gimp_drawable_channel(gfig_drawable)) gtk_widget_set_sensitive(page_menu_layers,FALSE); label = gtk_label_new ("with BG of:-"); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2, GTK_FILL, GTK_FILL, 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (label); page_menu_bg = paint_page_menu_bgs(); gtk_tooltips_set_tips(gfig_tooltips,page_menu_bg,"Layer background type. Copy causes previous layer to be copied before the draw is performed"); /* Default is original */ gtk_widget_set_sensitive(page_menu_bg,FALSE); - gtk_table_attach(GTK_TABLE(table), page_menu_bg, 3, 4, 1, 2, GTK_FILL , GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), page_menu_bg, 1, 2, 2, 3, GTK_FILL , GTK_FILL, 0, 0); + toggle = gtk_check_button_new_with_label ("Reverse line "); - gtk_table_attach(GTK_TABLE(table), toggle, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), toggle, 0, 1, 3, 4, GTK_FILL, GTK_FILL, 0, 0); gtk_signal_connect (GTK_OBJECT (toggle), "toggled", (GtkSignalFunc) gfig_toggle_update, (gpointer)&selvals.reverselines); @@ -2170,7 +3147,7 @@ paint_page() gtk_widget_show(toggle); toggle = gtk_check_button_new_with_label ("Scale to image "); - gtk_table_attach(GTK_TABLE(table), toggle, 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), toggle, 1, 2, 3, 4, GTK_FILL, GTK_FILL, 0, 0); gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(toggle),selvals.scaletoimage); gtk_signal_connect (GTK_OBJECT (toggle), "toggled", (GtkSignalFunc) gfig_scale2img_update, @@ -2190,13 +3167,13 @@ paint_page() &selvals.scaletoimagefp); gtk_widget_show (scale_scale); gtk_widget_show (hbox); - gtk_table_attach(GTK_TABLE(table), hbox, 2, 4, 2, 3, GTK_FILL|GTK_EXPAND , GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), hbox, 2, 4, 3, 4, GTK_FILL|GTK_EXPAND , GTK_FILL, 0, 0); gtk_widget_set_sensitive(GTK_WIDGET(scale_scale),FALSE); gtk_object_set_user_data (GTK_OBJECT (toggle), (gpointer)scale_scale_data); gtk_object_set_user_data (GTK_OBJECT (scale_scale_data), (gpointer)scale_scale); toggle = gtk_check_button_new_with_label ("Approx. Circles/Ellipses "); - gtk_table_attach(GTK_TABLE(table), toggle, 0, 2, 3, 4, GTK_FILL, GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), toggle, 0, 2, 4, 5, GTK_FILL, GTK_FILL, 0, 0); gtk_signal_connect (GTK_OBJECT (toggle), "toggled", (GtkSignalFunc) gfig_toggle_update, (gpointer)&selvals.approxcircles); @@ -2210,11 +3187,16 @@ static void gfig_get_brushes(GtkWidget *list) { GtkWidget *list_item; + gint list_item2sel; gint nreturn_vals; GParam *return_vals; gint num_brs; gchar **brush_names; + gchar *current_bname; gint i; + BRUSHDESC *fbdesc = (BRUSHDESC *)-1; + + current_bname = mygimp_brush_get(); return_vals = gimp_run_procedure ("gimp_brushes_list", &nreturn_vals, PARAM_END); @@ -2231,15 +3213,37 @@ gfig_get_brushes(GtkWidget *list) for( i = 0 ; i < num_brs; i++) { + BRUSHDESC *bdesc = g_malloc0(sizeof(BRUSHDESC)); + bdesc->bpp = 3; + list_item = gtk_list_item_new_with_label(brush_names[i]); gtk_container_add (GTK_CONTAINER (list), list_item); + bdesc->bname = g_strdup(brush_names[i]); + gtk_signal_connect(GTK_OBJECT(list_item), "button_press_event", + (GtkSignalFunc) brush_list_button_press, + (gpointer)bdesc); gtk_widget_show(list_item); + + if(!strcmp(brush_names[i],current_bname)) + { + fbdesc = bdesc; + list_item2sel = i; + } } + if(fbdesc != (BRUSHDESC*)-1) + { + /* First item selected by default - unselected it ! */ + /*gtk_list_unselect_item(GTK_LIST(list),0);*/ + brush_list_button_press(NULL,NULL,fbdesc); + } + gimp_destroy_params (return_vals, nreturn_vals); + gtk_list_select_item(GTK_LIST(list),list_item2sel); } +#if 0 /* NOT USED */ static gint set_brush_press(GtkWidget *widget, GdkEventButton *event, @@ -2281,6 +3285,8 @@ set_brush_press(GtkWidget *widget, return(FALSE); } +#endif /* NOT USED */ + static GtkWidget * brush_page() { @@ -2288,12 +3294,12 @@ brush_page() GtkWidget *list; GtkWidget *scrolled_win; GtkWidget *table; - GtkWidget *button; GtkWidget *label; - GtkWidget *fade_out_scale; + GtkWidget *pw; + GtkWidget *scale; GtkObject *fade_out_scale_data; + GtkObject *pressure_scale_data; GtkWidget *vbox; - GtkWidget *hbox; vbox = gtk_vbox_new(FALSE, 0); gtk_container_border_width(GTK_CONTAINER(vbox), 4); @@ -2304,30 +3310,63 @@ brush_page() gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); gtk_widget_show(table); +#if 0 /* Put buttons in */ button = gtk_button_new_with_label ("Set brush"); gtk_widget_show(button); gtk_table_attach(GTK_TABLE(table), button, 0, 1, 0, 1, 0 , 0, 0, 0); +#endif /* 0 */ /* Fade option */ /* the fade-out scale From GIMP itself*/ - hbox = gtk_hbox_new (FALSE, 1); + fade_out_hbox = gtk_hbox_new (FALSE, 1); label = gtk_label_new ("Fade Out:"); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (fade_out_hbox), label, FALSE, FALSE, 0); gtk_widget_show (label); - fade_out_scale_data = gtk_adjustment_new (0.0, 0.0, 1000.0, 1.0, 1.0, 0.0); - fade_out_scale = gtk_hscale_new (GTK_ADJUSTMENT (fade_out_scale_data)); - gtk_box_pack_start (GTK_BOX (hbox), fade_out_scale, TRUE, TRUE, 0); - gtk_scale_set_value_pos (GTK_SCALE (fade_out_scale), GTK_POS_TOP); - gtk_range_set_update_policy (GTK_RANGE (fade_out_scale), GTK_UPDATE_DELAYED); + fade_out_scale_data = gtk_adjustment_new (0.0, 0.0, 3000.0, 1.0, 1.0, 0.0); + scale = gtk_hscale_new (GTK_ADJUSTMENT (fade_out_scale_data)); + gtk_box_pack_start (GTK_BOX (fade_out_hbox), scale, TRUE, TRUE, 0); + gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP); + gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED); gtk_signal_connect (GTK_OBJECT (fade_out_scale_data), "value_changed", (GtkSignalFunc)gfig_scale_update_fp, &selvals.brushfade); - gtk_widget_show (fade_out_scale); - gtk_widget_show (hbox); - gtk_table_attach(GTK_TABLE(table), hbox, 1, 2, 0, 1, GTK_FILL , GTK_FILL, 0, 0); + gtk_widget_show (scale); + gtk_table_attach(GTK_TABLE(table), fade_out_hbox, 1, 2, 0, 1, GTK_FILL|GTK_EXPAND , GTK_FILL, 0, 0); + gtk_widget_show (fade_out_hbox); + + pressure_hbox = gtk_hbox_new (FALSE, 1); + label = gtk_label_new ("Pressure:"); + gtk_box_pack_start (GTK_BOX (pressure_hbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + pressure_scale_data = gtk_adjustment_new (20.0, 0.0, 100.0, 1.0, 1.0, 0.0); + scale = gtk_hscale_new (GTK_ADJUSTMENT (pressure_scale_data)); + gtk_box_pack_start (GTK_BOX (pressure_hbox), scale, TRUE, TRUE, 0); + gtk_widget_show (scale); + gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP); + gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED); + gtk_signal_connect (GTK_OBJECT (pressure_scale_data), "value_changed", + (GtkSignalFunc)gfig_scale_update_fp, + &selvals.airbrushpressure); + gtk_table_attach(GTK_TABLE(table), pressure_hbox, 1, 2, 0, 1, GTK_FILL|GTK_EXPAND , GTK_FILL, 0, 0); + + pencil_hbox = gtk_hbox_new (FALSE, 1); + label = gtk_label_new ("No options..."); + gtk_box_pack_start (GTK_BOX (pencil_hbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + gtk_table_attach(GTK_TABLE(table), pencil_hbox, 1, 2, 0, 1,GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0); + + + /* Preview widget */ + pw = gfig_brush_preview(&brush_page_pw); + gtk_table_attach(GTK_TABLE(table),pw, 0, 1, 0, 1, 0, 0, 0, 0); + + gtk_signal_connect (GTK_OBJECT (pressure_scale_data), "value_changed", + (GtkSignalFunc)gfig_brush_update_preview, + (gpointer)brush_page_pw); /* Brush list */ list_frame = gtk_frame_new(NULL); @@ -2341,7 +3380,7 @@ brush_page() gtk_widget_show (scrolled_win); list = gtk_list_new (); - gtk_list_set_selection_mode (GTK_LIST (list), GTK_SELECTION_BROWSE); + gtk_list_set_selection_mode (GTK_LIST (list), GTK_SELECTION_SINGLE); gtk_container_add (GTK_CONTAINER (scrolled_win), list); gtk_widget_show (list); gtk_table_attach(GTK_TABLE(table), list_frame, 0, 4, 1, 5, GTK_FILL|GTK_EXPAND , GTK_FILL|GTK_EXPAND, 0, 0); @@ -2349,35 +3388,334 @@ brush_page() /* Get brush list and insert in table */ gfig_get_brushes(list); - /* Now bit for the button */ - gtk_signal_connect (GTK_OBJECT (button), "button_press_event", - (GtkSignalFunc) set_brush_press, - (gpointer) list); - return(vbox); } +static void +select_menu_callback (GtkWidget *widget, gpointer data) +{ + gint mtype = (gint)data; + + if(mtype == SELECT_TYPE_MENU) + { + SELECTION_TYPE type = + (SELECTION_TYPE)gtk_object_get_user_data (GTK_OBJECT (widget)); + + selopt.type = type; + } + else if(mtype == SELECT_ARCTYPE_MENU) + { + ARC_TYPE type = + (ARC_TYPE)gtk_object_get_user_data (GTK_OBJECT (widget)); + + selopt.as_pie = type; + } + else if(mtype == SELECT_TYPE_MENU_FILL) + { + FILL_TYPE type = + (FILL_TYPE)gtk_object_get_user_data (GTK_OBJECT (widget)); + + selopt.fill_type = type; + } + else if(mtype == SELECT_TYPE_MENU_WHEN) + { + FILL_WHEN type = + (FILL_WHEN)gtk_object_get_user_data (GTK_OBJECT (widget)); + selopt.fill_when = type; + } +} + +GtkWidget * +select_page_menu_fill_when(void) +{ + GtkWidget *option_menu; + GtkWidget *menu; + GtkWidget *menuitem; + + option_menu = gtk_option_menu_new (); + + menu = gtk_menu_new(); + + menuitem = gtk_menu_item_new_with_label("Each selection"); + gtk_object_set_user_data (GTK_OBJECT (menuitem), (gpointer) FILL_EACH); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) select_menu_callback, + (gpointer)SELECT_TYPE_MENU_WHEN); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label("All selections"); + gtk_object_set_user_data (GTK_OBJECT (menuitem), (gpointer) FILL_AFTER); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) select_menu_callback, + (gpointer)SELECT_TYPE_MENU_WHEN); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu); + gtk_widget_show (option_menu); + + return option_menu; +} + + + +GtkWidget * +select_page_menu_fill_type(void) +{ + GtkWidget *option_menu; + GtkWidget *menu; + GtkWidget *menuitem; + + option_menu = gtk_option_menu_new (); + + menu = gtk_menu_new(); + + menuitem = gtk_menu_item_new_with_label("Pattern"); + gtk_object_set_user_data (GTK_OBJECT (menuitem), (gpointer) FILL_PATTERN); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) select_menu_callback, + (gpointer)SELECT_TYPE_MENU_FILL); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label("Foreground"); + gtk_object_set_user_data (GTK_OBJECT (menuitem), (gpointer) FILL_FOREGROUND); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) select_menu_callback, + (gpointer)SELECT_TYPE_MENU_FILL); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label("Background"); + gtk_object_set_user_data (GTK_OBJECT (menuitem), (gpointer) FILL_BACKGROUND); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) select_menu_callback, + (gpointer)SELECT_TYPE_MENU_FILL); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu); + gtk_widget_show (option_menu); + + return option_menu; +} + + +GtkWidget * +select_page_menu_type(void) +{ + GtkWidget *option_menu; + GtkWidget *menu; + GtkWidget *menuitem; + + option_menu = gtk_option_menu_new (); + + menu = gtk_menu_new(); + + menuitem = gtk_menu_item_new_with_label("Add"); + gtk_object_set_user_data (GTK_OBJECT (menuitem), (gpointer) ADD); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) select_menu_callback, + (gpointer)SELECT_TYPE_MENU); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label("Sub"); + gtk_object_set_user_data (GTK_OBJECT (menuitem), (gpointer) SUBTRACT); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) select_menu_callback, + (gpointer)SELECT_TYPE_MENU); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label("Replace"); + gtk_object_set_user_data (GTK_OBJECT (menuitem), (gpointer) REPLACE); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) select_menu_callback, + (gpointer)SELECT_TYPE_MENU); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label("Intersect"); + gtk_object_set_user_data (GTK_OBJECT (menuitem), (gpointer) INTERSECT); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) select_menu_callback, + (gpointer)SELECT_TYPE_MENU); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu); + gtk_widget_show (option_menu); + + return option_menu; +} + +GtkWidget * +select_page_menu_arctype(void) +{ + GtkWidget *option_menu; + GtkWidget *menu; + GtkWidget *menuitem; + + option_menu = gtk_option_menu_new (); + + menu = gtk_menu_new(); + + menuitem = gtk_menu_item_new_with_label("Segment"); + gtk_object_set_user_data (GTK_OBJECT (menuitem), (gpointer) ARC_SEGMENT); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) select_menu_callback, + (gpointer)SELECT_ARCTYPE_MENU); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + menuitem = gtk_menu_item_new_with_label("Sector"); + gtk_object_set_user_data (GTK_OBJECT (menuitem), (gpointer) ARC_SECTOR); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + (GtkSignalFunc) select_menu_callback, + (gpointer)SELECT_ARCTYPE_MENU); + gtk_widget_show (menuitem); + gtk_menu_append (GTK_MENU (menu), menuitem); + + gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu); + gtk_widget_show (option_menu); + + return option_menu; +} + + static GtkWidget * select_page() { - + GtkWidget *menu; + GtkWidget *label; + GtkWidget *toggle; + GtkWidget *hbox; + GtkWidget *scale; + GtkObject *scale_data; GtkWidget *table; - GtkWidget *button; GtkWidget *vbox; vbox = gtk_vbox_new(FALSE, 0); gtk_container_border_width(GTK_CONTAINER(vbox), 4); - table = gtk_table_new (6, 6, FALSE); + table = gtk_table_new (7, 7, FALSE); gtk_table_set_row_spacings(GTK_TABLE(table),6); gtk_container_border_width (GTK_CONTAINER (table), 1); gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); gtk_widget_show(table); - /* Put buttons in */ - button = gtk_button_new_with_label ("Select page"); - gtk_widget_show(button); - gtk_table_attach(GTK_TABLE(table), button, 0, 1, 0, 1, GTK_FILL , GTK_FILL, 0, 0); + /* The secltion settings - + * 1) Type (option menu) + * 2) Anti A (toggle) + * 3) Feather (toggle) + * 4) F radius (slider) + * 5) Fill type (option menu) + * 6) Opacity (slider) + * 7) When to fill (toggle) + * 8) Arc as segment/sector + */ + + /* Put widgets in */ + /* 1 */ + hbox = gtk_hbox_new (FALSE, 1); + label = gtk_label_new ("Selection type:"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + menu = select_page_menu_type(); + gtk_box_pack_start (GTK_BOX (hbox), menu, TRUE, TRUE, 0); + gtk_table_attach (GTK_TABLE (table), hbox, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (hbox); + + + /* 2 */ + toggle = gtk_check_button_new_with_label ("Antialiasing"); + gtk_table_attach(GTK_TABLE(table), toggle, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) gfig_toggle_update, + (gpointer)&selopt.antia); + gtk_widget_show(toggle); + + /* 3 */ + toggle = gtk_check_button_new_with_label ("Feather"); + gtk_table_attach(GTK_TABLE(table), toggle, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) gfig_toggle_update, + (gpointer)&selopt.feather); + gtk_widget_show(toggle); + + /* 4 */ + hbox = gtk_hbox_new (FALSE, 1); + + label = gtk_label_new ("Feather Radius:"); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + scale_data = gtk_adjustment_new (selopt.feather_radius, 0.0, 100.0, 1.0, 1.0, 0.0); + scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data)); + gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0); + gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP); + gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED); + gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed", + (GtkSignalFunc)gfig_scale_update_fp, + &selopt.feather_radius); + gtk_widget_show (scale); + gtk_table_attach(GTK_TABLE(table), hbox, 1, 3, 1, 2, GTK_FILL|GTK_EXPAND , GTK_FILL, 0, 0); + gtk_widget_show (hbox); + + /* 5 */ + hbox = gtk_hbox_new (FALSE, 1); + label = gtk_label_new ("Fill type:"); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + menu = select_page_menu_fill_type(); + gtk_box_pack_start (GTK_BOX (hbox), menu, TRUE, TRUE, 0); + gtk_table_attach (GTK_TABLE (table), hbox, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (hbox); + + /* 6 */ + hbox = gtk_hbox_new (FALSE, 1); + + label = gtk_label_new ("Fill Opacity:"); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + scale_data = gtk_adjustment_new (selopt.fill_opacity, 0.0, 100.0, 1.0, 1.0, 0.0); + scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data)); + gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0); + gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP); + gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED); + gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed", + (GtkSignalFunc)gfig_scale_update_fp, + &selopt.fill_opacity); + gtk_widget_show (scale); + gtk_table_attach(GTK_TABLE(table), hbox, 1, 3, 2, 3, GTK_FILL|GTK_EXPAND , GTK_FILL, 0, 0); + gtk_widget_show (hbox); + + /* 7 */ + hbox = gtk_hbox_new (FALSE, 1); + label = gtk_label_new ("Fill after: "); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + menu = select_page_menu_fill_when(); + gtk_box_pack_start (GTK_BOX (hbox), menu, TRUE, TRUE, 0); + gtk_table_attach (GTK_TABLE (table), hbox, 0, 1, 4, 5, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (hbox); + + /* 8 */ + hbox = gtk_hbox_new (FALSE, 1); + label = gtk_label_new ("Arc as: "); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + menu = select_page_menu_arctype(); + gtk_box_pack_start (GTK_BOX (hbox), menu, TRUE, TRUE, 0); + gtk_table_attach (GTK_TABLE (table), hbox, 0, 1, 5, 6, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (hbox); return(vbox); } @@ -2518,6 +3856,7 @@ options_page() GtkWidget *slider; GtkWidget *entry; GtkWidget *label; + GtkWidget *button; GtkWidget *vbox; GtkObject *size_data; char buf[256]; @@ -2542,6 +3881,13 @@ options_page() (gpointer)1); gtk_widget_show(toggle); + button = gtk_button_new_with_label ("Reload image"); + gtk_table_attach(GTK_TABLE(table), button, 1, 2, 0, 1, 0, 0, 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "button_press_event", + (GtkSignalFunc) reload_button_press, + NULL); + gtk_widget_show(button); + toggle = gtk_check_button_new_with_label ("Hide cntr pnts "); gtk_table_attach(GTK_TABLE(table), toggle, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0); gtk_signal_connect (GTK_OBJECT (toggle), "toggled", @@ -2554,18 +3900,18 @@ options_page() sprintf(buf,"Grid type:"); label = gtk_label_new (buf); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1, GTK_EXPAND, GTK_FILL, 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, GTK_EXPAND, GTK_FILL, 0, 0); gtk_widget_show (label); menu = option_page_menu_gridtype(); - gtk_table_attach(GTK_TABLE(table), menu, 2, 3, 0, 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), menu, 3, 4, 0, 1, GTK_FILL, GTK_FILL, 0, 0); sprintf(buf,"Grid Colour:"); label = gtk_label_new (buf); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_table_attach (GTK_TABLE (table), label, 1, 2, 1, 2, GTK_EXPAND, GTK_FILL, 0, 0); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2, GTK_EXPAND, GTK_FILL, 0, 0); gtk_widget_show (label); menu = option_page_menu_gridrender(); - gtk_table_attach(GTK_TABLE(table), menu, 2, 3, 1, 2, GTK_FILL, GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), menu, 3, 4, 1, 2, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show(toggle); @@ -2612,6 +3958,23 @@ options_page() gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(toggle),selvals.showtooltips); gtk_widget_show(toggle); + toggle = gtk_check_button_new_with_label ("Show pos"); + gtk_table_attach(GTK_TABLE(table), toggle, 1, 2, 3, 4, GTK_FILL, GTK_FILL, 0, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) gfig_toggle_update, + (gpointer)&selvals.showpos); + gtk_signal_connect_after (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) gfig_pos_enable, + (gpointer)1); + gtk_widget_show(toggle); + + button = gtk_button_new_with_label ("About"); + gtk_table_attach(GTK_TABLE(table), button, 3, 4, 4, 5, GTK_FILL, GTK_FILL, 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "button_press_event", + (GtkSignalFunc) about_button_press, + NULL); + gtk_widget_show(button); + return(vbox); } @@ -2822,6 +4185,203 @@ add_objects_list () return (frame); } +static gint x_pos_val; +static gint y_pos_val; +static gint pos_tag = -1; + +static void +gfig_pos_enable(GtkWidget *widget, gpointer data) +{ + gint enable = selvals.showpos; + gtk_widget_set_sensitive(GTK_WIDGET(x_pos_label),enable); + gtk_widget_set_sensitive(GTK_WIDGET(y_pos_label),enable); +} + +void +my_gtk_label_set2 (GtkLabel *label, + const char *str) +{ + gtk_label_set(label,str); + gtk_container_need_resize (GTK_CONTAINER (gtk_widget_get_toplevel (GTK_WIDGET(label)))); +} + +void +my_gtk_label_set (GtkLabel *label, + const char *str) +{ + char* p; + g_return_if_fail (label != NULL); + g_return_if_fail (GTK_IS_LABEL (label)); + g_return_if_fail (str != NULL); + if (label->label) + g_free (label->label); + label->label = g_strdup (str); + if (label->row) + g_slist_free (label->row); + label->row = NULL; + label->row = g_slist_append (label->row, label->label); + p = label->label; + while ((p = strchr(p, '\n'))) + label->row = g_slist_append (label->row, ++p); + if (GTK_WIDGET_VISIBLE (label)) + { + gdk_window_clear_area (GTK_WIDGET (label)->window, + GTK_WIDGET (label)->allocation.x, + GTK_WIDGET (label)->allocation.y, + GTK_WIDGET (label)->allocation.width, + GTK_WIDGET (label)->allocation.height); + gtk_widget_draw(GTK_WIDGET(label),NULL); + } +} + + +static void +gfig_pos_update_labels(gpointer data) +{ + static gchar buf[256]; + + gtk_idle_remove(pos_tag); + pos_tag = -1; + + if(x_pos_val < 0) + sprintf(buf," X:%.3d ",x_pos_val); + else + sprintf(buf," X: %.3d ",x_pos_val); + + my_gtk_label_set(GTK_LABEL(x_pos_label),buf); + + if(y_pos_val < 0) + sprintf(buf," Y:%.3d ",y_pos_val); + else + sprintf(buf," Y: %.3d ",y_pos_val); + + my_gtk_label_set(GTK_LABEL(y_pos_label),buf); +} + +static void +gfig_pos_update(gint x , gint y) +{ + gint update; + + if(x_pos_val != x || y_pos_val != y) + update = 1; + else + update = 0; + + x_pos_val = x; + y_pos_val = y; + + if(update && pos_tag == -1 && selvals.showpos) + { + pos_tag = gtk_idle_add((GtkFunction)gfig_pos_update_labels,NULL); + } +} + +#if 0 /* NOT USED */ +static void +gfig_obj_size_update(gint sz) +{ + static gchar buf[256]; + + sprintf(buf,"%6d",sz); + my_gtk_label_set(GTK_LABEL(obj_size_label),buf); +} + +static GtkWidget * +gfig_obj_size_label(void) +{ + GtkWidget *label; + GtkWidget *hbox; + gchar buf[256]; + + hbox = gtk_hbox_new (FALSE,0); + + /* Position labels */ + label = gtk_label_new("Size:- "); + gtk_widget_show(label); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + obj_size_label = gtk_label_new(""); + gtk_misc_set_alignment (GTK_MISC (obj_size_label), 0.5, 0.5); + gtk_widget_show(obj_size_label); + gtk_box_pack_start (GTK_BOX (hbox), obj_size_label, FALSE, FALSE, 0); + + gtk_widget_show(hbox); + + sprintf(buf,"%6d",0); + gtk_label_set(GTK_LABEL(obj_size_label),buf); + + return(hbox); +} + +#endif /* NOT USED */ + +static GtkWidget * +gfig_pos_labels(void) +{ + GtkWidget *label; + GtkWidget *hbox; + GtkWidget *vbox; + gchar buf[256]; + + hbox = gtk_hbox_new (FALSE, 0); + vbox = gtk_vbox_new (FALSE, 0); + + /* Position labels */ + label = gtk_label_new("XY Pos:- "); + gtk_box_pack_start (GTK_BOX (hbox),label, FALSE, FALSE, 0); + gtk_widget_show(label); + + x_pos_label = gtk_label_new(""); + gtk_widget_show(x_pos_label); + gtk_container_add (GTK_CONTAINER (vbox), x_pos_label); + + y_pos_label = gtk_label_new(""); + gtk_widget_show(y_pos_label); + gtk_container_add (GTK_CONTAINER (vbox), y_pos_label); + + gtk_container_border_width (GTK_CONTAINER (hbox), 1); + + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + gtk_widget_show(hbox); + gtk_widget_show(vbox); + + sprintf(buf," X: %.3d ",0); + gtk_label_set(GTK_LABEL(x_pos_label),buf); + sprintf(buf," Y: %.3d ",0); + gtk_label_set(GTK_LABEL(y_pos_label),buf); + + return(hbox); +} + +static GtkWidget * +make_pos_info(void) +{ + GtkWidget * xframe; + GtkWidget * hbox; + GtkWidget * label; + + xframe = gtk_frame_new("Obj Details"); + hbox = gtk_hbox_new (TRUE, 1); + + gtk_frame_set_shadow_type (GTK_FRAME (xframe), GTK_SHADOW_ETCHED_IN); + gtk_container_add (GTK_CONTAINER (xframe), hbox); + + /* Add labels */ + label = gfig_pos_labels(); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + gfig_pos_enable(NULL,NULL); + +#if 0 + label = gfig_obj_size_label(); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); +#endif /* 0 */ + + gtk_widget_show(hbox); + gtk_widget_show(xframe); + return(xframe); +} + static GtkWidget * make_status(void) @@ -2830,7 +4390,7 @@ make_status(void) GtkWidget * table; GtkWidget * label; - xframe = gtk_frame_new("Details"); + xframe = gtk_frame_new("Collection Details"); gtk_frame_set_shadow_type (GTK_FRAME (xframe), GTK_SHADOW_ETCHED_IN); table = gtk_table_new (6, 6, FALSE); @@ -2838,23 +4398,25 @@ make_status(void) label = gtk_label_new("Draw name:"); gtk_misc_set_alignment(GTK_MISC(label),0.5,0.5); gtk_widget_show(label); - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0 , GTK_FILL|GTK_EXPAND, 0, 0); + gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_RIGHT); + gtk_table_attach(GTK_TABLE(table), label, 1, 2, 0, 1, 0 , GTK_FILL, 0, 0); label = gtk_label_new("Filename:"); gtk_misc_set_alignment(GTK_MISC(label),0.5,0.5); gtk_widget_show(label); - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, 0 , GTK_FILL|GTK_EXPAND, 0, 0); + gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_RIGHT); + gtk_table_attach(GTK_TABLE(table), label, 1, 2, 1, 2, 0 , GTK_FILL, 0, 0); status_label_dname = gtk_label_new(""); gtk_misc_set_alignment(GTK_MISC(label),0.5,0.5); gtk_widget_show(status_label_dname); - gtk_table_attach(GTK_TABLE(table), status_label_dname, 1, 5, 0, 1, GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), status_label_dname, 2, 4, 0, 1, GTK_FILL|GTK_EXPAND, 0, 0, 0); status_label_fname = gtk_label_new(""); gtk_misc_set_alignment(GTK_MISC(label),0.5,0.5); gtk_widget_show(status_label_fname); - gtk_table_attach(GTK_TABLE(table), status_label_fname, 1, 5, 1, 2, GTK_FILL|GTK_EXPAND , GTK_FILL, 0, 0); + gtk_table_attach(GTK_TABLE(table), status_label_fname, 2, 4, 1, 2, GTK_FILL|GTK_EXPAND, 0, 0, 0); #if 0 label = gtk_label_new("Painting:"); @@ -2864,10 +4426,11 @@ make_status(void) progress_widget = gtk_progress_bar_new(); gtk_widget_show(progress_widget); - gtk_table_attach(GTK_TABLE(table), progress_widget, 2, 5, 2, 3, 0 , 0, 0, 0); + gtk_table_attach(GTK_TABLE(table), progress_widget, 2, 4, 2, 3, 0 , 0, 0, 0); #endif /* 0 */ gtk_container_add (GTK_CONTAINER (xframe), table); + gtk_widget_show(table); gtk_widget_show(xframe); return(xframe); @@ -2878,8 +4441,9 @@ make_preview(void) { GtkWidget * xframe; GtkWidget * vbox; + GtkWidget * hbox; GtkWidget * table; - GtkWidget *ruler; + GtkWidget * ruler; gfig_preview = gtk_preview_new(GTK_PREVIEW_COLOR); @@ -2899,8 +4463,9 @@ make_preview(void) xframe = gtk_frame_new(NULL); gtk_frame_set_shadow_type (GTK_FRAME (xframe), GTK_SHADOW_IN); - table = gtk_table_new (2, 2, FALSE); - gtk_table_attach(GTK_TABLE(table), gfig_preview, 1, 2, 1, 2, GTK_FILL , GTK_FILL, 0, 0); + + table = gtk_table_new (3, 3, FALSE); + gtk_table_attach(GTK_TABLE(table), gfig_preview, 1, 2, 1, 2, GTK_FILL ,GTK_FILL , 0, 0); gtk_container_add (GTK_CONTAINER (xframe), table); ruler = gtk_hruler_new (); @@ -2919,16 +4484,25 @@ make_preview(void) gtk_table_attach(GTK_TABLE(table),ruler, 0, 1, 1, 2, GTK_FILL , GTK_FILL, 0,0); gtk_widget_show(ruler); + gtk_widget_show(xframe); gtk_widget_show(table); - vbox = gtk_vbox_new (FALSE, 1); + vbox = gtk_vbox_new (FALSE, 0); + hbox = gtk_hbox_new (FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), xframe, FALSE, FALSE, 0); + gtk_container_border_width (GTK_CONTAINER (vbox), 2); - gtk_box_pack_start(GTK_BOX(vbox), xframe, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + xframe = make_pos_info(); + gtk_box_pack_start(GTK_BOX(vbox), xframe, TRUE, TRUE, 0); xframe = make_status(); gtk_box_pack_start(GTK_BOX(vbox), xframe, TRUE, TRUE, 0); + gtk_widget_show(vbox); + gtk_widget_show(hbox); return(vbox); } @@ -2975,12 +4549,14 @@ gfig_grid_colours(GtkWidget *w,GdkColormap *cmap) GDK_GC_STIPPLE); } + static gint gfig_dialog () { GtkWidget *button; GtkWidget *frame; GtkWidget *xframe; + GtkWidget *oframe; GtkWidget *table; GtkWidget *label; GtkWidget *notebook; @@ -3004,16 +4580,21 @@ gfig_dialog () plug_in_parse_gfig_path(); /* Get the stuff for the preview window...*/ + gtk_preview_set_gamma(gimp_gamma()); gtk_preview_set_install_cmap(gimp_install_cmap()); color_cube = gimp_color_cube(); gtk_preview_set_color_cube(color_cube[0], color_cube[1], color_cube[2], color_cube[3]); - gtk_widget_set_default_visual(gtk_preview_get_visual()); + gtk_widget_set_default_visual(yyy = gtk_preview_get_visual()); + gtk_widget_set_default_colormap(xxx = gtk_preview_get_cmap()); - cache_preview(); /* Get the preview image and store it also set has_alpha */ - + /*cache_preview(); Get the preview image and store it also set has_alpha */ + + img_width = gimp_drawable_width(gfig_select_drawable->id); + img_height = gimp_drawable_height(gfig_select_drawable->id); + /* Start buildng the dialog up */ top_level_dlg = gtk_dialog_new (); gtk_window_set_title (GTK_WINDOW (top_level_dlg), "Gfig"); @@ -3073,14 +4654,13 @@ gfig_dialog () button = gtk_button_new_with_label ("Cancel"); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); - gtk_signal_connect_object (GTK_OBJECT (button), "clicked", - (GtkSignalFunc) gtk_widget_destroy, - GTK_OBJECT (top_level_dlg)); + gtk_signal_connect(GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gfig_cancel_callback, + top_level_dlg); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (top_level_dlg)->action_area), button, TRUE, TRUE, 0); gtk_widget_show (button); /* Start building the frame for the preview area */ - frame = gtk_frame_new ("preview"); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_border_width (GTK_CONTAINER (frame), 1); @@ -3089,7 +4669,6 @@ gfig_dialog () gtk_container_add (GTK_CONTAINER (frame), table); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (top_level_dlg)->vbox), frame, TRUE, TRUE, 0); - /* Preview itself */ xframe = make_preview(); gtk_table_attach(GTK_TABLE(table), xframe, 1, 2, 0, 2, GTK_FILL, GTK_FILL, 0, 0); @@ -3115,8 +4694,8 @@ gfig_dialog () gtk_container_add (GTK_CONTAINER (frame), table); /* listbox + entry */ - xframe = add_objects_list(); - gtk_table_attach(GTK_TABLE(table), xframe, 0,6, 0 , 1, GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0); + oframe = add_objects_list(); + gtk_table_attach(GTK_TABLE(table), oframe, 0,6, 0 , 1, GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0); /* Grid entry */ @@ -3136,24 +4715,25 @@ gfig_dialog () gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label); gtk_widget_show(page); - page = brush_page(); + brush_page_widget = brush_page(); label = gtk_label_new("Brush"); - gtk_misc_set_alignment(GTK_MISC(label),2.5,2.5); + gtk_misc_set_alignment(GTK_MISC(label),0.5,0.5); gtk_widget_show(label); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label); - gtk_widget_show(page); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), brush_page_widget, label); + gtk_widget_show(brush_page_widget); + -#if 0 /* Sometime maybe allow all objects to be done by selections - this * would adjust the selection options. */ - page = select_page(); + select_page_widget = select_page(); label = gtk_label_new("Select"); gtk_widget_show(label); gtk_misc_set_alignment(GTK_MISC(label),0.5,0.5); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label); - gtk_widget_show(page); -#endif /* 0 */ + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), select_page_widget, label); + gtk_widget_show(select_page_widget); + gtk_widget_set_sensitive(select_page_widget,FALSE); + page = options_page(); label = gtk_label_new("Options"); @@ -3275,6 +4855,15 @@ gfig_ok_callback (GtkWidget *widget, gfig_run = TRUE; gtk_widget_destroy (GTK_WIDGET (data)); } + gfig_brush_img_del(); +} + +static void +gfig_cancel_callback(GtkWidget *widget, + gpointer data) +{ + gtk_widget_destroy(GTK_WIDGET(data)); + gfig_brush_img_del(); } @@ -3290,7 +4879,7 @@ update_draw_area(GtkWidget *widget,GdkEvent *event) gtk_signal_handler_unblock(GTK_OBJECT(widget),gfig_preview_exp_id ); draw_grid(widget,0); - draw_objects(current_obj->obj_list); + draw_objects(current_obj->obj_list,TRUE); } static gint @@ -3317,7 +4906,7 @@ pic_preview_expose( GtkWidget *widget, if(pic_obj) { drawing_pic = TRUE; - draw_objects(pic_obj->obj_list); + draw_objects(pic_obj->obj_list,FALSE); drawing_pic = FALSE; } return FALSE; @@ -3326,7 +4915,15 @@ pic_preview_expose( GtkWidget *widget, static gint adjust_pic_coords(gint coord,gint ratio) { - return((SMALL_PREVIEW_SZ * coord)/PREVIEW_SIZE); + /*return((SMALL_PREVIEW_SZ * coord)/PREVIEW_SIZE);*/ + static gint pratio = -1; + + if(pratio == -1) + { + pratio = MAX(preview_width,preview_height); + } + + return((SMALL_PREVIEW_SZ * coord)/pratio); } static gint @@ -3336,6 +4933,7 @@ gfig_preview_events ( GtkWidget *widget, GdkEventButton *bevent; GdkEventMotion *mevent; GdkPoint point; + static tmp_show_single = 0; switch (event->type) { @@ -3358,17 +4956,34 @@ gfig_preview_events ( GtkWidget *widget, point.y = gfig_invscale_y(point.y); } object_operation_start(&point,bevent->state & GDK_SHIFT_MASK); + + /* If constraining save start pnt */ + if(selvals.opts.snap2grid) + { + /* Save point to constained point ... if button 3 down */ + if(bevent->button == 3) + { + find_grid_pos(&point,&point,FALSE); + } + } } else { if(selvals.opts.snap2grid) - find_grid_pos(&point,&point); - + { + if(bevent->button == 3) + { + find_grid_pos(&point,&point,FALSE); + } + else + { + find_grid_pos(&point,&point,FALSE); + } + } object_start(&point,bevent->state & GDK_SHIFT_MASK); } break; - case GDK_BUTTON_RELEASE: bevent = (GdkEventButton *) event; point.x = bevent->x; @@ -3376,7 +4991,7 @@ gfig_preview_events ( GtkWidget *widget, if(selvals.opts.snap2grid) - find_grid_pos(&point,&point); + find_grid_pos(&point,&point,bevent->button == 3); /* Still got shift down ?*/ if(selvals.otype >= MOVE_OBJ) @@ -3389,7 +5004,14 @@ gfig_preview_events ( GtkWidget *widget, object_operation_end(&point,bevent->state & GDK_SHIFT_MASK); } else - object_end(&point,bevent->state & GDK_SHIFT_MASK); + { + if(obj_creating) + { + object_end(&point,bevent->state & GDK_SHIFT_MASK); + } + else + break; + } /* make small preview reflect changes ?*/ list_button_update(current_obj); @@ -3402,7 +5024,7 @@ gfig_preview_events ( GtkWidget *widget, point.y = mevent->y; if(selvals.opts.snap2grid) - find_grid_pos(&point,&point); + find_grid_pos(&point,&point,mevent->state & GDK_BUTTON3_MASK); if(selvals.otype >= MOVE_OBJ) { @@ -3413,6 +5035,7 @@ gfig_preview_events ( GtkWidget *widget, point.y = gfig_invscale_y(point.y); } object_operation(&point,mevent->state & GDK_SHIFT_MASK); + gfig_pos_update(point.x,point.y); return FALSE; } @@ -3420,9 +5043,22 @@ gfig_preview_events ( GtkWidget *widget, { object_update(&point); } - + gfig_pos_update(point.x,point.y); + break; + case GDK_KEY_PRESS: + if((tmp_show_single = obj_show_single) != -1) + { + obj_show_single = -1; + draw_grid_clear(NULL,NULL); /*Args not used */ + } + break; + case GDK_KEY_RELEASE: + if(tmp_show_single != -1) + { + obj_show_single = tmp_show_single; + draw_grid_clear(NULL,NULL); /*Args not used */ + } break; - default: break; } @@ -3792,7 +5428,7 @@ list_button_update(GFIGOBJ *obj) pic_obj = (GFIGOBJ *)obj; gtk_widget_draw(pic_preview, NULL); drawing_pic = TRUE; - draw_objects(pic_obj->obj_list); + draw_objects(pic_obj->obj_list,FALSE); drawing_pic = FALSE; } @@ -3869,6 +5505,7 @@ load_button_press(GtkWidget *widget, return(FALSE); } +#if 0 /* NOT USED */ static void mygimp_edit_clear(gint32 image_ID, gint32 layer_ID) { @@ -3881,6 +5518,7 @@ mygimp_edit_clear(gint32 image_ID, gint32 layer_ID) PARAM_END); gimp_destroy_params (return_vals, nreturn_vals); } +#endif /* NOT USED */ static gint32 mygimp_layer_copy (gint32 layer_ID) @@ -3964,6 +5602,28 @@ paint_layer_new(gchar *new_name) gimp_drawable_fill(layer_id,fill_type); } + +static void +paint_layer_fill() +{ + GParam *return_vals; + int nreturn_vals; + + return_vals = gimp_run_procedure ("gimp_bucket_fill", + &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_INT32, selopt.fill_type, /* Fill mode */ + PARAM_INT32, 0, /* NORMAL */ + PARAM_FLOAT, (gdouble)selopt.fill_opacity, /* Fill opacity */ + PARAM_FLOAT, (gdouble)0.0, /* threshold - ignored */ + PARAM_INT32, 0, /* Sample merged - ignored */ + PARAM_FLOAT, (gdouble)0.0, /* x - ignored */ + PARAM_FLOAT, (gdouble)0.0, /* y - ignored */ + PARAM_END); + + gimp_destroy_params (return_vals, nreturn_vals); +} static void gfig_paint_callback(GtkWidget *widget, @@ -3974,6 +5634,7 @@ gfig_paint_callback(GtkWidget *widget, gchar buf[128]; gint count; gint ccount = 0; + BRUSHDESC *bdesc; objs = current_obj->obj_list; @@ -3982,36 +5643,55 @@ gfig_paint_callback(GtkWidget *widget, gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_widget),(gfloat)0.0); #endif /* 0 */ + /* Set the brush up */ + bdesc = gtk_object_get_user_data (GTK_OBJECT (brush_page_pw)); + + if(bdesc) + mygimp_brush_set(bdesc->bname); + while(objs) { - sprintf(buf,"Gfig Layer %d",layer_count++); - switch(selvals.onlayers) + if(ccount == obj_show_single || obj_show_single == -1) { - case SINGLE_LAYER: - if(layer_count == 1) + sprintf(buf,"Gfig Layer %d",layer_count++); + + if(selvals.painttype != PAINT_SELECTION_TYPE) { - if(selvals.onlayerbg == LAYER_COPY_BG) - paint_layer_copy(buf); - else - paint_layer_new(buf); + switch(selvals.onlayers) + { + case SINGLE_LAYER: + if(layer_count == 1) + { + if(selvals.onlayerbg == LAYER_COPY_BG) + paint_layer_copy(buf); + else + paint_layer_new(buf); + } + break; + case MULTI_LAYER: + if(selvals.onlayerbg == LAYER_COPY_BG) + paint_layer_copy(buf); + else + paint_layer_new(buf); + break; + case ORIGINAL_LAYER: + /* Just use the given layer */ + break; + default: + g_warning("Error in onlayers val %d\n",selvals.onlayers); + break; + } } - break; - case MULTI_LAYER: - if(selvals.onlayerbg == LAYER_COPY_BG) - paint_layer_copy(buf); - else - paint_layer_new(buf); - break; - case ORIGINAL_LAYER: - /* Just use the given layer */ - break; - default: - g_warning("Error in onlayers val %d\n",selvals.onlayers); - break; + + objs->obj->paintfunc(objs->obj); + + /* Fill layer if required */ + if(selvals.painttype == PAINT_SELECTION_FILL_TYPE + && selopt.fill_when == FILL_EACH) + paint_layer_fill(); } - objs->obj->paintfunc(objs->obj); objs = objs->next; ccount++; @@ -4021,9 +5701,98 @@ gfig_paint_callback(GtkWidget *widget, #endif /* 0 */ } + /* Fill layer if required */ + if(selvals.painttype == PAINT_SELECTION_FILL_TYPE + && selopt.fill_when == FILL_AFTER) + paint_layer_fill(); + gimp_displays_flush(); } +static gint +reload_button_press(GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + refill_cache(); + draw_grid_clear(widget,data); + + return(FALSE); +} + +static gint +about_button_press(GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + /* Display the about box */ + GtkWidget *window = NULL; + GtkWidget *label; + GtkWidget *button; + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *pm; + + window = gtk_dialog_new (); + + gtk_window_set_title (GTK_WINDOW (window), "About"); + gtk_container_border_width (GTK_CONTAINER (window), 0); + + button = gtk_button_new_with_label ("OK"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) ok_warn_window, + window); + + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0); + gtk_widget_grab_default (button); + gtk_widget_show (button); + + /* Bits and bobs */ + pm = gfig_new_pixmap(window,rulers_comp_xpm); + gtk_widget_show(pm); + + hbox = gtk_hbox_new(FALSE,1); + gtk_widget_show(hbox); + + vbox = gtk_vbox_new(FALSE,1); + gtk_widget_show(vbox); + + gtk_box_pack_start (GTK_BOX (hbox), pm, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), hbox, TRUE, TRUE, 0); + + label = gtk_label_new("Gfig - GIMP plug-in"); + gtk_misc_set_padding (GTK_MISC (label), 2, 2); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + + label = gtk_label_new("Release 0.95"); + gtk_misc_set_padding (GTK_MISC (label), 2, 2); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + + label = gtk_label_new("Andy Thomas"); + gtk_misc_set_padding (GTK_MISC (label), 2, 2); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + + label = gtk_label_new("Email alt@picnic.demon.co.uk"); + gtk_misc_set_padding (GTK_MISC (label), 2, 2); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + + label = gtk_label_new("http://www.picnic.demon.co.uk/"); + gtk_misc_set_padding (GTK_MISC (label), 2, 2); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + + gtk_widget_show (window); + + return(FALSE); +} + + static gint save_button_press(GtkWidget *widget, GdkEventButton *event, @@ -4062,7 +5831,7 @@ new_gfig_obj(gchar * name) new_list_item = gfig_list_add(gfig); - obj_creating = tmp_line = NULL; + tmp_bezier = obj_creating = tmp_line = NULL; /* Redraw areas */ update_draw_area(gfig_preview,NULL); @@ -4300,6 +6069,9 @@ new_obj_2edit(GFIGOBJ *obj) /* Point at this one */ current_obj = obj; + /* Show all objects to start with */ + obj_show_single = -1; + /* Change options */ update_options(old_current); @@ -4438,14 +6210,18 @@ static void gfig_op_menu_create(GtkWidget *window) { GtkWidget *menu_item; +#if 0 GtkAcceleratorTable *accelerator_table; +#endif /* 0 */ gfig_op_menu = gtk_menu_new(); +#if 0 accelerator_table = gtk_accelerator_table_new(); gtk_menu_set_accelerator_table(GTK_MENU(gfig_op_menu), accelerator_table); gtk_window_add_accelerator_table(GTK_WINDOW(window),accelerator_table); +#endif /* 0 */ save_menu_item = menu_item = gtk_menu_item_new_with_label("Save"); gtk_menu_append(GTK_MENU(gfig_op_menu),menu_item); @@ -4455,9 +6231,11 @@ gfig_op_menu_create(GtkWidget *window) (GtkSignalFunc)gfig_save_menu_callback, NULL); +#if 0 gtk_widget_install_accelerator(menu_item, accelerator_table, "activate",'S',0); +#endif /* 0 */ menu_item = gtk_menu_item_new_with_label("Save as..."); gtk_menu_append(GTK_MENU(gfig_op_menu),menu_item); @@ -4465,9 +6243,12 @@ gfig_op_menu_create(GtkWidget *window) gtk_signal_connect(GTK_OBJECT(menu_item),"activate", (GtkSignalFunc)gfig_rename_menu_callback, NULL); + +#if 0 gtk_widget_install_accelerator(menu_item, accelerator_table, "activate",'A',0); +#endif /* 0 */ menu_item = gtk_menu_item_new_with_label("Copy"); gtk_menu_append(GTK_MENU(gfig_op_menu),menu_item); @@ -4475,9 +6256,12 @@ gfig_op_menu_create(GtkWidget *window) gtk_signal_connect(GTK_OBJECT(menu_item),"activate", (GtkSignalFunc)gfig_copy_menu_callback, NULL); + +#if 0 gtk_widget_install_accelerator(menu_item, accelerator_table, "activate",'C',0); +#endif /* 0 */ menu_item = gtk_menu_item_new_with_label("Edit"); gtk_menu_append(GTK_MENU(gfig_op_menu),menu_item); @@ -4485,9 +6269,12 @@ gfig_op_menu_create(GtkWidget *window) gtk_signal_connect(GTK_OBJECT(menu_item),"activate", (GtkSignalFunc)gfig_edit_menu_callback, NULL); + +#if 0 gtk_widget_install_accelerator(menu_item, accelerator_table, "activate",'E',0); +#endif /* 0 */ } @@ -4627,6 +6414,8 @@ gfig_scale_update_fp(GtkAdjustment *adjustment, gdouble *value) } } +#if 0 /* NOT USED */ + static void gfig_entry_update_fp(GtkWidget *widget, gdouble *value) { @@ -4649,6 +6438,7 @@ gfig_entry_update_fp(GtkWidget *widget, gdouble *value) } } } +#endif /* NOT USED */ /* Use to toggle the toggles */ static void @@ -4713,13 +6503,18 @@ dialog_update_preview(void) if(!selvals.showimage) { - memset(preview_row,-1,preview_width*img_bpp); + memset(preview_row,-1,preview_width*4); for (y = 0; y < preview_height; y++) { gtk_preview_draw_row(GTK_PREVIEW(gfig_preview), preview_row, 0, y, preview_width); } return; } + if(!pv_cache) + { + refill_cache(); + } + for (y = 0; y < preview_height; y++) { if ((y / CHECK_SIZE) & 1) { @@ -4810,10 +6605,13 @@ inside_sqr(GdkPoint *cpnt, GdkPoint *testpnt) /* return the new position in the passed point */ static void -find_grid_pos(GdkPoint *p,GdkPoint *gp) +find_grid_pos(GdkPoint *p,GdkPoint *gp,guint is_butt3) { gint16 x = p->x; gint16 y = p->y; + static GdkPoint cons_pnt; + static gdouble cons_radius; + static gdouble cons_ang; if(selvals.opts.gridtype == RECT_GRID) { @@ -4825,6 +6623,19 @@ find_grid_pos(GdkPoint *p,GdkPoint *gp) gp->x = (x/selvals.opts.gridspacing)*selvals.opts.gridspacing; gp->y = (y/selvals.opts.gridspacing)*selvals.opts.gridspacing; + + if(is_butt3) + { + if(abs(gp->x - cons_pnt.x) < abs(gp->y - cons_pnt.y)) + gp->x = cons_pnt.x; + else + gp->y = cons_pnt.y; + } + else + { + /* Store the point since might be used later */ + cons_pnt = *gp; /* Structure copy */ + } } else { @@ -4867,6 +6678,25 @@ find_grid_pos(GdkPoint *p,GdkPoint *gp) #endif /* DEBUG */ gp->x = (gint)rint((rounded_radius*cos(rounded_angle))) + preview_width/2; gp->y = -(gint)rint((rounded_radius*sin(rounded_angle))) + preview_height/2; + + if(is_butt3) + { + if(fabs(rounded_angle - cons_ang) > ang_grid/2) + { + gp->x = (gint)rint((cons_radius*cos(rounded_angle))) + preview_width/2; + gp->y = -(gint)rint((cons_radius*sin(rounded_angle))) + preview_height/2; + } + else + { + gp->x = (gint)rint((rounded_radius*cos(cons_ang))) + preview_width/2; + gp->y = -(gint)rint((rounded_radius*sin(cons_ang))) + preview_height/2; + } + } + else + { + cons_radius = rounded_radius; + cons_ang = rounded_angle; + } } } @@ -4915,7 +6745,7 @@ draw_grid_clear(GtkWidget *widget, /* wipe slate and start again */ dialog_update_preview(); draw_grid(widget,data); - draw_objects(current_obj->obj_list); + draw_objects(current_obj->obj_list,TRUE); gtk_widget_draw(gfig_preview, NULL); gdk_flush(); } @@ -4955,6 +6785,12 @@ toggle_obj_type(GtkWidget *widget, /* Mem leak */ obj_creating = NULL; tmp_line = NULL; + tmp_bezier = NULL; + + if((DOBJTYPE)data < MOVE_OBJ) + { + obj_show_single = -1; /* Cancel select preview */ + } /* Update draw areas */ update_draw_area(gfig_preview,NULL); /* And preview */ @@ -4970,6 +6806,9 @@ toggle_obj_type(GtkWidget *widget, case ELLIPSE: case ARC: case POLY: + case STAR: + case SPIRAL: + case BEZIER: default: ctype = GDK_CROSSHAIR; break; @@ -5078,9 +6917,9 @@ draw_grid_sq(GdkGC *drawgc) } static GdkGC * -gfig_get_grid_gc(GtkWidget *w) +gfig_get_grid_gc(GtkWidget *w, gint gctype) { - switch(grid_gc_type) + switch(gctype) { case GFIG_BLACK_GC: return(w->style->black_gc); @@ -5123,7 +6962,7 @@ draw_grid(GtkWidget *widget, } if(selvals.opts.drawgrid) - drawgc = gfig_get_grid_gc(gfig_preview); + drawgc = gfig_get_grid_gc(gfig_preview,grid_gc_type); else return; @@ -5224,6 +7063,7 @@ gfig_clear_callback (GtkWidget *widget, current_obj->obj_list = NULL; obj_creating = NULL; tmp_line = NULL; + tmp_bezier = NULL; update_draw_area(gfig_preview,NULL); /* And preview */ list_button_update(current_obj); @@ -5239,7 +7079,7 @@ gfig_undo_callback (GtkWidget *widget, /* Free current objects an reinstate previous */ free_all_objs(current_obj->obj_list); current_obj->obj_list = NULL; - obj_creating = NULL; + tmp_bezier = tmp_line = obj_creating = NULL; current_obj->obj_list = undo_table[undo_water_mark]; undo_water_mark--; /* Update the screen */ @@ -5353,7 +7193,7 @@ static gint gfig_invscale_y(gint y) { if(!selvals.scaletoimage) - return((gint)(y*(scale_x_factor))); + return((gint)(y*(scale_y_factor))); else return(y); } @@ -5379,7 +7219,7 @@ scale_to_xy(gdouble *list,gint size) for (i = 0 ; i < size*2 ; i +=2) { list[i] *= (org_scale_x_factor/scale_x_factor); - list[i + 1] *= (org_scale_x_factor/scale_y_factor); + list[i + 1] *= (org_scale_y_factor/scale_y_factor); } } @@ -5471,6 +7311,7 @@ get_nearest_objs(GFIGOBJ * obj,GdkPoint *pnt) /* Nearest object to given point or NULL */ DALLOBJS *all; DOBJECT *test_obj; + gint count = 0; if(!obj) return(NULL); @@ -5481,11 +7322,13 @@ get_nearest_objs(GFIGOBJ * obj,GdkPoint *pnt) { test_obj = all->obj; - if(scan_obj_points(test_obj->points,pnt)) - { - return(test_obj); - } + if(count == obj_show_single || obj_show_single == -1) + if(scan_obj_points(test_obj->points,pnt)) + { + return(test_obj); + } all = all->next; + count++; } return(NULL); } @@ -5531,6 +7374,13 @@ remove_obj_from_list(GFIGOBJ *obj,DOBJECT *del_obj) free_one_obj(del_obj); g_free(all); + + if(obj_show_single != -1) + { + /* We've just deleted the only visible one */ + draw_grid_clear(NULL,NULL); /*Args not used */ + obj_show_single = -1; /* Show all again */ + } return; } prev_all = all; @@ -5849,14 +7699,66 @@ d_paint_line(DOBJECT *obj) scale_to_xy(&line_pnts[0],i/2); /* One go */ - return_vals = gimp_run_procedure ("gimp_paintbrush", &nreturn_vals, - PARAM_IMAGE, gfig_image, - PARAM_DRAWABLE, gfig_drawable, - PARAM_FLOAT,(gdouble)selvals.brushfade, - PARAM_INT32,seg_count*2*GFIG_LCC,/* GIMP BUG should be 2!!!!*/ - PARAM_FLOATARRAY, &line_pnts[0], - PARAM_END); - + if(selvals.painttype == PAINT_BRUSH_TYPE) + { + switch(selvals.brshtype) + { + case BRUSH_BRUSH_TYPE: + return_vals = gimp_run_procedure ("gimp_paintbrush", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_FLOAT,(gdouble)selvals.brushfade, + PARAM_INT32,seg_count*2*GFIG_LCC,/* GIMP BUG should be 2!!!!*/ + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_PENCIL_TYPE: + return_vals = gimp_run_procedure ("gimp_pencil", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_INT32,seg_count*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_AIRBRUSH_TYPE: + return_vals = gimp_run_procedure ("gimp_airbrush", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_FLOAT,(gdouble)selvals.airbrushpressure, + PARAM_INT32,seg_count*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_PATTERN_TYPE: + return_vals = gimp_run_procedure ("gimp_clone", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_DRAWABLE, gfig_drawable, + PARAM_INT32, 1, + PARAM_FLOAT,(gdouble)0.0, + PARAM_FLOAT,(gdouble)0.0, + PARAM_INT32,seg_count*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + default: + break; + } + } + else + { + /* We want to do a selection */ + return_vals = gimp_run_procedure ("gimp_free_select", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_INT32,seg_count*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_INT32,selopt.type, + PARAM_INT32,selopt.antia, + PARAM_INT32,selopt.feather, + PARAM_FLOAT,(gdouble)selopt.feather_radius, + PARAM_END); + } + gimp_destroy_params (return_vals, nreturn_vals); g_free(line_pnts); @@ -6263,14 +8165,18 @@ d_paint_circle(DOBJECT *obj) PARAM_FLOAT,dpnts[1], PARAM_FLOAT,dpnts[2], PARAM_FLOAT,dpnts[3], - PARAM_INT32, 2, /* REPLACE */ - PARAM_INT32, 1, /* Antialiasing */ - PARAM_INT32, 0, /* Feather */ - PARAM_FLOAT,(gdouble)0.0, /* Feather options */ + PARAM_INT32,selopt.type, + PARAM_INT32,selopt.antia, + PARAM_INT32,selopt.feather, + PARAM_FLOAT,(gdouble)selopt.feather_radius, PARAM_END); gimp_destroy_params (return_vals, nreturn_vals); + /* Is selection all we need ? */ + if(selvals.painttype == PAINT_SELECTION_TYPE) + return; + return_vals = gimp_run_procedure ("gimp_edit_stroke", &nreturn_vals, PARAM_IMAGE, gfig_image, PARAM_DRAWABLE, gfig_drawable, @@ -6656,14 +8562,67 @@ d_paint_approx_ellipse(DOBJECT *obj) scale_to_xy(&line_pnts[0],i/2); /* One go */ - return_vals = gimp_run_procedure ("gimp_paintbrush", &nreturn_vals, - PARAM_IMAGE, gfig_image, - PARAM_DRAWABLE, gfig_drawable, - PARAM_FLOAT,(gdouble)selvals.brushfade, - PARAM_INT32,(i/2)*2*GFIG_LCC,/* GIMP BUG should be 2!!!!*/ - PARAM_FLOATARRAY, &line_pnts[0], - PARAM_END); - + if(selvals.painttype == PAINT_BRUSH_TYPE) + { + switch(selvals.brshtype) + { + case BRUSH_BRUSH_TYPE: + return_vals = gimp_run_procedure ("gimp_paintbrush", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_FLOAT,(gdouble)selvals.brushfade, + PARAM_INT32,(i/2)*2*GFIG_LCC,/* GIMP BUG should be 2!!!!*/ + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_PENCIL_TYPE: + return_vals = gimp_run_procedure ("gimp_pencil", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_AIRBRUSH_TYPE: + return_vals = gimp_run_procedure ("gimp_airbrush", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_FLOAT,(gdouble)selvals.airbrushpressure, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_PATTERN_TYPE: + return_vals = gimp_run_procedure ("gimp_clone", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_DRAWABLE, gfig_drawable, + PARAM_INT32, 1, + PARAM_FLOAT,(gdouble)0.0, + PARAM_FLOAT,(gdouble)0.0, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + default: + break; + } + } + else + { + /* We want to do a selection */ + return_vals = gimp_run_procedure ("gimp_free_select", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_INT32,selopt.type, + PARAM_INT32,selopt.antia, + PARAM_INT32,selopt.feather, + PARAM_FLOAT,(gdouble)selopt.feather_radius, + PARAM_END); + + } + gimp_destroy_params (return_vals, nreturn_vals); g_free(line_pnts); @@ -6694,7 +8653,7 @@ d_paint_ellipse(DOBJECT *obj) if(selvals.approxcircles) { #ifdef DEBUG - printf("Painting ellispe as polygon\n"); + printf("Painting ellipse as polygon\n"); #endif /* DEBUG */ d_paint_approx_ellipse(obj); return; @@ -6743,14 +8702,18 @@ d_paint_ellipse(DOBJECT *obj) PARAM_FLOAT,dpnts[1], PARAM_FLOAT,dpnts[2], PARAM_FLOAT,dpnts[3], - PARAM_INT32, 2, /* REPLACE */ - PARAM_INT32, 1, /* Antialiasing */ - PARAM_INT32, 0, /* Feather */ - PARAM_FLOAT,(gdouble)0.0, /* Feather options */ + PARAM_INT32,selopt.type, + PARAM_INT32,selopt.antia, + PARAM_INT32,selopt.feather, + PARAM_FLOAT,(gdouble)selopt.feather_radius, PARAM_END); gimp_destroy_params (return_vals, nreturn_vals); + /* Is selection all we need ? */ + if(selvals.painttype == PAINT_SELECTION_TYPE) + return; + return_vals = gimp_run_procedure ("gimp_edit_stroke", &nreturn_vals, PARAM_IMAGE, gfig_image, PARAM_DRAWABLE, gfig_drawable, @@ -7047,7 +9010,7 @@ d_draw_poly(DOBJECT *obj) if(!radius_pnt) { - g_warning("Internal error in ploygon - no vertice point \n"); + g_warning("Internal error in polygon - no vertice point \n"); return; } @@ -7235,14 +9198,66 @@ d_paint_poly(DOBJECT *obj) scale_to_xy(&line_pnts[0],i/2); /* One go */ - return_vals = gimp_run_procedure ("gimp_paintbrush", &nreturn_vals, - PARAM_IMAGE, gfig_image, - PARAM_DRAWABLE, gfig_drawable, - PARAM_FLOAT,(gdouble)selvals.brushfade, - PARAM_INT32,(i/2)*2*GFIG_LCC,/* GIMP BUG should be 2!!!!*/ - PARAM_FLOATARRAY, &line_pnts[0], - PARAM_END); - + if(selvals.painttype == PAINT_BRUSH_TYPE) + { + switch(selvals.brshtype) + { + case BRUSH_BRUSH_TYPE: + return_vals = gimp_run_procedure ("gimp_paintbrush", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_FLOAT,(gdouble)selvals.brushfade, + PARAM_INT32,(i/2)*2*GFIG_LCC,/* GIMP BUG should be 2!!!!*/ + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_PENCIL_TYPE: + return_vals = gimp_run_procedure ("gimp_pencil", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_AIRBRUSH_TYPE: + return_vals = gimp_run_procedure ("gimp_airbrush", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_FLOAT,(gdouble)selvals.airbrushpressure, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_PATTERN_TYPE: + return_vals = gimp_run_procedure ("gimp_clone", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_DRAWABLE, gfig_drawable, + PARAM_INT32, 1, + PARAM_FLOAT,(gdouble)0.0, + PARAM_FLOAT,(gdouble)0.0, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + default: + break; + } + } + else + { + /* We want to do a selection */ + return_vals = gimp_run_procedure ("gimp_free_select", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_INT32,selopt.type, + PARAM_INT32,selopt.antia, + PARAM_INT32,selopt.feather, + PARAM_FLOAT,(gdouble)selopt.feather_radius, + PARAM_END); + } + gimp_destroy_params (return_vals, nreturn_vals); g_free(line_pnts); @@ -7350,6 +9365,136 @@ d_poly2lines(DOBJECT *obj) obj->drawfunc(obj); } +static void +d_star2lines(DOBJECT *obj) +{ + /* first point center */ + /* Next point is radius */ + gint seg_count = 0; + DOBJPOINTS * center_pnt; + DOBJPOINTS * outer_radius_pnt; + DOBJPOINTS * inner_radius_pnt; + gint16 shift_x; + gint16 shift_y; + gdouble ang_grid; + gdouble ang_loop; + gdouble outer_radius; + gdouble inner_radius; + gdouble offset_angle; + gint loop; + GdkPoint first_pnt,last_pnt; + gint first = 1; + + g_assert(obj != NULL); + +#ifdef DEBUG + printf("d_star2lines --- \n"); +#endif /* DEBUG */ + + /* count - add one to close polygon */ + seg_count = 2*(gint)obj->type_data + 1; + + center_pnt = obj->points; + + if(!center_pnt) + return; /* no-line */ + + /* Undraw it to start with - removes control points */ + obj->drawfunc(obj); + + /* NULL out these points free later */ + obj->points = NULL; + + /* Go around all the points creating line points */ + /* Next point defines the radius */ + outer_radius_pnt = center_pnt->next; /* this defines the vetices */ + + if(!outer_radius_pnt) + { + g_warning("Internal error in star - no outer vertice point \n"); + return; + } + + inner_radius_pnt = outer_radius_pnt->next; /* this defines the vetices */ + + if(!inner_radius_pnt) + { + g_warning("Internal error in star - no inner vertice point \n"); + return; + } + + shift_x = outer_radius_pnt->pnt.x - center_pnt->pnt.x; + shift_y = outer_radius_pnt->pnt.y - center_pnt->pnt.y; + + outer_radius = sqrt((shift_x*shift_x) + (shift_y*shift_y)); + + /* Lines */ + ang_grid = 2*M_PI/(2.0*(gdouble)(gint)obj->type_data); + offset_angle = atan2(shift_y,shift_x); + + shift_x = inner_radius_pnt->pnt.x - center_pnt->pnt.x; + shift_y = inner_radius_pnt->pnt.y - center_pnt->pnt.y; + + inner_radius = sqrt((shift_x*shift_x) + (shift_y*shift_y)); + + for(loop = 0 ; loop < 2*(gint)obj->type_data ; loop++) + { + gdouble lx,ly; + GdkPoint calc_pnt; + + ang_loop = (gdouble)loop * ang_grid + offset_angle; + + if(loop%2) + { + lx = inner_radius * cos(ang_loop); + ly = inner_radius * sin(ang_loop); + } + else + { + lx = outer_radius * cos(ang_loop); + ly = outer_radius * sin(ang_loop); + } + + calc_pnt.x = (gint)rint(lx + center_pnt->pnt.x); + calc_pnt.y = (gint)rint(ly + center_pnt->pnt.y); + + if(!first) + { + if(calc_pnt.x == last_pnt.x && calc_pnt.y == last_pnt.y) + { + continue; + } + } + + d_pnt_add_line(obj,calc_pnt.x,calc_pnt.y,0); + + last_pnt.x = calc_pnt.x; + last_pnt.y = calc_pnt.y; + + if(first) + { + first_pnt.x = calc_pnt.x; + first_pnt.y = calc_pnt.y; + first = 0; + } + } + + d_pnt_add_line(obj,first_pnt.x,first_pnt.y,0); + /* Free old pnts */ + d_delete_dobjpoints(center_pnt); + + /* hey were a line now */ + obj->type = LINE; + obj->drawfunc = (DOBJFUNC)d_draw_line; + obj->loadfunc = (DOBJFUNC)d_load_line; + obj->savefunc = (DOBJSAVEFUNC)d_save_line; + obj->paintfunc = (DOBJFUNC)d_paint_line; + obj->copyfunc = (DOBJFUNC)d_copy_line; + + /* draw it + control pnts */ + obj->drawfunc(obj); +} + DOBJECT * d_copy_poly(DOBJECT * obj) { @@ -7969,7 +10114,8 @@ d_paint_arc(DOBJECT *obj) seg_count = 360; /* Should make a smoth-ish curve */ /* The second 2* to get around bug in GIMP */ - line_pnts = g_malloc0(GFIG_LCC*(2*seg_count + 1)*sizeof(gdouble)); + /* +3 because we MIGHT do pie selection */ + line_pnts = g_malloc0(GFIG_LCC*(2*seg_count + 3)*sizeof(gdouble)); /* Lines */ ang_grid = 2*M_PI/(gdouble)360; @@ -8021,13 +10167,72 @@ d_paint_arc(DOBJECT *obj) reverse_pairs_list(&line_pnts[0],i/2); /* One go */ - return_vals = gimp_run_procedure ("gimp_paintbrush", &nreturn_vals, - PARAM_IMAGE, gfig_image, - PARAM_DRAWABLE, gfig_drawable, - PARAM_FLOAT,(gdouble)selvals.brushfade, - PARAM_INT32,(i/2)*2*GFIG_LCC,/* GIMP BUG should be 2!!!!*/ - PARAM_FLOATARRAY, &line_pnts[0], - PARAM_END); + if(selvals.painttype == PAINT_BRUSH_TYPE) + { + switch(selvals.brshtype) + { + case BRUSH_BRUSH_TYPE: + return_vals = gimp_run_procedure ("gimp_paintbrush", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_FLOAT,(gdouble)selvals.brushfade, + PARAM_INT32,(i/2)*2*GFIG_LCC,/* GIMP BUG should be 2!!!!*/ + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_PENCIL_TYPE: + return_vals = gimp_run_procedure ("gimp_pencil", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_AIRBRUSH_TYPE: + return_vals = gimp_run_procedure ("gimp_airbrush", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_FLOAT,(gdouble)selvals.airbrushpressure, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_PATTERN_TYPE: + return_vals = gimp_run_procedure ("gimp_clone", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_DRAWABLE, gfig_drawable, + PARAM_INT32, 1, + PARAM_FLOAT,(gdouble)0.0, + PARAM_FLOAT,(gdouble)0.0, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + default: + break; + } + } + else + { + if(selopt.as_pie) + { + /* Add center point - cause a pie like selection... */ + line_pnts[i++] = center_pnt.x; + line_pnts[i++] = center_pnt.y; + } + + /* We want to do a selection */ + return_vals = gimp_run_procedure ("gimp_free_select", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_INT32,selopt.type, + PARAM_INT32,selopt.antia, + PARAM_INT32,selopt.feather, + PARAM_FLOAT,(gdouble)selopt.feather_radius, + PARAM_END); + } gimp_destroy_params (return_vals, nreturn_vals); @@ -8165,6 +10370,1663 @@ d_arc_end(GdkPoint *pnt, gint shift_down) } } +/*XXXXXXXXXXXXXXXXXXXXXXX*/ +/* Star shape */ + +void +d_save_star(DOBJECT * obj, FILE *to) +{ + DOBJPOINTS * spnt; + + spnt = obj->points; + + if(!spnt) + return; /* End-of-line */ + + fprintf(to,"\n"); + + while(spnt) + { + fprintf(to,"%d %d\n", + (gint)spnt->pnt.x, + (gint)spnt->pnt.y); + spnt = spnt->next; + } + + fprintf(to,"\n"); + fprintf(to,"%d\n\n",(gint)obj->type_data); + fprintf(to,"\n"); +} + +/* Load a circle from the specified stream */ + +DOBJECT * +d_load_star(FILE *from) +{ + DOBJECT *new_obj = NULL; + gint xpnt; + gint ypnt; + gchar buf[MAX_LOAD_LINE]; + +#ifdef DEBUG + printf("Load star called\n"); +#endif /* DEBUG */ + + while(get_line(buf,MAX_LOAD_LINE,from,0)) + { + if(sscanf(buf,"%d %d",&xpnt,&ypnt) != 2) + { + /* Must be the end */ + if(!strcmp("",buf)) + { + gint nsides = 3; + /* Number of sides - data item */ + if(!new_obj) + { + g_warning("[%d] Internal load error while loading star (extra area)", + line_no); + return(NULL); + } + get_line(buf,MAX_LOAD_LINE,from,0); + if(sscanf(buf,"%d",&nsides) != 1) + { + g_warning("[%d] Internal load error while loading star (extra area scanf)", + line_no); + return(NULL); + } + new_obj->type_data = (gpointer)nsides; + get_line(buf,MAX_LOAD_LINE,from,0); + if(strcmp("",buf)) + { + g_warning("[%d] Internal load error while loading star", + line_no); + return(NULL); + } + /* Go around and read the last line */ + continue; + } + else if(strcmp("",buf)) + { + g_warning("[%d] Internal load error while loading star", + line_no); + return(NULL); + } + return(new_obj); + } + + if(!new_obj) + new_obj = d_new_star(xpnt,ypnt); + else + d_pnt_add_line(new_obj,xpnt,ypnt,-1); + } + return(new_obj); +} + +static void +d_draw_star(DOBJECT *obj) +{ + DOBJPOINTS * center_pnt; + DOBJPOINTS * outer_radius_pnt; + DOBJPOINTS * inner_radius_pnt; + gint16 shift_x; + gint16 shift_y; + gdouble ang_grid; + gdouble ang_loop; + gdouble outer_radius; + gdouble inner_radius; + gdouble offset_angle; + gint loop; + GdkPoint start_pnt; + GdkPoint first_pnt; + gint do_line = 0; + + center_pnt = obj->points; + + if(!center_pnt) + return; /* End-of-line */ + + /* First point is the center */ + /* Just draw a control point around it */ + + draw_sqr(¢er_pnt->pnt); + + /* Next point defines the radius */ + outer_radius_pnt = center_pnt->next; /* this defines the vetices */ + + if(!outer_radius_pnt) + { + g_warning("Internal error in star - no outer vertice point \n"); + return; + } + + inner_radius_pnt = outer_radius_pnt->next; /* this defines the vetices */ + + if(!inner_radius_pnt) + { + g_warning("Internal error in star - no inner vertice point \n"); + return; + } + + /* Other control points */ + draw_sqr(&outer_radius_pnt->pnt); + draw_sqr(&inner_radius_pnt->pnt); + + /* Have center and radius - draw star */ + + shift_x = outer_radius_pnt->pnt.x - center_pnt->pnt.x; + shift_y = outer_radius_pnt->pnt.y - center_pnt->pnt.y; + + outer_radius = sqrt((shift_x*shift_x) + (shift_y*shift_y)); + + /* Lines */ + ang_grid = 2*M_PI/(2.0*(gdouble)(gint)obj->type_data); + offset_angle = atan2(shift_y,shift_x); + + shift_x = inner_radius_pnt->pnt.x - center_pnt->pnt.x; + shift_y = inner_radius_pnt->pnt.y - center_pnt->pnt.y; + + inner_radius = sqrt((shift_x*shift_x) + (shift_y*shift_y)); + + for(loop = 0 ; loop < 2*(gint)obj->type_data ; loop++) + { + gdouble lx,ly; + GdkPoint calc_pnt; + + ang_loop = (gdouble)loop * ang_grid + offset_angle; + + if(loop%2) + { + lx = inner_radius * cos(ang_loop); + ly = inner_radius * sin(ang_loop); + } + else + { + lx = outer_radius * cos(ang_loop); + ly = outer_radius * sin(ang_loop); + } + + calc_pnt.x = (gint)rint(lx + center_pnt->pnt.x); + calc_pnt.y = (gint)rint(ly + center_pnt->pnt.y); + + if(do_line) + { + + /* Miss out points that come to the same location */ + if(calc_pnt.x == start_pnt.x && calc_pnt.y == start_pnt.y) + continue; + + if(drawing_pic) + { + gdk_draw_line(pic_preview->window, + pic_preview->style->black_gc, + adjust_pic_coords(calc_pnt.x, + preview_width), + adjust_pic_coords(calc_pnt.y, + preview_height), + adjust_pic_coords(start_pnt.x, + preview_width), + adjust_pic_coords(start_pnt.y, + preview_height)); + } + else + { + gdk_draw_line(gfig_preview->window, + gfig_gc, + gfig_scale_x(calc_pnt.x), + gfig_scale_y(calc_pnt.y), + gfig_scale_x(start_pnt.x), + gfig_scale_y(start_pnt.y)); + } + } + else + { + do_line = 1; + first_pnt.x = calc_pnt.x; + first_pnt.y = calc_pnt.y; + } + start_pnt.x = calc_pnt.x; + start_pnt.y = calc_pnt.y; + } + + /* Join up */ + if(drawing_pic) + { + gdk_draw_line(pic_preview->window, + pic_preview->style->black_gc, + adjust_pic_coords(first_pnt.x,preview_width), + adjust_pic_coords(first_pnt.y,preview_width), + adjust_pic_coords(start_pnt.x,preview_width), + adjust_pic_coords(start_pnt.y,preview_width)); + } + else + { + gdk_draw_line(gfig_preview->window, + gfig_gc, + gfig_scale_x(first_pnt.x), + gfig_scale_y(first_pnt.y), + gfig_scale_x(start_pnt.x), + gfig_scale_y(start_pnt.y)); + } +} + +static void +d_paint_star(DOBJECT *obj) +{ + /* first point center */ + /* Next point is radius */ + gdouble *line_pnts; + GParam *return_vals; + gint nreturn_vals; + gint seg_count = 0; + gint i = 0; + DOBJPOINTS * center_pnt; + DOBJPOINTS * outer_radius_pnt; + DOBJPOINTS * inner_radius_pnt; + gint16 shift_x; + gint16 shift_y; + gdouble ang_grid; + gdouble ang_loop; + gdouble outer_radius; + gdouble inner_radius; + + gdouble offset_angle; + gint loop; + GdkPoint first_pnt,last_pnt; + gint first = 1; + + g_assert(obj != NULL); + + /* count - add one to close polygon */ + seg_count = 2*(gint)obj->type_data + 1; + + center_pnt = obj->points; + + if(!center_pnt || !seg_count) + return; /* no-line */ + + /* The second 2* to get around bug in GIMP */ + line_pnts = g_malloc0(GFIG_LCC*(2*seg_count + 1)*sizeof(gdouble)); + + /* Go around all the points drawing a line from one to the next */ + /* Next point defines the radius */ + outer_radius_pnt = center_pnt->next; /* this defines the vetices */ + + if(!outer_radius_pnt) + { + g_warning("Internal error in star - no outer vertice point \n"); + return; + } + + inner_radius_pnt = outer_radius_pnt->next; /* this defines the vetices */ + + if(!inner_radius_pnt) + { + g_warning("Internal error in star - no inner vertice point \n"); + return; + } + + shift_x = outer_radius_pnt->pnt.x - center_pnt->pnt.x; + shift_y = outer_radius_pnt->pnt.y - center_pnt->pnt.y; + + outer_radius = sqrt((shift_x*shift_x) + (shift_y*shift_y)); + + /* Lines */ + ang_grid = 2*M_PI/(2.0*(gdouble)(gint)obj->type_data); + offset_angle = atan2(shift_y,shift_x); + + shift_x = inner_radius_pnt->pnt.x - center_pnt->pnt.x; + shift_y = inner_radius_pnt->pnt.y - center_pnt->pnt.y; + + inner_radius = sqrt((shift_x*shift_x) + (shift_y*shift_y)); + + for(loop = 0 ; loop < 2*(gint)obj->type_data ; loop++) + { + gdouble lx,ly; + GdkPoint calc_pnt; + + ang_loop = (gdouble)loop * ang_grid + offset_angle; + + if(loop%2) + { + lx = inner_radius * cos(ang_loop); + ly = inner_radius * sin(ang_loop); + } + else + { + lx = outer_radius * cos(ang_loop); + ly = outer_radius * sin(ang_loop); + } + + calc_pnt.x = (gint)rint(lx + center_pnt->pnt.x); + calc_pnt.y = (gint)rint(ly + center_pnt->pnt.y); + + /* Miss out duped pnts */ + if(!first) + { + if(calc_pnt.x == last_pnt.x && calc_pnt.y == last_pnt.y) + { + continue; + } + } + + last_pnt.x = line_pnts[i++] = calc_pnt.x; + last_pnt.y = line_pnts[i++] = calc_pnt.y; + + if(first) + { + first_pnt.x = calc_pnt.x; + first_pnt.y = calc_pnt.y; + first = 0; + } + } + + line_pnts[i++] = first_pnt.x; + line_pnts[i++] = first_pnt.y; + + /* Reverse line if approp */ + if(selvals.reverselines) + reverse_pairs_list(&line_pnts[0],i/2); + + /* Scale before drawing */ + if(selvals.scaletoimage) + scale_to_original_xy(&line_pnts[0],i/2); + else + scale_to_xy(&line_pnts[0],i/2); + + /* One go */ + /* One go */ + if(selvals.painttype == PAINT_BRUSH_TYPE) + { + switch(selvals.brshtype) + { + case BRUSH_BRUSH_TYPE: + return_vals = gimp_run_procedure ("gimp_paintbrush", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_FLOAT,(gdouble)selvals.brushfade, + PARAM_INT32,(i/2)*2*GFIG_LCC,/* GIMP BUG should be 2!!!!*/ + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_PENCIL_TYPE: + return_vals = gimp_run_procedure ("gimp_pencil", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_AIRBRUSH_TYPE: + return_vals = gimp_run_procedure ("gimp_airbrush", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_FLOAT,(gdouble)selvals.airbrushpressure, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_PATTERN_TYPE: + return_vals = gimp_run_procedure ("gimp_clone", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_DRAWABLE, gfig_drawable, + PARAM_INT32, 1, + PARAM_FLOAT,(gdouble)0.0, + PARAM_FLOAT,(gdouble)0.0, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + default: + break; + } + } + else + { + /* We want to do a selection */ + return_vals = gimp_run_procedure ("gimp_free_select", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_INT32,selopt.type, + PARAM_INT32,selopt.antia, + PARAM_INT32,selopt.feather, + PARAM_FLOAT,(gdouble)selopt.feather_radius, + PARAM_END); + + } + + gimp_destroy_params (return_vals, nreturn_vals); + + g_free(line_pnts); +} + +DOBJECT * +d_copy_star(DOBJECT * obj) +{ + DOBJECT *np; + +#if DEBUG + printf("Copy star\n"); +#endif /*DEBUG*/ + if(!obj) + return(NULL); + + g_assert(obj->type == STAR); + + np = d_new_star(obj->points->pnt.x,obj->points->pnt.y); + + np->points->next = d_copy_dobjpoints(obj->points->next); + + np->type_data = obj->type_data; + +#if DEBUG + printf("Done star copy\n"); +#endif /*DEBUG*/ + return(np); +} + +DOBJECT * +d_new_star(gint x, gint y) +{ + DOBJECT *nobj; + DOBJPOINTS *npnt; + + /* Get new object and starting point */ + + /* Start point */ + npnt = (DOBJPOINTS *)g_malloc0(sizeof(DOBJPOINTS)); + +#if DEBUG + printf("New STAR start at (%x,%x)\n",x,y); +#endif /* DEBUG */ + npnt->pnt.x = x; + npnt->pnt.y = y; + + nobj = (DOBJECT *)g_malloc0(sizeof(DOBJECT)); + + nobj->type = STAR; + nobj->type_data = (gpointer)3; /* Default to three sides 6 points*/ + nobj->points = npnt; + nobj->drawfunc = (DOBJFUNC)d_draw_star; + nobj->loadfunc = (DOBJFUNC)d_load_star; + nobj->savefunc = (DOBJSAVEFUNC)d_save_star; + nobj->paintfunc = (DOBJFUNC)d_paint_star; + nobj->copyfunc = (DOBJFUNC)d_copy_star; + + return(nobj); +} + +void +d_update_star(GdkPoint *pnt) +{ + DOBJPOINTS *center_pnt, *inner_pnt, *outer_pnt; + gint saved_cnt_pnt = selvals.opts.showcontrol; + + /* Undraw last one then draw new one */ + center_pnt = obj_creating->points; + + if(!center_pnt) + return; /* No points */ + + /* Leave the first pnt alone - + * Edge point defines "radius" + * Only undraw if already have edge point. + */ + + /* Hack - turn off cnt points in draw routine + * Looking back over the other update routines I could + * use this trick again and cut down on code size! + */ + + + if((outer_pnt = center_pnt->next)) + { + /* Undraw */ + inner_pnt = outer_pnt->next; + draw_circle(&inner_pnt->pnt); + draw_circle(&outer_pnt->pnt); + selvals.opts.showcontrol = 0; + d_draw_star(obj_creating); + outer_pnt->pnt.x = pnt->x; + outer_pnt->pnt.y = pnt->y; + inner_pnt->pnt.x = pnt->x + (2*(center_pnt->pnt.x - pnt->x))/3; + inner_pnt->pnt.y = pnt->y + (2*(center_pnt->pnt.y - pnt->y))/3; + } + else + { + /* Radius is a few pixels away */ + /* First edge point */ + d_pnt_add_line(obj_creating,pnt->x,pnt->y,-1); + outer_pnt = center_pnt->next; + /* Inner radius */ + d_pnt_add_line(obj_creating, + pnt->x + (2*(center_pnt->pnt.x - pnt->x))/3, + pnt->y + (2*(center_pnt->pnt.y - pnt->y))/3, + -1); + inner_pnt = outer_pnt->next; + } + + /* draw it */ + selvals.opts.showcontrol = 0; + d_draw_star(obj_creating); + selvals.opts.showcontrol = saved_cnt_pnt; + + /* Realy draw the control points */ + draw_circle(&outer_pnt->pnt); + draw_circle(&inner_pnt->pnt); +} + +/* first point is center + * next defines the radius + */ + +void +d_star_start(GdkPoint *pnt,gint shift_down) +{ + gint16 x,y; + /* First is center point */ + obj_creating = d_new_star(x = pnt->x, y = pnt->y); + obj_creating->type_data = (gpointer)star_num_sides; +} + +void +d_star_end(GdkPoint *pnt, gint shift_down) +{ + draw_circle(pnt); + add_to_all_obj(current_obj,obj_creating); + obj_creating = NULL; +} + + +/* Spiral */ + +void +d_save_spiral(DOBJECT * obj, FILE *to) +{ + DOBJPOINTS * spnt; + + spnt = obj->points; + + if(!spnt) + return; /* End-of-line */ + + fprintf(to,"\n"); + + while(spnt) + { + fprintf(to,"%d %d\n", + (gint)spnt->pnt.x, + (gint)spnt->pnt.y); + spnt = spnt->next; + } + + fprintf(to,"\n"); + fprintf(to,"%d\n\n",(gint)obj->type_data); + fprintf(to,"\n"); + +} + +/* Load a spiral from the specified stream */ + +DOBJECT * +d_load_spiral(FILE *from) +{ + DOBJECT *new_obj = NULL; + gint xpnt; + gint ypnt; + gchar buf[MAX_LOAD_LINE]; + +#ifdef DEBUG + printf("Load spiral called\n"); +#endif /* DEBUG */ + + while(get_line(buf,MAX_LOAD_LINE,from,0)) + { + if(sscanf(buf,"%d %d",&xpnt,&ypnt) != 2) + { + /* Must be the end */ + if(!strcmp("",buf)) + { + gint nsides = 3; + /* Number of sides - data item */ + if(!new_obj) + { + g_warning("[%d] Internal load error while loading spiral (extra area)", + line_no); + return(NULL); + } + get_line(buf,MAX_LOAD_LINE,from,0); + if(sscanf(buf,"%d",&nsides) != 1) + { + g_warning("[%d] Internal load error while loading spiral (extra area scanf)", + line_no); + return(NULL); + } + new_obj->type_data = (gpointer)nsides; + get_line(buf,MAX_LOAD_LINE,from,0); + if(strcmp("",buf)) + { + g_warning("[%d] Internal load error while loading spiral", + line_no); + return(NULL); + } + /* Go around and read the last line */ + continue; + } + else if(strcmp("",buf)) + { + g_warning("[%d] Internal load error while loading spiral", + line_no); + return(NULL); + } + return(new_obj); + } + + if(!new_obj) + new_obj = d_new_spiral(xpnt,ypnt); + else + d_pnt_add_line(new_obj,xpnt,ypnt,-1); + } + return(new_obj); +} + +static void +d_draw_spiral(DOBJECT *obj) +{ + DOBJPOINTS * center_pnt; + DOBJPOINTS * radius_pnt; + gint16 shift_x; + gint16 shift_y; + gdouble ang_grid; + gdouble ang_loop; + gdouble radius; + gdouble offset_angle; + gdouble sp_cons; + gint loop; + GdkPoint start_pnt; + GdkPoint first_pnt; + gint do_line = 0; + gint clock_wise = 1; + + center_pnt = obj->points; + + if(!center_pnt) + return; /* End-of-line */ + + /* First point is the center */ + /* Just draw a control point around it */ + + draw_sqr(¢er_pnt->pnt); + + /* Next point defines the radius */ + radius_pnt = center_pnt->next; /* this defines the vetices */ + + if(!radius_pnt) + { + g_warning("Internal error in spiral - no vertice point \n"); + return; + } + + /* Other control point */ + draw_sqr(&radius_pnt->pnt); + + /* Have center and radius - draw spiral */ + + shift_x = radius_pnt->pnt.x - center_pnt->pnt.x; + shift_y = radius_pnt->pnt.y - center_pnt->pnt.y; + + radius = sqrt((shift_x*shift_x) + (shift_y*shift_y)); + + offset_angle = atan2(shift_y,shift_x); + + clock_wise = ((gint)obj->type_data)/(abs((gint)(obj->type_data))); + + if(offset_angle < 0) + offset_angle += 2*M_PI; + + sp_cons = radius/((gint)obj->type_data * 2 * M_PI + offset_angle); + /* Lines */ + ang_grid = 2.0*M_PI/(gdouble)180; + + + for(loop = 0 ; loop <= abs((gint)(obj->type_data)*180) + clock_wise*(gint)rint(offset_angle/ang_grid) ; loop++) + { + gdouble lx,ly; + GdkPoint calc_pnt; + + ang_loop = (gdouble)loop * ang_grid; + + lx = sp_cons * ang_loop * cos(ang_loop)*clock_wise; + ly = sp_cons * ang_loop * sin(ang_loop); + + calc_pnt.x = (gint)rint(lx + center_pnt->pnt.x); + calc_pnt.y = (gint)rint(ly + center_pnt->pnt.y); + + if(do_line) + { + + /* Miss out points that come to the same location */ + if(calc_pnt.x == start_pnt.x && calc_pnt.y == start_pnt.y) + continue; + + if(drawing_pic) + { + gdk_draw_line(pic_preview->window, + pic_preview->style->black_gc, + adjust_pic_coords(calc_pnt.x, + preview_width), + adjust_pic_coords(calc_pnt.y, + preview_height), + adjust_pic_coords(start_pnt.x, + preview_width), + adjust_pic_coords(start_pnt.y, + preview_height)); + } + else + { + gdk_draw_line(gfig_preview->window, + gfig_gc, + gfig_scale_x(calc_pnt.x), + gfig_scale_y(calc_pnt.y), + gfig_scale_x(start_pnt.x), + gfig_scale_y(start_pnt.y)); + } + } + else + { + do_line = 1; + first_pnt.x = calc_pnt.x; + first_pnt.y = calc_pnt.y; + } + start_pnt.x = calc_pnt.x; + start_pnt.y = calc_pnt.y; + } +} + +static void +d_paint_spiral(DOBJECT *obj) +{ + /* first point center */ + /* Next point is radius */ + gdouble *line_pnts; + GParam *return_vals; + gint nreturn_vals; + gint seg_count = 0; + gint i = 0; + DOBJPOINTS * center_pnt; + DOBJPOINTS * radius_pnt; + gint16 shift_x; + gint16 shift_y; + gdouble ang_grid; + gdouble ang_loop; + gdouble radius; + gdouble offset_angle; + gdouble sp_cons; + gint loop; + GdkPoint last_pnt; + gint clock_wise = 1; + + g_assert(obj != NULL); + + center_pnt = obj->points; + + if(!center_pnt) + return; /* no-line */ + + /* Go around all the points drawing a line from one to the next */ + + radius_pnt = center_pnt->next; /* this defines the vetices */ + + /* Have center and radius - get lines */ + shift_x = radius_pnt->pnt.x - center_pnt->pnt.x; + shift_y = radius_pnt->pnt.y - center_pnt->pnt.y; + + radius = sqrt((shift_x*shift_x) + (shift_y*shift_y)); + + clock_wise = ((gint)obj->type_data)/(abs((gint)(obj->type_data))); + + offset_angle = atan2(shift_y,shift_x); + + if(offset_angle < 0) + offset_angle += 2*M_PI; + + sp_cons = radius/((gint)obj->type_data * 2 * M_PI + offset_angle); + /* Lines */ + ang_grid = 2.0*M_PI/(gdouble)180; + + + /* count - */ + seg_count = abs((gint)(obj->type_data)*180) + clock_wise*(gint)rint(offset_angle/ang_grid); + + /* The second 2* to get around bug in GIMP */ + line_pnts = g_malloc0(GFIG_LCC*(2*seg_count + 3)*sizeof(gdouble)); + + for(loop = 0 ; loop <= seg_count; loop++) + { + gdouble lx,ly; + GdkPoint calc_pnt; + + ang_loop = (gdouble)loop * ang_grid; + + lx = sp_cons * ang_loop * cos(ang_loop)*clock_wise; + ly = sp_cons * ang_loop * sin(ang_loop); + + calc_pnt.x = (gint)rint(lx + center_pnt->pnt.x); + calc_pnt.y = (gint)rint(ly + center_pnt->pnt.y); + + /* Miss out duped pnts */ + if(!loop) + { + if(calc_pnt.x == last_pnt.x && calc_pnt.y == last_pnt.y) + { + continue; + } + } + + last_pnt.x = line_pnts[i++] = calc_pnt.x; + last_pnt.y = line_pnts[i++] = calc_pnt.y; + } + + /* Reverse line if approp */ + if(selvals.reverselines) + reverse_pairs_list(&line_pnts[0],i/2); + + /* Scale before drawing */ + if(selvals.scaletoimage) + scale_to_original_xy(&line_pnts[0],i/2); + else + scale_to_xy(&line_pnts[0],i/2); + + /* One go */ + /* One go */ + if(selvals.painttype == PAINT_BRUSH_TYPE) + { + switch(selvals.brshtype) + { + case BRUSH_BRUSH_TYPE: + return_vals = gimp_run_procedure ("gimp_paintbrush", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_FLOAT,(gdouble)selvals.brushfade, + PARAM_INT32,(i/2)*2*GFIG_LCC,/* GIMP BUG should be 2!!!!*/ + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_PENCIL_TYPE: + return_vals = gimp_run_procedure ("gimp_pencil", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_AIRBRUSH_TYPE: + return_vals = gimp_run_procedure ("gimp_airbrush", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_FLOAT,(gdouble)selvals.airbrushpressure, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_PATTERN_TYPE: + return_vals = gimp_run_procedure ("gimp_clone", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_DRAWABLE, gfig_drawable, + PARAM_INT32, 1, + PARAM_FLOAT,(gdouble)0.0, + PARAM_FLOAT,(gdouble)0.0, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + default: + break; + } + } + else + { + /* We want to do a selection */ + return_vals = gimp_run_procedure ("gimp_free_select", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_INT32,selopt.type, + PARAM_INT32,selopt.antia, + PARAM_INT32,selopt.feather, + PARAM_FLOAT,(gdouble)selopt.feather_radius, + PARAM_END); + + } + + gimp_destroy_params (return_vals, nreturn_vals); + + g_free(line_pnts); +} + +DOBJECT * +d_copy_spiral(DOBJECT * obj) +{ + DOBJECT *np; + +#if DEBUG + printf("Copy spiral\n"); +#endif /*DEBUG*/ + if(!obj) + return(NULL); + + g_assert(obj->type == SPIRAL); + + np = d_new_spiral(obj->points->pnt.x,obj->points->pnt.y); + + np->points->next = d_copy_dobjpoints(obj->points->next); + + np->type_data = obj->type_data; + +#if DEBUG + printf("Done spiral copy\n"); +#endif /*DEBUG*/ + return(np); +} + +DOBJECT * +d_new_spiral(gint x, gint y) +{ + DOBJECT *nobj; + DOBJPOINTS *npnt; + + /* Get new object and starting point */ + + /* Start point */ + npnt = (DOBJPOINTS *)g_malloc0(sizeof(DOBJPOINTS)); + +#if DEBUG + printf("New SPIRAL start at (%x,%x)\n",x,y); +#endif /* DEBUG */ + npnt->pnt.x = x; + npnt->pnt.y = y; + + nobj = (DOBJECT *)g_malloc0(sizeof(DOBJECT)); + + nobj->type = SPIRAL; + nobj->type_data = (gpointer)4; /* Default to four turns */ + nobj->points = npnt; + nobj->drawfunc = (DOBJFUNC)d_draw_spiral; + nobj->loadfunc = (DOBJFUNC)d_load_spiral; + nobj->savefunc = (DOBJSAVEFUNC)d_save_spiral; + nobj->paintfunc = (DOBJFUNC)d_paint_spiral; + nobj->copyfunc = (DOBJFUNC)d_copy_spiral; + + return(nobj); +} + +void +d_update_spiral(GdkPoint *pnt) +{ + DOBJPOINTS *center_pnt, *edge_pnt; + gint saved_cnt_pnt = selvals.opts.showcontrol; + + /* Undraw last one then draw new one */ + center_pnt = obj_creating->points; + + if(!center_pnt) + return; /* No points */ + + /* Leave the first pnt alone - + * Edge point defines "radius" + * Only undraw if already have edge point. + */ + + /* Hack - turn off cnt points in draw routine + * Looking back over the other update routines I could + * use this trick again and cut down on code size! + */ + + + if((edge_pnt = center_pnt->next)) + { + /* Undraw */ + draw_circle(&edge_pnt->pnt); + selvals.opts.showcontrol = 0; + d_draw_spiral(obj_creating); + + edge_pnt->pnt.x = pnt->x; + edge_pnt->pnt.y = pnt->y; + } + else + { + /* Radius is a few pixels away */ + /* First edge point */ + d_pnt_add_line(obj_creating,pnt->x,pnt->y,-1); + edge_pnt = center_pnt->next; + } + + /* draw it */ + selvals.opts.showcontrol = 0; + d_draw_spiral(obj_creating); + selvals.opts.showcontrol = saved_cnt_pnt; + + /* Realy draw the control points */ + draw_circle(&edge_pnt->pnt); +} + +/* first point is center + * next defines the radius + */ + +void +d_spiral_start(GdkPoint *pnt,gint shift_down) +{ + gint16 x,y; + /* First is center point */ + obj_creating = d_new_spiral(x = pnt->x, y = pnt->y); + obj_creating->type_data = (gpointer)(spiral_num_turns*((spiral_toggle == 0)?1:-1)); +} + +void +d_spiral_end(GdkPoint *pnt, gint shift_down) +{ + draw_circle(pnt); + add_to_all_obj(current_obj,obj_creating); + obj_creating = NULL; +} + +/* Stuff for bezier curves... */ + +void +d_save_bezier(DOBJECT * obj, FILE *to) +{ + DOBJPOINTS * spnt; + + spnt = obj->points; + + if(!spnt) + return; /* End-of-line */ + + fprintf(to,"\n"); + + while(spnt) + { + fprintf(to,"%d %d\n", + (gint)spnt->pnt.x, + (gint)spnt->pnt.y); + spnt = spnt->next; + } + + fprintf(to,"\n"); + fprintf(to,"%d\n\n",(gint)obj->type_data); + fprintf(to,"\n"); + +} + +/* Load a bezier from the specified stream */ + +DOBJECT * +d_load_bezier(FILE *from) +{ + DOBJECT *new_obj = NULL; + gint xpnt; + gint ypnt; + gchar buf[MAX_LOAD_LINE]; + +#ifdef DEBUG + printf("Load bezier called\n"); +#endif /* DEBUG */ + + while(get_line(buf,MAX_LOAD_LINE,from,0)) + { + if(sscanf(buf,"%d %d",&xpnt,&ypnt) != 2) + { + /* Must be the end */ + if(!strcmp("",buf)) + { + gint nsides = 3; + /* Number of sides - data item */ + if(!new_obj) + { + g_warning("[%d] Internal load error while loading bezier (extra area)", + line_no); + return(NULL); + } + get_line(buf,MAX_LOAD_LINE,from,0); + if(sscanf(buf,"%d",&nsides) != 1) + { + g_warning("[%d] Internal load error while loading bezier (extra area scanf)", + line_no); + return(NULL); + } + new_obj->type_data = (gpointer)nsides; + get_line(buf,MAX_LOAD_LINE,from,0); + if(strcmp("",buf)) + { + g_warning("[%d] Internal load error while loading bezier", + line_no); + return(NULL); + } + /* Go around and read the last line */ + continue; + } + else if(strcmp("",buf)) + { + g_warning("[%d] Internal load error while loading bezier", + line_no); + return(NULL); + } + return(new_obj); + } + + if(!new_obj) + new_obj = d_new_bezier(xpnt,ypnt); + else + d_pnt_add_line(new_obj,xpnt,ypnt,-1); + } + return(new_obj); +} + + +#define FP_PNT_MAX 10 + +static fp_pnt_cnt = 0; +static fp_pnt_chunk = 0; +gdouble *fp_pnt_pnts = NULL;; + + +static void +fp_pnt_start() +{ + fp_pnt_cnt = 0; +} + +/* Add a line segment to collection array */ +static void +fp_pnt_add(gdouble p1, gdouble p2, gdouble p3, gdouble p4) +{ + if(!fp_pnt_pnts) + { + fp_pnt_pnts = g_malloc0(FP_PNT_MAX*sizeof(gdouble)); + fp_pnt_chunk = 1; + } + + if(((fp_pnt_cnt+4)/FP_PNT_MAX) >= fp_pnt_chunk) + { + /* more space pls */ + fp_pnt_chunk++; + fp_pnt_pnts = (gdouble *)g_realloc(fp_pnt_pnts,sizeof(gdouble)*fp_pnt_chunk*FP_PNT_MAX); + } + + fp_pnt_pnts[fp_pnt_cnt++] = p1; + fp_pnt_pnts[fp_pnt_cnt++] = p2; + fp_pnt_pnts[fp_pnt_cnt++] = p3; + fp_pnt_pnts[fp_pnt_cnt++] = p4; +} + +static gdouble * +d_bz_get_array(gint *sz) +{ + *sz = fp_pnt_cnt; + return (fp_pnt_pnts); +} + + +static void +d_bz_line() +{ + gint i,x0,y0,x1,y1; + + g_assert((fp_pnt_cnt%4) == 0); + + for(i = 0 ; i < fp_pnt_cnt; i+=4) + { + x0 = (gint)fp_pnt_pnts[i]; + y0 = (gint)fp_pnt_pnts[i+1]; + x1 = (gint)fp_pnt_pnts[i+2]; + y1 = (gint)fp_pnt_pnts[i+3]; + + if(drawing_pic) + { + gdk_draw_line(pic_preview->window, + pic_preview->style->black_gc, + adjust_pic_coords((gint)x0, + preview_width), + adjust_pic_coords((gint)y0, + preview_height), + adjust_pic_coords((gint)x1, + preview_width), + adjust_pic_coords((gint)y1, + preview_height)); + } + else + { + gdk_draw_line(gfig_preview->window, + gfig_gc, + gfig_scale_x((gint)x0), + gfig_scale_y((gint)y0), + gfig_scale_x((gint)x1), + gfig_scale_y((gint)y1)); + } + } +} + +/* Return points to plot */ +/* Terminate by point with DBL_MAX,DBL_MAX */ +typedef gdouble (*fp_pnt)[2]; + +void +DrawBezier (gdouble (*points)[2], gint np, gdouble mid, gint depth) +{ + gint i,j,x0=0,y0=0,x1,y1; + fp_pnt left; + fp_pnt right; + + if (depth==0) /* draw polyline */ + { + for (i=0; i 0 && (x1 != x0 || y1 != y0)) + { + /* Add pnts up */ + fp_pnt_add((gdouble)x0,(gdouble)y0,(gdouble)x1,(gdouble)y1); + } + x0=x1; + y0=y1; + } + } + else /* subdivide control points at mid */ + { + left = (fp_pnt)g_new(gdouble,np*2); + right = (fp_pnt)g_new(gdouble,np*2); + for (i=0; i=1; j--) + { + for (i=0; i0) + { + DrawBezier(left,np,mid,depth-1); + DrawBezier(right,np,mid,depth-1); + g_free(left); + g_free(right); + } + } +} + + +static void +d_draw_bezier(DOBJECT *obj) +{ + DOBJPOINTS * spnt; + gint seg_count = 0; + gint i = 0; + gdouble (*line_pnts)[2]; + + spnt = obj->points; + + /* First count the number of points */ + + /* count */ + while(spnt) + { + seg_count++; + spnt = spnt->next; + } + + spnt = obj->points; + + if(!spnt || !seg_count) + return; /* no-line */ + + /* The second *2 to get around bug in GIMP */ + line_pnts = (fp_pnt)g_malloc0(GFIG_LCC*(2*seg_count + 1)*sizeof(gdouble)); + + /* Go around all the points drawing a line from one to the next */ + while(spnt) + { + draw_sqr(&spnt->pnt); + line_pnts[i][0] = spnt->pnt.x; + line_pnts[i++][1] = spnt->pnt.y; + spnt = spnt->next; + } + + /* Generate an array of doubles which are the control points */ + + if(!drawing_pic && bezier_line_frame && tmp_bezier) + { + fp_pnt_start(); + DrawBezier(line_pnts,seg_count,0.5,0); + d_bz_line(); + } + + fp_pnt_start(); + DrawBezier(line_pnts,seg_count,0.5,3); + d_bz_line(); + /*bezier4(line_pnts,seg_count,20);*/ + + g_free(line_pnts); +} + +static void +d_paint_bezier(DOBJECT *obj) +{ + gdouble *line_pnts; + gdouble (*bz_line_pnts)[2]; + DOBJPOINTS * spnt; + gint seg_count = 0; + + GParam *return_vals; + gint nreturn_vals; + gint i=0; + + spnt = obj->points; + + /* First count the number of points */ + + /* count */ + while(spnt) + { + seg_count++; + spnt = spnt->next; + } + + spnt = obj->points; + + if(!spnt || !seg_count) + return; /* no-line */ + + /* The second *2 to get around bug in GIMP */ + bz_line_pnts = (fp_pnt)g_malloc0(GFIG_LCC*(2*seg_count + 1)*sizeof(gdouble)); + + /* Go around all the points drawing a line from one to the next */ + while(spnt) + { + bz_line_pnts[i][0] = spnt->pnt.x; + bz_line_pnts[i++][1] = spnt->pnt.y; + spnt = spnt->next; + } + + fp_pnt_start(); + DrawBezier(bz_line_pnts,seg_count,0.5,5); + line_pnts = d_bz_get_array(&i); + + /* Reverse line if approp */ + if(selvals.reverselines) + reverse_pairs_list(&line_pnts[0],i/2); + + /* Scale before drawing */ + if(selvals.scaletoimage) + scale_to_original_xy(&line_pnts[0],i/2); + else + scale_to_xy(&line_pnts[0],i/2); + + if(selvals.painttype == PAINT_BRUSH_TYPE) + { + switch(selvals.brshtype) + { + case BRUSH_BRUSH_TYPE: + return_vals = gimp_run_procedure ("gimp_paintbrush", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_FLOAT,(gdouble)selvals.brushfade, + PARAM_INT32,(i/2)*2*GFIG_LCC,/* GIMP BUG should be 2!!!!*/ + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_PENCIL_TYPE: + return_vals = gimp_run_procedure ("gimp_pencil", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_AIRBRUSH_TYPE: + return_vals = gimp_run_procedure ("gimp_airbrush", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_FLOAT,(gdouble)selvals.airbrushpressure, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + case BRUSH_PATTERN_TYPE: + return_vals = gimp_run_procedure ("gimp_clone", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_DRAWABLE, gfig_drawable, + PARAM_DRAWABLE, gfig_drawable, + PARAM_INT32, 1, + PARAM_FLOAT,(gdouble)0.0, + PARAM_FLOAT,(gdouble)0.0, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_END); + break; + default: + break; + } + } + else + { + /* We want to do a selection */ + return_vals = gimp_run_procedure ("gimp_free_select", &nreturn_vals, + PARAM_IMAGE, gfig_image, + PARAM_INT32,(i/2)*2, + PARAM_FLOATARRAY, &line_pnts[0], + PARAM_INT32,selopt.type, + PARAM_INT32,selopt.antia, + PARAM_INT32,selopt.feather, + PARAM_FLOAT,(gdouble)selopt.feather_radius, + PARAM_END); + + } + + gimp_destroy_params (return_vals, nreturn_vals); + + g_free(bz_line_pnts); + /* Don't free line_pnts - may need again */ +} + +DOBJECT * +d_copy_bezier(DOBJECT * obj) +{ + DOBJECT *np; + +#if DEBUG + printf("Copy bezier\n"); +#endif /*DEBUG*/ + if(!obj) + return(NULL); + + g_assert(obj->type == BEZIER); + + np = d_new_bezier(obj->points->pnt.x,obj->points->pnt.y); + + np->points->next = d_copy_dobjpoints(obj->points->next); + + np->type_data = obj->type_data; + +#if DEBUG + printf("Done bezier copy\n"); +#endif /*DEBUG*/ + return(np); +} + +DOBJECT * +d_new_bezier(gint x, gint y) +{ + DOBJECT *nobj; + DOBJPOINTS *npnt; + + /* Get new object and starting point */ + + /* Start point */ + npnt = (DOBJPOINTS *)g_malloc0(sizeof(DOBJPOINTS)); + +#if DEBUG + printf("New BEZIER start at (%x,%x)\n",x,y); +#endif /* DEBUG */ + npnt->pnt.x = x; + npnt->pnt.y = y; + + nobj = (DOBJECT *)g_malloc0(sizeof(DOBJECT)); + + nobj->type = BEZIER; + nobj->type_data = (gpointer)4; /* Default to four turns */ + nobj->points = npnt; + nobj->drawfunc = (DOBJFUNC)d_draw_bezier; + nobj->loadfunc = (DOBJFUNC)d_load_bezier; + nobj->savefunc = (DOBJSAVEFUNC)d_save_bezier; + nobj->paintfunc = (DOBJFUNC)d_paint_bezier; + nobj->copyfunc = (DOBJFUNC)d_copy_bezier; + + return(nobj); +} + +void +d_update_bezier(GdkPoint *pnt) +{ + DOBJPOINTS *s_pnt, *l_pnt; + gint saved_cnt_pnt = selvals.opts.showcontrol; + + g_assert(tmp_bezier != NULL); + + /* Undraw last one then draw new one */ + s_pnt = tmp_bezier->points; + + if(!s_pnt) + return; /* No points */ + + /* Hack - turn off cnt points in draw routine + */ + + if((l_pnt = s_pnt->next)) + { + /* Undraw */ + while(l_pnt->next) + { + l_pnt = l_pnt->next; + } + + draw_circle(&l_pnt->pnt); + selvals.opts.showcontrol = 0; + d_draw_bezier(tmp_bezier); + l_pnt->pnt.x = pnt->x; + l_pnt->pnt.y = pnt->y; + } + else + { + /* Radius is a few pixels away */ + /* First edge point */ + d_pnt_add_line(tmp_bezier,pnt->x,pnt->y,-1); + l_pnt = s_pnt->next; + } + + /* draw it */ + selvals.opts.showcontrol = 0; + d_draw_bezier(tmp_bezier); + selvals.opts.showcontrol = saved_cnt_pnt; + + /* Realy draw the control points */ + draw_circle(&l_pnt->pnt); +} + +/* first point is center + * next defines the radius + */ + +void +d_bezier_start(GdkPoint *pnt,gint shift_down) +{ + gint16 x,y; + /* First is center point */ + if(!tmp_bezier) + { + /* New curve */ + tmp_bezier = obj_creating = d_new_bezier(x = pnt->x, y = pnt->y); + } +} + +void +d_bezier_end(GdkPoint *pnt, gint shift_down) +{ + DOBJPOINTS *l_pnt; + + if(!tmp_bezier) + { + tmp_bezier = obj_creating; + } + + l_pnt = tmp_bezier->points->next; + + if(shift_down) + { + /* Undraw circle on last pnt */ + while(l_pnt->next) + { + l_pnt = l_pnt->next; + } + + if(l_pnt) + { + draw_circle(&l_pnt->pnt); + draw_sqr(&l_pnt->pnt); + + if(bezier_closed) + { + gint tmp_frame = bezier_line_frame; + /* if closed then add first point */ + d_draw_bezier(tmp_bezier); + d_pnt_add_line(tmp_bezier, + tmp_bezier->points->pnt.x, + tmp_bezier->points->pnt.y,-1); + /* Final has no frame */ + bezier_line_frame = 0; /* False */ + d_draw_bezier(tmp_bezier); + bezier_line_frame = tmp_frame; /* What is was */ + } + else if(bezier_line_frame) + { + d_draw_bezier(tmp_bezier); + bezier_line_frame = 0; /* False */ + d_draw_bezier(tmp_bezier); + bezier_line_frame = 1; /* What is was */ + } + + add_to_all_obj(current_obj,obj_creating); + } + + /* small mem leak if !l_pnt ? */ + tmp_bezier = NULL; + obj_creating = NULL; + } + else + { + if(!tmp_bezier->points->next) + { + draw_circle(&tmp_bezier->points->pnt); + draw_sqr(&tmp_bezier->points->pnt); + } + + d_draw_bezier(tmp_bezier); + d_pnt_add_line(tmp_bezier,pnt->x,pnt->y,-1); + d_draw_bezier(tmp_bezier); + } +} + /* copy objs */ DALLOBJS * @@ -8204,12 +12066,20 @@ draw_one_obj(DOBJECT * obj) } void -draw_objects(DALLOBJS * objs) +draw_objects(DALLOBJS * objs,gint show_single) { + /* Show_single - only one object to draw Unless shift + * is down in whcih case show all. + */ + + gint count = 0; + while(objs) { - draw_one_obj(objs->obj); + if(!show_single || count == obj_show_single || obj_show_single == -1) + draw_one_obj(objs->obj); objs = objs->next; + count++; } } @@ -8272,17 +12142,41 @@ object_operation_start(GdkPoint *pnt,gint shift_down) if(!operation_obj) return;/* None to work on */ + setup_undo(); switch(selvals.otype) { case MOVE_OBJ: + if(operation_obj->type == BEZIER) + { + d_draw_bezier(operation_obj); + tmp_bezier = operation_obj; + d_draw_bezier(operation_obj); + } break; case MOVE_POINT: - /* If shift is down the break into sep lines */ - if(operation_obj->type == POLY && shift_down) + if(operation_obj->type == BEZIER) { - d_poly2lines(operation_obj); + d_draw_bezier(operation_obj); + tmp_bezier = operation_obj; + d_draw_bezier(operation_obj); + } + /* If shift is down the break into sep lines */ + if((operation_obj->type == POLY + || operation_obj->type == STAR) + && shift_down) + { + switch(operation_obj->type) + { + case POLY: + d_poly2lines(operation_obj); + break; + case STAR: + d_star2lines(operation_obj); + break; + default: + } /* Re calc which object point we are lookin at */ scan_obj_points(operation_obj->points,pnt); } @@ -8316,6 +12210,13 @@ object_operation_start(GdkPoint *pnt,gint shift_down) void object_operation_end(GdkPoint *pnt,gint shift_down) { + if(selvals.otype != DEL_OBJ && operation_obj && operation_obj->type == BEZIER) + { + d_draw_bezier(operation_obj); + tmp_bezier = NULL; /* use as switch */ + d_draw_bezier(operation_obj); + } + operation_obj = NULL; if(move_all_pnt) @@ -8327,6 +12228,8 @@ object_operation_end(GdkPoint *pnt,gint shift_down) /* Special case - if copying mode MUST be copy when button up received */ if(selvals.otype == MOVE_COPY_OBJ) selvals.otype = COPY_OBJ; + + } /* Move object around */ @@ -8357,6 +12260,9 @@ object_operation(GdkPoint *to_pnt,gint shift_down) case ELLIPSE: case POLY: case ARC: + case STAR: + case SPIRAL: + case BEZIER: do_move_obj(operation_obj,to_pnt); break; default: @@ -8373,6 +12279,9 @@ object_operation(GdkPoint *to_pnt,gint shift_down) case ELLIPSE: case POLY: case ARC: + case STAR: + case SPIRAL: + case BEZIER: do_move_obj_pnt(operation_obj,to_pnt); break; default: @@ -8427,6 +12336,20 @@ object_start(GdkPoint *pnt,gint shift_down) break; case ARC: d_arc_start(pnt,shift_down); + break; + case STAR: + draw_sqr(pnt); + d_star_start(pnt,shift_down); + break; + case SPIRAL: + draw_sqr(pnt); + d_spiral_start(pnt,shift_down); + break; + case BEZIER: + if(!tmp_bezier) + draw_sqr(pnt); + d_bezier_start(pnt,shift_down); + break; default: /* Internal error */ break; @@ -8459,9 +12382,21 @@ object_end(GdkPoint *pnt,gint shift_down) draw_sqr(pnt); d_poly_end(pnt,shift_down); break; + case STAR: + draw_sqr(pnt); + d_star_end(pnt,shift_down); + break; case ARC: draw_sqr(pnt); d_arc_end(pnt,shift_down); + break; + case SPIRAL: + draw_sqr(pnt); + d_spiral_end(pnt,shift_down); + break; + case BEZIER: + d_bezier_end(pnt,shift_down); + break; default: /* Internal error */ break; @@ -8493,9 +12428,18 @@ object_update(GdkPoint * pnt) case POLY: d_update_poly(pnt); break; + case STAR: + d_update_star(pnt); + break; case ARC: d_update_arc(pnt); break; + case SPIRAL: + d_update_spiral(pnt); + break; + case BEZIER: + d_update_bezier(pnt); + break; default: /* Internal error */ break; diff --git a/plug-ins/gflare-0.25.tar.gz b/plug-ins/gflare-0.25.tar.gz deleted file mode 100644 index e66134db33..0000000000 Binary files a/plug-ins/gflare-0.25.tar.gz and /dev/null differ diff --git a/plug-ins/gqbist/gqbist.c b/plug-ins/gqbist/gqbist.c index 98a3678099..2348406b01 100644 --- a/plug-ins/gqbist/gqbist.c +++ b/plug-ins/gqbist/gqbist.c @@ -32,6 +32,7 @@ * 1.7 added patch from Art Haas to make it compile with HP-UX, a small clean-up * 1.8 Dscho added transform file load/save, bug-fixes * 1.9 rewrote renderloop. + * 1.9a fixed a bug. */ #include @@ -258,7 +259,6 @@ void run(char *name, int nparams, GParam *param, int *nreturn_vals, GParam **ret gint sel_x1, sel_y1, sel_x2, sel_y2; gint img_height, img_width, img_bpp, img_has_alpha; - GParam values[1]; GDrawable *drawable; GRunModeType run_mode; GStatusType status; diff --git a/plug-ins/randomize/randomize.c b/plug-ins/randomize/randomize.c index 0e50f77851..151bdeb215 100644 --- a/plug-ins/randomize/randomize.c +++ b/plug-ins/randomize/randomize.c @@ -1,13 +1,15 @@ /**************************************************************************** - * This is a plugin for the GIMP v 0.99.8 or later. + * This is a plugin for the GIMP v 0.99.8 or later. Documentation is + * available at http://www.rru.com/~meo/gimp/ . * - * Copyright (C) 1997 Miles O'Neal + * Copyright (C) 1997 Miles O'Neal http://www.rru.com/~meo/ * Blur code Copyright (C) 1995 Spencer Kimball and Peter Mattis * GUI based on GTK code from: - * plasma (Copyright (C) 1996 Stephen Norris), - * oilify (Copyright (C) 1996 Torsten Martinsen), - * ripple (Copyright (C) 1997 Brian Degenhardt) and - * whirl (Copyright (C) 1997 Federico Mena Quintero). + * alienmap (Copyright (C) 1996, 1997 Daniel Cotting) + * plasma (Copyright (C) 1996 Stephen Norris), + * oilify (Copyright (C) 1996 Torsten Martinsen), + * ripple (Copyright (C) 1997 Brian Degenhardt) and + * whirl (Copyright (C) 1997 Federico Mena Quintero). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,8 +30,19 @@ /**************************************************************************** * Randomize: * - * randomize version 0.4c (17 May 1997, MEO) + * randomize version 1.0 (19 Oct 1997, MEO) * history + * 1.1 - 30 Nov 1997 MEO + * added tooltips + * 1.0 - 19 Nov 1997 MEO + * final cleanup for 1.0 GIMP release + * - added email and URL info for author + * - added doc URL info + * - final FCS comment cleanup + * - standardized constant strings + * - restored proper behavior when repeating + * - final UI labels + * - better help text (for when GIMP help arrives) * 0.5 - 20 May 1997 MEO * added seed initialization choices (current time or user value) * added randomization type to progress label @@ -99,7 +112,8 @@ * * TODO List * - * - Add a real melt function. + * - add a real melt function + * - split into multiple files ****************************************************************************/ #include @@ -107,23 +121,25 @@ #include "libgimp/gimp.h" #include "gtk/gtk.h" +/********************************* + * + * PLUGIN-SPECIFIC CONSTANTS + * + ********************************/ + /* - * Set this to 0 for faster processing, to 1 if for some + * Set this to 1 for faster processing, to 0 if for some * reason you want all functions to be subroutines */ -#define SUBS_NOT_DEFINES 0 +#define OPTIMIZE_SUBS 0 + /* * progress meter update frequency */ #define PROG_UPDATE_TIME ((row % 10) == 0) -#define RNDM_VERSION "Randomize 0.5" - -/********************************* - * - * LOCAL DATA - * - ********************************/ +#define PLUG_IN_NAME "plug_in_randomize" +#define RNDM_VERSION "Randomize 1.1" #define RNDM_BLUR 1 #define RNDM_PICK 2 @@ -136,6 +152,12 @@ #define ENTRY_WIDTH 75 #define SCALE_WIDTH 100 +/********************************* + * + * PLUGIN-SPECIFIC STRUCTURES AND DATA + * + ********************************/ + typedef struct { gint rndm_type; /* type of randomization to apply */ gdouble rndm_pct; /* likelihood of randomization (as %age) */ @@ -185,14 +207,15 @@ GPlugInInfo PLUG_IN_INFO = { }; static void randomize(GDrawable *drawable); -#if (SUBS_NOT_DEFINES == 1) -static void randomize_prepare_row( - GPixelRgn *pixel_rgn, - guchar *data, - int x, - int y, - int w -); + +#if (OPTIMIZE_SUBS == 0) + static void randomize_prepare_row( + GPixelRgn *pixel_rgn, + guchar *data, + int x, + int y, + int w + ); #endif static gint randomize_dialog(); @@ -224,6 +247,14 @@ static void randomize_text_update( gpointer data ); +static void set_tooltip( + GtkWidget *widget, + const char *tip +); + +static void setup_tooltips(); + +/************************************ Guts ***********************************/ MAIN() @@ -250,12 +281,18 @@ query() static int nargs = sizeof(args) / sizeof (args[0]); static int nreturn_vals = 0; - gimp_install_procedure("plug_in_randomize", - "Add a random factor to the image, by blurring, picking a nearby pixel, slurring (similar to melting), or just hurling on it.", - "This function randomly ``blurs'' the specified drawable, using either a 3x3 blur, picking a nearby pixel, slurring (cheezy melting), or hurling (spewing colors). The type and percentage are user selectable. Blurring is not supported for indexed images.", - "Miles O'Neal", - "Miles O'Neal, Spencer Kimball, Peter Mattis, Torsten Martinsen, Brian Degenhardt, Federico Mena Quintero", - "1995-1997", + const char *blurb = "Add a random factor to the image, by blurring, picking a nearby pixel, slurring (similar to melting), or just hurling on it."; + const char *help = "This function randomly ``blurs'' the specified drawable, using either a 3x3 blur, picking a nearby pixel, slurring (cheezy melting), or hurling (spewing colors). The type and percentage are user selectable. Blurring is not supported for indexed images."; + const char *author = "Miles O'Neal http://www.rru.com/~meo/"; + const char *copyrights = "Miles O'Neal, Spencer Kimball, Peter Mattis, Torsten Martinsen, Brian Degenhardt, Federico Mena Quintero, Stephen Norris, Daniel Cotting"; + const char *copyright_date = "1995-1997"; + + gimp_install_procedure(PLUG_IN_NAME, + (char *) blurb, + (char *) help, + (char *) author, + (char *) copyrights, + (char *) copyright_date, "/Filters/Distorts/Randomize", "RGB*, GRAY*, INDEXED*", PROC_PLUG_IN, @@ -292,12 +329,12 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals, GParam **return_vals) { - static GParam values[1]; GDrawable *drawable; GRunModeType run_mode; GStatusType status = STATUS_SUCCESS; /* assume the best! */ char *rndm_type_str = '\0'; char prog_label[32]; + static GParam values[1]; /* * Get the specified drawable, do standard initialization. */ @@ -321,7 +358,7 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals, */ case RUN_INTERACTIVE: FIX_INDEX_BLUR(); - gimp_get_data("plug_in_randomize", &pivals); + gimp_get_data(PLUG_IN_NAME, &pivals); if (!randomize_dialog()) /* return on Cancel */ return; break; @@ -355,7 +392,7 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals, * If we're running with the last set of values, get those values. */ case RUN_WITH_LAST_VALS: - gimp_get_data("plug_in_randomize", &pivals); + gimp_get_data(PLUG_IN_NAME, &pivals); break; /* * Hopefully we never get here! @@ -376,7 +413,7 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals, gimp_progress_init(prog_label); gimp_tile_cache_ntiles(2 * (drawable->width / gimp_tile_width() + 1)); /* - * Initialie the rand() function seed + * Initialize the rand() function seed */ if (pivals.seed_type == SEED_TIME) srand(time(NULL)); @@ -394,7 +431,7 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals, * If we use the dialog popup, set the data for future use. */ if (run_mode == RUN_INTERACTIVE) { - gimp_set_data("plug_in_randomize", &pivals, sizeof(RandomizeVals)); + gimp_set_data(PLUG_IN_NAME, &pivals, sizeof(RandomizeVals)); } } else { /* @@ -420,7 +457,7 @@ run(char *name, int nparams, GParam *param, int *nreturn_vals, * ********************************/ -#if (SUBS_NOT_DEFINES == 1) +#if (OPTIMIZE_SUBS == 0) static void randomize_prepare_row(GPixelRgn *pixel_rgn, guchar *data, int x, int y, int w) { @@ -474,7 +511,7 @@ randomize_prepare_row(GPixelRgn *pixel_rgn, guchar *data, int x, int y, int w) static void randomize(GDrawable *drawable) { - GPixelRgn srcPR, destPR; + GPixelRgn srcPR, destPR, destPR2, *sp, *dp, *tp; gint width, height; gint bytes; guchar *dest, *d; @@ -509,27 +546,32 @@ randomize(GDrawable *drawable) next_row = (guchar *) malloc((x2 - x1 + 2) * bytes); dest = (guchar *) malloc((x2 - x1) * bytes); - for (cnt = 1; cnt <= pivals.rndm_rcount; cnt++) { /* * initialize the pixel regions */ - gimp_pixel_rgn_init(&srcPR, drawable, 0, 0, width, height, FALSE, FALSE); - gimp_pixel_rgn_init(&destPR, drawable, 0, 0, width, height, TRUE, TRUE); + gimp_pixel_rgn_init(&srcPR, drawable, 0, 0, width, height, FALSE, FALSE); + gimp_pixel_rgn_init(&destPR, drawable, 0, 0, width, height, TRUE, TRUE); + gimp_pixel_rgn_init(&destPR2, drawable, 0, 0, width, height, TRUE, TRUE); + sp = &srcPR; + dp = &destPR; + tp = NULL; - pr = prev_row + bytes; - cr = cur_row + bytes; - nr = next_row + bytes; + pr = prev_row + bytes; + cr = cur_row + bytes; + nr = next_row + bytes; + + for (cnt = 1; cnt <= pivals.rndm_rcount; cnt++) { /* * prepare the first row and previous row */ - randomize_prepare_row(&srcPR, pr, x1, y1 - 1, (x2 - x1)); - randomize_prepare_row(&srcPR, cr, x1, y1, (x2 - x1)); + randomize_prepare_row(sp, pr, x1, y1 - 1, (x2 - x1)); + randomize_prepare_row(dp, cr, x1, y1, (x2 - x1)); /* * loop through the rows, applying the selected convolution */ for (row = y1; row < y2; row++) { /* prepare the next row */ - randomize_prepare_row(&srcPR, nr, x1, row + 1, (x2 - x1)); + randomize_prepare_row(sp, nr, x1, row + 1, (x2 - x1)); d = dest; for (col = 0; col < (x2 - x1) * bytes; col++) { @@ -621,7 +663,7 @@ randomize(GDrawable *drawable) * Save the modified row, shuffle the row pointers, and every * so often, update the progress meter. */ - gimp_pixel_rgn_set_row(&destPR, dest, x1, row, (x2 - x1)); + gimp_pixel_rgn_set_row(dp, dest, x1, row, (x2 - x1)); tmp = pr; pr = cr; @@ -631,6 +673,20 @@ randomize(GDrawable *drawable) if (PROG_UPDATE_TIME) gimp_progress_update((double) row / (double) (y2 - y1)); } +/* + * if we have more cycles to perform, swap the src and dest Pixel Regions + */ + if (cnt < pivals.rndm_rcount) { + if (tp != NULL) { + tp = dp; + dp = sp; + sp = tp; + } else { + tp = &srcPR; + sp = &destPR; + dp = &destPR2; + } + } } gimp_progress_update((double) 100); /* @@ -654,7 +710,7 @@ randomize(GDrawable *drawable) * ********************************/ -#define randomize_add_action_button(label, callback, dialog) \ +#define randomize_add_action_button(label, callback, dialog, tip) \ { \ GtkWidget *button; \ \ @@ -665,9 +721,10 @@ randomize(GDrawable *drawable) button, TRUE, TRUE, 0); \ gtk_widget_grab_default(button); \ gtk_widget_show(button); \ + set_tooltip(button, tip); \ } -#define randomize_add_radio_button(group, label, box, callback, value) \ +#define randomize_add_radio_button(group, label, box, callback, value, tip) \ { \ GtkWidget *toggle; \ \ @@ -679,6 +736,7 @@ randomize(GDrawable *drawable) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(toggle), *value); \ gtk_widget_show(toggle); \ gtk_widget_show(box); \ + set_tooltip(toggle, tip); \ } /********************************* @@ -723,13 +781,6 @@ randomize_dialog() gtk_window_position(GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE); gtk_signal_connect(GTK_OBJECT(dlg), "destroy", (GtkSignalFunc) randomize_close_callback, NULL); -/* - * Action area OK & Cancel buttons - */ - randomize_add_action_button("OK", - (GtkSignalFunc) randomize_ok_callback, dlg); - randomize_add_action_button("Cancel", - (GtkSignalFunc) randomize_cancel_callback, dlg); /* * Parameter settings * @@ -742,6 +793,17 @@ randomize_dialog() table = gtk_table_new(4, 2, FALSE); gtk_container_border_width(GTK_CONTAINER(table), 10); gtk_container_add(GTK_CONTAINER(frame), table); + gtk_widget_show(table); + setup_tooltips(table); +/* + * Action area OK & Cancel buttons + */ + randomize_add_action_button("OK", + (GtkSignalFunc) randomize_ok_callback, dlg, + "Accept settings and apply filter to image"); + randomize_add_action_button("Cancel", + (GtkSignalFunc) randomize_cancel_callback, dlg, + "Close plug-in without making any changes"); /* * Randomization Type - label & radio buttons */ @@ -761,22 +823,25 @@ randomize_dialog() */ if (! is_indexed_drawable) { randomize_add_radio_button(type_group, "Blur", toggle_hbox, - (GtkSignalFunc) randomize_toggle_update, &do_blur); + (GtkSignalFunc) randomize_toggle_update, &do_blur, + "Blur each pixel by averaging its value with those of its neighbors"); } /* * Hurl, Pick and Slur buttons */ randomize_add_radio_button(type_group, "Hurl", toggle_hbox, - (GtkSignalFunc) randomize_toggle_update, &do_hurl); + (GtkSignalFunc) randomize_toggle_update, &do_hurl, + "Hurl random colors onto pixels"); randomize_add_radio_button(type_group, "Pick", toggle_hbox, - (GtkSignalFunc) randomize_toggle_update, &do_pick); + (GtkSignalFunc) randomize_toggle_update, &do_pick, + "Pick at random from neighboring pixels"); randomize_add_radio_button(type_group, "Slur", toggle_hbox, - (GtkSignalFunc) randomize_toggle_update, &do_slur); - + (GtkSignalFunc) randomize_toggle_update, &do_slur, + "Simplistic melt"); /* * Randomization seed initialization controls */ - label = gtk_label_new("Seed"); + label = gtk_label_new("Randomization Seed"); gtk_misc_set_alignment(GTK_MISC (label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 5, 0); gtk_widget_show(label); @@ -791,7 +856,8 @@ randomize_dialog() * Time button */ randomize_add_radio_button(seed_group, "Current Time", seed_vbox, - (GtkSignalFunc) randomize_toggle_update, &do_time); + (GtkSignalFunc) randomize_toggle_update, &do_time, + "Seed random number generator from the current time - this guarantees a reasonable randomization"); /* * Box to hold seed user initialization controls */ @@ -801,10 +867,11 @@ randomize_dialog() /* * User button */ - randomize_add_radio_button(seed_group, "User", seed_hbox, - (GtkSignalFunc) randomize_toggle_update, &do_user); + randomize_add_radio_button(seed_group, "Other Value", seed_hbox, + (GtkSignalFunc) randomize_toggle_update, &do_user, + "Enable user-entered value for random number generator seed - this allows you to repeat a given \"random\" operation"); /* - * Randomization seed text + * Randomization seed number (text) */ entry = gtk_entry_new(); gtk_widget_set_usize(entry, ENTRY_WIDTH, 0); @@ -814,8 +881,8 @@ randomize_dialog() gtk_signal_connect(GTK_OBJECT(entry), "changed", (GtkSignalFunc) randomize_text_update, &pivals.rndm_seed); gtk_widget_show(entry); + set_tooltip(entry, "Value for seeding the random number generator"); gtk_widget_show(seed_hbox); - /* * Randomization percentage label & scale (1 to 100) */ @@ -837,6 +904,7 @@ randomize_dialog() (GtkSignalFunc) randomize_scale_update, &pivals.rndm_pct); gtk_widget_show(label); gtk_widget_show(scale); + set_tooltip(scale, "Percentage of pixels to be filtered"); /* * Repeat count label & scale (1 to 100) */ @@ -858,11 +926,11 @@ randomize_dialog() (GtkSignalFunc) randomize_scale_update, &pivals.rndm_rcount); gtk_widget_show(label); gtk_widget_show(scale); + set_tooltip(scale, "Number of times to apply filter"); /* * Display everything. */ gtk_widget_show(frame); - gtk_widget_show(table); gtk_widget_show(dlg); gtk_main(); @@ -898,28 +966,42 @@ randomize_dialog() * ********************************/ +/* + * DESTROY callback + */ static void randomize_close_callback(GtkWidget *widget, gpointer data) { gtk_main_quit(); } +/* + * OK BUTTON callback + */ static void randomize_ok_callback(GtkWidget *widget, gpointer data) { rndm_int.run = TRUE; gtk_widget_destroy(GTK_WIDGET(data)); } +/* + * CANCEL BUTTON callback + */ static void randomize_cancel_callback(GtkWidget *widget, gpointer data) { gtk_widget_destroy(GTK_WIDGET(data)); } - +/* + * SCALE UPDATE callback + */ static void randomize_scale_update(GtkAdjustment *adjustment, double *scale_val) { *scale_val = adjustment->value; } +/* + * TOGGLE UPDATE callback + */ static void randomize_toggle_update(GtkWidget *widget, gpointer data) { int *toggle_val; @@ -932,6 +1014,9 @@ randomize_toggle_update(GtkWidget *widget, gpointer data) { *toggle_val = FALSE; } +/* + * TEXT UPDATE callback + */ static void randomize_text_update(GtkWidget *widget, gpointer data) { gint *text_val; @@ -940,3 +1025,39 @@ randomize_text_update(GtkWidget *widget, gpointer data) { *text_val = atoi(gtk_entry_get_text(GTK_ENTRY(widget))); } + +/* + * TOOLTIPS ROUTINES + */ +static GtkTooltips *tips; + + +void setup_tooltips(GtkWidget *parent) +{ + static GdkColor tips_fg, tips_bg; + + tips = gtk_tooltips_new(); + + /* black as foreground: */ + + tips_fg.red = 0; + tips_fg.green = 0; + tips_fg.blue = 0; + gdk_color_alloc(gtk_widget_get_colormap(parent), &tips_fg); + + /* postit yellow (khaki) as background: */ + + tips_bg.red = 61669; + tips_bg.green = 59113; + tips_bg.blue = 35979; + gdk_color_alloc(gtk_widget_get_colormap(parent), &tips_bg); + + gtk_tooltips_set_colors(tips, &tips_bg, &tips_fg); +} + + +void set_tooltip(GtkWidget *widget, const char *tip) +{ + if (tip && tip[0]) + gtk_tooltips_set_tips(tips, widget, (char *) tip); +} diff --git a/plug-ins/warp/warp.c b/plug-ins/warp/warp.c index 945bfdde35..06826355e5 100644 --- a/plug-ins/warp/warp.c +++ b/plug-ins/warp/warp.c @@ -1,6 +1,6 @@ /* Warp --- image filter plug-in for The Gimp image manipulation program * Copyright (C) 1997 John P. Beale - * Much of the 'warp' code take from the displace plug-in by 1996 Stephen Robert Norris + * Much of the 'warp' code take from the Displace plug-in by 1996 Stephen Robert Norris * Much of the 'displace' code taken in turn from the pinch plug-in * which is by 1996 Federico Mena Quintero * @@ -18,20 +18,47 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * You can contact me (the Warp author) at beale@best.com + * You can contact me (the warp author) at beale@best.com * Please send me any patches or enhancements to this code. * You can contact the original The Gimp authors at gimp@xcf.berkeley.edu * + * -------------------------------------------------------------------- + * Warp Program structure: after running the user interface and setting the + * parameters, warp generates a brand-new image (later to be deleted + * before the user ever sees it) which contains two grayscale layers, + * representing the X and Y gradients of the "control" image. For this + * purpose, all channels of the control image are summed for a scalar + * value at each pixel coordinate for the gradient operation. * + * The X,Y components of the calculated gradient are then used to displace pixels + * from the source image into the destination image. The displacement vector is + * rotated a user-specified amount first. This displacement operation happens iteratively, + * generating a new displaced image from each prior image. I use a second + * image with one layer which I create for the purpose of a ping-pong between + * image buffers. When finished, the created image buffer is destroyed and the + * original is updated with the final image. + * ------------------------------------------------------------------- + * + * Revision History: + * + * Version 0.32 10/25/97 Added magnitude control map (secondary control) + * Changed undo behavior to be one undo-step per warp call. + * + * Version 0.31 10/25/97 Fixed src/dest pixregions so program works + * with multiple-layer images. Still don't know + * exactly what I did to fix it :-/ Also, added 'color' option for + * border pixels to use the current selected foreground color. + * + * Version 0.3 10/20/97 Initial release for Gimp 0.99.xx */ -/* Version 0.3 */ #include #include #include #include #include +#include /* time(NULL) for random # seed */ #include "gtk/gtk.h" #include "libgimp/gimp.h" #include "libgimp/gimpui.h" @@ -45,23 +72,30 @@ #define WRAP 0 #define SMEAR 1 #define BLACK 2 +#define COLOR 3 typedef struct { gdouble amount; gdouble angle; gdouble iter; - gint displace_map; - gint displace_type; -} DisplaceVals; + gdouble dither; + gint warp_map; + gint wrap_type; + gint mag_map; + gint mag_use; +} WarpVals; typedef struct { GtkWidget *amount; GtkWidget *angle; GtkWidget *iter; + GtkWidget *dither; GtkWidget *menu_map; + GtkWidget *mag_map; + GtkWidget *mag_use; gint run; -} DisplaceInterface; +} WarpInterface; /* * Function prototypes. @@ -85,19 +119,19 @@ static void diff_prepare_row (GPixelRgn *pixel_rgn, int y, int w); -static void warp_one (GDrawable *src_draw, - GDrawable *dest_draw, +static void warp_one (GDrawable *draw, GDrawable *map_x, - GDrawable *map_y ); + GDrawable *map_y, + GDrawable *mag_draw, + gint first_time ); -static void displace (GDrawable *drawable, +static void warp (GDrawable *drawable, GDrawable **map_x_p, GDrawable **map_y_p, - gint32 *xyimage_id, - gint32 *output_id ); + gint32 *xyimage_id ); -static gint displace_dialog (GDrawable *drawable); -static GTile * displace_pixel (GDrawable * drawable, +static gint warp_dialog (GDrawable *drawable); +static GTile * warp_pixel (GDrawable * drawable, GTile * tile, gint width, gint height, @@ -114,22 +148,28 @@ static guchar bilinear (gdouble x, gdouble y, guchar * v); -static gint displace_map_constrain (gint32 image_id, +static gint warp_map_constrain (gint32 image_id, gint32 drawable_id, gpointer data); -static void displace_map_callback (gint32 id, +static void warp_map_callback (gint32 id, gpointer data); -static void displace_close_callback (GtkWidget *widget, +static void warp_map_mag_callback (gint32 id, gpointer data); -static void displace_ok_callback (GtkWidget *widget, +static void warp_close_callback (GtkWidget *widget, gpointer data); -static void displace_toggle_update (GtkWidget *widget, +static void warp_ok_callback (GtkWidget *widget, gpointer data); -static void displace_entry_callback (GtkWidget *widget, +static void warp_toggle_update (GtkWidget *widget, gpointer data); -static gdouble displace_map_give_value (guchar* ptr, +static void warp_entry_callback (GtkWidget *widget, + gpointer data); +static gdouble warp_map_give_value (guchar* ptr, gint alpha, gint bytes); +static gdouble warp_map_mag_give_value (guchar *pt, + gint alpha, + gint bytes); + /***** Local vars *****/ GPlugInInfo PLUG_IN_INFO = @@ -140,25 +180,34 @@ GPlugInInfo PLUG_IN_INFO = run, /* run_proc */ }; -static DisplaceVals dvals = +static WarpVals dvals = { 10.0, /* amount */ 90.0, /* angle */ 5.0, /* iterations */ - -1, /* displace_map */ - WRAP /* displace_type */ + 0.0, /* dither */ + -1, /* warp_map */ + WRAP, /* wrap_type */ + -1, /* mag_map */ + FALSE /* mag_use */ }; -static DisplaceInterface dint = +static WarpInterface dint = { NULL, /* amount */ NULL, /* angle */ NULL, /* iter */ + NULL, /* dither */ NULL, /* menu_map */ - FALSE /* run */ + FALSE, /* run */ + NULL, /* mag_map */ + FALSE /* mag_use */ }; gint progress = 0; /* progress indicator bar */ +guint tile_width, tile_height; /* size of an image tile */ + +guchar color_pixel[4] = {0, 0, 0, 255}; /* current selected foreground color */ /***** Functions *****/ @@ -173,18 +222,21 @@ query () { PARAM_INT32, "run_mode", "Interactive, non-interactive" }, { PARAM_IMAGE, "image", "Input image (unused)" }, { PARAM_DRAWABLE, "drawable", "Input drawable" }, - { PARAM_FLOAT, "amount", "Displace multiplier" }, - { PARAM_FLOAT, "angle", "Angle of displacement" }, + { PARAM_FLOAT, "amount", "Pixel displacement multiplier" }, + { PARAM_FLOAT, "angle", "Angle of gradient vector rotation" }, { PARAM_FLOAT, "iter", "Iteration count" }, - { PARAM_DRAWABLE, "displace_map", "Displacement map" }, - { PARAM_INT32, "displace_type", "Edge behavior: { WRAP (0), SMEAR (1), BLACK (2) }" } + { PARAM_FLOAT, "dither", "Random dither amount" }, + { PARAM_DRAWABLE, "warp_map", "Displacement control map" }, + { PARAM_INT32, "wrap_type", "Edge behavior: { WRAP (0), SMEAR (1), BLACK (2), COLOR (3) }" }, + { PARAM_DRAWABLE, "mag_map", "Magnitude control map" }, + { PARAM_INT32, "mag_option", "Use magnitude map: { FALSE (0), TRUE (1) }" } }; static GParamDef *return_vals = NULL; static gint nargs = sizeof (args) / sizeof (args[0]); static gint nreturn_vals = 0; gimp_install_procedure ("plug_in_warp", - "Twist or smear the contents of an image", + "Twist or smear an image", "Smears an image along vector paths calculated as the gradient of a separate control matrix. The effect can look like brushstrokes of acrylic or watercolor paint, in some cases.", "John P. Beale", "John P. Beale", @@ -208,13 +260,20 @@ run (gchar *name, GDrawable *map_x = NULL; /* satisfy compiler complaints */ GDrawable *map_y = NULL; gint32 xyimage_id; - gint32 output_image_id; GRunModeType run_mode; GStatusType status = STATUS_SUCCESS; run_mode = param[0].data.d_int32; + tile_width = gimp_tile_width(); /* initialize some globals */ + tile_height = gimp_tile_height(); + + /* get currently selected foreground pixel color */ + gimp_palette_get_foreground (&color_pixel[0], &color_pixel[1], &color_pixel[2]); + + + /* Get the specified drawable */ drawable = gimp_drawable_get (param[2].data.d_drawable); @@ -228,10 +287,10 @@ run (gchar *name, { case RUN_INTERACTIVE: /* Possibly retrieve data */ - gimp_get_data ("plug_in_displace", &dvals); + gimp_get_data ("plug_in_warp", &dvals); /* First acquire information with a dialog */ - if (! displace_dialog (drawable)) + if (! warp_dialog (drawable)) return; break; @@ -244,14 +303,15 @@ run (gchar *name, dvals.amount = param[3].data.d_float; dvals.angle = param[4].data.d_float; dvals.iter = param[5].data.d_float; - dvals.displace_map = param[6].data.d_int32; - dvals.displace_type = param[7].data.d_int32; + dvals.dither = param[6].data.d_float; + dvals.warp_map = param[7].data.d_int32; + dvals.wrap_type = param[8].data.d_int32; } break; case RUN_WITH_LAST_VALS: /* Possibly retrieve data */ - gimp_get_data ("plug_in_displace", &dvals); + gimp_get_data ("plug_in_warp", &dvals); break; default: @@ -264,29 +324,28 @@ run (gchar *name, gimp_tile_cache_ntiles (TILE_CACHE_SIZE); /* run the warp effect */ - displace (drawable, &map_x, &map_y, &xyimage_id, &output_image_id); + warp (drawable, &map_x, &map_y, &xyimage_id); if (run_mode != RUN_NONINTERACTIVE) gimp_displays_flush (); /* Store data */ if (run_mode == RUN_INTERACTIVE) - gimp_set_data ("plug_in_displace", &dvals, sizeof (DisplaceVals)); + gimp_set_data ("plug_in_warp", &dvals, sizeof (WarpVals)); } values[0].data.d_status = status; - gimp_drawable_detach (drawable); + /* gimp_drawable_detach (drawable); */ gimp_drawable_detach (map_x); gimp_drawable_detach (map_y); gimp_image_delete(xyimage_id); - gimp_image_delete(output_image_id); } static int -displace_dialog (GDrawable *drawable) +warp_dialog (GDrawable *drawable) { GtkWidget *dlg; GtkWidget *label; @@ -297,18 +356,24 @@ displace_dialog (GDrawable *drawable) GtkWidget *table; GtkWidget *entry; GtkWidget *option_menu; + GtkWidget *option_menu_mag; GtkWidget *menu; + GtkWidget *magmenu; GSList *group = NULL; + GSList *groupmag = NULL; gchar **argv; gchar buffer[32]; gint argc; - gint use_wrap = (dvals.displace_type == WRAP); - gint use_smear = (dvals.displace_type == SMEAR); - gint use_black = (dvals.displace_type == BLACK); + gint use_wrap = (dvals.wrap_type == WRAP); + gint use_smear = (dvals.wrap_type == SMEAR); + gint use_black = (dvals.wrap_type == BLACK); + gint use_color = (dvals.wrap_type == COLOR); + gint mag_use_yes = (dvals.mag_use == TRUE); + gint mag_use_no = (dvals.mag_use == FALSE); argc = 1; argv = g_new (gchar *, 1); - argv[0] = g_strdup ("displace"); + argv[0] = g_strdup ("Warp"); gtk_init (&argc, &argv); @@ -316,14 +381,14 @@ displace_dialog (GDrawable *drawable) gtk_window_set_title (GTK_WINDOW (dlg), "Warp"); gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE); gtk_signal_connect (GTK_OBJECT (dlg), "destroy", - (GtkSignalFunc) displace_close_callback, + (GtkSignalFunc) warp_close_callback, NULL); /* Action area */ button = gtk_button_new_with_label ("OK"); GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); gtk_signal_connect (GTK_OBJECT (button), "clicked", - (GtkSignalFunc) displace_ok_callback, + (GtkSignalFunc) warp_ok_callback, dlg); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0); gtk_widget_grab_default (button); @@ -338,11 +403,12 @@ displace_dialog (GDrawable *drawable) gtk_widget_show (button); /* The main table */ - frame = gtk_frame_new ("Warp Options"); + frame = gtk_frame_new ("Main Options"); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); gtk_container_border_width (GTK_CONTAINER (frame), 10); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, TRUE, TRUE, 0); + /* table params: rows, columns */ table = gtk_table_new (4, 3, FALSE); gtk_container_border_width (GTK_CONTAINER (table), 5); gtk_container_add (GTK_CONTAINER (frame), table); @@ -357,11 +423,11 @@ displace_dialog (GDrawable *drawable) gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (label); - label = gtk_label_new ("Vector Rot. Angle"); + label = gtk_label_new ("Rotation Angle"); gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (label); - label = gtk_label_new ("Iterarations"); + label = gtk_label_new ("Iterations"); gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (label); @@ -372,7 +438,7 @@ displace_dialog (GDrawable *drawable) sprintf (buffer, "%f", dvals.amount); gtk_entry_set_text (GTK_ENTRY (entry), buffer); gtk_signal_connect (GTK_OBJECT (entry), "changed", - (GtkSignalFunc) displace_entry_callback, + (GtkSignalFunc) warp_entry_callback, &dvals.amount); gtk_widget_show (entry); @@ -382,7 +448,7 @@ displace_dialog (GDrawable *drawable) sprintf (buffer, "%f", dvals.angle); gtk_entry_set_text (GTK_ENTRY (entry), buffer); gtk_signal_connect (GTK_OBJECT (entry), "changed", - (GtkSignalFunc) displace_entry_callback, + (GtkSignalFunc) warp_entry_callback, &dvals.angle); gtk_widget_show (entry); @@ -392,11 +458,12 @@ displace_dialog (GDrawable *drawable) sprintf (buffer, "%f", dvals.iter); gtk_entry_set_text (GTK_ENTRY (entry), buffer); gtk_signal_connect (GTK_OBJECT (entry), "changed", - (GtkSignalFunc) displace_entry_callback, + (GtkSignalFunc) warp_entry_callback, &dvals.iter); gtk_widget_show (entry); - /* displacement map menu */ + + /* Displacement map menu */ label = gtk_label_new ("Displacement Map:"); gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, GTK_FILL, GTK_FILL, 0, 0); gtk_widget_show (label); @@ -404,12 +471,14 @@ displace_dialog (GDrawable *drawable) dint.menu_map = option_menu = gtk_option_menu_new (); gtk_table_attach (GTK_TABLE (table), option_menu, 2, 3, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); - menu = gimp_drawable_menu_new (displace_map_constrain, displace_map_callback, - drawable, dvals.displace_map); + menu = gimp_drawable_menu_new (warp_map_constrain, warp_map_callback, + drawable, dvals.warp_map); gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu); gtk_widget_show (option_menu); + /* ================================================================================== */ + /* Displacement Type */ toggle_hbox = gtk_hbox_new (FALSE, 10); gtk_container_border_width (GTK_CONTAINER (toggle_hbox), 5); @@ -423,7 +492,7 @@ displace_dialog (GDrawable *drawable) group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); gtk_box_pack_start (GTK_BOX (toggle_hbox), toggle, FALSE, FALSE, 0); gtk_signal_connect (GTK_OBJECT (toggle), "toggled", - (GtkSignalFunc) displace_toggle_update, + (GtkSignalFunc) warp_toggle_update, &use_wrap); gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_wrap); gtk_widget_show (toggle); @@ -432,7 +501,7 @@ displace_dialog (GDrawable *drawable) group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); gtk_box_pack_start (GTK_BOX (toggle_hbox), toggle, FALSE, FALSE, 0); gtk_signal_connect (GTK_OBJECT (toggle), "toggled", - (GtkSignalFunc) displace_toggle_update, + (GtkSignalFunc) warp_toggle_update, &use_smear); gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_smear); gtk_widget_show (toggle); @@ -441,26 +510,128 @@ displace_dialog (GDrawable *drawable) group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); gtk_box_pack_start (GTK_BOX (toggle_hbox), toggle, FALSE, FALSE, 0); gtk_signal_connect (GTK_OBJECT (toggle), "toggled", - (GtkSignalFunc) displace_toggle_update, + (GtkSignalFunc) warp_toggle_update, &use_black); gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_black); gtk_widget_show (toggle); + toggle = gtk_radio_button_new_with_label (group, "FG Color"); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); + gtk_box_pack_start (GTK_BOX (toggle_hbox), toggle, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) warp_toggle_update, + &use_color); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), use_color); + gtk_widget_show (toggle); + gtk_widget_show (toggle_hbox); + gtk_widget_show (table); gtk_widget_show (frame); + + /* -------------------------------------------------------------------- */ + + + /* The secondary table */ + frame = gtk_frame_new ("Secondary Options"); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN); + gtk_container_border_width (GTK_CONTAINER (frame), 10); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, TRUE, TRUE, 0); + + /* table params: rows, columns */ + table = gtk_table_new (2, 3, FALSE); + gtk_container_border_width (GTK_CONTAINER (table), 5); + gtk_container_add (GTK_CONTAINER (frame), table); + + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + + label = gtk_label_new ("Dither Size"); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + + dint.dither = entry = gtk_entry_new (); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_set_usize (entry, ENTRY_WIDTH, 0); + sprintf (buffer, "%f", dvals.dither); + gtk_entry_set_text (GTK_ENTRY (entry), buffer); + gtk_signal_connect (GTK_OBJECT (entry), "changed", + (GtkSignalFunc) warp_entry_callback, + &dvals.dither); + gtk_widget_show (entry); + + + /* Magnitude map menu */ + label = gtk_label_new ("Magnitude Map:"); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + + dint.mag_map = option_menu_mag = gtk_option_menu_new (); + gtk_table_attach (GTK_TABLE (table), option_menu_mag, 2, 3, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + magmenu = gimp_drawable_menu_new (warp_map_constrain, warp_map_mag_callback, + drawable, dvals.mag_map); + gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu_mag), magmenu); + gtk_widget_show (option_menu_mag); + + + /* ----------------------------------------------------------------------- */ + /* Magnitude Useage */ + toggle_hbox = gtk_hbox_new (FALSE, 10); + gtk_container_border_width (GTK_CONTAINER (toggle_hbox), 5); + gtk_table_attach (GTK_TABLE (table), toggle_hbox, 0, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0); + + label = gtk_label_new ("Use Mag Map: "); + gtk_box_pack_start (GTK_BOX (toggle_hbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + toggle = gtk_radio_button_new_with_label (groupmag, "Yes"); + groupmag = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); + gtk_box_pack_start (GTK_BOX (toggle_hbox), toggle, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) warp_toggle_update, + &mag_use_yes); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), mag_use_yes); + gtk_widget_show (toggle); + + toggle = gtk_radio_button_new_with_label (groupmag, "No"); + groupmag = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle)); + gtk_box_pack_start (GTK_BOX (toggle_hbox), toggle, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (toggle), "toggled", + (GtkSignalFunc) warp_toggle_update, + &mag_use_no); + gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), mag_use_no); + gtk_widget_show (toggle); + + gtk_widget_show (toggle_hbox); + + + + gtk_widget_show (table); + gtk_widget_show (frame); + /* --------------------------------------------------------------- */ + gtk_widget_show (dlg); gtk_main (); gdk_flush (); - /* determine displace type */ + /* determine wrap type */ if (use_wrap) - dvals.displace_type = WRAP; + dvals.wrap_type = WRAP; else if (use_smear) - dvals.displace_type = SMEAR; + dvals.wrap_type = SMEAR; else if (use_black) - dvals.displace_type = BLACK; + dvals.wrap_type = BLACK; + else if (use_color) + dvals.wrap_type = COLOR; + + /* determine whether to use magnitude multiplier map */ + if (mag_use_yes) + dvals.mag_use = TRUE; + else if (mag_use_no) + dvals.mag_use = FALSE; return dint.run; } @@ -533,7 +704,7 @@ diff (GDrawable *drawable, has_alpha = gimp_drawable_has_alpha(drawable->id); - /* -- Create an image with two layers: X and Y displacement vectors -- */ + /* -- Create an image with two layers: X and Y Displacement vectors -- */ new_image_id = gimp_image_new(width, height, GRAY); /* gimp_image_set_filename (new_image_id, "XY_Vectors"); */ @@ -650,23 +821,23 @@ diff (GDrawable *drawable, } /* end diff() */ -/* The displacement is done here. */ +/* The Warp displacement is done here. */ static void -displace (GDrawable *orig_draw, +warp (GDrawable *orig_draw, GDrawable **map_x_p, GDrawable **map_y_p, - gint32 *xyimage_id_p, - gint32 *output_image_id_p ) + gint32 *xyimage_id_p ) { - GDrawable *disp_map; /* displacement map, ie, control array */ + GDrawable *disp_map; /* Displacement map, ie, control array */ + GDrawable *mag_draw; /* Magnitude multiplier factor map */ - gint out_layer_id; /* Image, Layer IDs for new output image */ - GDrawable *output_d; GDrawable *map_x = NULL; GDrawable *map_y = NULL; + gchar string[80]; /* string to hold title of progress bar window */ + gint first_time = TRUE; gint width; gint height; gint bytes; @@ -676,13 +847,14 @@ displace (GDrawable *orig_draw, gint32 xdlayer = -1; gint32 ydlayer = -1; gint32 xyimage_id = -1; - gint32 output_image_id = -1; - gint warp_iter; /* index var. over all "warp" displacement iterations */ + gint warp_iter; /* index var. over all "warp" Displacement iterations */ - disp_map = gimp_drawable_get(dvals.displace_map); - /* calculate new X,Y displacement image maps */ + disp_map = gimp_drawable_get(dvals.warp_map); + mag_draw = gimp_drawable_get(dvals.mag_map); + + /* calculate new X,Y Displacement image maps */ gimp_progress_init ("Finding gradient..."); @@ -695,52 +867,39 @@ displace (GDrawable *orig_draw, height = orig_draw->height; bytes = orig_draw->bpp; - /* -- Create a new image for the output data -- */ - - output_image_id = gimp_image_new(width, height, RGB); - - out_layer_id = gimp_layer_new(output_image_id, "Warp_Output", - width, height, - RGB_IMAGE, 100.0, NORMAL_MODE); - gimp_image_add_layer (output_image_id, out_layer_id, 0); - map_x = gimp_drawable_get(xdlayer); map_y = gimp_drawable_get(ydlayer); - output_d = gimp_drawable_get(out_layer_id); - /* orig_draw = gimp_drawable_get(orig_id); */ - - /* warp_one(orig_draw, output_d, map_x, map_y); */ - /* gimp_display_new(output_image_id); */ - /* warp_one(output_d, orig_draw, map_x, map_y); */ for (warp_iter = 0; warp_iter < dvals.iter; warp_iter++) { sprintf(string,"Step %d...",warp_iter+1); gimp_progress_init (string); progress = 0; - warp_one(orig_draw, output_d, map_x, map_y); - warp_one(output_d, orig_draw, map_x, map_y); + warp_one(orig_draw, map_x, map_y, mag_draw, first_time); + + first_time = FALSE; } /* end for (warp_iter) */ *xyimage_id_p = xyimage_id; - *output_image_id_p = output_image_id; *map_x_p = map_x; *map_y_p = map_y; -} /* displace */ +} /* Warp */ static void -warp_one(GDrawable *src_draw, - GDrawable *dest_draw, +warp_one(GDrawable *draw, GDrawable *map_x, - GDrawable *map_y ) + GDrawable *map_y, + GDrawable *mag_draw, + gint first_time ) { GPixelRgn src_rgn; GPixelRgn dest_rgn; GPixelRgn map_x_rgn; GPixelRgn map_y_rgn; + GPixelRgn mag_rgn; GTile * tile = NULL; gint row = -1; gint col = -1; @@ -749,17 +908,20 @@ warp_one(GDrawable *src_draw, gint width = -1; gint height = -1; gint dest_bytes=-1; - guchar *srcrow, *src; + guchar *destrow, *dest; + guchar *srcrow, *src; guchar *mxrow=NULL, *mx; /* NULL ptr. to make gcc's -Wall fn. happy */ guchar *myrow=NULL, *my; + guchar *mmagrow=NULL, *mmag=NULL; guchar pixel[4][4]; gint x1, y1, x2, y2; gint x, y; gint max_progress; - gdouble amnt_x, amnt_y; /* amount of displacement of each pixel */ + gdouble amnt_x, amnt_y; /* amount of Displacement of each pixel */ gdouble needx, needy; + gdouble scalefac; /* multiplier for vector displacement scaling */ gint xi, yi; guchar values[4]; @@ -767,25 +929,29 @@ warp_one(GDrawable *src_draw, gint k; - gdouble dx, dy; /* X and Y displacement, integer from GRAY map */ + gdouble dx, dy; /* X and Y Displacement, integer from GRAY map */ gdouble r, theta, angled; /* Rect <-> Polar coordinate conversion variables */ gint xm_alpha = 0; gint ym_alpha = 0; + gint mmag_alpha = 0; gint xm_bytes = 1; gint ym_bytes = 1; + gint mmag_bytes = 1; + srand(time(NULL)); /* seed random # generator */ + /* ================ Outer Loop calculation =================================== */ /* Get selection area */ - gimp_drawable_mask_bounds (src_draw->id, &x1, &y1, &x2, &y2); - width = src_draw->width; - height = src_draw->height; - dest_bytes = src_draw->bpp; + gimp_drawable_mask_bounds (draw->id, &x1, &y1, &x2, &y2); + width = draw->width; + height = draw->height; + dest_bytes = draw->bpp; - /* fprintf(stderr,"Source bounds = %d %d %d %d\n",x1,y1,x2,y2); */ + max_progress = (x2 - x1) * (y2 - y1); gimp_pixel_rgn_init (&map_x_rgn, map_x, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE); if (gimp_drawable_has_alpha(map_x->id)) @@ -798,59 +964,86 @@ warp_one(GDrawable *src_draw, ym_bytes = gimp_drawable_bpp(map_y->id); - /* fprintf(stderr,"calling rgn_init\n"); */ - - gimp_pixel_rgn_init (&src_rgn, src_draw, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE); - gimp_pixel_rgn_init (&dest_rgn, dest_draw, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE); + gimp_pixel_rgn_init (&src_rgn, draw, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE); + + /* only update shadow tiles (& push undo-stack) the first time through. Thanks Spencer! */ + if (first_time==TRUE) + gimp_pixel_rgn_init (&dest_rgn, draw, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE); + else + gimp_pixel_rgn_init (&dest_rgn, draw, x1, y1, (x2 - x1), (y2 - y1), TRUE, FALSE); /* Register the pixel region */ - pr = gimp_pixel_rgns_register (4, &src_rgn, &dest_rgn, &map_x_rgn, &map_y_rgn); + if (dvals.mag_use == TRUE) { + gimp_pixel_rgn_init (&mag_rgn, mag_draw, x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE); + if (gimp_drawable_has_alpha(mag_draw->id)) + mmag_alpha = 1; + mmag_bytes = gimp_drawable_bpp(mag_draw->id); - /* fprintf(stderr,"called register\n"); */ + pr = gimp_pixel_rgns_register (5, &dest_rgn, &src_rgn, &map_x_rgn, &map_y_rgn, &mag_rgn); + } else { + pr = gimp_pixel_rgns_register (4, &dest_rgn, &src_rgn, &map_x_rgn, &map_y_rgn); + } - max_progress = (x2 - x1) * (y2 - y1) * 2; - for (pr = pr; pr != NULL; pr = gimp_pixel_rgns_process (pr)) - { - /* fprintf(stderr,"top of PR loop.\n"); */ + { srcrow = src_rgn.data; destrow = dest_rgn.data; mxrow = map_x_rgn.data; myrow = map_y_rgn.data; + if (dvals.mag_use == TRUE) + mmagrow = mag_rgn.data; + angled = dvals.angle * M_PI / 180; + /* loop over destination pixels */ for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++) { src = srcrow; dest = destrow; mx = mxrow; my = myrow; + if (dvals.mag_use == TRUE) + mmag = mmagrow; /* - * We could move the displacement image address calculation out of here, - * but when we can have different sized displacement and destination + * We could move the Displacement image address calculation out of here, + * but when we can have different sized Displacement and destination * images we'd have to move it back anyway. */ for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++) { - dx = (displace_map_give_value(mx, xm_alpha, xm_bytes)-127.5) / 127.5; - dy = (displace_map_give_value(my, ym_alpha, ym_bytes)-127.5) / 127.5; + dx = (warp_map_give_value(mx, xm_alpha, xm_bytes)-127.5) / 127.5; + dy = (warp_map_give_value(my, ym_alpha, ym_bytes)-127.5) / 127.5; r = sqrt(dx*dx + dy*dy); theta = atan2(dy,dx); theta += angled; + /* here is the displacement vector */ amnt_x = dvals.amount * r * cos(theta); amnt_y = dvals.amount * r * sin(theta); + if (dvals.mag_use == TRUE) { + scalefac = warp_map_mag_give_value(mmag, mmag_alpha, mmag_bytes)/255.0; + amnt_x *= scalefac; + amnt_y *= scalefac; + } + + if (dvals.dither != 0.0) { /* random dither is +/- dvals.dither pixels */ + amnt_x += dvals.dither*((gdouble)(rand() - (RAND_MAX >> 1)) / (RAND_MAX >> 1)); + amnt_y += dvals.dither*((gdouble)(rand() - (RAND_MAX >> 1)) / (RAND_MAX >> 1)); + } + needx = x + amnt_x; needy = y + amnt_y; mx += xm_bytes; my += ym_bytes; + if (dvals.mag_use == TRUE) + mmag += mmag_bytes; /* Calculations complete; now copy the proper pixel */ @@ -865,10 +1058,10 @@ warp_one(GDrawable *src_draw, yi = -((int) -needy + 1); /* get 4 neighboring pixel values from source drawable for linear interpolation */ - tile = displace_pixel (src_draw, tile, width, height, x1, y1, x2, y2, xi, yi, &row, &col, pixel[0]); - tile = displace_pixel (src_draw, tile, width, height, x1, y1, x2, y2, xi + 1, yi, &row, &col, pixel[1]); - tile = displace_pixel (src_draw, tile, width, height, x1, y1, x2, y2, xi, yi + 1, &row, &col, pixel[2]); - tile = displace_pixel (src_draw, tile, width, height, x1, y1, x2, y2, xi + 1, yi + 1, &row, &col, pixel[3]); + tile = warp_pixel (draw, tile, width, height, x1, y1, x2, y2, xi, yi, &row, &col, pixel[0]); + tile = warp_pixel (draw, tile, width, height, x1, y1, x2, y2, xi + 1, yi, &row, &col, pixel[1]); + tile = warp_pixel (draw, tile, width, height, x1, y1, x2, y2, xi, yi + 1, &row, &col, pixel[2]); + tile = warp_pixel (draw, tile, width, height, x1, y1, x2, y2, xi + 1, yi + 1, &row, &col, pixel[3]); for (k = 0; k < dest_bytes; k++) { @@ -879,36 +1072,44 @@ warp_one(GDrawable *src_draw, val = bilinear(needx, needy, values); *dest++ = val; - } /* for */ - } + } /* for k */ + + } /* for x */ + /* srcrow += src_rgn.rowstride; */ srcrow += src_rgn.rowstride; destrow += dest_rgn.rowstride; mxrow += map_x_rgn.rowstride; myrow += map_y_rgn.rowstride; - } - + if (dvals.mag_use == TRUE) + mmagrow += mag_rgn.rowstride; + + } /* for y */ + progress += (dest_rgn.w * dest_rgn.h); gimp_progress_update ((double) progress / (double) max_progress); - } /* for */ + } /* for pr */ if (tile) gimp_tile_unref (tile, FALSE); - /* update the region */ - gimp_drawable_flush (dest_draw); - gimp_drawable_merge_shadow(dest_draw->id, TRUE); - gimp_drawable_update (dest_draw->id, x1, y1, (x2 - x1), (y2 - y1)); + /* update the region */ + gimp_drawable_flush (draw); + + if (first_time==TRUE) + gimp_drawable_merge_shadow(draw->id, TRUE); + + gimp_drawable_update (draw->id, x1, y1, (x2 - x1), (y2 - y1)); + + /* if (run_mode != RUN_NONINTERACTIVE) */ + gimp_displays_flush(); - /* if (run_mode != RUN_NONINTERACTIVE) */ - gimp_displays_flush(); - /* detach from the displacement map drawables */ } /* warp_one */ static gdouble -displace_map_give_value(guchar *pt, gint alpha, gint bytes) +warp_map_give_value(guchar *pt, gint alpha, gint bytes) { gdouble ret, val_alpha; @@ -926,9 +1127,28 @@ displace_map_give_value(guchar *pt, gint alpha, gint bytes) return (ret); } +static gdouble +warp_map_mag_give_value(guchar *pt, gint alpha, gint bytes) +{ + gdouble ret, val_alpha; + + if (bytes >= 3) + ret = 0.30 * pt[0] + 0.59 * pt[1] + 0.11 * pt[2]; + else + ret = (gdouble) *pt; + + if (alpha) + { + val_alpha = pt[bytes - 1]; + ret = (ret * val_alpha / 255.0); + }; + + return (ret); +} + static GTile * -displace_pixel (GDrawable * drawable, +warp_pixel (GDrawable * drawable, GTile * tile, gint width, gint height, @@ -947,7 +1167,7 @@ displace_pixel (GDrawable * drawable, gint b; /* Tile the image. */ - if (dvals.displace_type == WRAP) + if (dvals.wrap_type == WRAP) { if (x < 0) x = width - (-x % width); @@ -960,7 +1180,7 @@ displace_pixel (GDrawable * drawable, y %= height; } /* Smear out the edges of the image by repeating pixels. */ - else if (dvals.displace_type == SMEAR) + else if (dvals.wrap_type == SMEAR) { if (x < 0) x = 0; @@ -975,20 +1195,25 @@ displace_pixel (GDrawable * drawable, if (x >= x1 && y >= y1 && x < x2 && y < y2) { - if ((x >> 6 != *col) || (y >> 6 != *row)) + if ((( (guint) (x / tile_width)) != *col) || (( (guint) (y / tile_height)) != *row)) { - *col = x / 64; - *row = y / 64; + *col = x / tile_width; + *row = y / tile_height; if (tile) gimp_tile_unref (tile, FALSE); tile = gimp_drawable_get_tile (drawable, FALSE, *row, *col); gimp_tile_ref (tile); } - data = tile->data + tile->bpp * (tile->ewidth * (y % 64) + (x % 64)); + data = tile->data + tile->bpp * (tile->ewidth * (y % tile_height) + (x % tile_width)); } else - data = empty_pixel; + { + if (dvals.wrap_type == BLACK) + data = empty_pixel; + else + data = color_pixel; /* must have selected COLOR type */ + } for (b = 0; b < drawable->bpp; b++) pixel[b] = data[b]; @@ -1017,10 +1242,10 @@ bilinear (gdouble x, gdouble y, guchar *v) } /* bilinear */ -/* Displace interface functions */ +/* Warp interface functions */ static gint -displace_map_constrain (gint32 image_id, +warp_map_constrain (gint32 image_id, gint32 drawable_id, gpointer data) { @@ -1039,21 +1264,28 @@ displace_map_constrain (gint32 image_id, } static void -displace_map_callback (gint32 id, +warp_map_callback (gint32 id, gpointer data) { - dvals.displace_map = id; + dvals.warp_map = id; } static void -displace_close_callback (GtkWidget *widget, +warp_map_mag_callback (gint32 id, + gpointer data) +{ + dvals.mag_map = id; +} + +static void +warp_close_callback (GtkWidget *widget, gpointer data) { gtk_main_quit (); } static void -displace_ok_callback (GtkWidget *widget, +warp_ok_callback (GtkWidget *widget, gpointer data) { dint.run = TRUE; @@ -1061,7 +1293,7 @@ displace_ok_callback (GtkWidget *widget, } static void -displace_toggle_update (GtkWidget *widget, +warp_toggle_update (GtkWidget *widget, gpointer data) { int *toggle_val; @@ -1075,7 +1307,7 @@ displace_toggle_update (GtkWidget *widget, } static void -displace_entry_callback (GtkWidget *widget, +warp_entry_callback (GtkWidget *widget, gpointer data) { double *text_val;