mirror of https://github.com/GNOME/gimp.git
1970 lines
54 KiB
C
1970 lines
54 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 <gtk/gtk.h>
|
|
|
|
#include <libgimp/gimp.h>
|
|
#include <libgimp/gimpui.h>
|
|
|
|
#include "libgimp/stdplugins-intl.h"
|
|
|
|
#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 HELP_ID "plug-in-filter-pack"
|
|
|
|
#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
|
|
}FP_Intensity;
|
|
|
|
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 *shadowsEntry;
|
|
GtkWidget *midtonesEntry;
|
|
GtkWidget *rangePreview;
|
|
GtkWidget *aliasingPreview;
|
|
GtkObject *aliasingData;
|
|
GtkWidget *aliasingGraph;
|
|
} AdvancedWindow;
|
|
|
|
|
|
typedef struct {
|
|
int Color;
|
|
float Rough;
|
|
GtkWidget *roughnessScale;
|
|
float Alias;
|
|
GtkWidget *aliasingScale;
|
|
float PreviewSize;
|
|
GtkWidget *previewSizeScale;
|
|
FP_Intensity Range;
|
|
gint ValueBy;
|
|
gint SlctnOnly;
|
|
gint RealTime;
|
|
guchar Offset;
|
|
guchar VisibleFrames;
|
|
guchar Cutoffs[INTENSITIES];
|
|
gint Touched[JUDGE_BY];
|
|
gint redAdj[JUDGE_BY][256];
|
|
gint blueAdj[JUDGE_BY][256];
|
|
gint greenAdj[JUDGE_BY][256];
|
|
gint satAdj[JUDGE_BY][256];
|
|
GtkWidget *rangeLabels[12];
|
|
} FP_Params;
|
|
|
|
static void fp_show_hide_frame(GtkWidget *button,
|
|
GtkWidget *frame);
|
|
|
|
static ReducedImage *Reduce_The_Image (GimpDrawable *,
|
|
GimpDrawable *,
|
|
gint,
|
|
gint);
|
|
|
|
static void fp_render_preview (GtkWidget *,
|
|
gint,
|
|
gint);
|
|
|
|
static void Update_Current_FP (gint,
|
|
gint);
|
|
|
|
static void fp_Create_Nudge (gint*);
|
|
|
|
static gboolean fp_dialog (void);
|
|
static void fp_advanced_dialog (void);
|
|
|
|
static void selectionMade (GtkWidget *,
|
|
gpointer );
|
|
static void fp_scale_update (GtkAdjustment *,
|
|
float* );
|
|
static void resetFilterPacks (void);
|
|
|
|
static void fp_create_smoothness_graph (GtkWidget* );
|
|
|
|
static void fp_range_preview_spill (GtkWidget*,
|
|
gint );
|
|
static gint fp_fake_transparency (gint i, gint j);
|
|
|
|
static void Adjust_Preview_Sizes (gint width,
|
|
gint height );
|
|
static void fp_redraw_all_windows (void);
|
|
static void refreshPreviews (int);
|
|
static void initializeFilterPacks (void);
|
|
|
|
static void As_You_Drag (GtkWidget *button);
|
|
static void preview_size_scale_update (GtkAdjustment *adjustment,
|
|
float *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,
|
|
FP_Params *current);
|
|
|
|
static void Create_A_Preview (GtkWidget **,
|
|
GtkWidget **,
|
|
int,
|
|
int );
|
|
|
|
static void Create_A_Table_Entry (GtkWidget **,
|
|
GtkWidget *,
|
|
const gchar *);
|
|
|
|
static void Check_Button_In_A_Box (GtkWidget *,
|
|
const gchar *label,
|
|
GtkSignalFunc func,
|
|
gpointer data,
|
|
int clicked);
|
|
|
|
static void Frames_Check_Button_In_A_Box (GtkWidget *,
|
|
const gchar *label,
|
|
GtkSignalFunc func,
|
|
GtkWidget *frame,
|
|
int clicked);
|
|
|
|
|
|
#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, 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;
|
|
} fpFrames;
|
|
|
|
static fpInterface FPint =
|
|
{
|
|
FALSE /* run */
|
|
};
|
|
|
|
static ReducedImage *reduced;
|
|
|
|
static FP_Params Current =
|
|
{
|
|
1,
|
|
.25, /* Initial Roughness */
|
|
NULL,
|
|
.6, /* Initial Degree of Aliasing */
|
|
NULL,
|
|
80,
|
|
NULL,
|
|
MIDTONES, /* Initial Range */
|
|
BY_VAL, /* Initial God knows what */
|
|
TRUE, /* Selection Only */
|
|
TRUE, /* Real Time */
|
|
0, /* Offset */
|
|
0,
|
|
{32,224,255},
|
|
{0,0,0}
|
|
};
|
|
|
|
static GimpDrawable *drawable, *mask;
|
|
static GimpRunMode run_mode;
|
|
|
|
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_filter_pack",
|
|
"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_filter_pack",
|
|
N_("<Image>/Filters/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;
|
|
|
|
*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;
|
|
|
|
initializeFilterPacks();
|
|
|
|
drawable = gimp_drawable_get (param[2].data.d_drawable);
|
|
mask = gimp_drawable_get (gimp_image_get_selection (param[1].data.d_image));
|
|
|
|
if (gimp_drawable_is_indexed (drawable->drawable_id) ||
|
|
gimp_drawable_is_gray (drawable->drawable_id) )
|
|
{
|
|
gimp_message (_("Convert the image to RGB first!"));
|
|
status = GIMP_PDB_EXECUTION_ERROR;
|
|
}
|
|
else if (gimp_drawable_is_rgb (drawable->drawable_id) && fp_dialog())
|
|
{
|
|
gimp_progress_init (_("Applying the Filter Pack..."));
|
|
gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
|
|
fp (drawable);
|
|
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 (!Current.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] + Current.satAdj[JudgeBy][Intensity], middle);
|
|
else if (P[k] == m)
|
|
P[k] = MIN (P[k] - Current.satAdj[JudgeBy][Intensity], middle);
|
|
}
|
|
|
|
P[0] += Current.redAdj[JudgeBy][Intensity];
|
|
P[1] += Current.greenAdj[JudgeBy][Intensity];
|
|
P[2] += Current.blueAdj[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, run_mode, fp_func, NULL);
|
|
}
|
|
|
|
/***********************************************************/
|
|
/************ Main Dialog Window ******************/
|
|
/***********************************************************/
|
|
|
|
static GtkWidget *
|
|
fp_create_bna (void)
|
|
{
|
|
GtkWidget *frame, *blabel, *alabel, *bframe, *aframe, *table;
|
|
|
|
Create_A_Preview (&origPreview, &bframe, reduced->width, reduced->height);
|
|
Create_A_Preview (&curPreview, &aframe, reduced->width, reduced->height);
|
|
|
|
frame = gtk_frame_new (_("Before and After"));
|
|
|
|
/* All the previews */
|
|
alabel = gtk_label_new (_("Current:"));
|
|
gtk_widget_show (alabel);
|
|
gtk_misc_set_alignment (GTK_MISC (alabel), 0.0, 0.5);
|
|
|
|
blabel = gtk_label_new (_("Original:"));
|
|
gtk_widget_show (blabel);
|
|
gtk_misc_set_alignment (GTK_MISC (blabel), 0.0, 0.5);
|
|
|
|
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);
|
|
|
|
gtk_container_add (GTK_CONTAINER (frame), table);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), blabel, 0, 1, 0, 1,
|
|
0, GTK_EXPAND | GTK_FILL, 0, 0);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), alabel, 1, 2, 0, 1,
|
|
0, GTK_EXPAND | GTK_FILL, 0, 0);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), bframe, 0, 1, 1, 2,
|
|
GTK_EXPAND, GTK_EXPAND, 0, 0);
|
|
|
|
gtk_table_attach (GTK_TABLE (table), aframe, 1, 2, 1, 2,
|
|
GTK_EXPAND, GTK_EXPAND, 0, 0);
|
|
|
|
gtk_widget_show (table);
|
|
gtk_widget_show (frame);
|
|
|
|
return frame;
|
|
}
|
|
|
|
/* 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, HELP_ID, 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);
|
|
|
|
Create_A_Preview (&rPreview, &rFrame, reduced->width, reduced->height);
|
|
Create_A_Preview (&gPreview, &gFrame, reduced->width, reduced->height);
|
|
Create_A_Preview (&bPreview, &bFrame, reduced->width, reduced->height);
|
|
Create_A_Preview (&cPreview, &cFrame, reduced->width, reduced->height);
|
|
Create_A_Preview (&yPreview, &yFrame, reduced->width, reduced->height);
|
|
Create_A_Preview (&mPreview, &mFrame, reduced->width, reduced->height);
|
|
Create_A_Preview (¢erPreview, ¢erFrame,
|
|
reduced->width, reduced->height);
|
|
|
|
Create_A_Table_Entry (&rVbox, rFrame, hue_red);
|
|
Create_A_Table_Entry (&gVbox, gFrame, hue_green);
|
|
Create_A_Table_Entry (&bVbox, bFrame, hue_blue);
|
|
Create_A_Table_Entry (&cVbox, cFrame, hue_cyan);
|
|
Create_A_Table_Entry (&yVbox, yFrame, hue_yellow);
|
|
Create_A_Table_Entry (&mVbox, mFrame, hue_magenta);
|
|
Create_A_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 (Current.Rough, 0, 1.0, 0.05, 0.01, 0.0);
|
|
Current.roughnessScale = 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),
|
|
&Current.Rough);
|
|
|
|
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)
|
|
{
|
|
refreshPreviews (Current.VisibleFrames);
|
|
if (AW.window && GTK_WIDGET_VISIBLE (AW.window))
|
|
fp_create_smoothness_graph (AW.aliasingPreview);
|
|
}
|
|
}
|
|
|
|
static GtkWidget *
|
|
fp_create_range (void)
|
|
{
|
|
GtkWidget *frame;
|
|
|
|
frame = gimp_int_radio_group_new (TRUE, _("Affected Range"),
|
|
G_CALLBACK (fp_change_current_range),
|
|
&Current.Range, Current.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);
|
|
|
|
Frames_Check_Button_In_A_Box (box, _("_Hue"),
|
|
GTK_SIGNAL_FUNC (fp_show_hide_frame),
|
|
fpFrames.palette,
|
|
Current.VisibleFrames & HUE);
|
|
Frames_Check_Button_In_A_Box (box, _("_Saturation"),
|
|
GTK_SIGNAL_FUNC (fp_show_hide_frame),
|
|
fpFrames.satur,
|
|
Current.VisibleFrames & SATURATION);
|
|
Frames_Check_Button_In_A_Box (box, _("_Value"),
|
|
GTK_SIGNAL_FUNC (fp_show_hide_frame),
|
|
fpFrames.lnd,
|
|
Current.VisibleFrames & VALUE);
|
|
Frames_Check_Button_In_A_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, HELP_ID, NULL);
|
|
|
|
gtk_window_set_title (GTK_WINDOW (win), _("Value Variations"));
|
|
|
|
g_signal_connect (win, "delete_event",
|
|
G_CALLBACK (sub_dialog_destroy),
|
|
NULL);
|
|
|
|
Create_A_Preview (&lighterPreview, &lighterFrame,
|
|
reduced->width, reduced->height);
|
|
Create_A_Preview (&middlePreview, &middleFrame,
|
|
reduced->width, reduced->height);
|
|
Create_A_Preview (&darkerPreview, &darkerFrame,
|
|
reduced->width, reduced->height);
|
|
|
|
Create_A_Table_Entry (&lighterVbox, lighterFrame, val_lighter);
|
|
Create_A_Table_Entry (&middleVbox, middleFrame, current_val);
|
|
Create_A_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, HELP_ID, NULL);
|
|
|
|
gtk_window_set_title (GTK_WINDOW (win), _("Saturation Variations"));
|
|
|
|
g_signal_connect (win, "delete_event",
|
|
G_CALLBACK (sub_dialog_destroy),
|
|
NULL);
|
|
|
|
Create_A_Preview (&minusSatPreview, &lessFrame,
|
|
reduced->width, reduced->height);
|
|
Create_A_Preview (&SatPreview, &middleFrame,
|
|
reduced->width, reduced->height);
|
|
Create_A_Preview (&plusSatPreview, &moreFrame,
|
|
reduced->width, reduced->height);
|
|
|
|
Create_A_Table_Entry (&moreVbox, moreFrame, sat_more);
|
|
Create_A_Table_Entry (&middleVbox, middleFrame, current_val);
|
|
Create_A_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)
|
|
{
|
|
refreshPreviews (Current.VisibleFrames);
|
|
if (AW.window && GTK_WIDGET_VISIBLE (AW.window) && AW.rangePreview)
|
|
fp_range_preview_spill (AW.rangePreview,Current.ValueBy);
|
|
}
|
|
}
|
|
|
|
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),
|
|
&Current.ValueBy,
|
|
Current.ValueBy,
|
|
|
|
_("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),
|
|
&Current.SlctnOnly,
|
|
Current.SlctnOnly,
|
|
|
|
_("_Entire Image"), 0, NULL,
|
|
_("Se_lection Only"), 1, NULL,
|
|
_("Selec_tion In Context"), 2, NULL,
|
|
|
|
NULL);
|
|
|
|
gtk_widget_show (frame);
|
|
|
|
return frame;
|
|
}
|
|
|
|
static void
|
|
Create_A_Preview (GtkWidget **preview,
|
|
GtkWidget **frame,
|
|
gint previewWidth,
|
|
gint previewHeight)
|
|
{
|
|
*frame = gtk_frame_new (NULL);
|
|
gtk_frame_set_shadow_type (GTK_FRAME (*frame), GTK_SHADOW_IN);
|
|
gtk_widget_show (*frame);
|
|
|
|
*preview = gtk_preview_new (Current.Color ?
|
|
GTK_PREVIEW_COLOR : GTK_PREVIEW_GRAYSCALE);
|
|
gtk_preview_size (GTK_PREVIEW (*preview), previewWidth, previewHeight);
|
|
gtk_widget_show (*preview);
|
|
gtk_container_add (GTK_CONTAINER (*frame), *preview);
|
|
}
|
|
|
|
static void
|
|
Check_Button_In_A_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
|
|
Frames_Check_Button_In_A_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
|
|
Create_A_Table_Entry (GtkWidget **box,
|
|
GtkWidget *SmallerFrame,
|
|
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), SmallerFrame);
|
|
|
|
g_signal_connect (button, "clicked",
|
|
G_CALLBACK (selectionMade),
|
|
(gchar *) description);
|
|
}
|
|
else
|
|
{
|
|
gtk_table_attach (GTK_TABLE (table), SmallerFrame, 0, 1, 1, 2,
|
|
0, 0, 0, 4);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fp_redraw_all_windows (void)
|
|
{
|
|
reduced = Reduce_The_Image (drawable,mask,
|
|
Current.PreviewSize,
|
|
Current.SlctnOnly);
|
|
Adjust_Preview_Sizes (reduced->width, reduced->height);
|
|
|
|
gtk_widget_queue_draw (fpFrames.palette);
|
|
gtk_widget_queue_draw (fpFrames.satur);
|
|
gtk_widget_queue_draw (fpFrames.lnd);
|
|
gtk_widget_queue_draw (dlg);
|
|
|
|
refreshPreviews (Current.VisibleFrames);
|
|
}
|
|
|
|
static void
|
|
fp_show_hide_frame (GtkWidget *button,
|
|
GtkWidget *frame)
|
|
{
|
|
gint prev = Current.VisibleFrames;
|
|
|
|
if (frame == NULL)
|
|
return;
|
|
|
|
if (GTK_TOGGLE_BUTTON (button)->active)
|
|
{
|
|
if (!GTK_WIDGET_VISIBLE (frame))
|
|
{
|
|
gtk_widget_show (frame);
|
|
|
|
if (frame==fpFrames.palette)
|
|
Current.VisibleFrames |= HUE;
|
|
else if (frame==fpFrames.satur)
|
|
Current.VisibleFrames |= SATURATION;
|
|
else if (frame==fpFrames.lnd)
|
|
Current.VisibleFrames |= VALUE;
|
|
|
|
refreshPreviews (Current.VisibleFrames & ~prev);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GTK_WIDGET_VISIBLE (frame))
|
|
{
|
|
gtk_widget_hide (frame);
|
|
|
|
if (frame==fpFrames.palette)
|
|
Current.VisibleFrames &= ~HUE;
|
|
else if (frame==fpFrames.satur)
|
|
Current.VisibleFrames &= ~SATURATION;
|
|
else if (frame==fpFrames.lnd)
|
|
Current.VisibleFrames &= ~VALUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
Adjust_Preview_Sizes (gint width,
|
|
gint height)
|
|
{
|
|
gtk_preview_size (GTK_PREVIEW (origPreview), width, height);
|
|
gtk_preview_size (GTK_PREVIEW (curPreview), width, height);
|
|
gtk_preview_size (GTK_PREVIEW (rPreview), width, height);
|
|
gtk_preview_size (GTK_PREVIEW (gPreview), width, height);
|
|
gtk_preview_size (GTK_PREVIEW (bPreview), width, height);
|
|
gtk_preview_size (GTK_PREVIEW (cPreview), width, height);
|
|
gtk_preview_size (GTK_PREVIEW (yPreview), width, height);
|
|
gtk_preview_size (GTK_PREVIEW (mPreview), width, height);
|
|
gtk_preview_size (GTK_PREVIEW (centerPreview), width, height);
|
|
gtk_preview_size (GTK_PREVIEW (lighterPreview), width, height);
|
|
gtk_preview_size (GTK_PREVIEW (darkerPreview), width, height);
|
|
gtk_preview_size (GTK_PREVIEW (middlePreview), width, height);
|
|
gtk_preview_size (GTK_PREVIEW (minusSatPreview), width, height);
|
|
gtk_preview_size (GTK_PREVIEW (SatPreview), width, height);
|
|
gtk_preview_size (GTK_PREVIEW (plusSatPreview), width, height);
|
|
}
|
|
|
|
static void
|
|
selectionMade (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
Current.Touched[Current.ValueBy] = 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);
|
|
}
|
|
|
|
refreshPreviews (Current.VisibleFrames);
|
|
}
|
|
|
|
static void
|
|
refreshPreviews (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:
|
|
resetFilterPacks ();
|
|
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,
|
|
float *scale_val)
|
|
{
|
|
static gfloat prevValue = 0.25;
|
|
|
|
*scale_val = adjustment->value;
|
|
|
|
if (prevValue != adjustment->value)
|
|
{
|
|
fp_Create_Nudge (nudgeArray);
|
|
refreshPreviews (Current.VisibleFrames);
|
|
if (AW.window != NULL && GTK_WIDGET_VISIBLE (AW.window))
|
|
fp_create_smoothness_graph (AW.aliasingPreview);
|
|
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 = Reduce_The_Image (drawable,mask,
|
|
Current.PreviewSize,
|
|
Current.SlctnOnly);
|
|
|
|
gimp_ui_init ("fp", TRUE);
|
|
|
|
dlg = gimp_dialog_new (_("Filter Pack Simulation"), "fp",
|
|
NULL, 0,
|
|
gimp_standard_help_func, HELP_ID,
|
|
|
|
GIMP_STOCK_RESET, RESPONSE_RESET,
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
GTK_STOCK_OK, GTK_RESPONSE_OK,
|
|
|
|
NULL);
|
|
|
|
g_signal_connect (dlg, "response",
|
|
G_CALLBACK (fp_response),
|
|
dlg);
|
|
|
|
g_signal_connect (dlg, "destroy",
|
|
G_CALLBACK (gtk_main_quit),
|
|
NULL);
|
|
|
|
fp_advanced_dialog ();
|
|
|
|
fpFrames.bna = bna = fp_create_bna();
|
|
fpFrames.rough = rough = fp_create_rough();
|
|
fpFrames.range = range = fp_create_range();
|
|
fpFrames.palette = palette = fp_create_circle_palette();
|
|
fpFrames.lnd = lnd = fp_create_lnd();
|
|
fpFrames.show = show = fp_create_show();
|
|
fpFrames.satur = satur = fp_create_msnls();
|
|
fpFrames.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);
|
|
|
|
refreshPreviews (Current.VisibleFrames);
|
|
|
|
gtk_main ();
|
|
|
|
return FPint.run;
|
|
}
|
|
|
|
/***********************************************************/
|
|
/************ Advanced Options Window ******************/
|
|
/***********************************************************/
|
|
|
|
static void
|
|
As_You_Drag (GtkWidget *button)
|
|
{
|
|
static gboolean notFirstTime = FALSE;
|
|
|
|
if (! notFirstTime)
|
|
return;
|
|
|
|
notFirstTime = TRUE;
|
|
|
|
if (GTK_TOGGLE_BUTTON (button)->active)
|
|
{
|
|
Current.RealTime=TRUE;
|
|
gtk_range_set_update_policy (GTK_RANGE (Current.roughnessScale),0);
|
|
gtk_range_set_update_policy (GTK_RANGE (Current.aliasingScale),0);
|
|
gtk_range_set_update_policy (GTK_RANGE (Current.previewSizeScale),0);
|
|
}
|
|
else
|
|
{
|
|
Current.RealTime=FALSE;
|
|
gtk_range_set_update_policy (GTK_RANGE (Current.roughnessScale),
|
|
GTK_UPDATE_DELAYED);
|
|
gtk_range_set_update_policy (GTK_RANGE (Current.aliasingScale),
|
|
GTK_UPDATE_DELAYED);
|
|
gtk_range_set_update_policy (GTK_RANGE (Current.previewSizeScale),
|
|
GTK_UPDATE_DELAYED);
|
|
}
|
|
}
|
|
|
|
static void
|
|
preview_size_scale_update (GtkAdjustment *adjustment,
|
|
float *scale_val)
|
|
{
|
|
Current.PreviewSize = 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;
|
|
gint i;
|
|
|
|
AW.window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
gimp_help_connect (AW.window, gimp_standard_help_func, HELP_ID, 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_frame_new (NULL);
|
|
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);
|
|
|
|
AW.aliasingPreview = gtk_preview_new (GTK_PREVIEW_COLOR);
|
|
gtk_preview_size (GTK_PREVIEW (AW.aliasingPreview), 256, MAX_ROUGHNESS);
|
|
gtk_box_pack_start (GTK_BOX (vbox), AW.aliasingPreview, TRUE, TRUE, 0);
|
|
gtk_widget_show (AW.aliasingPreview);
|
|
|
|
fp_create_smoothness_graph (AW.aliasingPreview);
|
|
|
|
AW.rangePreview = gtk_preview_new (GTK_PREVIEW_COLOR);
|
|
gtk_preview_size (GTK_PREVIEW (AW.rangePreview), 256, RANGE_HEIGHT);
|
|
gtk_box_pack_start(GTK_BOX(vbox),AW.rangePreview, TRUE, TRUE, 0);
|
|
gtk_widget_show (AW.rangePreview);
|
|
|
|
fp_range_preview_spill (AW.rangePreview, Current.ValueBy);
|
|
|
|
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 = Current.rangeLabels[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.aliasingGraph = gtk_drawing_area_new ();
|
|
gtk_widget_set_size_request (AW.aliasingGraph,
|
|
2 * MARGIN + 256,
|
|
RANGE_HEIGHT);
|
|
gtk_box_pack_start (GTK_BOX (vbox), AW.aliasingGraph, TRUE, TRUE, 0);
|
|
gtk_widget_show (AW.aliasingGraph);
|
|
gtk_widget_set_events (AW.aliasingGraph, RANGE_ADJUST_MASK);
|
|
|
|
g_signal_connect (AW.aliasingGraph, "event",
|
|
G_CALLBACK (FP_Range_Change_Events),
|
|
&Current);
|
|
|
|
/************************************************************/
|
|
|
|
smoothnessData = gtk_adjustment_new (Current.Alias, 0, 1.0, 0.05, 0.01, 0.0);
|
|
|
|
Current.aliasingScale = 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),
|
|
&Current.Alias);
|
|
|
|
/******************* MISC OPTIONS ***************************/
|
|
|
|
vbox = gtk_vbox_new (FALSE, 6);
|
|
gtk_box_pack_start (GTK_BOX (mainvbox), vbox, TRUE, TRUE, 0);
|
|
gtk_widget_show (vbox);
|
|
|
|
Check_Button_In_A_Box (vbox, _("Preview as You Drag"),
|
|
GTK_SIGNAL_FUNC (As_You_Drag),
|
|
NULL, TRUE);
|
|
|
|
frame = gimp_frame_new (_("Preview Size"));
|
|
gtk_widget_show (frame);
|
|
|
|
smoothnessData = gtk_adjustment_new (Current.PreviewSize,
|
|
50, MAX_PREVIEW_SIZE,
|
|
5, 5, 0.0);
|
|
|
|
Current.previewSizeScale = 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 (preview_size_scale_update),
|
|
&Current.PreviewSize);
|
|
|
|
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.aliasingGraph->window,
|
|
AW.aliasingGraph->style->black_gc,
|
|
AW.aliasingGraph->style->dark_gc[GTK_STATE_NORMAL],
|
|
Current.Cutoffs[SHADOWS]);
|
|
|
|
draw_slider (AW.aliasingGraph->window,
|
|
AW.aliasingGraph->style->black_gc,
|
|
AW.aliasingGraph->style->dark_gc[GTK_STATE_NORMAL],
|
|
Current.Cutoffs[MIDTONES]);
|
|
|
|
draw_slider (AW.aliasingGraph->window,
|
|
AW.aliasingGraph->style->black_gc,
|
|
AW.aliasingGraph->style->dark_gc[GTK_STATE_SELECTED],
|
|
Current.Offset);
|
|
}
|
|
|
|
static gboolean
|
|
FP_Range_Change_Events (GtkWidget *widget,
|
|
GdkEvent *event,
|
|
FP_Params *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 - Current.Cutoffs[SHADOWS]);
|
|
mid = abs (bevent->x - Current.Cutoffs[MIDTONES]);
|
|
offset = abs (bevent->x - Current.Offset);
|
|
|
|
min = MIN (MIN (shad, mid), offset);
|
|
|
|
if (bevent->x >0 && bevent->x<256)
|
|
{
|
|
if (min == shad)
|
|
new = &Current.Cutoffs[SHADOWS];
|
|
else if (min == mid)
|
|
new = &Current.Cutoffs[MIDTONES];
|
|
else
|
|
new = &Current.Offset;
|
|
|
|
slider_erase (AW.aliasingGraph->window, *new);
|
|
*new = bevent->x;
|
|
}
|
|
|
|
draw_it (NULL);
|
|
|
|
if (Current.RealTime)
|
|
{
|
|
fp_range_preview_spill (AW.rangePreview, Current.ValueBy);
|
|
update_range_labels ();
|
|
fp_create_smoothness_graph (AW.aliasingPreview);
|
|
refreshPreviews (Current.VisibleFrames);
|
|
}
|
|
break;
|
|
|
|
case GDK_BUTTON_RELEASE:
|
|
if (!Current.RealTime)
|
|
{
|
|
fp_range_preview_spill (AW.rangePreview, Current.ValueBy);
|
|
update_range_labels ();
|
|
fp_create_smoothness_graph (AW.aliasingPreview);
|
|
refreshPreviews (Current.VisibleFrames);
|
|
}
|
|
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.aliasingGraph->window, *new);
|
|
*new = x;
|
|
draw_it (NULL);
|
|
if (Current.RealTime)
|
|
{
|
|
fp_range_preview_spill (AW.rangePreview, Current.ValueBy);
|
|
update_range_labels ();
|
|
fp_create_smoothness_graph (AW.aliasingPreview);
|
|
refreshPreviews (Current.VisibleFrames);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
update_range_labels (void)
|
|
{
|
|
gchar buffer[3];
|
|
|
|
gtk_label_set_text (GTK_LABEL(Current.rangeLabels[1]),"0");
|
|
|
|
g_snprintf (buffer, sizeof (buffer), "%d", Current.Cutoffs[SHADOWS]);
|
|
gtk_label_set_text (GTK_LABEL (Current.rangeLabels[3]), buffer);
|
|
gtk_label_set_text (GTK_LABEL (Current.rangeLabels[5]), buffer);
|
|
|
|
g_snprintf (buffer, sizeof (buffer), "%d", Current.Cutoffs[MIDTONES]);
|
|
gtk_label_set_text (GTK_LABEL (Current.rangeLabels[7]), buffer);
|
|
gtk_label_set_text (GTK_LABEL (Current.rangeLabels[9]), buffer);
|
|
|
|
gtk_label_set_text (GTK_LABEL(Current.rangeLabels[11]), "255");
|
|
}
|
|
|
|
static void
|
|
initializeFilterPacks (void)
|
|
{
|
|
gint i, j;
|
|
for (i = 0; i < 256; i++)
|
|
for (j = BY_HUE; j < JUDGE_BY; j++)
|
|
{
|
|
Current.redAdj [j][i] = 0;
|
|
Current.greenAdj [j][i] = 0;
|
|
Current.blueAdj [j][i] = 0;
|
|
Current.satAdj [j][i] = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
resetFilterPacks (void)
|
|
{
|
|
initializeFilterPacks ();
|
|
refreshPreviews (Current.VisibleFrames);
|
|
}
|
|
|
|
static ReducedImage *
|
|
Reduce_The_Image (GimpDrawable *drawable,
|
|
GimpDrawable *mask,
|
|
gint LongerSize,
|
|
gint Slctn)
|
|
{
|
|
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 (Slctn == 0)
|
|
{
|
|
x1 = 0;
|
|
x2 = drawable->width;
|
|
y1 = 0;
|
|
y2 = drawable->height;
|
|
}
|
|
else if (Slctn == 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 = LongerSize;
|
|
RH = (gfloat) height * (gfloat) LongerSize / (gfloat) width;
|
|
}
|
|
else
|
|
{
|
|
RH = LongerSize;
|
|
RW = (gfloat) width * (gfloat) LongerSize / (gfloat) 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 = (gfloat) i * (gfloat) height / (gfloat) 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 = (gfloat) j * (gfloat) width / (gfloat) 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 changewhat,
|
|
gint changewhich)
|
|
{
|
|
guchar *a;
|
|
gint Inten, bytes = drawable->bpp;
|
|
gint i, j, k, nudge, M, m, middle,JudgeBy;
|
|
float partial;
|
|
gint RW = reduced->width;
|
|
gint RH = reduced->height;
|
|
gint backupP[3], P[3], tempSat[JUDGE_BY][256];
|
|
|
|
a =(guchar *) malloc(bytes*RW);
|
|
|
|
if (changewhat==SATURATION)
|
|
for (k=0; k<256; k++) {
|
|
for (JudgeBy=BY_HUE; JudgeBy<JUDGE_BY; JudgeBy++)
|
|
tempSat[JudgeBy][k]=0;
|
|
tempSat[Current.ValueBy][k] += changewhich*nudgeArray[(k+Current.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 (!Current.Touched[JudgeBy]) continue;
|
|
|
|
Inten = reduced->hsv[i*RW*bytes + j*bytes + JudgeBy]*255.0;
|
|
|
|
/*DO SATURATION FIRST*/
|
|
if (changewhat != NONEATALL) {
|
|
if (M!=m) {
|
|
for (k=0; k<3; k++)
|
|
if (backupP[k] == M)
|
|
P[k] = MAX(P[k]+partial*Current.satAdj[JudgeBy][Inten],middle);
|
|
else if (backupP[k] == m)
|
|
P[k] = MIN(P[k]-partial*Current.satAdj[JudgeBy][Inten],middle);
|
|
}
|
|
P[0] += partial*Current.redAdj[JudgeBy][Inten];
|
|
P[1] += partial*Current.greenAdj[JudgeBy][Inten];
|
|
P[2] += partial*Current.blueAdj[JudgeBy][Inten];
|
|
}
|
|
}
|
|
|
|
Inten = reduced->hsv[i*RW*bytes + j*bytes + Current.ValueBy]*255.0;
|
|
nudge = partial*nudgeArray[(Inten+Current.Offset)%256];
|
|
|
|
switch (changewhat) {
|
|
case HUE:
|
|
P[0] += colorSign[RED][changewhich] * nudge;
|
|
P[1] += colorSign[GREEN][changewhich] * nudge;
|
|
P[2] += colorSign[BLUE][changewhich] * 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] += changewhich * nudge;
|
|
P[1] += changewhich * nudge;
|
|
P[2] += changewhich * nudge;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
a[j * 3 + 0] = CLAMP0255(P[0]);
|
|
a[j * 3 + 1] = CLAMP0255(P[1]);
|
|
a[j * 3 + 2] = CLAMP0255(P[2]);
|
|
|
|
if (bytes == 4)
|
|
for (k = 0; k < 3; k++) {
|
|
float transp = reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
|
|
a[3*j+k]=transp*a[3*j+k]+(1-transp)*fp_fake_transparency(i,j);
|
|
}
|
|
}
|
|
gtk_preview_draw_row (GTK_PREVIEW (preview), a, 0, i, RW);
|
|
}
|
|
|
|
free (a);
|
|
gtk_widget_queue_draw (preview);
|
|
}
|
|
|
|
static void
|
|
Update_Current_FP (gint changewhat,
|
|
gint changewhich)
|
|
{
|
|
gint i;
|
|
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
gint nudge;
|
|
|
|
fp_Create_Nudge (nudgeArray);
|
|
nudge = nudgeArray[(i + Current.Offset) % 256];
|
|
|
|
switch (changewhat) {
|
|
case HUE:
|
|
Current.redAdj[Current.ValueBy][i] +=
|
|
colorSign[RED][changewhich] * nudge;
|
|
|
|
Current.greenAdj[Current.ValueBy][i] +=
|
|
colorSign[GREEN][changewhich] * nudge;
|
|
|
|
Current.blueAdj[Current.ValueBy][i] +=
|
|
colorSign[BLUE][changewhich] * nudge;
|
|
break;
|
|
|
|
case SATURATION:
|
|
Current.satAdj[Current.ValueBy][i] += changewhich * nudge;
|
|
break;
|
|
|
|
case VALUE:
|
|
Current.redAdj[Current.ValueBy][i] += changewhich * nudge;
|
|
Current.greenAdj[Current.ValueBy][i] += changewhich * nudge;
|
|
Current.blueAdj[Current.ValueBy][i] += changewhich * nudge;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
fp_create_smoothness_graph (GtkWidget *preview)
|
|
{
|
|
guchar data[256 * 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 * j + 0] = 255;
|
|
data[3 * j + 1] = 255;
|
|
data[3 * j + 2] = 255;
|
|
if (!(i % (MAX_ROUGHNESS / 4))) {
|
|
data[3 * j + 0] = 255;
|
|
data[3 * j + 1] = 128;
|
|
data[3 * j + 2] = 128;
|
|
}
|
|
if (!((j + 1) % 32)) {
|
|
data[3 * j + 0] = 255;
|
|
data[3 * j + 1] = 128;
|
|
data[3 * 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 * j + 0] = 0;
|
|
data[3 * j + 1] = 0;
|
|
data[3 * j + 2] = 0;
|
|
}
|
|
}
|
|
gtk_preview_draw_row (GTK_PREVIEW (preview), data, 0, i, 256);
|
|
}
|
|
gtk_widget_queue_draw (preview);
|
|
}
|
|
|
|
static void
|
|
fp_range_preview_spill (GtkWidget *preview,
|
|
gint type)
|
|
{
|
|
gint i;
|
|
|
|
for (i = 0; i < RANGE_HEIGHT; i++)
|
|
{
|
|
gint j;
|
|
|
|
for (j = 0; j < 256; j++)
|
|
{
|
|
guchar data[256 * 3];
|
|
GimpRGB rgb;
|
|
GimpHSV hsv;
|
|
|
|
if (! ((j + 1) % 32))
|
|
{
|
|
data[3 * j + 0] = 255;
|
|
data[3 * j + 1] = 128;
|
|
data[3 * j + 2] = 128;
|
|
}
|
|
else
|
|
{
|
|
switch (type)
|
|
{
|
|
case BY_VAL:
|
|
data[3 * j + 0] = j - Current.Offset;
|
|
data[3 * j + 1] = j - Current.Offset;
|
|
data[3 * j + 2] = j - Current.Offset;
|
|
break;
|
|
|
|
case BY_HUE:
|
|
gimp_hsv_set (&hsv,
|
|
((j - Current.Offset + 256) % 256) / 255.0,
|
|
1.0,
|
|
0.5);
|
|
gimp_hsv_to_rgb (&hsv, &rgb);
|
|
gimp_rgb_get_uchar (&rgb,
|
|
&data[3 * j + 0],
|
|
&data[3 * j + 1],
|
|
&data[3 * j + 2]);
|
|
break;
|
|
|
|
case BY_SAT:
|
|
gimp_hsv_set (&hsv,
|
|
0.5,
|
|
((j-(gint)Current.Offset+256)%256) / 255.0,
|
|
0.5);
|
|
gimp_hsv_to_rgb (&hsv, &rgb);
|
|
gimp_rgb_get_uchar (&rgb,
|
|
&data[3 * j + 0],
|
|
&data[3 * j + 1],
|
|
&data[3 * j + 2]);
|
|
break;
|
|
}
|
|
|
|
gtk_preview_draw_row (GTK_PREVIEW (preview), data, 0, i, 256);
|
|
}
|
|
}
|
|
}
|
|
gtk_widget_queue_draw (preview);
|
|
}
|
|
|
|
static void
|
|
fp_Create_Nudge(gint *adjArray)
|
|
{
|
|
gint left, right, middle,i;
|
|
/* The following function was determined by trial and error */
|
|
gdouble Steepness = pow (1 - Current.Alias, 4) * .8;
|
|
|
|
left = (Current.Range == SHADOWS) ? 0 : Current.Cutoffs[Current.Range - 1];
|
|
right = Current.Cutoffs[Current.Range];
|
|
middle = (left + right)/2;
|
|
|
|
if (Current.Alias)
|
|
for (i = 0; i < 256; i++)
|
|
if (i <= middle)
|
|
adjArray[i] = MAX_ROUGHNESS *
|
|
Current.Rough * (1 + tanh (Steepness * (i - left))) / 2;
|
|
else
|
|
adjArray[i] = MAX_ROUGHNESS *
|
|
Current.Rough * (1 + tanh (Steepness * (right - i))) / 2;
|
|
else
|
|
for (i = 0; i < 256; i++)
|
|
adjArray[i] = (left <= i && i <= right)
|
|
? MAX_ROUGHNESS * Current.Rough : 0;
|
|
}
|
|
|
|
static gint
|
|
fp_fake_transparency (gint i, gint j)
|
|
{
|
|
return (((i % 20) - 10) * ((j % 20) - 10) > 0) ? 64 : 196;
|
|
}
|