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