remove whitespace at eol
[goodguy/history.git] / cinelerra-5.1 / plugins / color3way / color3waywindow.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcsignals.h"
23 #include "color3waywindow.h"
24 #include "keys.h"
25 #include "language.h"
26 #include "theme.h"
27 #include "units.h"
28 #include <string.h>
29
30
31
32
33
34
35
36
37
38
39 Color3WayWindow::Color3WayWindow(Color3WayMain *plugin)
40  : PluginClientWindow(plugin,
41         plugin->w,
42         plugin->h,
43         500,
44         370,
45         1)
46 {
47         this->plugin = plugin;
48 }
49
50 Color3WayWindow::~Color3WayWindow()
51 {
52 }
53
54 void Color3WayWindow::create_objects()
55 {
56         int margin = plugin->get_theme()->widget_border;
57         int x = plugin->get_theme()->widget_border;
58         int y = plugin->get_theme()->widget_border;
59
60         for(int i = 0; i < SECTIONS; i++)
61         {
62                 sections[i] = new Color3WaySection(plugin,
63                         this,
64                         x,
65                         y,
66                         (get_w() - margin * 4) / 3,
67                         get_h() - margin * 2,
68                         i);
69                 sections[i]->create_objects();
70                 x += sections[i]->w + margin;
71         }
72
73
74
75         flash(0);
76         show_window();
77 }
78
79 int Color3WayWindow::resize_event(int w, int h)
80 {
81         int margin = plugin->get_theme()->widget_border;
82         int x = sections[0]->x;
83         int y = sections[0]->y;
84
85         for(int i = 0; i < SECTIONS; i++)
86         {
87                 sections[i]->reposition_window(x,
88                         y,
89                         (w - margin * 4) / 3,
90                         w - margin * 2);
91                 x += sections[i]->w + margin;
92         }
93
94         plugin->w = w;
95         plugin->h = h;
96         flush();
97         return 1;
98 }
99
100
101 void Color3WayWindow::update()
102 {
103         for(int i = 0; i < SECTIONS; i++)
104         {
105                 sections[i]->update();
106         }
107 }
108
109
110
111 Color3WaySection::Color3WaySection(Color3WayMain *plugin,
112                 Color3WayWindow *gui,
113                 int x,
114                 int y,
115                 int w,
116                 int h,
117                 int section)
118 {
119         this->plugin = plugin;
120         this->gui = gui;
121         this->section = section;
122         this->x = x;
123         this->y = y;
124         this->w = w;
125         this->h = h;
126
127 }
128
129 void Color3WaySection::create_objects()
130 {
131         int margin = plugin->get_theme()->widget_border;
132         int x = this->x;
133         int y = this->y;
134         const char *titles[] =
135         {
136                 _("Shadows"),
137                 _("Midtones"),
138                 _("Highlights")
139         };
140
141
142         gui->add_tool(title = new BC_Title(x + w / 2 -
143                 gui->get_text_width(MEDIUMFONT, titles[section]) / 2,
144                 y,
145                 titles[section]));
146         y += title->get_h() + margin;
147         gui->add_tool(point = new Color3WayPoint(plugin,
148                 gui,
149                 &plugin->config.hue_x[section],
150                 &plugin->config.hue_y[section],
151                 x,
152                 y,
153                 w / 2,
154                 section));
155         y += point->get_h() + margin;
156
157         gui->add_tool(value_title = new BC_Title(x, y, _("Value:")));
158         y += value_title->get_h() + margin;
159         gui->add_tool(value = new Color3WaySlider(plugin,
160                 gui,
161                 &plugin->config.value[section],
162                 x,
163                 y,
164                 w,
165                 section));
166         y += value->get_h() + margin;
167
168         gui->add_tool(sat_title = new BC_Title(x, y, _("Saturation:")));
169         y += sat_title->get_h() + margin;
170         gui->add_tool(saturation = new Color3WaySlider(plugin,
171                 gui,
172                 &plugin->config.saturation[section],
173                 x,
174                 y,
175                 w,
176                 section));
177         y += saturation->get_h() + margin;
178
179         gui->add_tool(reset = new Color3WayResetSection(plugin,
180                 gui,
181                 x,
182                 y,
183                 section));
184
185         y += reset->get_h() + margin;
186         gui->add_tool(balance = new Color3WayBalanceSection(plugin,
187                 gui,
188                 x,
189                 y,
190                 section));
191
192         y += balance->get_h() + margin;
193         gui->add_tool(copy = new Color3WayCopySection(plugin,
194                 gui,
195                 x,
196                 y,
197                 section));
198 }
199
200 int Color3WaySection::reposition_window(int x, int y, int w, int h)
201 {
202         int margin = plugin->get_theme()->widget_border;
203         this->x = x;
204         this->y = y;
205         this->w = w;
206         this->h = h;
207
208         title->reposition_window(x + w / 2 -
209                 title->get_w() / 2,
210                 title->get_y());
211         point->reposition_window(x, point->get_y(), w / 2);
212         y = point->get_y() + point->get_h() + margin;
213         value_title->reposition_window(x, y);
214         y += value_title->get_h() + margin;
215         value->reposition_window(x, y, w, value->get_h());
216         value->set_pointer_motion_range(w);
217         y += value->get_h() + margin;
218
219         sat_title->reposition_window(x, y);
220         y += sat_title->get_h() + margin;
221         saturation->reposition_window(x, y, w, saturation->get_h());
222         saturation->set_pointer_motion_range(w);
223         y += saturation->get_h() + margin;
224         reset->reposition_window(x, y);
225         y += reset->get_h() + margin;
226         balance->reposition_window(x, y);
227         y += balance->get_h() + margin;
228         copy->reposition_window(x, y);
229         gui->flush();
230         return 0;
231 }
232
233 void Color3WaySection::update()
234 {
235         point->update();
236         value->update(plugin->config.value[section]);
237         saturation->update(plugin->config.saturation[section]);
238 }
239
240
241
242
243
244 Color3WayPoint::Color3WayPoint(Color3WayMain *plugin,
245         Color3WayWindow *gui,
246         float *x_output,
247         float *y_output,
248         int x,
249         int y,
250         int radius,
251         int section)
252  : BC_SubWindow(x,
253         y,
254         radius * 2,
255         radius * 2)
256 {
257         this->plugin = plugin;
258         this->x_output = x_output;
259         this->y_output = y_output;
260         this->radius = radius;
261         this->gui = gui;
262         drag_operation = 0;
263         status = COLOR_UP;
264         memset(fg_images, 0, sizeof(BC_Pixmap*) * COLOR_IMAGES);
265         bg_image = 0;
266         active = 0;
267         this->section = section;
268 }
269
270 Color3WayPoint::~Color3WayPoint()
271 {
272         for(int i = 0; i < COLOR_IMAGES; i++)
273                 if(fg_images[i]) delete fg_images[i];
274
275         delete bg_image;
276 }
277
278 int Color3WayPoint::initialize()
279 {
280         BC_SubWindow::initialize();
281
282
283         VFrame **data = plugin->get_theme()->get_image_set("color3way_point");
284         for(int i = 0; i < COLOR_IMAGES; i++)
285         {
286                 if(fg_images[i]) delete fg_images[i];
287                 fg_images[i] = new BC_Pixmap(gui, data[i], PIXMAP_ALPHA);
288         }
289
290
291         draw_face(1, 0);
292
293         return 0;
294 }
295
296 int Color3WayPoint::reposition_window(int x, int y, int radius)
297 {
298         this->radius = radius;
299         BC_SubWindow::reposition_window(x, y, radius * 2, radius * 2);
300
301         delete bg_image;
302         bg_image = 0;
303         draw_face(1, 0);
304         return 0;
305 }
306
307 void Color3WayPoint::draw_face(int flash, int flush)
308 {
309 // Draw the color wheel
310         if(!bg_image)
311         {
312                 VFrame frame(0, -1, radius * 2, radius * 2, BC_RGB888, -1);
313                 for(int i = 0; i < radius * 2; i++)
314                 {
315                         unsigned char *row = frame.get_rows()[i];
316                         for(int j = 0; j < radius * 2; j++)
317                         {
318                                 float point_radius = sqrt(SQR(i - radius) + SQR(j - radius));
319                                 int r, g, b;
320
321                                 if(point_radius < radius - 1)
322                                 {
323                                         float r_f, g_f, b_f;
324                                         float angle = atan2((float)(j - radius) / radius,
325                                                 (float)(i - radius) / radius) *
326                                                 360 /
327                                                 2 /
328                                                 M_PI;
329                                         angle -= 180;
330                                         while(angle < 0)
331                                                 angle += 360;
332                                         HSV::hsv_to_rgb(r_f, g_f, b_f, angle, point_radius / radius, 1.0);
333                                         r = (int)(r_f * 0xff);
334                                         g = (int)(g_f * 0xff);
335                                         b = (int)(b_f * 0xff);
336                                 }
337                                 else
338                                 if(point_radius < radius)
339                                 {
340                                         if(radius * 2 - i < j)
341                                         {
342                                                 r = MEGREY >> 16;
343                                                 g = (MEGREY >> 8) &  0xff;
344                                                 b = MEGREY & 0xff;
345                                         }
346                                         else
347                                         {
348                                                 r = 0;
349                                                 g = 0;
350                                                 b = 0;
351                                         }
352                                 }
353                                 else
354                                 {
355                                         r = (gui->get_bg_color() & 0xff0000) >> 16;
356                                         g = (gui->get_bg_color() & 0xff00) >> 8;
357                                         b = (gui->get_bg_color() & 0xff);
358                                 }
359
360                                 *row++ = r;
361                                 *row++ = g;
362                                 *row++ = b;
363                         }
364                 }
365
366                 bg_image = new BC_Pixmap(get_parent(), &frame, PIXMAP_ALPHA);
367         }
368
369         draw_pixmap(bg_image);
370
371 //      set_color(BLACK);
372 //      draw_arc(0, 0, radius * 2, radius * 2, 45, 180);
373 // 
374 //      set_color(MEGREY);
375 //      draw_arc(0, 0, radius * 2, radius * 2, 45, -180);
376
377
378         fg_x = (int)(*x_output * (radius - fg_images[0]->get_w() / 2) + radius) -
379                 fg_images[0]->get_w() / 2;
380         fg_y = (int)(*y_output * (radius - fg_images[0]->get_h() / 2) + radius) -
381                 fg_images[0]->get_h() / 2;
382
383         draw_pixmap(fg_images[status], fg_x, fg_y);
384
385 // Text
386         if(active)
387         {
388                 int margin = plugin->get_theme()->widget_border;
389                 set_color(BLACK);
390                 set_font(MEDIUMFONT);
391                 char string[BCTEXTLEN];
392
393                 sprintf(string, "%.3f", *y_output);
394                 draw_text(radius - get_text_width(MEDIUMFONT, string) / 2,
395                         get_text_ascent(MEDIUMFONT) + margin,
396                         string);
397
398                 sprintf(string, "%.3f", *x_output);
399                 draw_text(margin,
400                         radius + get_text_ascent(MEDIUMFONT) / 2,
401                         string);
402
403
404 //              float r_factor;
405 //              float g_factor;
406 //              float b_factor;
407 //              plugin->calculate_factors(&r_factor, &g_factor, &b_factor, section);
408 //
409 //              sprintf(string, "%.3f", r_factor);
410 //              draw_text(radius - get_text_width(MEDIUMFONT, string) / 2,
411 //                      get_text_ascent(MEDIUMFONT) + margin,
412 //                      string);
413 //
414 //              sprintf(string, "%.3f", g_factor);
415 //              draw_text(margin + radius - radius * 1.0 / ROOT_2,
416 //                      radius + radius * 1.0 / ROOT_2 - margin,
417 //                      string);
418 //
419 //              sprintf(string, "%.3f", b_factor);
420 //              draw_text(radius + radius * 1.0 / ROOT_2 - margin - get_text_width(MEDIUMFONT, string),
421 //                      radius + radius * 1.0 / ROOT_2 - margin,
422 //                      string);
423                 set_font(MEDIUMFONT);
424         }
425
426         if(flash) this->flash(0);
427         if(flush) this->flush();
428 }
429
430 int Color3WayPoint::deactivate()
431 {
432         if(active)
433         {
434                 active = 0;
435                 draw_face(1, 1);
436         }
437         return 1;
438 }
439
440 int Color3WayPoint::activate()
441 {
442         if(!active)
443         {
444                 get_top_level()->set_active_subwindow(this);
445                 active = 1;
446         }
447         return 1;
448 }
449
450 void Color3WayPoint::update()
451 {
452         draw_face(1, 1);
453 }
454
455 int Color3WayPoint::button_press_event()
456 {
457         if(is_event_win())
458         {
459                 status = COLOR_DN;
460                 get_top_level()->deactivate();
461                 activate();
462                 draw_face(1, 1);
463
464                 starting_x = fg_x;
465                 starting_y = fg_y;
466                 offset_x = gui->get_relative_cursor_x();
467                 offset_y = gui->get_relative_cursor_y();
468         }
469         return 0;
470 }
471
472 int Color3WayPoint::button_release_event()
473 {
474         if(status == COLOR_DN)
475         {
476                 status = COLOR_HI;
477                 draw_face(1, 1);
478                 return 1;
479         }
480         return 0;
481 }
482
483 int Color3WayPoint::cursor_motion_event()
484 {
485         int cursor_x = gui->get_relative_cursor_x();
486         int cursor_y = gui->get_relative_cursor_y();
487
488 //printf("Color3WayPoint::cursor_motion_event %d %d\n", __LINE__, status);
489         if(status == COLOR_DN)
490         {
491 //printf("Color3WayPoint::cursor_motion_event %d %d %d\n", __LINE__, starting_x, offset_x);
492                 int new_x = starting_x + cursor_x - offset_x;
493                 int new_y = starting_y + cursor_y - offset_y;
494
495                 *x_output = (float)(new_x + fg_images[0]->get_w() / 2 - radius) /
496                         (radius - fg_images[0]->get_w() / 2);
497                 *y_output = (float)(new_y + fg_images[0]->get_h() / 2 - radius) /
498                         (radius - fg_images[0]->get_h() / 2);
499
500                 plugin->config.boundaries();
501                 if(plugin->copy_to_all[section]) plugin->config.copy_to_all(section);
502                 plugin->send_configure_change();
503
504
505                 gui->update();
506
507
508                 handle_event();
509
510
511                 return 1;
512         }
513
514         return 0;
515 }
516
517 int Color3WayPoint::handle_event()
518 {
519         return 1;
520 }
521
522
523 int Color3WayPoint::cursor_enter_event()
524 {
525         if(is_event_win() && status != COLOR_HI && status != COLOR_DN)
526         {
527                 status = COLOR_HI;
528                 draw_face(1, 1);
529         }
530         return 0;
531 }
532
533 int Color3WayPoint::cursor_leave_event()
534 {
535         if(status == COLOR_HI)
536         {
537                 status = COLOR_UP;
538                 draw_face(1, 1);
539         }
540         return 0;
541 }
542
543 int Color3WayPoint::keypress_event()
544 {
545         int result = 0;
546         if(!active) return 0;
547         if(ctrl_down() || shift_down()) return 0;
548
549         switch(get_keypress())
550         {
551                 case UP:
552                         *y_output -= 0.001;
553                         result = 1;
554                         break;
555                 case DOWN:
556                         *y_output += 0.001;
557                         result = 1;
558                         break;
559                 case LEFT:
560                         *x_output -= 0.001;
561                         result = 1;
562                         break;
563                 case RIGHT:
564                         *x_output += 0.001;
565                         result = 1;
566                         break;
567         }
568
569         if(result)
570         {
571                 plugin->config.boundaries();
572                 if(plugin->copy_to_all[section]) plugin->config.copy_to_all(section);
573                 plugin->send_configure_change();
574                 gui->update();
575         }
576         return result;
577 }
578
579
580
581
582
583
584
585
586 Color3WaySlider::Color3WaySlider(Color3WayMain *plugin,
587         Color3WayWindow *gui,
588         float *output,
589         int x,
590         int y,
591         int w,
592         int section)
593  : BC_FSlider(x,
594         y,
595         0,
596         w,
597         w,
598         -1.0,
599         1.0,
600         *output)
601 {
602         this->gui = gui;
603         this->plugin = plugin;
604         this->output = output;
605         this->section = section;
606     old_value = *output;
607         set_precision(0.001);
608 }
609
610 Color3WaySlider::~Color3WaySlider()
611 {
612 }
613
614 int Color3WaySlider::handle_event()
615 {
616         *output = get_value();
617         if(plugin->copy_to_all[section]) plugin->config.copy_to_all(section);
618         plugin->send_configure_change();
619         gui->update();
620         return 1;
621 }
622
623 char* Color3WaySlider::get_caption()
624 {
625         sprintf(string, "%0.3f", *output);
626         return string;
627 }
628
629
630
631
632
633 Color3WayResetSection::Color3WayResetSection(Color3WayMain *plugin,
634         Color3WayWindow *gui,
635         int x,
636         int y,
637         int section)
638  : BC_GenericButton(x, y, _("Reset"))
639 {
640         this->plugin = plugin;
641         this->gui = gui;
642         this->section = section;
643 }
644
645 int Color3WayResetSection::handle_event()
646 {
647         plugin->config.hue_x[section] = 0;
648         plugin->config.hue_y[section] = 0;
649         plugin->config.value[section] = 0;
650         plugin->config.saturation[section] = 0;
651         if(plugin->copy_to_all[section]) plugin->config.copy_to_all(section);
652         plugin->send_configure_change();
653         gui->update();
654         return 1;
655 }
656
657
658
659
660
661
662 Color3WayCopySection::Color3WayCopySection(Color3WayMain *plugin,
663         Color3WayWindow *gui,
664         int x,
665         int y,
666         int section)
667  : BC_CheckBox(x, y, plugin->copy_to_all[section], _("Copy to all"))
668 {
669         this->plugin = plugin;
670         this->gui = gui;
671         this->section = section;
672 }
673
674 int Color3WayCopySection::handle_event()
675 {
676         if(get_value()) plugin->config.copy_to_all(section);
677         plugin->copy_to_all[section] = get_value();
678         gui->update();
679         plugin->send_configure_change();
680         return 1;
681 }
682
683
684
685
686
687 Color3WayBalanceSection::Color3WayBalanceSection(Color3WayMain *plugin,
688         Color3WayWindow *gui,
689         int x,
690         int y,
691         int section)
692  : BC_GenericButton(x, y, _("White balance"))
693 {
694         this->plugin = plugin;
695         this->gui = gui;
696         this->section = section;
697 }
698
699 int Color3WayBalanceSection::handle_event()
700 {
701 // Get colorpicker value
702         float r = plugin->get_red();
703         float g = plugin->get_green();
704         float b = plugin->get_blue();
705
706 // Since the transfers aren't linear, use brute force search
707         float step = 0.1;
708         float center_x = 0;
709         float center_y = 0;
710         float range = 1;
711         float best_diff = 255;
712         float new_x = 0;
713         float new_y = 0;
714
715         while(step >= 0.001)
716         {
717                 for(float x = center_x - range; x < center_x + range; x += step)
718                 {
719                         for(float y = center_y - range; y < center_y + range; y += step)
720                         {
721                                 float new_r;
722                                 float new_g;
723                                 float new_b;
724                                 plugin->process_pixel(&new_r,
725                                         &new_g,
726                                         &new_b,
727                                         r,
728                                         g,
729                                         b,
730                                         x,
731                                         y);
732                                 float min = MIN(new_r, new_g);
733                                 min = MIN(min, new_b);
734                                 float max = MAX(new_r, new_g);
735                                 max = MAX(max, new_b);
736                                 float diff = max - min;
737
738                                 if(diff < best_diff)
739                                 {
740                                         best_diff = diff;
741                                         new_x = x;
742                                         new_y = y;
743                                 }
744                         }
745                 }
746
747                 step /= 2;
748                 range /= 2;
749                 center_x = new_x;
750                 center_y = new_y;
751         }
752
753         new_x = Units::quantize(new_x, 0.001);
754         new_y = Units::quantize(new_y, 0.001);
755
756         plugin->config.hue_x[section] = new_x;
757         plugin->config.hue_y[section] = new_y;
758         plugin->config.boundaries();
759         if(plugin->copy_to_all[section]) plugin->config.copy_to_all(section);
760         plugin->send_configure_change();
761
762
763         gui->update();
764
765         return 1;
766 }
767
768
769
770
771
772
773
774
775