2
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
4
* This is a plug-in for the GIMP.
6
* Colormap-Rotation plug-in. Exchanges two color ranges.
8
* Copyright (C) 1999 Sven Anders (anderss@fmi.uni-passau.de)
9
* Based on code from Pavel Grinfeld (pavel@ml.com)
12
* This program is free software; you can redistribute it and/or modify
13
* it under the terms of the GNU General Public License as published by
14
* the Free Software Foundation; either version 2 of the License, or
15
* (at your option) any later version.
17
* This program is distributed in the hope that it will be useful,
18
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
* GNU General Public License for more details.
22
* You should have received a copy of the GNU General Public License
23
* along with this program; if not, write to the Free Software
24
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27
/*---------------------------------------------------------------------------
30
* Version 2.0, 04 April 1999.
31
* Nearly complete rewrite, made plug-in stable.
32
* (Works with GIMP 1.1 and GTK+ 1.2)
34
* Version 1.0, 27 March 1997.
35
* Initial (unstable) release by Pavel Grinfeld
37
*---------------------------------------------------------------------------*/
46
#include "libgimpmath/gimpmath.h"
47
#include "libgimpwidgets/gimpwidgets.h"
48
#include "libgimp/gimp.h"
53
#include "rcm_dialog.h"
54
#include "rcm_callback.h"
55
#include "rcm_stock.h"
57
#include "images/rcm-stock-pixbufs.h"
63
rcm_units_factor (gint units)
67
case DEGREES: return 180.0 / G_PI;
68
case RADIANS: return 1.0;
69
case RADIANS_OVER_PI: return 1.0 / G_PI;
75
rcm_units_string (gint units)
79
case DEGREES: return "deg";
80
case RADIANS: return "rad";
81
case RADIANS_OVER_PI: return "rad/pi";
82
default: return "(unknown)";
90
rcm_360_degrees (GtkWidget *button,
93
circle->action_flag = DO_NOTHING;
94
gtk_widget_queue_draw (circle->preview);
95
circle->angle->beta = circle->angle->alpha-circle->angle->cw_ccw * 0.001;
96
rcm_draw_arrows (circle->preview->window, circle->preview->style->black_gc,
98
circle->action_flag = VIRGIN;
99
rcm_render_preview (Current.Bna->after, CURRENT);
103
rcm_cw_ccw (GtkWidget *button,
106
circle->angle->cw_ccw *= -1;
108
g_object_set (button,
110
(circle->angle->cw_ccw>0) ?
111
STOCK_COLORMAP_SWITCH_CLOCKWISE :
112
STOCK_COLORMAP_SWITCH_COUNTERCLOCKWISE,
116
rcm_a_to_b (button, circle);
120
rcm_a_to_b (GtkWidget *button,
123
circle->action_flag = DO_NOTHING;
124
gtk_widget_queue_draw (circle->preview);
126
SWAP (circle->angle->alpha, circle->angle->beta);
128
rcm_draw_arrows (circle->preview->window, circle->preview->style->black_gc,
131
circle->action_flag = VIRGIN;
132
rcm_render_preview (Current.Bna->after, CURRENT);
136
/* Misc: units buttons */
139
rcm_spinbutton_to_degrees (GtkWidget *button,
145
adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (button));
146
adj->value = value * rcm_units_factor (Current.Units);
148
adj->step_increment = 0.01;
149
adj->page_increment = 1.0;
150
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (button), 2);
152
gtk_label_set_text (GTK_LABEL (label), rcm_units_string (Current.Units));
156
rcm_switch_to_degrees (GtkWidget *button,
159
if (GTK_TOGGLE_BUTTON (button)->active)
161
Current.Units = DEGREES;
163
rcm_spinbutton_to_degrees (Current.From->alpha_entry,
164
Current.From->angle->alpha,
165
Current.From->alpha_units_label);
167
rcm_spinbutton_to_degrees (Current.From->beta_entry,
168
Current.From->angle->beta,
169
Current.From->beta_units_label);
171
rcm_spinbutton_to_degrees (Current.To->alpha_entry,
172
Current.To->angle->alpha,
173
Current.To->alpha_units_label);
175
rcm_spinbutton_to_degrees (Current.To->beta_entry,
176
Current.To->angle->beta,
177
Current.To->beta_units_label);
179
rcm_spinbutton_to_degrees (Current.Gray->hue_entry,
181
Current.Gray->hue_units_label);
183
Current.From->action_flag = VIRGIN;
184
Current.To->action_flag = VIRGIN;
185
Current.Gray->action_flag = VIRGIN;
190
rcm_spinbutton_to_radians (GtkWidget *button,
196
adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (button));
197
adj->value = value * rcm_units_factor (Current.Units);
199
adj->step_increment = 0.0001;
200
adj->page_increment = 0.001;
201
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (button), 4);
203
gtk_label_set_text (GTK_LABEL (label), rcm_units_string (Current.Units));
207
rcm_switch_to_radians (GtkWidget *button,
210
if (GTK_TOGGLE_BUTTON (button)->active)
212
Current.Units = RADIANS;
214
rcm_spinbutton_to_radians (Current.From->alpha_entry,
215
Current.From->angle->alpha,
216
Current.From->alpha_units_label);
218
rcm_spinbutton_to_radians (Current.From->beta_entry,
219
Current.From->angle->beta,
220
Current.From->beta_units_label);
222
rcm_spinbutton_to_radians (Current.To->alpha_entry,
223
Current.To->angle->alpha,
224
Current.To->alpha_units_label);
226
rcm_spinbutton_to_radians (Current.To->beta_entry,
227
Current.To->angle->beta,
228
Current.To->beta_units_label);
230
rcm_spinbutton_to_radians (Current.Gray->hue_entry,
232
Current.Gray->hue_units_label);
234
Current.From->action_flag = VIRGIN;
235
Current.To->action_flag = VIRGIN;
236
Current.Gray->action_flag = VIRGIN;
241
rcm_spinbutton_to_radians_over_PI (GtkWidget *button,
247
adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (button));
248
adj->value = value * rcm_units_factor (Current.Units);
250
adj->step_increment = 0.0001;
251
adj->page_increment = 0.001;
252
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (button), 4);
254
gtk_label_set_text (GTK_LABEL (label), rcm_units_string (Current.Units));
258
rcm_switch_to_radians_over_PI (GtkWidget *button,
261
if (GTK_TOGGLE_BUTTON (button)->active)
263
Current.Units = RADIANS_OVER_PI;
265
rcm_spinbutton_to_radians_over_PI (Current.From->alpha_entry,
266
Current.From->angle->alpha,
267
Current.From->alpha_units_label);
269
rcm_spinbutton_to_radians_over_PI (Current.From->beta_entry,
270
Current.From->angle->beta,
271
Current.From->beta_units_label);
273
rcm_spinbutton_to_radians_over_PI (Current.To->alpha_entry,
274
Current.To->angle->alpha,
275
Current.To->alpha_units_label);
277
rcm_spinbutton_to_radians_over_PI (Current.To->beta_entry,
278
Current.To->angle->beta,
279
Current.To->beta_units_label);
281
rcm_spinbutton_to_radians_over_PI (Current.Gray->hue_entry,
283
Current.Gray->hue_units_label);
285
Current.From->action_flag = VIRGIN;
286
Current.To->action_flag = VIRGIN;
287
Current.Gray->action_flag = VIRGIN;
292
/* Misc: Gray: mode buttons */
295
rcm_switch_to_gray_to (GtkWidget *button,
298
if (! GTK_TOGGLE_BUTTON (button)->active)
301
Current.Gray_to_from = GRAY_TO;
302
rcm_render_preview (Current.Bna->after, CURRENT);
306
rcm_switch_to_gray_from (GtkWidget *button,
309
if (! GTK_TOGGLE_BUTTON (button)->active)
312
Current.Gray_to_from = GRAY_FROM;
313
rcm_render_preview (Current.Bna->after, CURRENT);
317
/* Misc: Preview buttons */
320
rcm_preview_as_you_drag (GtkWidget *button,
323
Current.RealTime = GTK_TOGGLE_BUTTON (button)->active;
327
rcm_change_preview (void)
329
/* must hide and show or resize would not work ... */
331
gtk_widget_hide (Current.Bna->before);
332
gtk_widget_hide (Current.Bna->after);
334
gtk_widget_set_size_request (Current.Bna->before,
335
Current.reduced->width,
336
Current.reduced->height);
338
gtk_widget_set_size_request (Current.Bna->after,
339
Current.reduced->width,
340
Current.reduced->height);
342
rcm_render_preview (Current.Bna->before, ORIGINAL);
343
rcm_render_preview (Current.Bna->after, CURRENT);
345
gtk_widget_queue_draw (Current.Bna->before);
346
gtk_widget_queue_draw (Current.Bna->after);
348
gtk_widget_show (Current.Bna->before);
349
gtk_widget_show (Current.Bna->after);
353
rcm_combo_callback (GtkWidget *widget,
358
gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), &value);
360
Current.reduced = rcm_reduce_image (Current.drawable, Current.mask,
361
MAX_PREVIEW_SIZE, value);
362
rcm_change_preview ();
369
rcm_expose_event (GtkWidget *widget,
373
switch (circle->action_flag)
375
case DO_NOTHING: return FALSE; break;
377
case VIRGIN: rcm_draw_arrows(widget->window, widget->style->black_gc,
381
default: if (Current.RealTime)
382
rcm_render_preview(Current.Bna->after,CURRENT);
389
rcm_button_press_event (GtkWidget *widget,
396
GdkEventButton *bevent;
398
alpha = &circle->angle->alpha;
399
beta = &circle->angle->beta;
400
bevent = (GdkEventButton *) event;
402
circle->action_flag = DRAG_START;
403
clicked_angle = angle_mod_2PI (arctg (CENTER-bevent->y, bevent->x-CENTER));
404
circle->prev_clicked = clicked_angle;
406
if ((sqrt (SQR (bevent->y-CENTER) +
407
SQR (bevent->x-CENTER)) > RADIUS * EACH_OR_BOTH) &&
408
(min_prox (*alpha, *beta, clicked_angle) < G_PI / 12))
411
circle->target = closest (alpha, beta, clicked_angle);
413
if (*(circle->target) != clicked_angle)
415
*(circle->target) = clicked_angle;
416
gtk_widget_queue_draw (circle->preview);
417
rcm_draw_arrows (widget->window,
418
widget->style->black_gc, circle->angle);
420
gtk_spin_button_set_value (GTK_SPIN_BUTTON (circle->alpha_entry),
421
circle->angle->alpha *
422
rcm_units_factor(Current.Units));
424
gtk_spin_button_set_value (GTK_SPIN_BUTTON (circle->beta_entry),
425
circle->angle->beta *
426
rcm_units_factor(Current.Units));
428
if (Current.RealTime)
429
rcm_render_preview (Current.Bna->after, CURRENT);
439
rcm_release_event (GtkWidget *widget,
443
if (circle->action_flag == DRAGING)
445
gtk_widget_queue_draw (circle->preview);
446
rcm_draw_arrows (widget->window, widget->style->black_gc, circle->angle);
449
circle->action_flag = VIRGIN;
451
if (! Current.RealTime)
452
rcm_render_preview (Current.Bna->after, CURRENT);
458
rcm_motion_notify_event (GtkWidget *widget,
463
gfloat clicked_angle, delta;
464
gfloat *alpha, *beta;
468
alpha = &(circle->angle->alpha);
469
beta = &(circle->angle->beta);
470
cw_ccw = circle->angle->cw_ccw;
471
delta = angle_mod_2PI (cw_ccw * (*beta - *alpha));
473
values.foreground = Current.From->preview->style->white;
474
values.function = GDK_XOR;
475
xor_gc = gdk_gc_new_with_values (Current.From->preview->window,
477
GDK_GC_FOREGROUND | GDK_GC_FUNCTION);
479
gdk_window_get_pointer (widget->window, &x, &y, NULL);
480
clicked_angle = angle_mod_2PI (arctg (CENTER-y, x-CENTER));
482
delta = clicked_angle - circle->prev_clicked;
483
circle->prev_clicked = clicked_angle;
487
if (circle->action_flag == DRAG_START)
489
gtk_widget_queue_draw (circle->preview);
490
circle->action_flag = DRAGING;
494
/* this should be erasing entire angle */
495
rcm_draw_arrows (widget->window, xor_gc, circle->angle);
498
if (circle->mode == EACH)
500
*(circle->target)=clicked_angle;
504
circle->angle->alpha=angle_mod_2PI(circle->angle->alpha + delta);
505
circle->angle->beta =angle_mod_2PI(circle->angle->beta + delta);
508
gdk_window_process_updates (widget->window, FALSE);
509
rcm_draw_arrows (widget->window, xor_gc, circle->angle);
511
gtk_spin_button_set_value (GTK_SPIN_BUTTON (circle->alpha_entry),
512
circle->angle->alpha *
513
rcm_units_factor(Current.Units));
515
gtk_spin_button_set_value (GTK_SPIN_BUTTON (circle->beta_entry),
516
circle->angle->beta *
517
rcm_units_factor(Current.Units));
519
if (Current.RealTime)
520
rcm_render_preview (Current.Bna->after, CURRENT);
527
/* Gray circle events */
530
rcm_gray_expose_event (GtkWidget *widget,
534
if (circle->action_flag == VIRGIN)
536
rcm_draw_little_circle (widget->window, widget->style->black_gc,
537
circle->hue, circle->satur);
539
rcm_draw_large_circle (widget->window,
540
widget->style->black_gc, circle->gray_sat);
542
else if (Current.RealTime)
543
rcm_render_preview (Current.Bna->after, CURRENT);
549
rcm_gray_button_press_event (GtkWidget *widget,
553
GdkEventButton *bevent;
556
bevent = (GdkEventButton *) event;
557
x = bevent->x - GRAY_CENTER - LITTLE_RADIUS;
558
y = GRAY_CENTER - bevent->y + LITTLE_RADIUS;
560
circle->action_flag = DRAG_START;
561
circle->hue = angle_mod_2PI(arctg(y, x));
562
circle->satur = sqrt (SQR (x) + SQR (y)) / GRAY_RADIUS;
564
if (circle->satur > 1.0)
567
gtk_widget_queue_draw (circle->preview);
568
rcm_draw_little_circle (widget->window, widget->style->black_gc,
569
circle->hue, circle->satur);
571
rcm_draw_large_circle (circle->preview->window,
572
circle->preview->style->black_gc,
575
gtk_spin_button_set_value (GTK_SPIN_BUTTON (circle->hue_entry),
576
circle->hue * rcm_units_factor (Current.Units));
578
gtk_spin_button_set_value (GTK_SPIN_BUTTON (circle->satur_entry),
581
if (Current.RealTime)
582
rcm_render_preview (Current.Bna->after,CURRENT);
588
rcm_gray_release_event (GtkWidget *widget,
592
if (circle->action_flag == DRAGING)
593
rcm_draw_little_circle (widget->window,
594
widget->style->black_gc,
598
circle->action_flag = VIRGIN;
600
if (!Current.RealTime)
601
rcm_render_preview (Current.Bna->after, CURRENT);
607
rcm_gray_motion_notify_event (GtkWidget *widget,
614
values.foreground = Current.From->preview->style->white;
615
values.function = GDK_XOR;
616
xor_gc = gdk_gc_new_with_values (Current.From->preview->window,
618
GDK_GC_FOREGROUND | GDK_GC_FUNCTION);
620
if (circle->action_flag == DRAG_START)
622
gtk_widget_queue_draw (circle->preview);
623
rcm_draw_large_circle (circle->preview->window,
624
circle->preview->style->black_gc,
627
circle->action_flag = DRAGING;
631
rcm_draw_little_circle (widget->window, xor_gc,
632
circle->hue, circle->satur); /* erase */
635
gdk_window_get_pointer (widget->window, &x, &y, NULL);
637
x = x - GRAY_CENTER - LITTLE_RADIUS;
638
y = GRAY_CENTER - y + LITTLE_RADIUS;
640
circle->hue = angle_mod_2PI (arctg (y, x));
641
circle->satur = sqrt (SQR (x) + SQR (y)) / GRAY_RADIUS;
643
if (circle->satur > 1.0)
646
rcm_draw_little_circle (widget->window, xor_gc, circle->hue, circle->satur);
648
gtk_spin_button_set_value (GTK_SPIN_BUTTON (circle->hue_entry),
649
circle->hue * rcm_units_factor(Current.Units));
651
gtk_spin_button_set_value (GTK_SPIN_BUTTON (circle->satur_entry),
654
if (Current.RealTime)
655
rcm_render_preview (Current.Bna->after, CURRENT);
664
rcm_set_alpha (GtkWidget *entry,
667
RcmCircle *circle = data;
669
if (circle->action_flag != VIRGIN)
672
circle->angle->alpha = (gtk_spin_button_get_value (GTK_SPIN_BUTTON (entry)) /
673
rcm_units_factor (Current.Units));
675
gtk_widget_queue_draw (circle->preview);
677
rcm_draw_arrows (circle->preview->window, circle->preview->style->black_gc,
680
rcm_render_preview (Current.Bna->after, CURRENT);
684
rcm_set_beta (GtkWidget *entry,
687
RcmCircle *circle = data;
689
if (circle->action_flag != VIRGIN)
692
circle->angle->beta = (gtk_spin_button_get_value (GTK_SPIN_BUTTON (entry)) /
693
rcm_units_factor(Current.Units));
695
gtk_widget_queue_draw (circle->preview);
697
rcm_draw_arrows (circle->preview->window, circle->preview->style->black_gc,
700
rcm_render_preview (Current.Bna->after, CURRENT);
704
rcm_set_hue (GtkWidget *entry,
707
RcmGray *circle = data;
709
if (circle->action_flag != VIRGIN
712
circle->hue = (gtk_spin_button_get_value (GTK_SPIN_BUTTON (entry)) /
713
rcm_units_factor(Current.Units));
715
gtk_widget_queue_draw (circle->preview);
717
rcm_draw_little_circle (circle->preview->window,
718
circle->preview->style->black_gc,
719
circle->hue, circle->satur);
721
rcm_draw_large_circle (circle->preview->window,
722
circle->preview->style->black_gc,
725
rcm_render_preview (Current.Bna->after, CURRENT);
729
rcm_set_satur (GtkWidget *entry,
732
RcmGray *circle = data;
734
if (circle->action_flag != VIRGIN)
737
circle->satur = gtk_spin_button_get_value (GTK_SPIN_BUTTON (entry));
739
gtk_widget_queue_draw (circle->preview);
741
rcm_draw_little_circle (circle->preview->window,
742
circle->preview->style->black_gc,
743
circle->hue, circle->satur);
745
rcm_draw_large_circle (circle->preview->window,
746
circle->preview->style->black_gc,
749
rcm_render_preview (Current.Bna->after, CURRENT);
753
rcm_set_gray_sat (GtkWidget *entry,
756
RcmGray *circle = data;
758
circle->gray_sat = gtk_spin_button_get_value (GTK_SPIN_BUTTON (entry));
760
gtk_widget_queue_draw (circle->preview);
762
rcm_draw_large_circle (circle->preview->window,
763
circle->preview->style->black_gc,
766
rcm_render_preview (Current.Bna->after, CURRENT);