2005-09-09 Michael Natterer <mitch@gimp.org> Added parent window API to the GimpProgress interface and to the libgimp progress stuff. Might look strange, but does the right thing in almost all cases (image window, file dialog, script-fu dialog etc). Fixes bug #62988. * app/core/gimpprogress.[ch]: added GimpProgress::get_window() which should return a toplevel window ID if the progress is in a window that wants to be the transient parent of plug-in dialogs. * app/widgets/gimpwidgets-utils.[ch] (gimp_window_get_native): new function which returns the window handle of a GtkWindow's GdkWindow. * app/widgets/gimpfiledialog.c: implement ::get_window(). * app/display/gimpdisplay.[ch]: ditto. Removed window handle API. * app/gui/gui-vtable.c: changed accordingly. * libgimpbase/gimpbaseenums.[ch] (enum GimpProgressCommand): added GIMP_PROGRESS_COMMAND_GET_WINDOW. * app/plug-in/plug-in-progress.[ch] (plug_in_progress_get_window): new function. Also renamed some functions to match the GimpProgress interface, and not the legacy PDB procedure names. * tools/pdbgen/pdb/progress.pdb * app/core/gimppdbprogress.c: implement get_window() on both sides of the wire, keeping backward compatibility (hopefully). * libgimp/gimpprogress.[ch]: deprecated gimp_progress_install() and added gimp_progress_install_vtable() which takes a vtable with padding to be extensible. Added get_window() vtable entry and dispatch it accordingly. Also added pulse() which was implemented in a hackish way before. Everything is of course backward compatible. * libgimp/gimpprogressbar.c: inmplement the get_window() stuff so a plug-in dialog containing a progress can be the transient parent of another dialog in another plug-in. * libgimp/gimpui.[ch] (gimp_ui_get_progress_window): new function which returns a foreign GdkWindow of this plug-ins progress window. Renamed gimp_window_set_transient_for_default_display() to gimp_window_set_transient() and make it use the progress' window handle instead of the display's (which is the right thing to do in almost all cases). * libgimp/gimp.def * libgimp/gimpui.def: add the new functions. * tools/pdbgen/enums.pl * app/pdb/internal_procs.c * app/pdb/progress_cmds.c * libgimp/gimpprogress_pdb.[ch]: regenerated. * libgimp/gimpexport.c * plug-ins/*/*.c: follow API change.
2085 lines
64 KiB
C
2085 lines
64 KiB
C
/*
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
*
|
|
* This is a plug-in for the GIMP.
|
|
*
|
|
* Copyright (C) Pavel Grinfeld (pavel@ml.com)
|
|
*
|
|
*
|
|
* 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
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <libgimp/gimp.h>
|
|
#include <libgimp/gimpui.h>
|
|
|
|
#include "libgimp/stdplugins-intl.h"
|
|
|
|
#define PLUG_IN_PROC "plug-in-filter-pack"
|
|
#define PLUG_IN_BINARY "fp"
|
|
|
|
#define MAX_PREVIEW_SIZE 125
|
|
#define MAX_ROUGHNESS 128
|
|
#define RANGE_HEIGHT 15
|
|
#define PR_BX_BRDR 4
|
|
#define ALL 255
|
|
#define MARGIN 4
|
|
|
|
#define RANGE_ADJUST_MASK GDK_EXPOSURE_MASK | \
|
|
GDK_ENTER_NOTIFY_MASK | \
|
|
GDK_BUTTON_PRESS_MASK | \
|
|
GDK_BUTTON_RELEASE_MASK | \
|
|
GDK_BUTTON1_MOTION_MASK | \
|
|
GDK_POINTER_MOTION_HINT_MASK
|
|
|
|
|
|
typedef struct
|
|
{
|
|
gint run;
|
|
} fpInterface;
|
|
|
|
typedef struct
|
|
{
|
|
gint width;
|
|
gint height;
|
|
guchar *rgb;
|
|
gdouble *hsv;
|
|
guchar *mask;
|
|
} ReducedImage;
|
|
|
|
typedef enum
|
|
{
|
|
SHADOWS,
|
|
MIDTONES,
|
|
HIGHLIGHTS,
|
|
INTENSITIES
|
|
}FPIntensity;
|
|
|
|
enum
|
|
{
|
|
NONEATALL = 0,
|
|
CURRENT = 1,
|
|
HUE = 2,
|
|
SATURATION = 4,
|
|
VALUE = 8
|
|
};
|
|
|
|
enum
|
|
{
|
|
BY_HUE,
|
|
BY_SAT,
|
|
BY_VAL,
|
|
JUDGE_BY
|
|
};
|
|
|
|
enum
|
|
{
|
|
RED,
|
|
GREEN,
|
|
BLUE,
|
|
CYAN,
|
|
YELLOW,
|
|
MAGENTA,
|
|
ALL_PRIMARY
|
|
};
|
|
|
|
enum
|
|
{
|
|
DOWN = -1,
|
|
UP = 1
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
GtkWidget *window;
|
|
GtkWidget *range_preview;
|
|
GtkWidget *aliasing_preview;
|
|
GtkWidget *aliasing_graph;
|
|
} AdvancedWindow;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
gdouble roughness;
|
|
gdouble aliasing;
|
|
gdouble preview_size;
|
|
FPIntensity intensity_range;
|
|
gint value_by;
|
|
gint selection_only;
|
|
gboolean real_time;
|
|
guchar offset;
|
|
guchar visible_frames;
|
|
guchar cutoff[INTENSITIES];
|
|
gint touched[JUDGE_BY];
|
|
gint red_adjust[JUDGE_BY][256];
|
|
gint blue_adjust[JUDGE_BY][256];
|
|
gint green_adjust[JUDGE_BY][256];
|
|
gint sat_adjust[JUDGE_BY][256];
|
|
} FPValues;
|
|
|
|
typedef struct
|
|
{
|
|
GtkWidget *roughness_scale;
|
|
GtkWidget *aliasing_scale;
|
|
GtkWidget *preview_size_scale;
|
|
GtkWidget *range_label[12];
|
|
} FPWidgets;
|
|
|
|
static void fp_show_hide_frame (GtkWidget *button,
|
|
GtkWidget *frame);
|
|
|
|
static ReducedImage * fp_reduce_image (GimpDrawable *drawable,
|
|
GimpDrawable *mask,
|
|
gint longer_size,
|
|
gint selection);
|
|
|
|
static void fp_render_preview (GtkWidget *preview,
|
|
gint change_what,
|
|
gint change_which);
|
|
|
|
static void update_current_fp (gint change_what,
|
|
gint change_which);
|
|
|
|
static void fp_create_nudge (gint *adj_array);
|
|
|
|
static gboolean fp_dialog (void);
|
|
static void fp_advanced_dialog (void);
|
|
|
|
static void fp_selection_made (GtkWidget *widget,
|
|
gpointer data);
|
|
static void fp_scale_update (GtkAdjustment *adjustment,
|
|
gdouble *scale_val);
|
|
static void fp_reset_filter_packs (void);
|
|
|
|
static void fp_create_smoothness_graph (GtkWidget *preview);
|
|
|
|
static void fp_range_preview_spill (GtkWidget *preview,
|
|
gint type);
|
|
static void fp_adjust_preview_sizes (gint width,
|
|
gint height);
|
|
static void fp_redraw_all_windows (void);
|
|
static void fp_refresh_previews (gint which);
|
|
static void fp_init_filter_packs (void);
|
|
|
|
static void fp_drag (GtkWidget *button);
|
|
static void fp_preview_scale_update (GtkAdjustment *adjustment,
|
|
gdouble *scale_val);
|
|
|
|
static void fp (GimpDrawable *drawable);
|
|
static GtkWidget * fp_create_bna (void);
|
|
static GtkWidget * fp_create_rough (void);
|
|
static GtkWidget * fp_create_range (void);
|
|
static GtkWidget * fp_create_circle_palette (void);
|
|
static GtkWidget * fp_create_lnd (void);
|
|
static GtkWidget * fp_create_show (void);
|
|
static GtkWidget * fp_create_msnls (void);
|
|
static GtkWidget * fp_create_pixels_select_by (void);
|
|
static void update_range_labels (void);
|
|
static gboolean fp_range_change_events (GtkWidget *widget,
|
|
GdkEvent *event,
|
|
FPValues *current);
|
|
|
|
static void fp_create_preview (GtkWidget **preview,
|
|
GtkWidget **frame,
|
|
gint preview_width,
|
|
gint preview_height);
|
|
|
|
static void fp_create_table_entry (GtkWidget **box,
|
|
GtkWidget *smaller_frame,
|
|
const gchar *description);
|
|
|
|
static void fp_checkbutton_in_box (GtkWidget *vbox,
|
|
const gchar *label,
|
|
GtkSignalFunc func,
|
|
gpointer data,
|
|
gboolean clicked);
|
|
|
|
static void fp_frames_checkbutton_in_box (GtkWidget *vbox,
|
|
const gchar *label,
|
|
GtkSignalFunc func,
|
|
GtkWidget *frame,
|
|
gboolean clicked);
|
|
|
|
static void fp_preview_size_allocate (GtkWidget *widget,
|
|
GtkAllocation *allocation);
|
|
|
|
#define RESPONSE_RESET 1
|
|
|
|
/* These values are translated for the GUI but also used internally
|
|
to figure out which button the user pushed, etc.
|
|
Not my design, please don't blame me -- njl */
|
|
|
|
static const gchar *hue_red = N_("Red:");
|
|
static const gchar *hue_green = N_("Green:");
|
|
static const gchar *hue_blue = N_("Blue:");
|
|
static const gchar *hue_cyan = N_("Cyan:");
|
|
static const gchar *hue_yellow = N_("Yellow:");
|
|
static const gchar *hue_magenta = N_("Magenta:");
|
|
|
|
static const gchar *val_darker = N_("Darker:");
|
|
static const gchar *val_lighter = N_("Lighter:");
|
|
|
|
static const gchar *sat_more = N_("More Sat:");
|
|
static const gchar *sat_less = N_("Less Sat:");
|
|
|
|
static const gchar *current_val = N_("Current:");
|
|
|
|
static gint colorSign[3][ALL_PRIMARY]=
|
|
{{1,-1,-1,-1,1,1},{-1,1,-1,1,1,-1},{-1,-1,1,1,-1,1}};
|
|
|
|
static AdvancedWindow AW = { NULL, NULL, NULL, NULL };
|
|
|
|
static FPWidgets fp_widgets = { NULL, NULL, NULL };
|
|
|
|
static gint nudgeArray[256];
|
|
|
|
static GtkWidget *origPreview, *curPreview;
|
|
static GtkWidget *rPreview, *gPreview, *bPreview;
|
|
static GtkWidget *cPreview, *yPreview, *mPreview;
|
|
static GtkWidget *centerPreview;
|
|
static GtkWidget *darkerPreview, *lighterPreview, *middlePreview;
|
|
static GtkWidget *dlg;
|
|
static GtkWidget *plusSatPreview, *SatPreview, *minusSatPreview;
|
|
|
|
static struct
|
|
{
|
|
GtkWidget *bna;
|
|
GtkWidget *palette;
|
|
GtkWidget *rough;
|
|
GtkWidget *range;
|
|
GtkWidget *show;
|
|
GtkWidget *lnd;
|
|
GtkWidget *pixelsBy;
|
|
GtkWidget *frameSelect;
|
|
GtkWidget *satur;
|
|
} fp_frames;
|
|
|
|
static fpInterface FPint =
|
|
{
|
|
FALSE /* run */
|
|
};
|
|
|
|
static ReducedImage *reduced;
|
|
|
|
static FPValues fpvals =
|
|
{
|
|
.25, /* Initial Roughness */
|
|
.6, /* Initial Degree of Aliasing */
|
|
80, /* Initial preview size */
|
|
MIDTONES, /* Initial Range */
|
|
BY_VAL, /* Initial God knows what */
|
|
TRUE, /* Selection Only */
|
|
TRUE, /* Real Time */
|
|
0, /* Offset */
|
|
0, /* Visible frames */
|
|
{32,224,255}, /* cutoffs */
|
|
{0,0,0} /* touched */
|
|
};
|
|
|
|
static GimpDrawable *drawable, *mask;
|
|
|
|
static void query (void);
|
|
static void run (const gchar *name,
|
|
gint nparams,
|
|
const GimpParam *param,
|
|
gint *nreturn_vals,
|
|
GimpParam **return_vals);
|
|
|
|
GimpPlugInInfo PLUG_IN_INFO =
|
|
{
|
|
NULL, /* init_proc */
|
|
NULL, /* quit_proc */
|
|
query, /* query_proc */
|
|
run, /* run_proc */
|
|
};
|
|
|
|
MAIN()
|
|
|
|
static void
|
|
query (void)
|
|
{
|
|
GimpParamDef args[] =
|
|
{
|
|
{ GIMP_PDB_INT32, "run-mode", "Interactive, non-interactive" },
|
|
{ GIMP_PDB_IMAGE, "image", "Input image (used for indexed images)" },
|
|
{ GIMP_PDB_DRAWABLE, "drawable", "Input drawable" }
|
|
};
|
|
|
|
gimp_install_procedure (PLUG_IN_PROC,
|
|
"Allows the user to change H, S, or C with many previews",
|
|
"No help available",
|
|
"Pavel Grinfeld (pavel@ml.com)",
|
|
"Pavel Grinfeld (pavel@ml.com)",
|
|
"27th March 1997",
|
|
N_("_Filter Pack..."),
|
|
"RGB*",
|
|
GIMP_PLUGIN,
|
|
G_N_ELEMENTS (args), 0,
|
|
args, NULL);
|
|
|
|
gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/Colors");
|
|
}
|
|
|
|
/********************************STANDARD RUN*************************/
|
|
|
|
static void
|
|
run (const gchar *name,
|
|
gint nparams,
|
|
const GimpParam *param,
|
|
gint *nreturn_vals,
|
|
GimpParam **return_vals)
|
|
{
|
|
GimpParam values[1];
|
|
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
|
GimpRunMode run_mode;
|
|
|
|
*nreturn_vals = 1;
|
|
*return_vals = values;
|
|
|
|
run_mode = param[0].data.d_int32;
|
|
|
|
INIT_I18N ();
|
|
|
|
values[0].type = GIMP_PDB_STATUS;
|
|
values[0].data.d_status = status;
|
|
|
|
fp_init_filter_packs();
|
|
|
|
drawable = gimp_drawable_get (param[2].data.d_drawable);
|
|
mask = gimp_drawable_get (gimp_image_get_selection (param[1].data.d_image));
|
|
|
|
switch (run_mode)
|
|
{
|
|
case GIMP_RUN_INTERACTIVE:
|
|
/* Possibly retrieve data */
|
|
gimp_get_data (PLUG_IN_PROC, &fpvals);
|
|
|
|
if (gimp_drawable_is_indexed (drawable->drawable_id) ||
|
|
gimp_drawable_is_gray (drawable->drawable_id) )
|
|
{
|
|
gimp_message (_("FP can only be used on RGB images."));
|
|
status = GIMP_PDB_EXECUTION_ERROR;
|
|
}
|
|
else if (! fp_dialog())
|
|
{
|
|
status = GIMP_PDB_CANCEL;
|
|
}
|
|
break;
|
|
|
|
case GIMP_RUN_NONINTERACTIVE:
|
|
gimp_message (_("FP can only be run interactively."));
|
|
status = GIMP_PDB_CALLING_ERROR;
|
|
break;
|
|
|
|
case GIMP_RUN_WITH_LAST_VALS:
|
|
/* Possibly retrieve data */
|
|
gimp_get_data (PLUG_IN_PROC, &fpvals);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (status == GIMP_PDB_SUCCESS)
|
|
{
|
|
/* Make sure that the drawable is gray or RGB color */
|
|
if (gimp_drawable_is_rgb (drawable->drawable_id))
|
|
{
|
|
gimp_progress_init (_("Applying Filter Pack..."));
|
|
gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
|
|
fp (drawable);
|
|
|
|
/* Store data */
|
|
if (run_mode == GIMP_RUN_INTERACTIVE)
|
|
gimp_set_data (PLUG_IN_PROC, &fpvals, sizeof (FPValues));
|
|
|
|
gimp_displays_flush ();
|
|
}
|
|
else status = GIMP_PDB_EXECUTION_ERROR;
|
|
}
|
|
|
|
values[0].data.d_status = status;
|
|
|
|
if (status == GIMP_PDB_SUCCESS)
|
|
gimp_drawable_detach (drawable);
|
|
}
|
|
|
|
static void
|
|
fp_func (const guchar *src,
|
|
guchar *dest,
|
|
gint bpp,
|
|
gpointer data)
|
|
{
|
|
gint bytenum, k;
|
|
gint JudgeBy, Intensity = 0, P[3];
|
|
GimpRGB rgb;
|
|
GimpHSV hsv;
|
|
gint M, m, middle;
|
|
|
|
P[0] = src[0];
|
|
P[1] = src[1];
|
|
P[2] = src[2];
|
|
|
|
gimp_rgb_set_uchar (&rgb, (guchar) P[0], (guchar) P[1], (guchar) P[2]);
|
|
gimp_rgb_to_hsv (&rgb, &hsv);
|
|
|
|
for (JudgeBy = BY_HUE; JudgeBy < JUDGE_BY; JudgeBy++)
|
|
{
|
|
if (!fpvals.touched[JudgeBy])
|
|
continue;
|
|
|
|
switch (JudgeBy)
|
|
{
|
|
case BY_HUE:
|
|
Intensity = 255 * hsv.h;
|
|
break;
|
|
|
|
case BY_SAT:
|
|
Intensity = 255 * hsv.s;
|
|
break;
|
|
|
|
case BY_VAL:
|
|
Intensity = 255 * hsv.v;
|
|
break;
|
|
}
|
|
|
|
|
|
/* It's important to take care of Saturation first!!! */
|
|
|
|
m = MIN (MIN (P[0], P[1]), P[2]);
|
|
M = MAX (MAX (P[0], P[1]), P[2]);
|
|
middle = (M + m) / 2;
|
|
|
|
for (k = 0; k < 3; k++)
|
|
if (P[k] != m && P[k] != M)
|
|
middle = P[k];
|
|
|
|
for (k = 0; k < 3; k++)
|
|
if (M != m)
|
|
{
|
|
if (P[k] == M)
|
|
P[k] = MAX (P[k] + fpvals.sat_adjust[JudgeBy][Intensity], middle);
|
|
else if (P[k] == m)
|
|
P[k] = MIN (P[k] - fpvals.sat_adjust[JudgeBy][Intensity], middle);
|
|
}
|
|
|
|
P[0] += fpvals.red_adjust[JudgeBy][Intensity];
|
|
P[1] += fpvals.green_adjust[JudgeBy][Intensity];
|
|
P[2] += fpvals.blue_adjust[JudgeBy][Intensity];
|
|
|
|
P[0] = CLAMP0255(P[0]);
|
|
P[1] = CLAMP0255(P[1]);
|
|
P[2] = CLAMP0255(P[2]);
|
|
}
|
|
|
|
dest[0] = P[0];
|
|
dest[1] = P[1];
|
|
dest[2] = P[2];
|
|
|
|
for (bytenum = 3; bytenum < bpp; bytenum++)
|
|
dest[bytenum] = src[bytenum];
|
|
}
|
|
|
|
static void
|
|
fp (GimpDrawable *drawable)
|
|
{
|
|
gimp_rgn_iterate2 (drawable, 0 /* unused */, fp_func, NULL);
|
|
}
|
|
|
|
/***********************************************************/
|
|
/************ Main Dialog Window ******************/
|
|
/***********************************************************/
|
|
|
|
static GtkWidget *
|
|
fp_create_bna (void)
|
|
{
|
|
GtkWidget *table;
|
|
GtkWidget *label;
|
|
GtkWidget *bframe, *aframe;
|
|
|
|
fp_create_preview (&origPreview, &bframe, reduced->width, reduced->height);
|
|
fp_create_preview (&curPreview, &aframe, reduced->width, reduced->height);
|
|
|
|
table = gtk_table_new (2, 2, FALSE);
|
|
gtk_table_set_row_spacings (GTK_TABLE (table), 6);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
|
|
|
|
label = gtk_label_new (_("Original:"));
|
|
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
|
|
GTK_SHRINK, GTK_SHRINK, 0, 0);
|
|
gtk_widget_show (label);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), bframe, 0, 1, 1, 2,
|
|
GTK_EXPAND, 0, 0, 0);
|
|
|
|
label = gtk_label_new (_("Current:"));
|
|
gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
|
|
GTK_SHRINK, GTK_SHRINK, 0, 0);
|
|
gtk_widget_show (label);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), aframe, 1, 2, 1, 2,
|
|
GTK_EXPAND, 0, 0, 0);
|
|
|
|
gtk_widget_show (table);
|
|
|
|
return table;
|
|
}
|
|
|
|
/* close a sub dialog (from window manager) by simulating toggle click */
|
|
static gboolean
|
|
sub_dialog_destroy (GtkWidget *dialog,
|
|
GdkEvent *ev,
|
|
gpointer dummy)
|
|
{
|
|
GtkWidget *button =
|
|
GTK_WIDGET (g_object_get_data (G_OBJECT (dialog), "ctrlButton"));
|
|
|
|
gtk_button_clicked (GTK_BUTTON (button));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static GtkWidget *
|
|
fp_create_circle_palette (void)
|
|
{
|
|
GtkWidget *table;
|
|
GtkWidget *rVbox, *rFrame;
|
|
GtkWidget *gVbox, *gFrame;
|
|
GtkWidget *bVbox, *bFrame;
|
|
GtkWidget *cVbox, *cFrame;
|
|
GtkWidget *yVbox, *yFrame;
|
|
GtkWidget *mVbox, *mFrame;
|
|
GtkWidget *centerVbox, *centerFrame;
|
|
GtkWidget *win;
|
|
|
|
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
gimp_help_connect (win, gimp_standard_help_func, PLUG_IN_PROC, NULL);
|
|
|
|
gtk_window_set_title (GTK_WINDOW (win), _("Hue Variations"));
|
|
|
|
g_signal_connect (win, "delete-event",
|
|
G_CALLBACK (sub_dialog_destroy),
|
|
NULL);
|
|
|
|
table = gtk_table_new (11, 11, FALSE);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
|
|
gtk_table_set_row_spacings (GTK_TABLE (table), 6);
|
|
gtk_container_set_border_width (GTK_CONTAINER (table), 12);
|
|
gtk_container_add (GTK_CONTAINER (win), table);
|
|
gtk_widget_show (table);
|
|
|
|
fp_create_preview (&rPreview, &rFrame, reduced->width, reduced->height);
|
|
fp_create_preview (&gPreview, &gFrame, reduced->width, reduced->height);
|
|
fp_create_preview (&bPreview, &bFrame, reduced->width, reduced->height);
|
|
fp_create_preview (&cPreview, &cFrame, reduced->width, reduced->height);
|
|
fp_create_preview (&yPreview, &yFrame, reduced->width, reduced->height);
|
|
fp_create_preview (&mPreview, &mFrame, reduced->width, reduced->height);
|
|
fp_create_preview (¢erPreview, ¢erFrame,
|
|
reduced->width, reduced->height);
|
|
|
|
fp_create_table_entry (&rVbox, rFrame, hue_red);
|
|
fp_create_table_entry (&gVbox, gFrame, hue_green);
|
|
fp_create_table_entry (&bVbox, bFrame, hue_blue);
|
|
fp_create_table_entry (&cVbox, cFrame, hue_cyan);
|
|
fp_create_table_entry (&yVbox, yFrame, hue_yellow);
|
|
fp_create_table_entry (&mVbox, mFrame, hue_magenta);
|
|
fp_create_table_entry (¢erVbox, centerFrame, current_val);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), rVbox, 8, 11 ,4 , 7,
|
|
GTK_EXPAND , GTK_EXPAND, 0 ,0);
|
|
gtk_table_attach (GTK_TABLE (table), gVbox, 2, 5, 0, 3,
|
|
GTK_EXPAND, GTK_EXPAND, 0, 0);
|
|
gtk_table_attach (GTK_TABLE (table), bVbox, 2, 5, 8, 11,
|
|
GTK_EXPAND, GTK_EXPAND,0,0);
|
|
gtk_table_attach (GTK_TABLE (table), cVbox, 0, 3, 4, 7,
|
|
GTK_EXPAND, GTK_EXPAND, 0 ,0);
|
|
gtk_table_attach (GTK_TABLE (table), yVbox, 6, 9, 0, 3,
|
|
GTK_EXPAND, GTK_EXPAND, 0 ,0);
|
|
gtk_table_attach (GTK_TABLE (table), mVbox, 6, 9, 8, 11,
|
|
GTK_EXPAND, GTK_EXPAND, 0 ,0);
|
|
gtk_table_attach (GTK_TABLE (table), centerVbox, 4, 7, 4, 7,
|
|
GTK_EXPAND, GTK_EXPAND, 0 ,0);
|
|
|
|
return win;
|
|
}
|
|
|
|
static GtkWidget *
|
|
fp_create_rough (void)
|
|
{
|
|
GtkWidget *frame, *vbox, *scale;
|
|
GtkObject *data;
|
|
|
|
frame = gimp_frame_new (_("Roughness"));
|
|
gtk_widget_show (frame);
|
|
|
|
vbox = gtk_vbox_new (FALSE, 6);
|
|
gtk_container_add (GTK_CONTAINER (frame), vbox);
|
|
gtk_widget_show (vbox);
|
|
|
|
data = gtk_adjustment_new (fpvals.roughness, 0, 1.0, 0.05, 0.01, 0.0);
|
|
fp_widgets.roughness_scale = scale = gtk_hscale_new (GTK_ADJUSTMENT (data));
|
|
|
|
gtk_widget_set_size_request (scale, 60, -1);
|
|
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
|
|
gtk_scale_set_digits (GTK_SCALE (scale), 2);
|
|
gtk_widget_show (scale);
|
|
|
|
g_signal_connect (data, "value-changed",
|
|
G_CALLBACK (fp_scale_update),
|
|
&fpvals.roughness);
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
|
|
|
|
return frame;
|
|
}
|
|
|
|
static void
|
|
fp_change_current_range (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gimp_radio_button_update (widget, data);
|
|
|
|
if (GTK_TOGGLE_BUTTON (widget)->active)
|
|
{
|
|
fp_refresh_previews (fpvals.visible_frames);
|
|
if (AW.window && GTK_WIDGET_VISIBLE (AW.window))
|
|
fp_create_smoothness_graph (AW.aliasing_preview);
|
|
}
|
|
}
|
|
|
|
static GtkWidget *
|
|
fp_create_range (void)
|
|
{
|
|
GtkWidget *frame;
|
|
|
|
frame = gimp_int_radio_group_new (TRUE, _("Affected Range"),
|
|
G_CALLBACK (fp_change_current_range),
|
|
&fpvals.intensity_range, fpvals.intensity_range,
|
|
|
|
_("Sha_dows"), SHADOWS, NULL,
|
|
_("_Midtones"), MIDTONES, NULL,
|
|
_("H_ighlights"), HIGHLIGHTS, NULL,
|
|
|
|
NULL);
|
|
|
|
gtk_widget_show (frame);
|
|
|
|
return frame;
|
|
}
|
|
|
|
static GtkWidget *
|
|
fp_create_control (void)
|
|
{
|
|
GtkWidget *frame, *box;
|
|
|
|
frame = gimp_frame_new (_("Windows"));
|
|
|
|
box = gtk_vbox_new (FALSE, 6);
|
|
gtk_container_add (GTK_CONTAINER (frame), box);
|
|
gtk_widget_show (box);
|
|
|
|
fp_frames_checkbutton_in_box (box, _("_Hue"),
|
|
GTK_SIGNAL_FUNC (fp_show_hide_frame),
|
|
fp_frames.palette,
|
|
fpvals.visible_frames & HUE);
|
|
fp_frames_checkbutton_in_box (box, _("_Saturation"),
|
|
GTK_SIGNAL_FUNC (fp_show_hide_frame),
|
|
fp_frames.satur,
|
|
fpvals.visible_frames & SATURATION);
|
|
fp_frames_checkbutton_in_box (box, _("_Value"),
|
|
GTK_SIGNAL_FUNC (fp_show_hide_frame),
|
|
fp_frames.lnd,
|
|
fpvals.visible_frames & VALUE);
|
|
fp_frames_checkbutton_in_box (box, _("A_dvanced"),
|
|
GTK_SIGNAL_FUNC (fp_show_hide_frame),
|
|
AW.window,
|
|
FALSE);
|
|
gtk_widget_show (frame);
|
|
|
|
return frame;
|
|
}
|
|
|
|
static GtkWidget *
|
|
fp_create_lnd (void)
|
|
{
|
|
GtkWidget *table, *lighterFrame, *middleFrame, *darkerFrame;
|
|
GtkWidget *lighterVbox, *middleVbox, *darkerVbox;
|
|
GtkWidget *win;
|
|
|
|
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
gimp_help_connect (win, gimp_standard_help_func, PLUG_IN_PROC, NULL);
|
|
|
|
gtk_window_set_title (GTK_WINDOW (win), _("Value Variations"));
|
|
|
|
g_signal_connect (win, "delete-event",
|
|
G_CALLBACK (sub_dialog_destroy),
|
|
NULL);
|
|
|
|
fp_create_preview (&lighterPreview, &lighterFrame,
|
|
reduced->width, reduced->height);
|
|
fp_create_preview (&middlePreview, &middleFrame,
|
|
reduced->width, reduced->height);
|
|
fp_create_preview (&darkerPreview, &darkerFrame,
|
|
reduced->width, reduced->height);
|
|
|
|
fp_create_table_entry (&lighterVbox, lighterFrame, val_lighter);
|
|
fp_create_table_entry (&middleVbox, middleFrame, current_val);
|
|
fp_create_table_entry (&darkerVbox, darkerFrame, val_darker);
|
|
|
|
table = gtk_table_new (1, 11, FALSE);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
|
|
gtk_container_set_border_width (GTK_CONTAINER (table), 12);
|
|
gtk_container_add (GTK_CONTAINER (win), table);
|
|
gtk_widget_show (table);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), lighterVbox, 0, 3, 0, 1,
|
|
GTK_EXPAND , GTK_EXPAND, 0, 0);
|
|
gtk_table_attach (GTK_TABLE (table), middleVbox, 4, 7, 0, 1,
|
|
GTK_EXPAND, GTK_EXPAND, 0, 0);
|
|
gtk_table_attach (GTK_TABLE (table), darkerVbox, 8, 11, 0, 1,
|
|
GTK_EXPAND, GTK_EXPAND, 0, 0);
|
|
|
|
return win;
|
|
}
|
|
|
|
static GtkWidget *
|
|
fp_create_msnls (void)
|
|
{
|
|
GtkWidget *table, *lessFrame, *middleFrame, *moreFrame;
|
|
GtkWidget *lessVbox, *middleVbox, *moreVbox;
|
|
GtkWidget *win;
|
|
|
|
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
gimp_help_connect (win, gimp_standard_help_func, PLUG_IN_PROC, NULL);
|
|
|
|
gtk_window_set_title (GTK_WINDOW (win), _("Saturation Variations"));
|
|
|
|
g_signal_connect (win, "delete-event",
|
|
G_CALLBACK (sub_dialog_destroy),
|
|
NULL);
|
|
|
|
fp_create_preview (&minusSatPreview, &lessFrame,
|
|
reduced->width, reduced->height);
|
|
fp_create_preview (&SatPreview, &middleFrame,
|
|
reduced->width, reduced->height);
|
|
fp_create_preview (&plusSatPreview, &moreFrame,
|
|
reduced->width, reduced->height);
|
|
|
|
fp_create_table_entry (&moreVbox, moreFrame, sat_more);
|
|
fp_create_table_entry (&middleVbox, middleFrame, current_val);
|
|
fp_create_table_entry (&lessVbox, lessFrame, sat_less);
|
|
|
|
table = gtk_table_new (1, 11, FALSE);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
|
|
gtk_container_set_border_width (GTK_CONTAINER (table), 12);
|
|
gtk_container_add (GTK_CONTAINER (win), table);
|
|
gtk_widget_show (table);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), moreVbox, 0, 3, 0, 1,
|
|
GTK_EXPAND, GTK_EXPAND, 0, 0);
|
|
gtk_table_attach (GTK_TABLE (table), middleVbox, 4, 7, 0, 1,
|
|
GTK_EXPAND, GTK_EXPAND, 0, 0);
|
|
gtk_table_attach (GTK_TABLE (table), lessVbox, 8, 11, 0, 1,
|
|
GTK_EXPAND, GTK_EXPAND, 0, 0);
|
|
|
|
return win;
|
|
}
|
|
|
|
static void
|
|
fp_change_current_pixels_by (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gimp_radio_button_update (widget, data);
|
|
|
|
if (GTK_TOGGLE_BUTTON (widget)->active)
|
|
{
|
|
fp_refresh_previews (fpvals.visible_frames);
|
|
if (AW.window && GTK_WIDGET_VISIBLE (AW.window) && AW.range_preview)
|
|
fp_range_preview_spill (AW.range_preview,fpvals.value_by);
|
|
}
|
|
}
|
|
|
|
static GtkWidget *
|
|
fp_create_pixels_select_by (void)
|
|
{
|
|
GtkWidget *frame;
|
|
|
|
frame = gimp_int_radio_group_new (TRUE, _("Select Pixels By"),
|
|
G_CALLBACK (fp_change_current_pixels_by),
|
|
&fpvals.value_by,
|
|
fpvals.value_by,
|
|
|
|
_("H_ue"), 0, NULL,
|
|
_("Satu_ration"), 1, NULL,
|
|
_("V_alue"), 2, NULL,
|
|
|
|
NULL);
|
|
|
|
gtk_widget_show (frame);
|
|
|
|
return frame;
|
|
}
|
|
|
|
static void
|
|
fp_change_selection (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gimp_radio_button_update (widget, data);
|
|
|
|
if (GTK_TOGGLE_BUTTON (widget)->active)
|
|
{
|
|
fp_redraw_all_windows ();
|
|
}
|
|
}
|
|
|
|
static GtkWidget *
|
|
fp_create_show (void)
|
|
{
|
|
GtkWidget *frame;
|
|
|
|
frame = gimp_int_radio_group_new (TRUE, _("Show"),
|
|
G_CALLBACK (fp_change_selection),
|
|
&fpvals.selection_only,
|
|
fpvals.selection_only,
|
|
|
|
_("_Entire image"), 0, NULL,
|
|
_("Se_lection only"), 1, NULL,
|
|
_("Selec_tion in context"), 2, NULL,
|
|
|
|
NULL);
|
|
|
|
gtk_widget_show (frame);
|
|
|
|
return frame;
|
|
}
|
|
|
|
static void
|
|
fp_create_preview (GtkWidget **preview,
|
|
GtkWidget **frame,
|
|
gint preview_width,
|
|
gint preview_height)
|
|
{
|
|
*frame = gtk_frame_new (NULL);
|
|
gtk_frame_set_shadow_type (GTK_FRAME (*frame), GTK_SHADOW_IN);
|
|
gtk_widget_show (*frame);
|
|
|
|
*preview = gimp_preview_area_new ();
|
|
gtk_widget_set_size_request (*preview, preview_width, preview_height);
|
|
g_signal_connect (*preview, "size_allocate",
|
|
G_CALLBACK (fp_preview_size_allocate), NULL);
|
|
gtk_widget_show (*preview);
|
|
gtk_container_add (GTK_CONTAINER (*frame), *preview);
|
|
}
|
|
|
|
static void
|
|
fp_checkbutton_in_box (GtkWidget *vbox,
|
|
const gchar *label,
|
|
GtkSignalFunc function,
|
|
gpointer data,
|
|
gboolean clicked)
|
|
{
|
|
GtkWidget *button;
|
|
|
|
button = gtk_check_button_new_with_mnemonic (label);
|
|
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
|
gtk_widget_show (button);
|
|
|
|
g_signal_connect (button, "clicked",
|
|
G_CALLBACK (function),
|
|
data);
|
|
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), clicked);
|
|
}
|
|
|
|
static void
|
|
fp_frames_checkbutton_in_box (GtkWidget *vbox,
|
|
const gchar *label,
|
|
GtkSignalFunc function,
|
|
GtkWidget *frame,
|
|
gboolean clicked)
|
|
{
|
|
GtkWidget *button;
|
|
|
|
button = gtk_check_button_new_with_mnemonic (label);
|
|
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
|
g_object_set_data (G_OBJECT (frame), "ctrlButton", (gpointer) button);
|
|
gtk_widget_show (button);
|
|
|
|
g_signal_connect (button, "clicked",
|
|
G_CALLBACK (function),
|
|
frame);
|
|
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), clicked);
|
|
}
|
|
|
|
static void
|
|
fp_create_table_entry (GtkWidget **box,
|
|
GtkWidget *smaller_frame,
|
|
const gchar *description)
|
|
{
|
|
GtkWidget *label, *button, *table;
|
|
|
|
*box = gtk_vbox_new (FALSE, 1);
|
|
gtk_container_set_border_width (GTK_CONTAINER (*box), PR_BX_BRDR);
|
|
gtk_widget_show (*box);
|
|
|
|
/* Delayed translation applied here */
|
|
label = gtk_label_new (gettext (description));
|
|
|
|
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
|
|
gtk_widget_show (label);
|
|
|
|
table = gtk_table_new (2, 1, FALSE);
|
|
gtk_widget_show (table);
|
|
|
|
gtk_box_pack_start (GTK_BOX (*box), table, TRUE, TRUE, 0);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
|
|
0, 0, 0, 0);
|
|
|
|
if (description != current_val)
|
|
{
|
|
button = gtk_button_new ();
|
|
gtk_table_attach (GTK_TABLE (table), button, 0, 1, 1, 2,
|
|
0, 0, 0, 4);
|
|
gtk_widget_show (button);
|
|
|
|
gtk_container_add (GTK_CONTAINER (button), smaller_frame);
|
|
|
|
g_signal_connect (button, "clicked",
|
|
G_CALLBACK (fp_selection_made),
|
|
(gchar *) description);
|
|
}
|
|
else
|
|
{
|
|
gtk_table_attach (GTK_TABLE (table), smaller_frame, 0, 1, 1, 2,
|
|
0, 0, 0, 4);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fp_redraw_all_windows (void)
|
|
{
|
|
reduced = fp_reduce_image (drawable,mask,
|
|
fpvals.preview_size,
|
|
fpvals.selection_only);
|
|
fp_adjust_preview_sizes (reduced->width, reduced->height);
|
|
|
|
gtk_widget_queue_draw (fp_frames.palette);
|
|
gtk_widget_queue_draw (fp_frames.satur);
|
|
gtk_widget_queue_draw (fp_frames.lnd);
|
|
gtk_widget_queue_draw (dlg);
|
|
|
|
fp_refresh_previews (fpvals.visible_frames);
|
|
}
|
|
|
|
static void
|
|
fp_show_hide_frame (GtkWidget *button,
|
|
GtkWidget *frame)
|
|
{
|
|
gint prev = fpvals.visible_frames;
|
|
|
|
if (frame == NULL)
|
|
return;
|
|
|
|
if (GTK_TOGGLE_BUTTON (button)->active)
|
|
{
|
|
if (!GTK_WIDGET_VISIBLE (frame))
|
|
{
|
|
gtk_widget_show (frame);
|
|
|
|
if (frame==fp_frames.palette)
|
|
fpvals.visible_frames |= HUE;
|
|
else if (frame==fp_frames.satur)
|
|
fpvals.visible_frames |= SATURATION;
|
|
else if (frame==fp_frames.lnd)
|
|
fpvals.visible_frames |= VALUE;
|
|
|
|
fp_refresh_previews (fpvals.visible_frames & ~prev);
|
|
fp_create_smoothness_graph (AW.aliasing_preview);
|
|
fp_range_preview_spill (AW.range_preview,fpvals.value_by);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GTK_WIDGET_VISIBLE (frame))
|
|
{
|
|
gtk_widget_hide (frame);
|
|
|
|
if (frame==fp_frames.palette)
|
|
fpvals.visible_frames &= ~HUE;
|
|
else if (frame==fp_frames.satur)
|
|
fpvals.visible_frames &= ~SATURATION;
|
|
else if (frame==fp_frames.lnd)
|
|
fpvals.visible_frames &= ~VALUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
fp_adjust_preview_sizes (gint width,
|
|
gint height)
|
|
{
|
|
gtk_widget_set_size_request (origPreview, width, height);
|
|
gtk_widget_set_size_request (curPreview, width, height);
|
|
gtk_widget_set_size_request (rPreview, width, height);
|
|
gtk_widget_set_size_request (gPreview, width, height);
|
|
gtk_widget_set_size_request (bPreview, width, height);
|
|
gtk_widget_set_size_request (cPreview, width, height);
|
|
gtk_widget_set_size_request (yPreview, width, height);
|
|
gtk_widget_set_size_request (mPreview, width, height);
|
|
gtk_widget_set_size_request (centerPreview, width, height);
|
|
gtk_widget_set_size_request (lighterPreview, width, height);
|
|
gtk_widget_set_size_request (darkerPreview, width, height);
|
|
gtk_widget_set_size_request (middlePreview, width, height);
|
|
gtk_widget_set_size_request (minusSatPreview, width, height);
|
|
gtk_widget_set_size_request (SatPreview, width, height);
|
|
gtk_widget_set_size_request (plusSatPreview, width, height);
|
|
|
|
}
|
|
|
|
static void
|
|
fp_selection_made (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
fpvals.touched[fpvals.value_by] = 1;
|
|
|
|
if (data == (gpointer) hue_red) {
|
|
update_current_fp (HUE, RED);
|
|
} else if (data == (gpointer) hue_green) {
|
|
update_current_fp (HUE, GREEN);
|
|
} else if (data == (gpointer) hue_blue) {
|
|
update_current_fp (HUE, BLUE);
|
|
} else if (data == (gpointer) hue_cyan) {
|
|
update_current_fp (HUE, CYAN);
|
|
} else if (data == (gpointer) hue_yellow) {
|
|
update_current_fp (HUE, YELLOW);
|
|
} else if (data == (gpointer) hue_magenta) {
|
|
update_current_fp (HUE, MAGENTA);
|
|
} else if (data == (gpointer) val_darker) {
|
|
update_current_fp (VALUE, DOWN);
|
|
} else if (data == (gpointer) val_lighter) {
|
|
update_current_fp (VALUE, UP);
|
|
} else if (data == (gpointer) sat_more) {
|
|
update_current_fp (SATURATION, UP);
|
|
} else if (data == (gpointer) sat_less) {
|
|
update_current_fp (SATURATION, DOWN);
|
|
}
|
|
|
|
fp_refresh_previews (fpvals.visible_frames);
|
|
}
|
|
|
|
static void
|
|
fp_refresh_previews (gint which)
|
|
{
|
|
fp_create_nudge (nudgeArray);
|
|
fp_render_preview (origPreview, NONEATALL, 0);
|
|
fp_render_preview (curPreview, CURRENT, 0);
|
|
if (which & HUE)
|
|
{
|
|
fp_render_preview (rPreview, HUE, RED);
|
|
fp_render_preview (gPreview, HUE, GREEN);
|
|
fp_render_preview (bPreview, HUE, BLUE);
|
|
fp_render_preview (cPreview, HUE, CYAN);
|
|
fp_render_preview (yPreview, HUE, YELLOW);
|
|
fp_render_preview (mPreview, HUE, MAGENTA);
|
|
fp_render_preview (centerPreview, CURRENT, 0);
|
|
}
|
|
if (which & VALUE)
|
|
{
|
|
fp_render_preview (lighterPreview, VALUE, UP);
|
|
fp_render_preview (middlePreview, CURRENT, 0);
|
|
fp_render_preview (darkerPreview, VALUE, DOWN);
|
|
}
|
|
if (which & SATURATION)
|
|
{
|
|
fp_render_preview (plusSatPreview, SATURATION, UP);
|
|
fp_render_preview (SatPreview, CURRENT, 0);
|
|
fp_render_preview (minusSatPreview, SATURATION, DOWN);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fp_response (GtkWidget *widget,
|
|
gint response_id,
|
|
gpointer data)
|
|
{
|
|
switch (response_id)
|
|
{
|
|
case RESPONSE_RESET:
|
|
fp_reset_filter_packs ();
|
|
break;
|
|
|
|
case GTK_RESPONSE_OK:
|
|
FPint.run = TRUE;
|
|
gtk_widget_destroy (widget);
|
|
break;
|
|
|
|
default:
|
|
gtk_widget_destroy (widget);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
fp_scale_update (GtkAdjustment *adjustment,
|
|
gdouble *scale_val)
|
|
{
|
|
static gdouble prevValue = 0.25;
|
|
|
|
*scale_val = adjustment->value;
|
|
|
|
if (prevValue != adjustment->value)
|
|
{
|
|
fp_create_nudge (nudgeArray);
|
|
fp_refresh_previews (fpvals.visible_frames);
|
|
if (AW.window != NULL && GTK_WIDGET_VISIBLE (AW.window))
|
|
fp_create_smoothness_graph (AW.aliasing_preview);
|
|
prevValue = adjustment->value;
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
fp_dialog (void)
|
|
{
|
|
GtkWidget *bna;
|
|
GtkWidget *palette;
|
|
GtkWidget *lnd;
|
|
GtkWidget *show;
|
|
GtkWidget *rough;
|
|
GtkWidget *range;
|
|
GtkWidget *pixelsBy;
|
|
GtkWidget *satur;
|
|
GtkWidget *control;
|
|
GtkWidget *table;
|
|
|
|
reduced = fp_reduce_image (drawable,mask,
|
|
fpvals.preview_size,
|
|
fpvals.selection_only);
|
|
|
|
gimp_ui_init (PLUG_IN_BINARY, TRUE);
|
|
|
|
dlg = gimp_dialog_new (_("Filter Pack Simulation"), PLUG_IN_BINARY,
|
|
NULL, 0,
|
|
gimp_standard_help_func, PLUG_IN_PROC,
|
|
|
|
GIMP_STOCK_RESET, RESPONSE_RESET,
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
GTK_STOCK_OK, GTK_RESPONSE_OK,
|
|
|
|
NULL);
|
|
|
|
gtk_dialog_set_alternative_button_order (GTK_DIALOG (dlg),
|
|
RESPONSE_RESET,
|
|
GTK_RESPONSE_OK,
|
|
GTK_RESPONSE_CANCEL,
|
|
-1);
|
|
|
|
gimp_window_set_transient (GTK_WINDOW (dlg));
|
|
|
|
g_signal_connect (dlg, "response",
|
|
G_CALLBACK (fp_response),
|
|
dlg);
|
|
|
|
g_signal_connect (dlg, "destroy",
|
|
G_CALLBACK (gtk_main_quit),
|
|
NULL);
|
|
|
|
fp_advanced_dialog ();
|
|
|
|
fp_frames.bna = bna = fp_create_bna();
|
|
fp_frames.rough = rough = fp_create_rough();
|
|
fp_frames.range = range = fp_create_range();
|
|
fp_frames.palette = palette = fp_create_circle_palette();
|
|
fp_frames.lnd = lnd = fp_create_lnd();
|
|
fp_frames.show = show = fp_create_show();
|
|
fp_frames.satur = satur = fp_create_msnls();
|
|
fp_frames.pixelsBy = pixelsBy = fp_create_pixels_select_by();
|
|
control = fp_create_control();
|
|
/********************************************************************/
|
|
/******************** PUT EVERYTHING TOGETHER ******************/
|
|
|
|
table = gtk_table_new (4, 2, FALSE);
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
|
|
gtk_table_set_row_spacings (GTK_TABLE (table), 6);
|
|
gtk_container_set_border_width (GTK_CONTAINER (table), 12);
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), table, TRUE, TRUE, 0);
|
|
gtk_widget_show (table);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), bna, 0, 2, 0, 1,
|
|
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), control, 1, 2, 1, 3,
|
|
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), rough, 1, 2, 3, 4,
|
|
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), show, 0, 1, 1, 2,
|
|
GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), range, 0, 1, 2, 3,
|
|
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), pixelsBy, 0, 1, 3, 4,
|
|
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
|
|
|
|
gtk_widget_show (dlg);
|
|
|
|
fp_refresh_previews (fpvals.visible_frames);
|
|
|
|
gtk_main ();
|
|
|
|
return FPint.run;
|
|
}
|
|
|
|
/***********************************************************/
|
|
/************ Advanced Options Window ******************/
|
|
/***********************************************************/
|
|
|
|
static void
|
|
fp_drag (GtkWidget *button)
|
|
{
|
|
static gboolean notFirstTime = FALSE;
|
|
|
|
if (! notFirstTime)
|
|
return;
|
|
|
|
notFirstTime = TRUE;
|
|
|
|
if (GTK_TOGGLE_BUTTON (button)->active)
|
|
{
|
|
fpvals.real_time=TRUE;
|
|
gtk_range_set_update_policy (GTK_RANGE (fp_widgets.roughness_scale),0);
|
|
gtk_range_set_update_policy (GTK_RANGE (fp_widgets.aliasing_scale),0);
|
|
gtk_range_set_update_policy (GTK_RANGE (fp_widgets.preview_size_scale),0);
|
|
}
|
|
else
|
|
{
|
|
fpvals.real_time=FALSE;
|
|
gtk_range_set_update_policy (GTK_RANGE (fp_widgets.roughness_scale),
|
|
GTK_UPDATE_DELAYED);
|
|
gtk_range_set_update_policy (GTK_RANGE (fp_widgets.aliasing_scale),
|
|
GTK_UPDATE_DELAYED);
|
|
gtk_range_set_update_policy (GTK_RANGE (fp_widgets.preview_size_scale),
|
|
GTK_UPDATE_DELAYED);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fp_preview_scale_update (GtkAdjustment *adjustment,
|
|
gdouble *scale_val)
|
|
{
|
|
fpvals.preview_size = adjustment->value;
|
|
fp_redraw_all_windows();
|
|
}
|
|
|
|
static void
|
|
fp_advanced_dialog (void)
|
|
{
|
|
gchar *rangeNames[] = { N_("Shadows:"),
|
|
N_("Midtones:"),
|
|
N_("Highlights:") };
|
|
GtkWidget *frame, *mainvbox;
|
|
GtkObject *smoothnessData;
|
|
GtkWidget *graphFrame, *table, *scale;
|
|
GtkWidget *vbox, *label, *labelTable, *alignment, *inner_vbox;
|
|
gint i;
|
|
|
|
AW.window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
gimp_help_connect (AW.window, gimp_standard_help_func, PLUG_IN_PROC, NULL);
|
|
|
|
gtk_window_set_title (GTK_WINDOW (AW.window),
|
|
_("Advanced Filter Pack Options"));
|
|
|
|
g_signal_connect (AW.window, "delete-event",
|
|
G_CALLBACK (sub_dialog_destroy),
|
|
NULL);
|
|
|
|
mainvbox = gtk_hbox_new (FALSE, 12);
|
|
gtk_container_set_border_width (GTK_CONTAINER (mainvbox), 12);
|
|
gtk_container_add (GTK_CONTAINER (AW.window), mainvbox);
|
|
gtk_widget_show (mainvbox);
|
|
|
|
frame = gimp_frame_new (_("Smoothness of Aliasing"));
|
|
gtk_box_pack_start (GTK_BOX (mainvbox), frame, TRUE, TRUE, 0);
|
|
gtk_widget_show (frame);
|
|
|
|
table = gtk_table_new (3, 1, FALSE);
|
|
gtk_table_set_row_spacings (GTK_TABLE (table), 6);
|
|
gtk_container_add (GTK_CONTAINER (frame), table);
|
|
gtk_widget_show (table);
|
|
|
|
graphFrame = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1, TRUE);
|
|
gtk_frame_set_shadow_type (GTK_FRAME (graphFrame), GTK_SHADOW_IN);
|
|
gtk_container_set_border_width (GTK_CONTAINER (graphFrame),0);
|
|
gtk_widget_show (graphFrame);
|
|
gtk_table_attach (GTK_TABLE (table), graphFrame, 0, 1, 0, 1,
|
|
GTK_EXPAND, 0, 0, 0);
|
|
|
|
vbox = gtk_vbox_new (FALSE, 0);
|
|
gtk_container_add (GTK_CONTAINER (graphFrame), vbox);
|
|
gtk_widget_show (vbox);
|
|
|
|
alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
|
|
gtk_box_pack_start_defaults (GTK_BOX (vbox), alignment);
|
|
gtk_widget_show (alignment);
|
|
|
|
inner_vbox = gtk_vbox_new (FALSE, 0);
|
|
gtk_container_add (GTK_CONTAINER (alignment), inner_vbox);
|
|
gtk_widget_show (inner_vbox);
|
|
|
|
AW.aliasing_preview = gimp_preview_area_new ();
|
|
gtk_widget_set_size_request (AW.aliasing_preview, 256, MAX_ROUGHNESS);
|
|
gtk_box_pack_start (GTK_BOX (inner_vbox), AW.aliasing_preview, TRUE, TRUE, 0);
|
|
gtk_widget_show (AW.aliasing_preview);
|
|
|
|
fp_create_smoothness_graph (AW.aliasing_preview);
|
|
|
|
AW.range_preview = gimp_preview_area_new ();
|
|
gtk_widget_set_size_request (AW.range_preview, 256, RANGE_HEIGHT);
|
|
gtk_box_pack_start(GTK_BOX (inner_vbox), AW.range_preview, TRUE, TRUE, 0);
|
|
gtk_widget_show (AW.range_preview);
|
|
|
|
fp_range_preview_spill (AW.range_preview, fpvals.value_by);
|
|
|
|
labelTable = gtk_table_new (3, 4, FALSE);
|
|
gtk_table_set_col_spacings (GTK_TABLE (labelTable), 6);
|
|
gtk_table_set_row_spacings (GTK_TABLE (labelTable), 6);
|
|
gtk_widget_show (labelTable);
|
|
gtk_table_attach (GTK_TABLE (table), labelTable, 0, 1, 1, 2,
|
|
GTK_EXPAND, 0, 0, 0);
|
|
|
|
for (i = 0; i < 12; i++)
|
|
{
|
|
label = fp_widgets.range_label[i] = gtk_label_new ("-");
|
|
if (!(i % 4))
|
|
{
|
|
gtk_label_set_text (GTK_LABEL(label), gettext (rangeNames[i/4]));
|
|
gtk_misc_set_alignment (GTK_MISC (label), 1.0, 1.0);
|
|
}
|
|
gtk_widget_show (label);
|
|
gtk_table_attach (GTK_TABLE (labelTable), label, i%4, i%4+1, i/4, i/4+1,
|
|
GTK_EXPAND | GTK_FILL, 0, 0, 0);
|
|
}
|
|
|
|
/************************************************************/
|
|
|
|
AW.aliasing_graph = gtk_drawing_area_new ();
|
|
gtk_widget_set_size_request (AW.aliasing_graph,
|
|
2 * MARGIN + 256,
|
|
RANGE_HEIGHT);
|
|
gtk_box_pack_start (GTK_BOX (vbox), AW.aliasing_graph, TRUE, TRUE, 0);
|
|
gtk_widget_show (AW.aliasing_graph);
|
|
gtk_widget_set_events (AW.aliasing_graph, RANGE_ADJUST_MASK);
|
|
|
|
g_signal_connect (AW.aliasing_graph, "event",
|
|
G_CALLBACK (fp_range_change_events),
|
|
&fpvals);
|
|
|
|
/************************************************************/
|
|
|
|
smoothnessData = gtk_adjustment_new (fpvals.aliasing, 0, 1.0, 0.05, 0.01, 0.0);
|
|
|
|
fp_widgets.aliasing_scale = scale =
|
|
gtk_hscale_new (GTK_ADJUSTMENT (smoothnessData));
|
|
gtk_widget_set_size_request (scale, 200, -1);
|
|
gtk_scale_set_digits (GTK_SCALE (scale), 2);
|
|
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
|
|
gtk_range_set_update_policy (GTK_RANGE (scale), 0);
|
|
gtk_table_attach (GTK_TABLE (table), scale, 0, 1, 2, 3,
|
|
0, 0, 0, 0);
|
|
gtk_widget_show (scale);
|
|
|
|
g_signal_connect (smoothnessData, "value-changed",
|
|
G_CALLBACK (fp_scale_update),
|
|
&fpvals.aliasing);
|
|
|
|
/******************* MISC OPTIONS ***************************/
|
|
|
|
vbox = gtk_vbox_new (FALSE, 6);
|
|
gtk_box_pack_start (GTK_BOX (mainvbox), vbox, TRUE, TRUE, 0);
|
|
gtk_widget_show (vbox);
|
|
|
|
fp_checkbutton_in_box (vbox, _("Preview as You Drag"),
|
|
GTK_SIGNAL_FUNC (fp_drag),
|
|
NULL, TRUE);
|
|
|
|
frame = gimp_frame_new (_("Preview Size"));
|
|
gtk_widget_show (frame);
|
|
|
|
smoothnessData = gtk_adjustment_new (fpvals.preview_size,
|
|
50, MAX_PREVIEW_SIZE,
|
|
5, 5, 0.0);
|
|
|
|
fp_widgets.preview_size_scale = scale =
|
|
gtk_hscale_new (GTK_ADJUSTMENT (smoothnessData));
|
|
gtk_container_add (GTK_CONTAINER (frame), scale);
|
|
gtk_widget_set_size_request (scale, 100, -1);
|
|
gtk_scale_set_digits (GTK_SCALE (scale), 0);
|
|
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
|
|
gtk_range_set_update_policy (GTK_RANGE (scale), 0);
|
|
gtk_widget_show (scale);
|
|
|
|
g_signal_connect (smoothnessData, "value-changed",
|
|
G_CALLBACK (fp_preview_scale_update),
|
|
&fpvals.preview_size);
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
|
}
|
|
|
|
static void
|
|
slider_erase (GdkWindow *window,
|
|
int xpos)
|
|
{
|
|
gdk_window_clear_area (window, MARGIN + xpos - (RANGE_HEIGHT - 1) / 2, 0,
|
|
RANGE_HEIGHT, RANGE_HEIGHT);
|
|
}
|
|
|
|
static void
|
|
draw_slider (GdkWindow *window,
|
|
GdkGC *border_gc,
|
|
GdkGC *fill_gc,
|
|
gint xpos)
|
|
{
|
|
gint i;
|
|
|
|
for (i = 0; i < RANGE_HEIGHT; i++)
|
|
gdk_draw_line (window, fill_gc, MARGIN + xpos-i/2, i, MARGIN + xpos+i/2,i);
|
|
|
|
gdk_draw_line (window, border_gc, MARGIN + xpos, 0,
|
|
MARGIN + xpos - (RANGE_HEIGHT - 1) / 2, RANGE_HEIGHT - 1);
|
|
|
|
gdk_draw_line (window, border_gc, MARGIN + xpos, 0,
|
|
MARGIN + xpos + (RANGE_HEIGHT - 1) / 2, RANGE_HEIGHT - 1);
|
|
|
|
gdk_draw_line (window, border_gc, MARGIN + xpos- (RANGE_HEIGHT - 1)/2,
|
|
RANGE_HEIGHT-1, MARGIN + xpos + (RANGE_HEIGHT-1)/2,
|
|
RANGE_HEIGHT - 1);
|
|
}
|
|
|
|
static void
|
|
draw_it (GtkWidget *widget)
|
|
{
|
|
draw_slider (AW.aliasing_graph->window,
|
|
AW.aliasing_graph->style->black_gc,
|
|
AW.aliasing_graph->style->dark_gc[GTK_STATE_NORMAL],
|
|
fpvals.cutoff[SHADOWS]);
|
|
|
|
draw_slider (AW.aliasing_graph->window,
|
|
AW.aliasing_graph->style->black_gc,
|
|
AW.aliasing_graph->style->dark_gc[GTK_STATE_NORMAL],
|
|
fpvals.cutoff[MIDTONES]);
|
|
|
|
draw_slider (AW.aliasing_graph->window,
|
|
AW.aliasing_graph->style->black_gc,
|
|
AW.aliasing_graph->style->dark_gc[GTK_STATE_SELECTED],
|
|
fpvals.offset);
|
|
}
|
|
|
|
static gboolean
|
|
fp_range_change_events (GtkWidget *widget,
|
|
GdkEvent *event,
|
|
FPValues *current)
|
|
{
|
|
GdkEventButton *bevent;
|
|
GdkEventMotion *mevent;
|
|
gint shad, mid, offset, min;
|
|
static guchar *new;
|
|
gint x;
|
|
|
|
switch (event->type)
|
|
{
|
|
case GDK_EXPOSE:
|
|
draw_it (NULL);
|
|
break;
|
|
|
|
case GDK_BUTTON_PRESS:
|
|
bevent= (GdkEventButton *) event;
|
|
|
|
shad = abs (bevent->x - fpvals.cutoff[SHADOWS]);
|
|
mid = abs (bevent->x - fpvals.cutoff[MIDTONES]);
|
|
offset = abs (bevent->x - fpvals.offset);
|
|
|
|
min = MIN (MIN (shad, mid), offset);
|
|
|
|
if (bevent->x >0 && bevent->x<256)
|
|
{
|
|
if (min == shad)
|
|
new = &fpvals.cutoff[SHADOWS];
|
|
else if (min == mid)
|
|
new = &fpvals.cutoff[MIDTONES];
|
|
else
|
|
new = &fpvals.offset;
|
|
|
|
slider_erase (AW.aliasing_graph->window, *new);
|
|
*new = bevent->x;
|
|
}
|
|
|
|
draw_it (NULL);
|
|
|
|
if (fpvals.real_time)
|
|
{
|
|
fp_range_preview_spill (AW.range_preview, fpvals.value_by);
|
|
update_range_labels ();
|
|
fp_create_smoothness_graph (AW.aliasing_preview);
|
|
fp_refresh_previews (fpvals.visible_frames);
|
|
}
|
|
break;
|
|
|
|
case GDK_BUTTON_RELEASE:
|
|
if (!fpvals.real_time)
|
|
{
|
|
fp_range_preview_spill (AW.range_preview, fpvals.value_by);
|
|
update_range_labels ();
|
|
fp_create_smoothness_graph (AW.aliasing_preview);
|
|
fp_refresh_previews (fpvals.visible_frames);
|
|
}
|
|
break;
|
|
|
|
case GDK_MOTION_NOTIFY:
|
|
mevent = (GdkEventMotion *) event;
|
|
gdk_window_get_pointer (widget->window, &x, NULL, NULL);
|
|
|
|
if (x >= 0 && x < 256)
|
|
{
|
|
slider_erase (AW.aliasing_graph->window, *new);
|
|
*new = x;
|
|
draw_it (NULL);
|
|
if (fpvals.real_time)
|
|
{
|
|
fp_range_preview_spill (AW.range_preview, fpvals.value_by);
|
|
update_range_labels ();
|
|
fp_create_smoothness_graph (AW.aliasing_preview);
|
|
fp_refresh_previews (fpvals.visible_frames);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
update_range_labels (void)
|
|
{
|
|
gchar buffer[3];
|
|
|
|
gtk_label_set_text (GTK_LABEL(fp_widgets.range_label[1]),"0");
|
|
|
|
g_snprintf (buffer, sizeof (buffer), "%d", fpvals.cutoff[SHADOWS]);
|
|
gtk_label_set_text (GTK_LABEL (fp_widgets.range_label[3]), buffer);
|
|
gtk_label_set_text (GTK_LABEL (fp_widgets.range_label[5]), buffer);
|
|
|
|
g_snprintf (buffer, sizeof (buffer), "%d", fpvals.cutoff[MIDTONES]);
|
|
gtk_label_set_text (GTK_LABEL (fp_widgets.range_label[7]), buffer);
|
|
gtk_label_set_text (GTK_LABEL (fp_widgets.range_label[9]), buffer);
|
|
|
|
gtk_label_set_text (GTK_LABEL(fp_widgets.range_label[11]), "255");
|
|
}
|
|
|
|
static void
|
|
fp_init_filter_packs (void)
|
|
{
|
|
gint i, j;
|
|
for (i = 0; i < 256; i++)
|
|
for (j = BY_HUE; j < JUDGE_BY; j++)
|
|
{
|
|
fpvals.red_adjust [j][i] = 0;
|
|
fpvals.green_adjust [j][i] = 0;
|
|
fpvals.blue_adjust [j][i] = 0;
|
|
fpvals.sat_adjust [j][i] = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
fp_reset_filter_packs (void)
|
|
{
|
|
fp_init_filter_packs ();
|
|
fp_refresh_previews (fpvals.visible_frames);
|
|
}
|
|
|
|
static ReducedImage *
|
|
fp_reduce_image (GimpDrawable *drawable,
|
|
GimpDrawable *mask,
|
|
gint longer_size,
|
|
gint selection)
|
|
{
|
|
gint RH, RW, width, height, bytes=drawable->bpp;
|
|
ReducedImage *temp = (ReducedImage *) malloc (sizeof (ReducedImage));
|
|
guchar *tempRGB, *src_row, *tempmask, *src_mask_row, R, G, B;
|
|
gint i, j, whichcol, whichrow, x1, x2, y1, y2;
|
|
GimpPixelRgn srcPR, srcMask;
|
|
gboolean NoSelectionMade = TRUE;
|
|
gdouble *tempHSV;
|
|
GimpRGB rgb;
|
|
GimpHSV hsv;
|
|
|
|
gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);
|
|
width = x2 - x1;
|
|
height = y2 - y1;
|
|
|
|
if (width != drawable->width && height != drawable->height)
|
|
NoSelectionMade = FALSE;
|
|
|
|
if (selection == 0)
|
|
{
|
|
x1 = 0;
|
|
x2 = drawable->width;
|
|
y1 = 0;
|
|
y2 = drawable->height;
|
|
}
|
|
else if (selection == 2)
|
|
{
|
|
x1 = MAX (0, x1 - width / 2.0);
|
|
x2 = MIN (drawable->width, x2 + width / 2.0);
|
|
y1 = MAX (0, y1 - height / 2.0);
|
|
y2 = MIN (drawable->height, y2 + height / 2.0);
|
|
}
|
|
|
|
width = x2 - x1;
|
|
height = y2 - y1;
|
|
|
|
if (width > height)
|
|
{
|
|
RW = longer_size;
|
|
RH = (gdouble) height * (gdouble) longer_size / (gdouble) width;
|
|
}
|
|
else
|
|
{
|
|
RH = longer_size;
|
|
RW = (gdouble) width * (gdouble) longer_size / (gdouble) height;
|
|
}
|
|
|
|
tempRGB = (guchar *) malloc (RW * RH * bytes);
|
|
tempHSV = (gdouble *) malloc (RW * RH * bytes * sizeof (gdouble));
|
|
tempmask = (guchar *) malloc (RW * RH);
|
|
|
|
gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height, FALSE, FALSE);
|
|
gimp_pixel_rgn_init (&srcMask, mask, x1, y1, width, height, FALSE, FALSE);
|
|
|
|
src_row = (guchar *) malloc (width * bytes);
|
|
src_mask_row = (guchar *) malloc (width * bytes);
|
|
|
|
for (i = 0; i < RH; i++)
|
|
{
|
|
whichrow = (gdouble) i * (gdouble) height / (gdouble) RH;
|
|
|
|
gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y1 + whichrow, width);
|
|
gimp_pixel_rgn_get_row (&srcMask, src_mask_row, x1, y1 + whichrow, width);
|
|
|
|
for (j = 0; j < RW; j++)
|
|
{
|
|
whichcol = (gdouble) j * (gdouble) width / (gdouble) RW;
|
|
|
|
if (NoSelectionMade)
|
|
tempmask[i * RW + j] = 255;
|
|
else
|
|
tempmask[i * RW + j] = src_mask_row[whichcol];
|
|
|
|
R = src_row[whichcol * bytes + 0];
|
|
G = src_row[whichcol * bytes + 1];
|
|
B = src_row[whichcol * bytes + 2];
|
|
|
|
gimp_rgb_set_uchar (&rgb, R, G, B);
|
|
gimp_rgb_to_hsv (&rgb, &hsv);
|
|
|
|
tempRGB[i * RW * bytes + j * bytes + 0] = R;
|
|
tempRGB[i * RW * bytes + j * bytes + 1] = G;
|
|
tempRGB[i * RW * bytes + j * bytes + 2] = B;
|
|
|
|
tempHSV[i * RW * bytes + j * bytes + 0] = hsv.h;
|
|
tempHSV[i * RW * bytes + j * bytes + 1] = hsv.s;
|
|
tempHSV[i * RW * bytes + j * bytes + 2] = hsv.v;
|
|
|
|
if (bytes == 4)
|
|
tempRGB[i * RW * bytes + j * bytes + 3] =
|
|
src_row[whichcol * bytes + 3];
|
|
}
|
|
}
|
|
|
|
temp->width = RW;
|
|
temp->height = RH;
|
|
temp->rgb = tempRGB;
|
|
temp->hsv = tempHSV;
|
|
temp->mask = tempmask;
|
|
|
|
return temp;
|
|
}
|
|
|
|
static void
|
|
fp_render_preview(GtkWidget *preview,
|
|
gint change_what,
|
|
gint change_which)
|
|
{
|
|
guchar *a;
|
|
gint Inten;
|
|
gint bytes = drawable->bpp;
|
|
gint i, j, k, nudge, M, m, middle, JudgeBy;
|
|
gdouble partial;
|
|
gint RW = reduced->width;
|
|
gint RH = reduced->height;
|
|
gint backupP[3];
|
|
gint P[3];
|
|
gint tempSat[JUDGE_BY][256];
|
|
|
|
a = g_new (guchar, 4*RW*RH);
|
|
|
|
if (change_what==SATURATION)
|
|
for (k = 0; k < 256; k++)
|
|
{
|
|
for (JudgeBy = BY_HUE; JudgeBy < JUDGE_BY; JudgeBy++)
|
|
tempSat[JudgeBy][k] = 0;
|
|
tempSat[fpvals.value_by][k] += change_which * nudgeArray[(k + fpvals.offset) % 256];
|
|
}
|
|
|
|
for (i = 0; i < RH; i++)
|
|
{
|
|
for (j = 0; j < RW; j++)
|
|
{
|
|
backupP[0] = P[0] = (int) reduced->rgb[i * RW * bytes + j * bytes + 0];
|
|
backupP[1] = P[1] = (int) reduced->rgb[i * RW * bytes + j * bytes + 1];
|
|
backupP[2] = P[2] = (int) reduced->rgb[i * RW * bytes + j * bytes + 2];
|
|
|
|
m = MIN (MIN (P[0], P[1]), P[2]);
|
|
M = MAX (MAX (P[0], P[1]), P[2]);
|
|
|
|
middle = (M + m) / 2;
|
|
|
|
for (k = 0; k < 3; k++)
|
|
if (P[k] != m && P[k] != M) middle = P[k];
|
|
|
|
partial = reduced->mask[i * RW + j] / 255.0;
|
|
|
|
for (JudgeBy = BY_HUE; JudgeBy < JUDGE_BY; JudgeBy++)
|
|
{
|
|
if (!fpvals.touched[JudgeBy]) continue;
|
|
|
|
Inten = reduced->hsv[i * RW * bytes + j * bytes + JudgeBy] * 255.0;
|
|
|
|
/*DO SATURATION FIRST*/
|
|
if (change_what != NONEATALL)
|
|
{
|
|
if (M != m)
|
|
{
|
|
for (k = 0; k < 3; k++)
|
|
if (backupP[k] == M)
|
|
P[k] = MAX (P[k] + partial * fpvals.sat_adjust[JudgeBy][Inten],
|
|
middle);
|
|
else if (backupP[k] == m)
|
|
P[k] = MIN (P[k] - partial * fpvals.sat_adjust[JudgeBy][Inten],
|
|
middle);
|
|
}
|
|
|
|
P[0] += partial * fpvals.red_adjust[JudgeBy][Inten];
|
|
P[1] += partial * fpvals.green_adjust[JudgeBy][Inten];
|
|
P[2] += partial * fpvals.blue_adjust[JudgeBy][Inten];
|
|
}
|
|
}
|
|
|
|
Inten = reduced->hsv[i * RW * bytes + j * bytes + fpvals.value_by] * 255.0;
|
|
nudge = partial * nudgeArray[(Inten + fpvals.offset) % 256];
|
|
|
|
switch (change_what)
|
|
{
|
|
case HUE:
|
|
P[0] += colorSign[RED][change_which] * nudge;
|
|
P[1] += colorSign[GREEN][change_which] * nudge;
|
|
P[2] += colorSign[BLUE][change_which] * nudge;
|
|
break;
|
|
|
|
case SATURATION:
|
|
for (JudgeBy = BY_HUE; JudgeBy < JUDGE_BY; JudgeBy++)
|
|
for (k = 0; k < 3; k++)
|
|
if (M != m)
|
|
{
|
|
if (backupP[k] == M)
|
|
P[k] = MAX (P[k] + partial * tempSat[JudgeBy][Inten],
|
|
middle);
|
|
else if (backupP[k] == m)
|
|
P[k] = MIN (P[k]- partial * tempSat[JudgeBy][Inten],
|
|
middle);
|
|
}
|
|
break;
|
|
|
|
case VALUE:
|
|
P[0] += change_which * nudge;
|
|
P[1] += change_which * nudge;
|
|
P[2] += change_which * nudge;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
a[(i * RW + j) * 4 + 0] = CLAMP0255(P[0]);
|
|
a[(i * RW + j) * 4 + 1] = CLAMP0255(P[1]);
|
|
a[(i * RW + j) * 4 + 2] = CLAMP0255(P[2]);
|
|
|
|
if (bytes == 4)
|
|
a[(i * RW + j) * 4 + 3] = reduced->rgb[i * RW * bytes + j * bytes + 3];
|
|
else
|
|
a[(i * RW + j) * 4 + 3] = 255;
|
|
}
|
|
}
|
|
|
|
gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview),
|
|
0, 0, RW, RH,
|
|
GIMP_RGBA_IMAGE,
|
|
a,
|
|
RW * 4);
|
|
g_free (a);
|
|
}
|
|
|
|
static void
|
|
update_current_fp (gint change_what,
|
|
gint change_which)
|
|
{
|
|
gint i;
|
|
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
gint nudge;
|
|
|
|
fp_create_nudge (nudgeArray);
|
|
nudge = nudgeArray[(i + fpvals.offset) % 256];
|
|
|
|
switch (change_what) {
|
|
case HUE:
|
|
fpvals.red_adjust[fpvals.value_by][i] +=
|
|
colorSign[RED][change_which] * nudge;
|
|
|
|
fpvals.green_adjust[fpvals.value_by][i] +=
|
|
colorSign[GREEN][change_which] * nudge;
|
|
|
|
fpvals.blue_adjust[fpvals.value_by][i] +=
|
|
colorSign[BLUE][change_which] * nudge;
|
|
break;
|
|
|
|
case SATURATION:
|
|
fpvals.sat_adjust[fpvals.value_by][i] += change_which * nudge;
|
|
break;
|
|
|
|
case VALUE:
|
|
fpvals.red_adjust[fpvals.value_by][i] += change_which * nudge;
|
|
fpvals.green_adjust[fpvals.value_by][i] += change_which * nudge;
|
|
fpvals.blue_adjust[fpvals.value_by][i] += change_which * nudge;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
fp_create_smoothness_graph (GtkWidget *preview)
|
|
{
|
|
guchar data[256 * MAX_ROUGHNESS * 3];
|
|
gint nArray[256];
|
|
gint i, j;
|
|
gboolean toBeBlack;
|
|
|
|
fp_create_nudge(nArray);
|
|
|
|
for (i = 0; i < MAX_ROUGHNESS; i++)
|
|
{
|
|
gint coor = MAX_ROUGHNESS - i;
|
|
for (j = 0; j < 256; j++) {
|
|
data[3 * (i * 256 + j) + 0] = 255;
|
|
data[3 * (i * 256 + j) + 1] = 255;
|
|
data[3 * (i * 256 + j) + 2] = 255;
|
|
if (!(i % (MAX_ROUGHNESS / 4))) {
|
|
data[3 * (i * 256 + j) + 0] = 255;
|
|
data[3 * (i * 256 + j) + 1] = 128;
|
|
data[3 * (i * 256 + j) + 2] = 128;
|
|
}
|
|
if (!((j + 1) % 32)) {
|
|
data[3 * (i * 256 + j) + 0] = 255;
|
|
data[3 * (i * 256 + j) + 1] = 128;
|
|
data[3 * (i * 256 + j) + 2] = 128;
|
|
}
|
|
toBeBlack = FALSE;
|
|
if (nArray[j] == coor)
|
|
toBeBlack = TRUE;
|
|
|
|
if (j < 255) {
|
|
gint jump = abs (nArray[j] - nArray[j+1]);
|
|
if (abs (coor - nArray[j]) < jump &&
|
|
abs (coor - nArray[j + 1]) < jump)
|
|
toBeBlack = TRUE;
|
|
}
|
|
if (toBeBlack) {
|
|
data[3 * (i * 256 + j) + 0] = 0;
|
|
data[3 * (i * 256 + j) + 1] = 0;
|
|
data[3 * (i * 256 + j) + 2] = 0;
|
|
}
|
|
}
|
|
}
|
|
gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview),
|
|
0, 0, 256, MAX_ROUGHNESS,
|
|
GIMP_RGB_IMAGE,
|
|
data,
|
|
256 * 3);
|
|
}
|
|
|
|
static void
|
|
fp_range_preview_spill (GtkWidget *preview,
|
|
gint type)
|
|
{
|
|
gint i, j;
|
|
guchar data[256 * RANGE_HEIGHT * 3];
|
|
|
|
for (i = 0; i < RANGE_HEIGHT; i++)
|
|
{
|
|
for (j = 0; j < 256; j++)
|
|
{
|
|
GimpRGB rgb;
|
|
GimpHSV hsv;
|
|
|
|
if (! ((j + 1) % 32))
|
|
{
|
|
data[3 * (i * 256 + j) + 0] = 255;
|
|
data[3 * (i * 256 + j) + 1] = 128;
|
|
data[3 * (i * 256 + j) + 2] = 128;
|
|
}
|
|
else
|
|
{
|
|
switch (type)
|
|
{
|
|
case BY_VAL:
|
|
data[3 * (i * 256 + j) + 0] = j - fpvals.offset;
|
|
data[3 * (i * 256 + j) + 1] = j - fpvals.offset;
|
|
data[3 * (i * 256 + j) + 2] = j - fpvals.offset;
|
|
break;
|
|
|
|
case BY_HUE:
|
|
gimp_hsv_set (&hsv,
|
|
((j - fpvals.offset + 256) % 256) / 255.0,
|
|
1.0,
|
|
0.5);
|
|
gimp_hsv_to_rgb (&hsv, &rgb);
|
|
gimp_rgb_get_uchar (&rgb,
|
|
&data[3 * (i * 256 + j) + 0],
|
|
&data[3 * (i * 256 + j) + 1],
|
|
&data[3 * (i * 256 + j) + 2]);
|
|
break;
|
|
|
|
case BY_SAT:
|
|
gimp_hsv_set (&hsv,
|
|
0.5,
|
|
((j-(gint)fpvals.offset+256)%256) / 255.0,
|
|
0.5);
|
|
gimp_hsv_to_rgb (&hsv, &rgb);
|
|
gimp_rgb_get_uchar (&rgb,
|
|
&data[3 * (i * 256 + j) + 0],
|
|
&data[3 * (i * 256 + j) + 1],
|
|
&data[3 * (i * 256 + j) + 2]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview),
|
|
0, 0, 256, RANGE_HEIGHT,
|
|
GIMP_RGB_IMAGE,
|
|
data,
|
|
256 * 3);
|
|
}
|
|
|
|
static void
|
|
fp_create_nudge (gint *adj_array)
|
|
{
|
|
gint left, right, middle,i;
|
|
/* The following function was determined by trial and error */
|
|
gdouble Steepness = pow (1 - fpvals.aliasing, 4) * .8;
|
|
|
|
left = (fpvals.intensity_range == SHADOWS) ? 0 : fpvals.cutoff[fpvals.intensity_range - 1];
|
|
right = fpvals.cutoff[fpvals.intensity_range];
|
|
middle = (left + right)/2;
|
|
|
|
if (fpvals.aliasing)
|
|
for (i = 0; i < 256; i++)
|
|
if (i <= middle)
|
|
adj_array[i] = MAX_ROUGHNESS *
|
|
fpvals.roughness * (1 + tanh (Steepness * (i - left))) / 2;
|
|
else
|
|
adj_array[i] = MAX_ROUGHNESS *
|
|
fpvals.roughness * (1 + tanh (Steepness * (right - i))) / 2;
|
|
else
|
|
for (i = 0; i < 256; i++)
|
|
adj_array[i] = (left <= i && i <= right)
|
|
? MAX_ROUGHNESS * fpvals.roughness : 0;
|
|
}
|
|
|
|
static void
|
|
fp_preview_size_allocate (GtkWidget *widget,
|
|
GtkAllocation *allocation)
|
|
{
|
|
gint which = fpvals.visible_frames;
|
|
|
|
if (widget == origPreview)
|
|
fp_render_preview (origPreview, NONEATALL, 0);
|
|
else if (widget == curPreview)
|
|
fp_render_preview (curPreview, CURRENT, 0);
|
|
|
|
if (which & HUE)
|
|
{
|
|
if (widget == rPreview)
|
|
fp_render_preview (rPreview, HUE, RED);
|
|
else if (widget == gPreview)
|
|
fp_render_preview (gPreview, HUE, GREEN);
|
|
else if (widget == bPreview)
|
|
fp_render_preview (bPreview, HUE, BLUE);
|
|
else if (widget == cPreview)
|
|
fp_render_preview (cPreview, HUE, CYAN);
|
|
else if (widget == yPreview)
|
|
fp_render_preview (yPreview, HUE, YELLOW);
|
|
else if (widget == mPreview)
|
|
fp_render_preview (mPreview, HUE, MAGENTA);
|
|
else if (widget == centerPreview)
|
|
fp_render_preview (centerPreview, CURRENT, 0);
|
|
}
|
|
|
|
if (which & VALUE)
|
|
{
|
|
if (widget == lighterPreview)
|
|
fp_render_preview (lighterPreview, VALUE, UP);
|
|
else if (widget == middlePreview)
|
|
fp_render_preview (middlePreview, CURRENT, 0);
|
|
else if (widget == darkerPreview)
|
|
fp_render_preview (darkerPreview, VALUE, DOWN);
|
|
}
|
|
|
|
if (which & SATURATION)
|
|
{
|
|
if (widget == plusSatPreview)
|
|
fp_render_preview (plusSatPreview, SATURATION, UP);
|
|
else if (widget == SatPreview)
|
|
fp_render_preview (SatPreview, CURRENT, 0);
|
|
else if (widget == minusSatPreview)
|
|
fp_render_preview (minusSatPreview, SATURATION, DOWN);
|
|
}
|
|
}
|