mirror of https://github.com/GNOME/gimp.git
1289 lines
35 KiB
C
1289 lines
35 KiB
C
/* vpropagate.c -- This is a plug-in for the GIMP (1.0's API)
|
|
* Author: Shuji Narazaki <narazaki@InetQ.or.jp>
|
|
* Time-stamp: <1998/04/11 19:46:08 narazaki@InetQ.or.jp>
|
|
* Version: 0.89a
|
|
*
|
|
* Copyright (C) 1996-1997 Shuji Narazaki <narazaki@InetQ.or.jp>
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
/* memo
|
|
the initial value of each pixel is the value of the pixel itself.
|
|
To determine whether it is an isolated local peak point, use:
|
|
(self == min && (! modified_flag)) ; modified_flag holds history of update
|
|
In other word, pixel itself is not a neighbor of it.
|
|
*/
|
|
|
|
#include "libgimp/gimp.h"
|
|
#include "gtk/gtk.h"
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define PLUG_IN_NAME "plug_in_vpropagate"
|
|
#define SHORT_NAME "vpropagate"
|
|
#define PROGRESS_NAME "value propagating..."
|
|
#define MENU_POSITION "<Image>/Filters/Distorts/Value Propagate"
|
|
|
|
typedef guchar CH;
|
|
#define RGB (1 << 0)
|
|
#define GRAY (1 << 1)
|
|
#define WITH_ALPHA (1 << 2)
|
|
#define WO_ALPHA (1 << 3)
|
|
#define num_direction 4
|
|
#define Right2Left 0
|
|
#define Bottom2Top 1
|
|
#define Left2Right 2
|
|
#define Top2Bottom 3
|
|
|
|
static void query (void);
|
|
static void run (char *name,
|
|
int nparams,
|
|
GParam *param,
|
|
int *nreturn_vals,
|
|
GParam **return_vals);
|
|
|
|
static GStatusType value_propagate (gint drawable_id);
|
|
static void value_propagate_body (gint drawable_id);
|
|
static int vpropagate_dialog (GImageType image_type);
|
|
static void prepare_row (GPixelRgn *pixel_rgn,
|
|
guchar *data,
|
|
int x,
|
|
int y,
|
|
int w);
|
|
static void
|
|
gtkW_gint_update (GtkWidget *widget,
|
|
gpointer data);
|
|
static void
|
|
gtkW_scale_update (GtkAdjustment *adjustment,
|
|
double *data);
|
|
static void
|
|
gtkW_close_callback (GtkWidget *widget,
|
|
gpointer data);
|
|
static void
|
|
vpropagate_ok_callback (GtkWidget *widget,
|
|
gpointer data);
|
|
static void
|
|
gtkW_toggle_update (GtkWidget *widget,
|
|
gpointer data);
|
|
static GtkWidget *
|
|
gtkW_dialog_new (char *name,
|
|
GtkSignalFunc ok_callback,
|
|
GtkSignalFunc close_callback);
|
|
static GtkWidget *
|
|
gtkW_table_add_toggle (GtkWidget *table,
|
|
gchar *name,
|
|
gint x1,
|
|
gint x2,
|
|
gint y,
|
|
GtkSignalFunc update,
|
|
gint *value);
|
|
static GSList *
|
|
gtkW_vbox_add_radio_button (GtkWidget *vbox,
|
|
gchar *name,
|
|
GSList *group,
|
|
GtkSignalFunc update,
|
|
gint *value);
|
|
static void
|
|
gtkW_table_add_gint (GtkWidget *table,
|
|
gchar *name,
|
|
gint x,
|
|
gint y,
|
|
GtkSignalFunc update,
|
|
gint *value,
|
|
gchar *buffer);
|
|
static void
|
|
gtkW_table_add_scale (GtkWidget *table,
|
|
gchar *name,
|
|
gint x1,
|
|
gint y,
|
|
GtkSignalFunc update,
|
|
gdouble *value,
|
|
gdouble min,
|
|
gdouble max,
|
|
gdouble step);
|
|
GtkWidget *gtkW_frame_new (gchar *name, GtkWidget *parent);
|
|
GtkWidget *gtkW_hbox_new (GtkWidget *parent);
|
|
GtkWidget *gtkW_vbox_new (GtkWidget *parent);
|
|
|
|
static int value_difference_check(CH *, CH *, int);
|
|
static void set_value (GImageType, int, CH *, CH *, CH *, void *);
|
|
static void initialize_white (GImageType, int, CH *, CH *, void **);
|
|
static void propagate_white (GImageType, int, CH *, CH *, CH *, void *);
|
|
static void initialize_black (GImageType, int, CH *, CH *, void **);
|
|
static void propagate_black (GImageType, int, CH *, CH *, CH *, void *);
|
|
static void initialize_middle (GImageType, int, CH *, CH *, void **);
|
|
static void propagate_middle (GImageType, int, CH *, CH *, CH *, void *);
|
|
static void set_middle_to_peak (GImageType, int, CH *, CH *, CH *, void *);
|
|
static void set_foreground_to_peak (GImageType, int, CH *, CH *, CH *, void *);
|
|
static void initialize_foreground (GImageType, int, CH *, CH *, void **);
|
|
static void initialize_background (GImageType, int, CH *, CH *, void **);
|
|
static void propagate_a_color (GImageType, int, CH *, CH *, CH *, void *);
|
|
static void propagate_opaque (GImageType, int, CH *, CH *, CH *, void *);
|
|
static void propagate_transparent (GImageType, int, CH *, CH *, CH *, void *);
|
|
|
|
GPlugInInfo PLUG_IN_INFO =
|
|
{
|
|
NULL, /* init_proc */
|
|
NULL, /* quit_proc */
|
|
query, /* query_proc */
|
|
run, /* run_proc */
|
|
};
|
|
|
|
#define ENTRY_WIDTH 100
|
|
#define UPDATE_STEP 20
|
|
#define SCALE_WIDTH 100
|
|
#define PROPAGATING_VALUE 1<<0
|
|
#define PROPAGATING_ALPHA 1<<1
|
|
|
|
/* parameters */
|
|
typedef struct
|
|
{
|
|
gint propagate_mode;
|
|
gint propagating_channel;
|
|
gdouble propagating_rate;
|
|
gint direction_mask;
|
|
gint lower_limit;
|
|
gint upper_limit;
|
|
/* gint channel_mask[3]; */
|
|
/* gint peak_includes_equals; */
|
|
/* gint overwrite; */
|
|
} VPValueType;
|
|
|
|
static VPValueType vpvals =
|
|
{
|
|
0,
|
|
3, /* PROPAGATING_VALUE + PROPAGATING_ALPHA */
|
|
1.0, /* [0.0:1.0] */
|
|
15, /* propagate to all 4 directions */
|
|
0,
|
|
255
|
|
};
|
|
|
|
/* dialog vairables */
|
|
gint propagate_alpha;
|
|
gint propagate_value;
|
|
gint direction_mask_vec[4];
|
|
gint channel_mask [] = {1, 1, 1};
|
|
gint peak_max = 1;
|
|
gint peak_min = 1;
|
|
gint peak_includes_equals = 1;
|
|
guchar fore[3];
|
|
|
|
typedef struct
|
|
{
|
|
int applicable_image_type;
|
|
char *name;
|
|
void (*initializer)();
|
|
void (*updater)();
|
|
void (*finalizer)();
|
|
gint selected;
|
|
} ModeParam;
|
|
|
|
#define num_mode 8
|
|
static ModeParam modes[num_mode] = {
|
|
{ RGB | GRAY | WITH_ALPHA | WO_ALPHA, "more white (larger value)",
|
|
initialize_white, propagate_white, set_value, FALSE},
|
|
{ RGB | GRAY | WITH_ALPHA | WO_ALPHA, "more black (smaller value)",
|
|
initialize_black, propagate_black, set_value, FALSE},
|
|
{ RGB | GRAY | WITH_ALPHA | WO_ALPHA, "middle value to peaks",
|
|
initialize_middle, propagate_middle, set_middle_to_peak,
|
|
FALSE},
|
|
{ RGB | GRAY | WITH_ALPHA | WO_ALPHA, "foreground to peaks",
|
|
initialize_middle, propagate_middle, set_foreground_to_peak,
|
|
FALSE},
|
|
{ RGB | WITH_ALPHA | WO_ALPHA, "only foreground",
|
|
initialize_foreground, propagate_a_color, set_value, FALSE},
|
|
{ RGB | WITH_ALPHA | WO_ALPHA, "only background",
|
|
initialize_background, propagate_a_color, set_value, FALSE},
|
|
{ RGB | GRAY | WITH_ALPHA, "more opaque",
|
|
NULL, propagate_opaque, set_value, FALSE},
|
|
{ RGB | GRAY | WITH_ALPHA, "more transparent",
|
|
NULL, propagate_transparent, set_value, FALSE}
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
gint run;
|
|
} VPInterface;
|
|
|
|
static VPInterface vpropagate_interface = { FALSE };
|
|
gint drawable_id;
|
|
|
|
MAIN ()
|
|
|
|
static void
|
|
query ()
|
|
{
|
|
static GParamDef args [] =
|
|
{
|
|
{ PARAM_INT32, "run_mode", "Interactive, non-interactive"},
|
|
{ PARAM_IMAGE, "image", "Input image (not used)"},
|
|
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
|
|
{ PARAM_INT32, "propagate-mode", "propagate 0:white, 1:black, 2:middle value 3:foreground to peak, 4:foreground, 5:background, 6:opaque, 7:transparent"},
|
|
{ PARAM_INT32, "propagating-channel", "channels which values are propagated"},
|
|
{ PARAM_FLOAT, "propagating-rate", "0.0 <= propagatating_rate <= 1.0"},
|
|
{ PARAM_INT32, "direction-mask", "0 <= direction-mask <= 15"},
|
|
{ PARAM_INT32, "lower-limit", "0 <= lower-limit <= 255"},
|
|
{ PARAM_INT32, "upper-limit", "0 <= upper-limit <= 255"},
|
|
};
|
|
static GParamDef *return_vals = NULL;
|
|
static int nargs = sizeof (args) / sizeof (args[0]);
|
|
static int nreturn_vals = 0;
|
|
|
|
gimp_install_procedure (PLUG_IN_NAME,
|
|
"Propagate values of the layer",
|
|
"Propagate values of the layer",
|
|
"Shuji Narazaki (narazaki@InetQ.or.jp)",
|
|
"Shuji Narazaki",
|
|
"1996-1997",
|
|
MENU_POSITION,
|
|
"RGB*,GRAY*",
|
|
PROC_PLUG_IN,
|
|
nargs, nreturn_vals,
|
|
args, return_vals);
|
|
}
|
|
|
|
static void
|
|
run (char *name,
|
|
int nparams,
|
|
GParam *param,
|
|
int *nreturn_vals,
|
|
GParam **return_vals)
|
|
{
|
|
static GParam values[1];
|
|
GStatusType status = STATUS_SUCCESS;
|
|
GRunModeType run_mode;
|
|
|
|
run_mode = param[0].data.d_int32;
|
|
drawable_id = param[2].data.d_int32;
|
|
|
|
*nreturn_vals = 1;
|
|
*return_vals = values;
|
|
|
|
values[0].type = PARAM_STATUS;
|
|
values[0].data.d_status = status;
|
|
|
|
switch ( run_mode )
|
|
{
|
|
case RUN_INTERACTIVE:
|
|
gimp_get_data (PLUG_IN_NAME, &vpvals);
|
|
/* building the values of dialog variables from vpvals. */
|
|
modes[vpvals.propagate_mode].selected = TRUE;
|
|
propagate_alpha = (vpvals.propagating_channel & PROPAGATING_ALPHA) ?
|
|
TRUE : FALSE;
|
|
propagate_value = (vpvals.propagating_channel & PROPAGATING_VALUE) ?
|
|
TRUE : FALSE;
|
|
{
|
|
int i;
|
|
for (i = 0; i < 4; i++)
|
|
direction_mask_vec[i] = (vpvals.direction_mask & (1 << i))
|
|
? TRUE : FALSE;
|
|
}
|
|
if (! vpropagate_dialog (gimp_drawable_type(drawable_id)))
|
|
return;
|
|
break;
|
|
case RUN_NONINTERACTIVE:
|
|
vpvals.propagate_mode = param[3].data.d_int32;
|
|
vpvals.propagating_channel = param[4].data.d_int32;
|
|
vpvals.propagating_rate = param[5].data.d_float;
|
|
vpvals.direction_mask = param[6].data.d_int32;
|
|
vpvals.lower_limit = param[7].data.d_int32;
|
|
vpvals.upper_limit = param[8].data.d_int32;
|
|
break;
|
|
case RUN_WITH_LAST_VALS:
|
|
gimp_get_data (PLUG_IN_NAME, &vpvals);
|
|
break;
|
|
}
|
|
|
|
status = value_propagate (drawable_id);
|
|
|
|
if (run_mode != RUN_NONINTERACTIVE)
|
|
gimp_displays_flush();
|
|
if (run_mode == RUN_INTERACTIVE && status == STATUS_SUCCESS )
|
|
gimp_set_data (PLUG_IN_NAME, &vpvals, sizeof (VPValueType));
|
|
|
|
values[0].type = PARAM_STATUS;
|
|
values[0].data.d_status = status;
|
|
}
|
|
|
|
/* registered function entry */
|
|
static GStatusType
|
|
value_propagate (gint drawable_id)
|
|
{
|
|
/* check the validness of parameters */
|
|
if (!(vpvals.propagating_channel & (PROPAGATING_VALUE | PROPAGATING_ALPHA)))
|
|
{
|
|
/* gimp_message ("No channel selected."); */
|
|
return STATUS_EXECUTION_ERROR;
|
|
}
|
|
if (vpvals.direction_mask == 0)
|
|
{
|
|
/* gimp_message ("No direction selected."); */
|
|
return STATUS_EXECUTION_ERROR;
|
|
}
|
|
if ( (vpvals.lower_limit < 0) || (255 < vpvals.lower_limit) ||
|
|
(vpvals.upper_limit < 0) || (255 < vpvals.lower_limit) ||
|
|
(vpvals.upper_limit < vpvals.lower_limit) )
|
|
{
|
|
/* gimp_message ("Limit values are not valid."); */
|
|
return STATUS_EXECUTION_ERROR;
|
|
}
|
|
value_propagate_body (drawable_id);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static void
|
|
value_propagate_body (gint drawable_id)
|
|
{
|
|
GDrawable *drawable;
|
|
GImageType dtype;
|
|
ModeParam operation;
|
|
GPixelRgn srcRgn, destRgn;
|
|
guchar *here, *best, *dest;
|
|
guchar *dest_row, *prev_row, *cur_row, *next_row, *pr, *cr, *nr, *swap;
|
|
int width, height, bytes, index;
|
|
int begx, begy, endx, endy, x, y, dx;
|
|
int left_index, right_index, up_index, down_index;
|
|
void *tmp;
|
|
|
|
/* calculate neighbors' indexes */
|
|
left_index = (vpvals.direction_mask & (1 << Left2Right)) ? -1 : 0;
|
|
right_index = (vpvals.direction_mask & (1 << Right2Left)) ? 1 : 0;
|
|
up_index = (vpvals.direction_mask & (1 << Top2Bottom)) ? -1 : 0;
|
|
down_index = (vpvals.direction_mask & (1 << Bottom2Top)) ? 1 : 0;
|
|
operation = modes[vpvals.propagate_mode];
|
|
tmp = NULL;
|
|
|
|
drawable = gimp_drawable_get (drawable_id);
|
|
dtype = gimp_drawable_type (drawable_id);
|
|
|
|
/* Here I use the algorithm of blur.c . */
|
|
gimp_drawable_mask_bounds (drawable->id, &begx, &begy, &endx, &endy);
|
|
|
|
width = drawable->width;
|
|
height = drawable->height;
|
|
bytes = drawable->bpp;
|
|
|
|
prev_row = (guchar *) malloc ((endx - begx + 2) * bytes);
|
|
cur_row = (guchar *) malloc ((endx - begx + 2) * bytes);
|
|
next_row = (guchar *) malloc ((endx - begx + 2) * bytes);
|
|
dest_row = (guchar *) malloc ((endx - begx) * bytes);
|
|
|
|
gimp_pixel_rgn_init (&srcRgn, drawable, 0, 0, width, height, FALSE, FALSE);
|
|
gimp_pixel_rgn_init (&destRgn, drawable, 0, 0, width, height, TRUE, TRUE);
|
|
|
|
pr = prev_row + bytes;
|
|
cr = cur_row + bytes;
|
|
nr = next_row + bytes;
|
|
|
|
prepare_row (&srcRgn, pr, begx, (0 < begy) ? begy : begy - 1, endx-begx);
|
|
prepare_row (&srcRgn, cr, begx, begy, endx-begx);
|
|
|
|
best = (guchar *) malloc (bytes);
|
|
|
|
gimp_progress_init (PROGRESS_NAME);
|
|
gimp_palette_get_foreground (fore+0, fore+1, fore+2);
|
|
|
|
/* start real job */
|
|
for ( y = begy ; y < endy ; y++)
|
|
{
|
|
prepare_row (&srcRgn, nr, begx, ((y+1) < endy) ? y+1 : endy, endx-begx);
|
|
for (index = 0; index < (endx - begx) * bytes; index++)
|
|
dest_row[index] = cr[index];
|
|
for ( x = 0 ; x < endx - begx; x++ )
|
|
{
|
|
dest = dest_row + (x * bytes);
|
|
here = cr + (x * bytes);
|
|
/* *** copy source value to best value holder *** */
|
|
memcpy ((void *)best, (void *)here, bytes);
|
|
if ( operation.initializer )
|
|
(* operation.initializer)(dtype, bytes, best, here, &tmp);
|
|
/* *** gather neighbors' values: loop-unfolded version *** */
|
|
if (up_index == -1)
|
|
for (dx = left_index ; dx <= right_index ; dx++)
|
|
(* operation.updater)(dtype, bytes, here, pr+((x+dx)*bytes), best, tmp);
|
|
for (dx = left_index ; dx <= right_index ; dx++)
|
|
if ( dx != 0 )
|
|
(* operation.updater)(dtype, bytes, here, cr+((x+dx)*bytes), best, tmp);
|
|
if (down_index == 1)
|
|
for (dx = left_index ; dx <= right_index ; dx++)
|
|
(* operation.updater)(dtype, bytes, here, nr+((x+dx)*bytes), best, tmp);
|
|
/* *** store it to dest_row*** */
|
|
(* operation.finalizer)(dtype, bytes, best, here, dest, tmp);
|
|
}
|
|
/* now store destline to destRgn */
|
|
gimp_pixel_rgn_set_row (&destRgn, dest_row, begx, y, endx - begx);
|
|
/* shift the row pointers */
|
|
swap = pr;
|
|
pr = cr;
|
|
cr = nr;
|
|
nr = swap;
|
|
/* update each UPDATE_STEP (optimizer must generate cheap code) */
|
|
if ((y % 5) == 0) /*(y % (int) ((endy - begy) / UPDATE_STEP)) == 0 */
|
|
gimp_progress_update ((double)y / (double)(endy - begy));
|
|
}
|
|
/* update the region */
|
|
gimp_progress_update(1.0);
|
|
gimp_drawable_flush (drawable);
|
|
gimp_drawable_merge_shadow (drawable->id, TRUE);
|
|
gimp_drawable_update (drawable->id, begx, begy, endx-begx, endy-begy);
|
|
}
|
|
|
|
static void
|
|
prepare_row (GPixelRgn *pixel_rgn,
|
|
guchar *data,
|
|
int x,
|
|
int y,
|
|
int w)
|
|
{
|
|
int b;
|
|
|
|
if (y == 0)
|
|
gimp_pixel_rgn_get_row (pixel_rgn, data, x, (y + 1), w);
|
|
else if (y == pixel_rgn->h)
|
|
gimp_pixel_rgn_get_row (pixel_rgn, data, x, (y - 1), w);
|
|
else
|
|
gimp_pixel_rgn_get_row (pixel_rgn, data, x, y, w);
|
|
|
|
/* Fill in edge pixels */
|
|
for (b = 0; b < pixel_rgn->bpp; b++)
|
|
{
|
|
data[-(gint)pixel_rgn->bpp + b] = data[b];
|
|
data[w * pixel_rgn->bpp + b] = data[(w - 1) * pixel_rgn->bpp + b];
|
|
}
|
|
}
|
|
|
|
static void
|
|
set_value (dtype, bytes, best, here, dest, tmp)
|
|
GImageType dtype;
|
|
int bytes;
|
|
guchar *best, *here, *dest;
|
|
void *tmp;
|
|
{
|
|
int value_chs = 0;
|
|
int alpha = 0;
|
|
int ch;
|
|
|
|
switch ( dtype )
|
|
{
|
|
case RGB_IMAGE:
|
|
value_chs = 3;
|
|
break;
|
|
case RGBA_IMAGE:
|
|
value_chs = 3;
|
|
alpha = 3;
|
|
break;
|
|
case GRAY_IMAGE:
|
|
value_chs = 1;
|
|
break;
|
|
case GRAYA_IMAGE:
|
|
value_chs = 1;
|
|
alpha = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
for (ch = 0; ch < value_chs; ch++)
|
|
{
|
|
if ( vpvals.propagating_channel & PROPAGATING_VALUE ) /* value channel */
|
|
*dest++ = (CH)(vpvals.propagating_rate * best[ch]
|
|
+ (1.0 - vpvals.propagating_rate) * here[ch]);
|
|
else
|
|
*dest++ = here[ch];
|
|
}
|
|
if ( alpha )
|
|
{
|
|
if ( vpvals.propagating_channel & PROPAGATING_ALPHA ) /* alpha channel */
|
|
*dest++ = (CH)(vpvals.propagating_rate * best[alpha]
|
|
+ (1.0 - vpvals.propagating_rate) * here[alpha]);
|
|
else
|
|
*dest++ = here[alpha];
|
|
}
|
|
}
|
|
|
|
static int
|
|
value_difference_check(pos1, pos2, ch)
|
|
CH *pos1, *pos2;
|
|
int ch;
|
|
{
|
|
int index;
|
|
int diff;
|
|
|
|
for (index = 0 ; index < ch; index++ )
|
|
if ( channel_mask[index] != 0 )
|
|
{
|
|
diff = abs(pos1[index] - pos2[index]);
|
|
if ( ! ((vpvals.lower_limit <= diff) && (diff <= vpvals.upper_limit)) )
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* mothods for each mode */
|
|
static void
|
|
initialize_white (dtype, bytes, best, here, tmp)
|
|
GImageType dtype;
|
|
int bytes;
|
|
CH *best, *here;
|
|
void **tmp;
|
|
{
|
|
if (*tmp == NULL)
|
|
*tmp = (void *)malloc(sizeof(float));
|
|
*(float *)*tmp = sqrt (channel_mask[0] * here[0] * here[0]
|
|
+ channel_mask[1] * here[1] * here[1]
|
|
+ channel_mask[2] * here[2] * here[2]);
|
|
}
|
|
|
|
static void
|
|
propagate_white (dtype, bytes, orig, here, best, tmp)
|
|
GImageType dtype;
|
|
int bytes;
|
|
CH *orig, *here, *best;
|
|
void *tmp;
|
|
{
|
|
float v_here;
|
|
|
|
switch ( dtype )
|
|
{
|
|
case RGB_IMAGE:
|
|
case RGBA_IMAGE:
|
|
v_here = sqrt (channel_mask[0] * here[0] * here[0]
|
|
+ channel_mask[1] * here[1] * here[1]
|
|
+ channel_mask[2] * here[2] * here[2]);
|
|
if ( *(float *)tmp < v_here && value_difference_check(orig, here, 3) )
|
|
{
|
|
*(float *)tmp = v_here;
|
|
memcpy(best, here, 3 * sizeof(CH)); /* alpha channel holds old value */
|
|
}
|
|
break;
|
|
case GRAYA_IMAGE:
|
|
case GRAY_IMAGE:
|
|
if ( *best < *here && value_difference_check(orig, here, 1))
|
|
*best = *here;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
initialize_black (image_type, channels, best, here, tmp)
|
|
GImageType image_type;
|
|
int channels;
|
|
CH *best, *here;
|
|
void **tmp;
|
|
{
|
|
if (*tmp == NULL)
|
|
*tmp = (void *)malloc(sizeof(float));
|
|
*(float *)*tmp = sqrt (channel_mask[0] * here[0] * here[0]
|
|
+ channel_mask[1] * here[1] * here[1]
|
|
+ channel_mask[2] * here[2] * here[2]);
|
|
}
|
|
|
|
static void
|
|
propagate_black (image_type, channels, orig, here, best, tmp)
|
|
GImageType image_type;
|
|
int channels;
|
|
CH *orig, *here, *best;
|
|
void *tmp;
|
|
{
|
|
float v_here;
|
|
|
|
switch ( image_type )
|
|
{
|
|
case RGB_IMAGE:
|
|
case RGBA_IMAGE:
|
|
v_here = sqrt (channel_mask[0] * here[0] * here[0]
|
|
+ channel_mask[1] * here[1] * here[1]
|
|
+ channel_mask[2] * here[2] * here[2]);
|
|
if ( v_here < *(float *)tmp && value_difference_check(orig, here, 3) )
|
|
{
|
|
*(float *)tmp = v_here;
|
|
memcpy (best, here, 3 * sizeof(CH)); /* alpha channel holds old value */
|
|
}
|
|
break;
|
|
case GRAYA_IMAGE:
|
|
case GRAY_IMAGE:
|
|
if ( *here < *best && value_difference_check(orig, here, 1) )
|
|
*best = *here;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
short min_modified;
|
|
short max_modified;
|
|
long original_value;
|
|
long minv;
|
|
CH min[3];
|
|
long maxv;
|
|
CH max[3];
|
|
} MiddlePacket;
|
|
|
|
static void
|
|
initialize_middle (image_type, channels, best, here, tmp)
|
|
GImageType image_type;
|
|
int channels;
|
|
CH *best, *here;
|
|
void **tmp;
|
|
{
|
|
int index;
|
|
MiddlePacket *data;
|
|
|
|
if (*tmp == NULL)
|
|
*tmp = (void *)malloc(sizeof(MiddlePacket));
|
|
data = (MiddlePacket *)*tmp;
|
|
for (index = 0; index < channels; index++)
|
|
data->min[index] = data->max[index] = here[index];
|
|
switch ( image_type )
|
|
{
|
|
case RGB_IMAGE:
|
|
case RGBA_IMAGE:
|
|
data->original_value = sqrt (channel_mask[0] * here[0] * here[0]
|
|
+ channel_mask[1] * here[1] * here[1]
|
|
+ channel_mask[2] * here[2] * here[2]);
|
|
break;
|
|
case GRAYA_IMAGE:
|
|
case GRAY_IMAGE:
|
|
data->original_value = *here;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
data->minv = data->maxv = data->original_value;
|
|
data->min_modified = data->max_modified = 0;
|
|
}
|
|
|
|
static void
|
|
propagate_middle (image_type, channels, orig, here, best, tmp)
|
|
GImageType image_type;
|
|
int channels;
|
|
CH *orig, *here, *best;
|
|
void *tmp;
|
|
{
|
|
float v_here;
|
|
MiddlePacket *data;
|
|
|
|
data = (MiddlePacket *)tmp;
|
|
|
|
switch ( image_type )
|
|
{
|
|
case RGB_IMAGE:
|
|
case RGBA_IMAGE:
|
|
v_here = sqrt (channel_mask[0] * here[0] * here[0]
|
|
+ channel_mask[1] * here[1] * here[1]
|
|
+ channel_mask[2] * here[2] * here[2]);
|
|
if ( (v_here <= data->minv) && value_difference_check(orig, here, 3) )
|
|
{
|
|
data->minv = v_here;
|
|
memcpy (data->min, here, 3*sizeof(CH));
|
|
data->min_modified = 1;
|
|
}
|
|
if ( data->maxv <= v_here && value_difference_check(orig, here, 3) )
|
|
{
|
|
data->maxv = v_here;
|
|
memcpy (data->max, here, 3*sizeof(CH));
|
|
data->max_modified = 1;
|
|
}
|
|
break;
|
|
case GRAYA_IMAGE:
|
|
case GRAY_IMAGE:
|
|
if ( (*here <= data->min[0]) && value_difference_check(orig, here, 1) )
|
|
{
|
|
data->min[0] = *here;
|
|
data->min_modified = 1;
|
|
}
|
|
if ( (data->max[0] <= *here) && value_difference_check(orig, here, 1) )
|
|
{
|
|
data->max[0] = *here;
|
|
data->max_modified = 1;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
set_middle_to_peak (image_type, channels, best, here, dest, tmp)
|
|
GImageType image_type;
|
|
int channels;
|
|
CH *best, *here, *dest;
|
|
void *tmp;
|
|
{
|
|
int value_chs = 0;
|
|
int alpha = 0;
|
|
int ch;
|
|
MiddlePacket *data;
|
|
|
|
data = (MiddlePacket *)tmp;
|
|
if (! ((peak_min & (data->minv == data->original_value))
|
|
|| (peak_max & (data->maxv == data->original_value))) )
|
|
return;
|
|
if ((! peak_includes_equals)
|
|
&& ((peak_min & (! data->min_modified))
|
|
|| (peak_max & (! data->max_modified))))
|
|
return;
|
|
|
|
switch ( image_type )
|
|
{
|
|
case RGB_IMAGE:
|
|
value_chs = 3;
|
|
break;
|
|
case RGBA_IMAGE:
|
|
value_chs = 3;
|
|
alpha = 3;
|
|
break;
|
|
case GRAY_IMAGE:
|
|
value_chs = 1;
|
|
break;
|
|
case GRAYA_IMAGE:
|
|
value_chs = 1;
|
|
alpha = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
for (ch = 0; ch < value_chs; ch++)
|
|
{
|
|
if ( vpvals.propagating_channel & PROPAGATING_VALUE ) /* value channel */
|
|
*dest++ = (CH)(vpvals.propagating_rate * 0.5 * (data->min[ch] + data->max[ch])
|
|
+ (1.0 - vpvals.propagating_rate) * here[ch]);
|
|
else
|
|
*dest++ = here[ch];
|
|
}
|
|
if ( alpha )
|
|
{
|
|
if ( vpvals.propagating_channel & PROPAGATING_ALPHA ) /* alpha channel */
|
|
*dest++ = (CH)(vpvals.propagating_rate * best[alpha]
|
|
+ (1.0 - vpvals.propagating_rate) * here[alpha]);
|
|
else
|
|
*dest++ = here[alpha];
|
|
}
|
|
}
|
|
|
|
static void
|
|
set_foreground_to_peak (image_type, channels, best, here, dest, tmp)
|
|
GImageType image_type;
|
|
int channels;
|
|
CH *best, *here, *dest;
|
|
void *tmp;
|
|
{
|
|
int value_chs = 0;
|
|
int alpha = 0;
|
|
int ch;
|
|
MiddlePacket *data;
|
|
|
|
data = (MiddlePacket *)tmp;
|
|
if (! ((peak_min & (data->minv == data->original_value))
|
|
|| (peak_max & (data->maxv == data->original_value))) )
|
|
return;
|
|
if (peak_includes_equals
|
|
&& ((peak_min & (! data->min_modified))
|
|
|| (peak_max & (! data->max_modified))))
|
|
return;
|
|
|
|
switch ( image_type )
|
|
{
|
|
case RGB_IMAGE:
|
|
value_chs = 3;
|
|
break;
|
|
case RGBA_IMAGE:
|
|
value_chs = 3;
|
|
alpha = 3;
|
|
break;
|
|
case GRAY_IMAGE:
|
|
value_chs = 1;
|
|
break;
|
|
case GRAYA_IMAGE:
|
|
value_chs = 1;
|
|
alpha = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
for (ch = 0; ch < value_chs; ch++)
|
|
{
|
|
if ( vpvals.propagating_channel & PROPAGATING_VALUE ) /* value channel */
|
|
*dest++ = (CH)(vpvals.propagating_rate*fore[ch]
|
|
+ (1.0 - vpvals.propagating_rate)*here[ch]);
|
|
else
|
|
*dest++ = here[ch];
|
|
}
|
|
}
|
|
|
|
static void
|
|
initialize_foreground (image_type, channels, best, here, tmp)
|
|
GImageType image_type;
|
|
int channels;
|
|
CH *best, *here;
|
|
void **tmp;
|
|
{
|
|
CH *ch;
|
|
|
|
if (*tmp == NULL)
|
|
{
|
|
*tmp = (void *)malloc(3 * sizeof(CH));
|
|
ch = (CH *)*tmp;
|
|
gimp_palette_get_foreground (&ch[0], &ch[1], &ch[2]);
|
|
}
|
|
}
|
|
|
|
static void
|
|
initialize_background (image_type, channels, best, here, tmp)
|
|
GImageType image_type;
|
|
int channels;
|
|
CH *best, *here;
|
|
void **tmp;
|
|
{
|
|
CH *ch;
|
|
|
|
if (*tmp == NULL)
|
|
{
|
|
*tmp = (void *)malloc(3 * sizeof(CH));
|
|
ch = (CH *)*tmp;
|
|
gimp_palette_get_background (&ch[0], &ch[1], &ch[2]);
|
|
}
|
|
}
|
|
|
|
static void
|
|
propagate_a_color (image_type, channels, orig, here, best, tmp)
|
|
GImageType image_type;
|
|
int channels;
|
|
CH *orig, *here, *best;
|
|
void *tmp;
|
|
{
|
|
CH *fg = (CH *)tmp;
|
|
|
|
switch ( image_type )
|
|
{
|
|
case RGB_IMAGE:
|
|
case RGBA_IMAGE:
|
|
if ( here[0] == fg[0] && here[1] == fg[1] && here[2] == fg[2] &&
|
|
value_difference_check(orig, here, 3) )
|
|
{
|
|
memcpy (best, here, 3 * sizeof(CH)); /* alpha channel holds old value */
|
|
}
|
|
break;
|
|
case GRAYA_IMAGE:
|
|
case GRAY_IMAGE:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
propagate_opaque (image_type, channels, orig, here, best, tmp)
|
|
GImageType image_type;
|
|
int channels;
|
|
CH *orig, *here, *best;
|
|
void *tmp;
|
|
{
|
|
switch ( image_type )
|
|
{
|
|
case RGBA_IMAGE:
|
|
if ( best[3] < here[3] && value_difference_check(orig, here, 3) )
|
|
memcpy(best, here, channels * sizeof(CH));
|
|
break;
|
|
case GRAYA_IMAGE:
|
|
if ( best[1] < here[1] && value_difference_check(orig, here, 1))
|
|
memcpy(best, here, channels * sizeof(CH));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
propagate_transparent (image_type, channels, orig, here, best, tmp)
|
|
GImageType image_type;
|
|
int channels;
|
|
CH *orig, *here, *best;
|
|
void *tmp;
|
|
{
|
|
switch ( image_type )
|
|
{
|
|
case RGBA_IMAGE:
|
|
if ( here[3] < best[3] && value_difference_check(orig, here, 3))
|
|
memcpy(best, here, channels * sizeof(CH));
|
|
break;
|
|
case GRAYA_IMAGE:
|
|
if ( here[1] < best[1] && value_difference_check(orig, here, 1))
|
|
memcpy(best, here, channels * sizeof(CH));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* dialog stuff */
|
|
|
|
static int
|
|
vpropagate_dialog (GImageType image_type)
|
|
{
|
|
GtkWidget *dlg;
|
|
GtkWidget *hbox;
|
|
GtkWidget *frame;
|
|
GtkWidget *table;
|
|
GtkWidget *sep;
|
|
gchar **argv;
|
|
gint argc;
|
|
static gchar buffer[3][10];
|
|
|
|
argc = 1;
|
|
argv = g_new (gchar *, 1);
|
|
argv[0] = g_strdup (SHORT_NAME);
|
|
gtk_init (&argc, &argv);
|
|
gtk_rc_parse (gimp_gtkrc ());
|
|
|
|
dlg = gtkW_dialog_new (PLUG_IN_NAME,
|
|
(GtkSignalFunc) vpropagate_ok_callback,
|
|
(GtkSignalFunc) gtkW_close_callback);
|
|
|
|
hbox = gtkW_hbox_new((GTK_DIALOG (dlg)->vbox));
|
|
|
|
/* Propagate Mode */
|
|
{
|
|
GtkWidget *frame;
|
|
GtkWidget *toggle_vbox;
|
|
GSList *group = NULL;
|
|
gint index = 0;
|
|
|
|
frame = gtkW_frame_new ("Propagate Mode", hbox);
|
|
toggle_vbox = gtkW_vbox_new (frame);
|
|
|
|
for (index = 0; index < num_mode ; index++ )
|
|
group = gtkW_vbox_add_radio_button (toggle_vbox, modes[index].name, group,
|
|
(GtkSignalFunc) gtkW_toggle_update,
|
|
&modes[index].selected);
|
|
gtk_widget_show (toggle_vbox);
|
|
gtk_widget_show (frame);
|
|
}
|
|
|
|
/* Parameter settings */
|
|
frame = gtkW_frame_new ("Parameter Settings", hbox);
|
|
table = gtk_table_new (9,2, FALSE); /* 4 raw, 2 columns(name and value) */
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (table), 10);
|
|
gtk_container_add (GTK_CONTAINER (frame), table);
|
|
|
|
gtkW_table_add_gint (table, "Lower threshold", 0, 0,
|
|
(GtkSignalFunc) gtkW_gint_update,
|
|
&vpvals.lower_limit, buffer[0]);
|
|
gtkW_table_add_gint (table, "Upper threshold", 0, 1,
|
|
(GtkSignalFunc) gtkW_gint_update,
|
|
&vpvals.upper_limit, buffer[1]);
|
|
gtkW_table_add_scale (table, "Propagating Rate", 0, 2,
|
|
(GtkSignalFunc) gtkW_scale_update,
|
|
&vpvals.propagating_rate, 0.0, 1.0, 0.01);
|
|
|
|
sep = gtk_hseparator_new ();
|
|
gtk_table_attach (GTK_TABLE (table), sep, 0, 2, 3, 4, GTK_FILL, 0, 0, 0);
|
|
gtk_widget_show (sep);
|
|
|
|
gtkW_table_add_toggle (table, "to Left", 0, 1, 4,
|
|
(GtkSignalFunc) gtkW_toggle_update,
|
|
&direction_mask_vec[Right2Left]);
|
|
gtkW_table_add_toggle (table, "to Right", 1, 2, 4,
|
|
(GtkSignalFunc) gtkW_toggle_update,
|
|
&direction_mask_vec[Left2Right]);
|
|
gtkW_table_add_toggle (table, "to Top", 0, 1, 5,
|
|
(GtkSignalFunc) gtkW_toggle_update,
|
|
&direction_mask_vec[Bottom2Top]);
|
|
gtkW_table_add_toggle (table, "to Bottom", 1, 2, 5,
|
|
(GtkSignalFunc) gtkW_toggle_update,
|
|
&direction_mask_vec[Top2Bottom]);
|
|
if ((image_type == RGBA_IMAGE) | (image_type == GRAYA_IMAGE))
|
|
{
|
|
GtkWidget *sep;
|
|
|
|
sep = gtk_hseparator_new ();
|
|
gtk_table_attach (GTK_TABLE (table), sep, 0, 2, 6, 7, GTK_FILL, 0, 0, 0);
|
|
gtk_widget_show (sep);
|
|
|
|
{
|
|
GtkWidget *toggle;
|
|
|
|
toggle = gtkW_table_add_toggle (table, "Propagating Alpha Channel",
|
|
0, 2, 7,
|
|
(GtkSignalFunc) gtkW_toggle_update,
|
|
&propagate_alpha);
|
|
if (gimp_layer_get_preserve_transparency (drawable_id))
|
|
{
|
|
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), 0);
|
|
gtk_widget_set_sensitive (toggle, FALSE);
|
|
}
|
|
}
|
|
gtkW_table_add_toggle (table, "Propagating Value Channel", 0, 2, 8,
|
|
(GtkSignalFunc) gtkW_toggle_update,
|
|
&propagate_value);
|
|
}
|
|
gtk_widget_show (table);
|
|
gtk_widget_show (frame);
|
|
gtk_widget_show (hbox);
|
|
gtk_widget_show (dlg);
|
|
|
|
gtk_main ();
|
|
gdk_flush ();
|
|
|
|
return vpropagate_interface.run;
|
|
}
|
|
|
|
/* VFtext interface functions */
|
|
static void
|
|
gtkW_gint_update (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
*(gint *)data = (gint)atof (gtk_entry_get_text (GTK_ENTRY (widget)));
|
|
}
|
|
|
|
static void
|
|
gtkW_scale_update (GtkAdjustment *adjustment,
|
|
gdouble *scale_val)
|
|
{
|
|
*scale_val = (gdouble) adjustment->value;
|
|
}
|
|
|
|
static void
|
|
gtkW_close_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gtk_main_quit ();
|
|
}
|
|
|
|
static void
|
|
vpropagate_ok_callback (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gint index;
|
|
|
|
for (index = 0; index < num_mode; index++ )
|
|
if (modes[index].selected)
|
|
{
|
|
vpvals.propagate_mode = index;
|
|
break;
|
|
}
|
|
{
|
|
gint i, result;
|
|
for (i = result = 0; i < 4; i++)
|
|
result |= (direction_mask_vec[i] ? 1 : 0) << i;
|
|
vpvals.direction_mask = result;
|
|
}
|
|
vpvals.propagating_channel = (propagate_alpha ? PROPAGATING_ALPHA : 0) |
|
|
(propagate_value ? PROPAGATING_VALUE : 0);
|
|
vpropagate_interface.run = TRUE;
|
|
gtk_widget_destroy (GTK_WIDGET (data));
|
|
}
|
|
|
|
static void
|
|
gtkW_toggle_update (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
int *toggle_val;
|
|
|
|
toggle_val = (int *) data;
|
|
|
|
if (GTK_TOGGLE_BUTTON (widget)->active)
|
|
*toggle_val = TRUE;
|
|
else
|
|
*toggle_val = FALSE;
|
|
}
|
|
|
|
/* gtkW is the abbreviation of gtk Wrapper */
|
|
static GtkWidget *
|
|
gtkW_dialog_new (char * name,
|
|
GtkSignalFunc ok_callback,
|
|
GtkSignalFunc close_callback)
|
|
{
|
|
GtkWidget *dlg, *button;
|
|
|
|
dlg = gtk_dialog_new ();
|
|
gtk_window_set_title (GTK_WINDOW (dlg), name);
|
|
gtk_window_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE);
|
|
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
|
|
(GtkSignalFunc) gtkW_close_callback, NULL);
|
|
|
|
/* Action Area */
|
|
button = gtk_button_new_with_label ("OK");
|
|
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
|
|
gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
|
(GtkSignalFunc) ok_callback, dlg);
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button,
|
|
TRUE, TRUE, 0);
|
|
gtk_widget_grab_default (button);
|
|
gtk_widget_show (button);
|
|
|
|
button = gtk_button_new_with_label ("Cancel");
|
|
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
|
|
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
|
|
(GtkSignalFunc) gtk_widget_destroy,
|
|
GTK_OBJECT(dlg));
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button,
|
|
TRUE, TRUE, 0);
|
|
gtk_widget_show (button);
|
|
|
|
return dlg;
|
|
}
|
|
|
|
GtkWidget *
|
|
gtkW_hbox_new (GtkWidget *parent)
|
|
{
|
|
GtkWidget *hbox;
|
|
|
|
hbox = gtk_hbox_new (FALSE, 5);
|
|
gtk_container_border_width (GTK_CONTAINER (hbox), 5);
|
|
gtk_box_pack_start (GTK_BOX (parent), hbox, FALSE, TRUE, 0);
|
|
return hbox;
|
|
}
|
|
|
|
GtkWidget *
|
|
gtkW_vbox_new (GtkWidget *parent)
|
|
{
|
|
GtkWidget *vbox;
|
|
|
|
vbox = gtk_vbox_new (FALSE, 5);
|
|
gtk_container_border_width (GTK_CONTAINER (vbox), 10);
|
|
/* gtk_box_pack_start (GTK_BOX (parent), vbox, TRUE, TRUE, 0); */
|
|
gtk_container_add (GTK_CONTAINER (parent), vbox);
|
|
return vbox;
|
|
}
|
|
|
|
GtkWidget *
|
|
gtkW_frame_new (gchar *name,
|
|
GtkWidget *parent)
|
|
{
|
|
GtkWidget *frame;
|
|
|
|
frame = gtk_frame_new (name);
|
|
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
|
|
gtk_container_border_width (GTK_CONTAINER (frame), 5);
|
|
gtk_box_pack_start (GTK_BOX(parent), frame, FALSE, FALSE, 0);
|
|
gtk_widget_show (frame);
|
|
return frame;
|
|
}
|
|
|
|
static GtkWidget *
|
|
gtkW_table_add_toggle (GtkWidget *table,
|
|
gchar *name,
|
|
gint x1,
|
|
gint x2,
|
|
gint y,
|
|
GtkSignalFunc update,
|
|
gint *value)
|
|
{
|
|
GtkWidget *toggle;
|
|
|
|
toggle = gtk_check_button_new_with_label(name);
|
|
gtk_table_attach (GTK_TABLE (table), toggle, x1, x2, y, y+1,
|
|
GTK_FILL|GTK_EXPAND, 0, 0, 0);
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
(GtkSignalFunc) update,
|
|
value);
|
|
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), *value);
|
|
gtk_widget_show (toggle);
|
|
return toggle;
|
|
}
|
|
|
|
static GSList *
|
|
gtkW_vbox_add_radio_button (GtkWidget *vbox,
|
|
gchar *name,
|
|
GSList *group,
|
|
GtkSignalFunc update,
|
|
gint *value)
|
|
{
|
|
GtkWidget *toggle;
|
|
|
|
toggle = gtk_radio_button_new_with_label(group, name);
|
|
group = gtk_radio_button_group (GTK_RADIO_BUTTON (toggle));
|
|
gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
|
|
gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
|
|
(GtkSignalFunc) update, value);
|
|
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (toggle), *value);
|
|
gtk_widget_show (toggle);
|
|
return group;
|
|
}
|
|
|
|
static void
|
|
gtkW_table_add_gint (GtkWidget *table,
|
|
gchar *name,
|
|
gint x,
|
|
gint y,
|
|
GtkSignalFunc update,
|
|
gint *value,
|
|
gchar *buffer)
|
|
{
|
|
GtkWidget *label, *entry;
|
|
|
|
label = gtk_label_new (name);
|
|
gtk_misc_set_alignment (GTK_MISC(label), 0.0, 0.5);
|
|
gtk_table_attach (GTK_TABLE(table), label, x, x+1, y, y+1,
|
|
GTK_FILL|GTK_EXPAND, GTK_FILL, 5, 0);
|
|
gtk_widget_show(label);
|
|
|
|
entry = gtk_entry_new();
|
|
gtk_table_attach (GTK_TABLE(table), entry, x+1, x+2, y, y+1,
|
|
GTK_FILL|GTK_EXPAND, GTK_FILL, 10, 0);
|
|
gtk_widget_set_usize (entry, ENTRY_WIDTH, 0);
|
|
sprintf (buffer, "%d", *(gint *)value);
|
|
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
|
|
gtk_signal_connect (GTK_OBJECT (entry), "changed",
|
|
(GtkSignalFunc) update, value);
|
|
gtk_widget_show(entry);
|
|
}
|
|
|
|
static void
|
|
gtkW_table_add_scale (GtkWidget *table,
|
|
gchar *name,
|
|
gint x,
|
|
gint y,
|
|
GtkSignalFunc update,
|
|
gdouble *value,
|
|
gdouble min,
|
|
gdouble max,
|
|
gdouble step)
|
|
{
|
|
GtkObject *scale_data;
|
|
GtkWidget *label, *scale;
|
|
|
|
label = gtk_label_new (name);
|
|
gtk_misc_set_alignment (GTK_MISC(label), 0.0, 0.5);
|
|
gtk_table_attach (GTK_TABLE(table), label, x, x+1, y, y+1,
|
|
GTK_FILL|GTK_EXPAND, GTK_FILL, 5, 0);
|
|
gtk_widget_show (label);
|
|
|
|
scale_data = gtk_adjustment_new (*value, min, max, step, step, 0.0);
|
|
|
|
scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data));
|
|
gtk_widget_set_usize (scale, SCALE_WIDTH, 0);
|
|
gtk_table_attach (GTK_TABLE (table), scale, x+1, x+2, y, y+1,
|
|
GTK_FILL|GTK_EXPAND, GTK_FILL, 10, 5);
|
|
gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
|
|
gtk_scale_set_digits (GTK_SCALE (scale), 2);
|
|
gtk_range_set_update_policy (GTK_RANGE (scale), GTK_UPDATE_DELAYED);
|
|
gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed",
|
|
(GtkSignalFunc) update, value);
|
|
gtk_widget_show (label);
|
|
gtk_widget_show (scale);
|
|
}
|
|
|
|
/* end of vpropagate.c */
|