qmask-commands.c 10.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * 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.
 */
18 19 20

#include "config.h"

21
#include <stdlib.h>
22
#include <stdio.h>
23 24
#include <string.h>

Sven Neumann's avatar
Sven Neumann committed
25 26
#include <gtk/gtk.h>

27
#include "libgimpcolor/gimpcolor.h"
28
#include "libgimpwidgets/gimpwidgets.h"
29

Sven Neumann's avatar
Sven Neumann committed
30 31
#include "apptypes.h"

32
#include "channel.h"
33
#include "color_panel.h"
34
#include "drawable.h"
35
#include "floating_sel.h"
36
#include "gdisplay.h"
37 38
#include "gimage_mask.h"
#include "gimpimage.h"
39
#include "gimpcontext.h"
40 41 42 43
#include "global_edit.h"
#include "qmask.h"
#include "undo.h"

Sven Neumann's avatar
Sven Neumann committed
44 45
#include "libgimp/gimpintl.h"

46

47 48
struct _EditQmaskOptions
{
49 50
  GtkWidget   *query_box;
  GtkWidget   *name_entry;
51
  GtkWidget   *color_panel;
52

53
  GimpImage   *gimage;
54 55 56 57 58
};

typedef struct _EditQmaskOptions EditQmaskOptions;

/*  Global variables  */
59
/*  Static variables  */
60
/*  Prototypes */
61 62 63 64 65 66 67 68 69 70 71
static void edit_qmask_channel_query         (GDisplay        *gdisp);
static void edit_qmask_query_ok_callback     (GtkWidget       *widget, 
                                              gpointer         client_data);
static void edit_qmask_query_cancel_callback (GtkWidget       *widget, 
                                              gpointer         client_data);
static void qmask_query_scale_update         (GtkAdjustment   *adjustment,
                                              gpointer         data);
static void qmask_color_changed              (GimpColorButton *button,
					      gpointer         data);
static void qmask_removed_callback           (GtkObject       *qmask, 
					      gpointer         data);
72 73

/* Actual code */
74

75
static void 
76
qmask_query_scale_update (GtkAdjustment *adjustment, 
77
			  gpointer       data)
78
{
79
  GimpRGB  color;
80

81 82 83 84
  gimp_color_button_get_color (GIMP_COLOR_BUTTON (data), &color);
  gimp_rgb_set_alpha (&color, adjustment->value / 100.0);
  gimp_color_button_set_color (GIMP_COLOR_BUTTON (data), &color);
}
85

86 87 88 89 90 91 92 93 94
static void
qmask_color_changed (GimpColorButton *button,
		     gpointer         data)
{
  GtkAdjustment *adj = GTK_ADJUSTMENT (data);
  GimpRGB        color;

  gimp_color_button_get_color (button, &color);
  gtk_adjustment_set_value (adj, color.a * 100.0);
95 96
}

97 98 99 100 101 102 103 104 105
static void
qmask_removed_callback (GtkObject *qmask,
			gpointer   data)
{
  GDisplay *gdisp = (GDisplay*) data;
  
  if (!gdisp->gimage)
    return;
  
106
  gdisp->gimage->qmask_state = FALSE;
107 108 109 110 111

  qmask_buttons_update (gdisp);
}


112 113 114
void
qmask_buttons_update (GDisplay *gdisp)
{
115 116
  g_assert (gdisp);
  g_assert (gdisp->gimage);
117

118
  if (gdisp->gimage->qmask_state != GTK_TOGGLE_BUTTON (gdisp->qmaskon)->active)
119 120 121 122 123 124 125 126
    {
      /* Disable toggle from doing anything */
      gtk_signal_handler_block_by_func(GTK_OBJECT(gdisp->qmaskoff), 
				       (GtkSignalFunc) qmask_deactivate,
				       gdisp);
      gtk_signal_handler_block_by_func(GTK_OBJECT(gdisp->qmaskon), 
				       (GtkSignalFunc) qmask_activate,
				       gdisp);
127
   
128 129 130
      /* Change the state of the buttons */
      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gdisp->qmaskon), 
				   gdisp->gimage->qmask_state);
131

132 133
      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gdisp->qmaskoff),
				   !gdisp->gimage->qmask_state);
134
   
135 136 137 138 139 140 141 142
      /* Enable toggle again */
      gtk_signal_handler_unblock_by_func(GTK_OBJECT(gdisp->qmaskoff), 
					 (GtkSignalFunc) qmask_deactivate,
					 gdisp);
      gtk_signal_handler_unblock_by_func(GTK_OBJECT(gdisp->qmaskon), 
					 (GtkSignalFunc) qmask_activate,
					 gdisp);
    }
143 144
}

145 146 147 148 149 150
void 
qmask_click_handler (GtkWidget       *widget,
		     GdkEventButton  *event,
                     gpointer         data)
{
  GDisplay *gdisp;
151 152

  gdisp = (GDisplay *) data;
153 154 155

  if ((event->type == GDK_2BUTTON_PRESS) &&
      (event->button == 1))
156
    {
157
      edit_qmask_channel_query (gdisp); 
158
    }
159 160
}

161
void
162 163
qmask_deactivate (GtkWidget *widget,
		  GDisplay  *gdisp)
164
{
165
  GimpImage   *gimg;
166 167 168 169 170
  GimpChannel *gmask;

  if (gdisp)
    {
      gimg = gdisp->gimage;
171 172
      if (!gimg) 
	return;
173
      
174
      if (!gdisp->gimage->qmask_state)
175 176
	return; /* if already set do nothing */

177
      if ( (gmask = gimp_image_get_channel_by_name (gimg, "Qmask")) )
178
  	{ 
179 180 181 182 183
	  undo_push_group_start (gimg, QMASK_UNDO);
	  /*  push the undo here since removing the mask will
	      call the qmask_removed_callback() which will set
	      the qmask_state to FALSE  */
	  undo_push_qmask (gimg);
184
	  gimage_mask_load (gimg, gmask);
185
	  gimp_image_remove_channel (gimg, gmask);
186
	  undo_push_group_end (gimg);
187
	}
188 189

      gdisp->gimage->qmask_state = FALSE;
190 191

      if (gmask)
192
	gdisplays_flush ();
193
    }
194 195 196
}

void
197
qmask_activate (GtkWidget *widget,
198
		GDisplay  *gdisp)
199
{
200
  GimpImage   *gimg;
201
  GimpChannel *gmask;
202
  GimpLayer   *layer;
203
  GimpRGB      color;
204

205 206 207
  if (gdisp)
    {
      gimg = gdisp->gimage;
208 209
      if (!gimg) 
	return;
210

211
      if (gdisp->gimage->qmask_state)
212
	return; /* If already set, do nothing */
213
  
214 215
      /* Set the defaults */
      color = gimg->qmask_color;
216
 
217
      if ((gmask = gimp_image_get_channel_by_name (gimg, "Qmask"))) 
218
	{
219 220
	  gimg->qmask_state = TRUE; 
	  /* if the user was clever and created his own */
221 222
	  return; 
	}
223 224

      undo_push_group_start (gimg, QMASK_UNDO);
225

226
      if (gimage_mask_is_empty (gimg))
227
	{ 
228 229
	  /* if no selection */

230
	  if ((layer = gimp_image_floating_sel (gimg)))
231 232 233
	    {
	      floating_sel_to_layer (layer);
	    }
234

235 236 237
	  gmask = channel_new (gimg, 
			       gimg->width, 
			       gimg->height,
238
			       "Qmask",
239
			       &color);
240
	  gimp_image_add_channel (gimg, gmask, 0);
241
	  drawable_fill (GIMP_DRAWABLE (gmask), TRANSPARENT_FILL);
242
	}
243
      else
244 245 246
	{
	  /* if selection */

247
	  gmask = channel_copy (gimp_image_get_mask (gimg));
248
	  gimp_image_add_channel (gimg, gmask, 0);
249
	  channel_set_color (gmask, &color);
250
	  gimp_object_set_name (GIMP_OBJECT (gmask), "Qmask");
251 252
	  gimage_mask_none (gimg);           /* Clear the selection */
	}
253 254 255 256 257

      undo_push_qmask (gimg);
      undo_push_group_end (gimg);
      gdisp->gimage->qmask_state = TRUE;
      gdisplays_flush ();
258

259 260
      /* connect to the removed signal, so the buttons get updated */
      gtk_signal_connect (GTK_OBJECT (gmask), "removed", 
261 262
			  GTK_SIGNAL_FUNC (qmask_removed_callback),
			  gdisp);
263 264
    }
}
265 266 267 268 269

static void
edit_qmask_channel_query (GDisplay * gdisp)
{
  EditQmaskOptions *options;
270 271 272 273 274 275
  GtkWidget        *hbox;
  GtkWidget        *vbox;
  GtkWidget        *table;
  GtkWidget        *label;
  GtkWidget        *opacity_scale;
  GtkObject        *opacity_scale_data;
276 277

  /*  the new options structure  */
278
  options = g_new0 (EditQmaskOptions, 1);
279

280
  options->gimage      = gdisp->gimage;
281 282
  options->color_panel = gimp_color_panel_new (_("Edit Qmask Color"),
					       &options->gimage->qmask_color,
283 284
					       GIMP_COLOR_AREA_LARGE_CHECKS, 
					       48, 64);
285 286

  /*  The dialog  */
287 288 289
  options->query_box =
    gimp_dialog_new (_("Edit Qmask Attributes"), "edit_qmask_attributes",
		     gimp_standard_help_func,
290
		     "dialogs/edit_qmask_attributes.html",
291 292 293 294
		     GTK_WIN_POS_MOUSE,
		     FALSE, TRUE, FALSE,

		     _("OK"), edit_qmask_query_ok_callback,
295
		     options, NULL, NULL, TRUE, FALSE,
296
		     _("Cancel"), edit_qmask_query_cancel_callback,
297
		     options, NULL, NULL, FALSE, TRUE,
298 299

		     NULL);
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322

  /*  The main hbox  */
  hbox = gtk_hbox_new (FALSE, 2);
  gtk_container_set_border_width (GTK_CONTAINER (hbox), 4);
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (options->query_box)->vbox),
                     hbox);
  /*  The vbox  */
  vbox = gtk_vbox_new (FALSE, 2);
  gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);

  /*  The table  */
  table = gtk_table_new (2, 3, FALSE);
  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);

  /*  The opacity scale  */
  label = gtk_label_new (_("Mask Opacity:"));
  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 1.0);
  gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
                    GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  gtk_widget_show (label);

  opacity_scale_data =
323 324
    gtk_adjustment_new (options->gimage->qmask_color.a * 100.0, 
			0.0, 100.0, 1.0, 1.0, 0.0);
325 326 327 328
  opacity_scale = gtk_hscale_new (GTK_ADJUSTMENT (opacity_scale_data));
  gtk_table_attach_defaults (GTK_TABLE (table), opacity_scale, 1, 2, 1, 2);
  gtk_scale_set_value_pos (GTK_SCALE (opacity_scale), GTK_POS_TOP);
  gtk_signal_connect (GTK_OBJECT (opacity_scale_data), "value_changed",
329
                      GTK_SIGNAL_FUNC (qmask_query_scale_update),
330
                      options->color_panel);
331 332 333
  gtk_widget_show (opacity_scale);

  /*  The color panel  */
334
  gtk_signal_connect (GTK_OBJECT (options->color_panel), "color_changed",
335
		      GTK_SIGNAL_FUNC (qmask_color_changed),
336 337
		      opacity_scale_data);		      
  gtk_box_pack_start (GTK_BOX (hbox), options->color_panel,
338
                      TRUE, TRUE, 0);
339
  gtk_widget_show (options->color_panel);
340 341 342 343 344 345 346

  gtk_widget_show (table);
  gtk_widget_show (vbox);
  gtk_widget_show (hbox);
  gtk_widget_show (options->query_box);
}

347 348
static void 
edit_qmask_query_ok_callback (GtkWidget *widget, 
349
			      gpointer   data) 
350 351
{
  EditQmaskOptions *options;
352
  Channel          *channel;
353
  GimpRGB           color;
354

355 356
  options = (EditQmaskOptions *) data;

357
  channel = gimp_image_get_channel_by_name (options->gimage, "Qmask");
358

359 360
  if (options->gimage && channel)
    {
361 362 363 364
      gimp_color_button_get_color (GIMP_COLOR_BUTTON (options->color_panel),
				   &color);

      if (gimp_rgba_distance (&color, &channel->color) > 0.0001)
365
	{
366
	  channel->color = color;
367 368
	  channel_update (channel);
	}
369
    }
370

371
  /* update the qmask color no matter what */
372
  options->gimage->qmask_color = color;
373 374 375 376 377

  gtk_widget_destroy (options->query_box);
  g_free (options);
}

378 379
static void
edit_qmask_query_cancel_callback (GtkWidget *widget,
380
				  gpointer   data)
381 382 383
{
  EditQmaskOptions *options;

384
  options = (EditQmaskOptions *) data;
385 386 387 388

  gtk_widget_destroy (options->query_box);
  g_free (options);
}