From 3d86014f32dcdbac2e2a29654120fcd245237762 Mon Sep 17 00:00:00 2001 From: Adrian Likins Date: Mon, 8 Dec 1997 21:37:39 +0000 Subject: [PATCH] updated a few plugins (randomize, gqbist, warp, fuse,gfig) with there latest version removed gflare-tar.gz from plugins dir removed a Makefile and libtool script from gfig dir --- ChangeLog | 6 + plug-ins/common/gqbist.c | 2 +- plug-ins/common/randomize.c | 261 +- plug-ins/fuse/fuse.c | 546 +++- plug-ins/gfig/Makefile | 361 --- plug-ins/gfig/gfig | 80 - plug-ins/gfig/gfig.c | 4334 ++++++++++++++++++++++++++++++-- plug-ins/gflare-0.25.tar.gz | Bin 44104 -> 0 bytes plug-ins/gqbist/gqbist.c | 2 +- plug-ins/randomize/randomize.c | 261 +- plug-ins/warp/warp.c | 540 ++-- 11 files changed, 5326 insertions(+), 1067 deletions(-) delete mode 100644 plug-ins/gfig/Makefile delete mode 100755 plug-ins/gfig/gfig delete mode 100644 plug-ins/gflare-0.25.tar.gz 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 e66134db33e38346157bc81c5d505bb093516c9b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44104 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 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;