Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / plugins / color3way / color3waywindow.C
diff --git a/cinelerra-5.1/plugins/color3way/color3waywindow.C b/cinelerra-5.1/plugins/color3way/color3waywindow.C
new file mode 100644 (file)
index 0000000..8827b4e
--- /dev/null
@@ -0,0 +1,775 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
+ * 
+ * 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
+ * 
+ */
+
+#include "bcsignals.h"
+#include "color3waywindow.h"
+#include "keys.h"
+#include "language.h"
+#include "theme.h"
+#include "units.h"
+#include <string.h>
+
+
+
+
+
+
+
+
+
+
+Color3WayWindow::Color3WayWindow(Color3WayMain *plugin)
+ : PluginClientWindow(plugin,
+       plugin->w, 
+       plugin->h, 
+       500, 
+       370, 
+       1)
+{ 
+       this->plugin = plugin; 
+}
+
+Color3WayWindow::~Color3WayWindow()
+{
+}
+
+void Color3WayWindow::create_objects()
+{
+       int margin = plugin->get_theme()->widget_border;
+       int x = plugin->get_theme()->widget_border;
+       int y = plugin->get_theme()->widget_border;
+
+       for(int i = 0; i < SECTIONS; i++)
+       {
+               sections[i] = new Color3WaySection(plugin, 
+                       this,
+                       x,
+                       y,
+                       (get_w() - margin * 4) / 3,
+                       get_h() - margin * 2,
+                       i);
+               sections[i]->create_objects();
+               x += sections[i]->w + margin;
+       }
+
+
+
+       flash(0);
+       show_window();
+}
+
+int Color3WayWindow::resize_event(int w, int h)
+{
+       int margin = plugin->get_theme()->widget_border;
+       int x = sections[0]->x;
+       int y = sections[0]->y;
+
+       for(int i = 0; i < SECTIONS; i++)
+       {
+               sections[i]->reposition_window(x,
+                       y,
+                       (w - margin * 4) / 3,
+                       w - margin * 2);
+               x += sections[i]->w + margin;
+       }
+
+       plugin->w = w;
+       plugin->h = h;
+       flush();
+       return 1;
+}
+
+
+void Color3WayWindow::update()
+{
+       for(int i = 0; i < SECTIONS; i++)
+       {
+               sections[i]->update();
+       }
+}
+
+
+
+Color3WaySection::Color3WaySection(Color3WayMain *plugin, 
+               Color3WayWindow *gui,
+               int x,
+               int y,
+               int w,
+               int h,
+               int section)
+{
+       this->plugin = plugin;
+       this->gui = gui;
+       this->section = section;
+       this->x = x;
+       this->y = y;
+       this->w = w;
+       this->h = h;
+
+}
+
+void Color3WaySection::create_objects()
+{
+       int margin = plugin->get_theme()->widget_border;
+       int x = this->x;
+       int y = this->y;
+       const char *titles[] = 
+       {
+               _("Shadows"),
+               _("Midtones"),
+               _("Highlights")
+       };
+       
+       
+       gui->add_tool(title = new BC_Title(x + w / 2 - 
+               gui->get_text_width(MEDIUMFONT, titles[section]) / 2,
+               y,
+               titles[section]));
+       y += title->get_h() + margin;
+       gui->add_tool(point = new Color3WayPoint(plugin, 
+               gui,
+               &plugin->config.hue_x[section], 
+               &plugin->config.hue_y[section],
+               x, 
+               y,
+               w / 2,
+               section));
+       y += point->get_h() + margin;
+       
+       gui->add_tool(value_title = new BC_Title(x, y, _("Value:")));
+       y += value_title->get_h() + margin;
+       gui->add_tool(value = new Color3WaySlider(plugin, 
+               gui,
+               &plugin->config.value[section], 
+               x, 
+               y,
+               w,
+               section));
+       y += value->get_h() + margin;
+
+       gui->add_tool(sat_title = new BC_Title(x, y, _("Saturation:")));
+       y += sat_title->get_h() + margin;
+       gui->add_tool(saturation = new Color3WaySlider(plugin, 
+               gui,
+               &plugin->config.saturation[section], 
+               x, 
+               y,
+               w,
+               section));
+       y += saturation->get_h() + margin;
+
+       gui->add_tool(reset = new Color3WayResetSection(plugin, 
+               gui, 
+               x, 
+               y,
+               section));
+
+       y += reset->get_h() + margin;
+       gui->add_tool(balance = new Color3WayBalanceSection(plugin, 
+               gui, 
+               x, 
+               y,
+               section));
+
+       y += balance->get_h() + margin;
+       gui->add_tool(copy = new Color3WayCopySection(plugin, 
+               gui, 
+               x, 
+               y,
+               section));
+}
+
+int Color3WaySection::reposition_window(int x, int y, int w, int h)
+{
+       int margin = plugin->get_theme()->widget_border;
+       this->x = x;
+       this->y = y;
+       this->w = w;
+       this->h = h;
+
+       title->reposition_window(x + w / 2 -
+               title->get_w() / 2,
+               title->get_y());
+       point->reposition_window(x, point->get_y(), w / 2);
+       y = point->get_y() + point->get_h() + margin;
+       value_title->reposition_window(x, y);
+       y += value_title->get_h() + margin;
+       value->reposition_window(x, y, w, value->get_h());
+       value->set_pointer_motion_range(w);
+       y += value->get_h() + margin;
+       
+       sat_title->reposition_window(x, y);
+       y += sat_title->get_h() + margin;
+       saturation->reposition_window(x, y, w, saturation->get_h());
+       saturation->set_pointer_motion_range(w);
+       y += saturation->get_h() + margin;
+       reset->reposition_window(x, y);
+       y += reset->get_h() + margin;
+       balance->reposition_window(x, y);
+       y += balance->get_h() + margin;
+       copy->reposition_window(x, y);
+       gui->flush();
+       return 0;
+}
+
+void Color3WaySection::update()
+{
+       point->update();
+       value->update(plugin->config.value[section]);
+       saturation->update(plugin->config.saturation[section]);
+}
+
+
+
+
+
+Color3WayPoint::Color3WayPoint(Color3WayMain *plugin, 
+       Color3WayWindow *gui,
+       float *x_output, 
+       float *y_output,
+       int x, 
+       int y,
+       int radius,
+       int section)
+ : BC_SubWindow(x, 
+       y, 
+       radius * 2,
+       radius * 2)
+{
+       this->plugin = plugin;
+       this->x_output = x_output;
+       this->y_output = y_output;
+       this->radius = radius;
+       this->gui = gui;
+       drag_operation = 0;
+       status = COLOR_UP;
+       memset(fg_images, 0, sizeof(BC_Pixmap*) * COLOR_IMAGES);
+       bg_image = 0;
+       active = 0;
+       this->section = section;
+}
+
+Color3WayPoint::~Color3WayPoint()
+{
+       for(int i = 0; i < COLOR_IMAGES; i++)
+               if(fg_images[i]) delete fg_images[i];
+               
+       delete bg_image;
+}
+
+int Color3WayPoint::initialize()
+{
+       BC_SubWindow::initialize();
+
+
+       VFrame **data = plugin->get_theme()->get_image_set("color3way_point");
+       for(int i = 0; i < COLOR_IMAGES; i++)
+       {
+               if(fg_images[i]) delete fg_images[i];
+               fg_images[i] = new BC_Pixmap(gui, data[i], PIXMAP_ALPHA);
+       }
+
+
+       draw_face(1, 0);
+
+       return 0;
+}
+
+int Color3WayPoint::reposition_window(int x, int y, int radius)
+{
+       this->radius = radius;
+       BC_SubWindow::reposition_window(x, y, radius * 2, radius * 2);
+       
+       delete bg_image;
+       bg_image = 0;
+       draw_face(1, 0);
+       return 0;
+}
+
+void Color3WayPoint::draw_face(int flash, int flush)
+{
+// Draw the color wheel
+       if(!bg_image)
+       {
+               VFrame frame(0, -1, radius * 2, radius * 2, BC_RGB888, -1);
+               for(int i = 0; i < radius * 2; i++)
+               {
+                       unsigned char *row = frame.get_rows()[i];
+                       for(int j = 0; j < radius * 2; j++)
+                       {
+                               float point_radius = sqrt(SQR(i - radius) + SQR(j - radius));
+                               int r, g, b;
+
+                               if(point_radius < radius - 1)
+                               {
+                                       float r_f, g_f, b_f;
+                                       float angle = atan2((float)(j - radius) / radius, 
+                                               (float)(i - radius) / radius) *
+                                               360 /
+                                               2 / 
+                                               M_PI;
+                                       angle -= 180;
+                                       while(angle < 0)
+                                               angle += 360;
+                                       HSV::hsv_to_rgb(r_f, g_f, b_f, angle, point_radius / radius, 1.0);
+                                       r = (int)(r_f * 0xff);
+                                       g = (int)(g_f * 0xff);
+                                       b = (int)(b_f * 0xff);
+                               }
+                               else
+                               if(point_radius < radius)
+                               {
+                                       if(radius * 2 - i < j)
+                                       {
+                                               r = MEGREY >> 16;
+                                               g = (MEGREY >> 8) &  0xff;
+                                               b = MEGREY & 0xff;
+                                       }
+                                       else
+                                       {
+                                               r = 0;
+                                               g = 0;
+                                               b = 0;
+                                       }
+                               }
+                               else
+                               {
+                                       r = (gui->get_bg_color() & 0xff0000) >> 16;
+                                       g = (gui->get_bg_color() & 0xff00) >> 8;
+                                       b = (gui->get_bg_color() & 0xff);
+                               }
+
+                               *row++ = r;
+                               *row++ = g;
+                               *row++ = b;
+                       }
+               }
+
+               bg_image = new BC_Pixmap(get_parent(), &frame, PIXMAP_ALPHA);
+       }
+
+       draw_pixmap(bg_image);
+       
+//     set_color(BLACK);
+//     draw_arc(0, 0, radius * 2, radius * 2, 45, 180);
+//     
+//     set_color(MEGREY);
+//     draw_arc(0, 0, radius * 2, radius * 2, 45, -180);
+
+
+       fg_x = (int)(*x_output * (radius - fg_images[0]->get_w() / 2) + radius) - 
+               fg_images[0]->get_w() / 2;
+       fg_y = (int)(*y_output * (radius - fg_images[0]->get_h() / 2) + radius) - 
+               fg_images[0]->get_h() / 2;
+       
+       draw_pixmap(fg_images[status], fg_x, fg_y);
+       
+// Text
+       if(active)
+       {
+               int margin = plugin->get_theme()->widget_border;
+               set_color(BLACK);
+               set_font(MEDIUMFONT);
+               char string[BCTEXTLEN];
+
+               sprintf(string, "%.3f", *y_output);
+               draw_text(radius - get_text_width(MEDIUMFONT, string) / 2, 
+                       get_text_ascent(MEDIUMFONT) + margin,
+                       string);
+
+               sprintf(string, "%.3f", *x_output);
+               draw_text(margin, 
+                       radius + get_text_ascent(MEDIUMFONT) / 2,
+                       string);
+
+
+//             float r_factor;
+//             float g_factor;
+//             float b_factor;
+//             plugin->calculate_factors(&r_factor, &g_factor, &b_factor, section);
+// 
+//             sprintf(string, "%.3f", r_factor);
+//             draw_text(radius - get_text_width(MEDIUMFONT, string) / 2, 
+//                     get_text_ascent(MEDIUMFONT) + margin,
+//                     string);
+// 
+//             sprintf(string, "%.3f", g_factor);
+//             draw_text(margin + radius - radius * 1.0 / ROOT_2, 
+//                     radius + radius * 1.0 / ROOT_2 - margin,
+//                     string);
+// 
+//             sprintf(string, "%.3f", b_factor);
+//             draw_text(radius + radius * 1.0 / ROOT_2 - margin - get_text_width(MEDIUMFONT, string), 
+//                     radius + radius * 1.0 / ROOT_2 - margin,
+//                     string);
+               set_font(MEDIUMFONT);
+       }
+       
+       if(flash) this->flash(0);
+       if(flush) this->flush();
+}
+
+int Color3WayPoint::deactivate()
+{
+       if(active)
+       {
+               active = 0;
+               draw_face(1, 1);
+       }
+       return 1;
+}
+
+int Color3WayPoint::activate()
+{
+       if(!active)
+       {
+               get_top_level()->set_active_subwindow(this);
+               active = 1;
+       }
+       return 1;
+}
+
+void Color3WayPoint::update()
+{
+       draw_face(1, 1);
+}
+
+int Color3WayPoint::button_press_event()
+{
+       if(is_event_win())
+       {
+               status = COLOR_DN;
+               get_top_level()->deactivate();
+               activate();
+               draw_face(1, 1);
+
+               starting_x = fg_x;
+               starting_y = fg_y;
+               offset_x = gui->get_relative_cursor_x();
+               offset_y = gui->get_relative_cursor_y();
+       }
+       return 0;
+}
+
+int Color3WayPoint::button_release_event()
+{
+       if(status == COLOR_DN)
+       {
+               status = COLOR_HI;
+               draw_face(1, 1);
+               return 1;
+       }
+       return 0;
+}
+
+int Color3WayPoint::cursor_motion_event()
+{
+       int cursor_x = gui->get_relative_cursor_x();
+       int cursor_y = gui->get_relative_cursor_y();
+
+//printf("Color3WayPoint::cursor_motion_event %d %d\n", __LINE__, status);
+       if(status == COLOR_DN)
+       {
+//printf("Color3WayPoint::cursor_motion_event %d %d %d\n", __LINE__, starting_x, offset_x);
+               int new_x = starting_x + cursor_x - offset_x;
+               int new_y = starting_y + cursor_y - offset_y;
+
+               *x_output = (float)(new_x + fg_images[0]->get_w() / 2 - radius) / 
+                       (radius - fg_images[0]->get_w() / 2);
+               *y_output = (float)(new_y + fg_images[0]->get_h() / 2 - radius) / 
+                       (radius - fg_images[0]->get_h() / 2);
+
+               plugin->config.boundaries();
+               if(plugin->copy_to_all[section]) plugin->config.copy_to_all(section);
+               plugin->send_configure_change();
+
+
+               gui->update();
+
+               
+               handle_event();
+
+
+               return 1;
+       }
+
+       return 0;
+}
+
+int Color3WayPoint::handle_event()
+{
+       return 1;
+}
+
+
+int Color3WayPoint::cursor_enter_event()
+{
+       if(is_event_win() && status != COLOR_HI && status != COLOR_DN)
+       {
+               status = COLOR_HI;
+               draw_face(1, 1);
+       }
+       return 0;
+}
+
+int Color3WayPoint::cursor_leave_event()
+{
+       if(status == COLOR_HI)
+       {
+               status = COLOR_UP;
+               draw_face(1, 1);
+       }
+       return 0;
+}
+
+int Color3WayPoint::keypress_event()
+{
+       int result = 0;
+       if(!active) return 0;
+       if(ctrl_down() || shift_down()) return 0;
+
+       switch(get_keypress())
+       {
+               case UP:
+                       *y_output -= 0.001;
+                       result = 1;
+                       break;
+               case DOWN:
+                       *y_output += 0.001;
+                       result = 1;
+                       break;
+               case LEFT:
+                       *x_output -= 0.001;
+                       result = 1;
+                       break;
+               case RIGHT:
+                       *x_output += 0.001;
+                       result = 1;
+                       break;
+       }
+
+       if(result)
+       {
+               plugin->config.boundaries();
+               if(plugin->copy_to_all[section]) plugin->config.copy_to_all(section);
+               plugin->send_configure_change();
+               gui->update();
+       }
+       return result;
+}
+
+
+
+
+
+
+
+
+Color3WaySlider::Color3WaySlider(Color3WayMain *plugin, 
+       Color3WayWindow *gui, 
+       float *output, 
+       int x, 
+       int y,
+       int w,
+       int section)
+ : BC_FSlider(x, 
+       y, 
+       0, 
+       w, 
+       w,
+       -1.0, 
+       1.0, 
+       *output)
+{
+       this->gui = gui;
+       this->plugin = plugin;
+       this->output = output;
+       this->section = section;
+    old_value = *output;
+       set_precision(0.001);
+}
+
+Color3WaySlider::~Color3WaySlider()
+{
+}
+
+int Color3WaySlider::handle_event()
+{
+       *output = get_value();
+       if(plugin->copy_to_all[section]) plugin->config.copy_to_all(section);
+       plugin->send_configure_change();
+       gui->update();
+       return 1;
+}
+
+char* Color3WaySlider::get_caption()
+{
+       sprintf(string, "%0.3f", *output);
+       return string;
+}
+
+
+
+
+
+Color3WayResetSection::Color3WayResetSection(Color3WayMain *plugin, 
+       Color3WayWindow *gui, 
+       int x, 
+       int y,
+       int section)
+ : BC_GenericButton(x, y, _("Reset"))
+{
+       this->plugin = plugin;
+       this->gui = gui;
+       this->section = section;
+}
+
+int Color3WayResetSection::handle_event()
+{
+       plugin->config.hue_x[section] = 0;
+       plugin->config.hue_y[section] = 0;
+       plugin->config.value[section] = 0;
+       plugin->config.saturation[section] = 0;
+       if(plugin->copy_to_all[section]) plugin->config.copy_to_all(section);
+       plugin->send_configure_change();
+       gui->update();
+       return 1;
+}
+
+
+
+
+
+
+Color3WayCopySection::Color3WayCopySection(Color3WayMain *plugin, 
+       Color3WayWindow *gui, 
+       int x, 
+       int y,
+       int section)
+ : BC_CheckBox(x, y, plugin->copy_to_all[section], _("Copy to all"))
+{
+       this->plugin = plugin;
+       this->gui = gui;
+       this->section = section;
+}
+
+int Color3WayCopySection::handle_event()
+{
+       if(get_value()) plugin->config.copy_to_all(section);
+       plugin->copy_to_all[section] = get_value();
+       gui->update();
+       plugin->send_configure_change();
+       return 1;
+}
+
+
+
+
+
+Color3WayBalanceSection::Color3WayBalanceSection(Color3WayMain *plugin, 
+       Color3WayWindow *gui,
+       int x, 
+       int y,
+       int section)
+ : BC_GenericButton(x, y, _("White balance"))
+{
+       this->plugin = plugin;
+       this->gui = gui;
+       this->section = section;
+}
+
+int Color3WayBalanceSection::handle_event()
+{
+// Get colorpicker value
+       float r = plugin->get_red();
+       float g = plugin->get_green();
+       float b = plugin->get_blue();
+
+// Since the transfers aren't linear, use brute force search
+       float step = 0.1;
+       float center_x = 0;
+       float center_y = 0;
+       float range = 1;
+       float best_diff = 255;
+       float new_x = 0;
+       float new_y = 0;
+       
+       while(step >= 0.001)
+       {
+               for(float x = center_x - range; x < center_x + range; x += step)
+               {
+                       for(float y = center_y - range; y < center_y + range; y += step)
+                       {
+                               float new_r;
+                               float new_g;
+                               float new_b;
+                               plugin->process_pixel(&new_r,
+                                       &new_g,
+                                       &new_b,
+                                       r, 
+                                       g, 
+                                       b,
+                                       x,
+                                       y);
+                               float min = MIN(new_r, new_g);
+                               min = MIN(min, new_b);
+                               float max = MAX(new_r, new_g);
+                               max = MAX(max, new_b);
+                               float diff = max - min;
+                               
+                               if(diff < best_diff)
+                               {
+                                       best_diff = diff;
+                                       new_x = x;
+                                       new_y = y;
+                               }
+                       }
+               }
+
+               step /= 2;
+               range /= 2;
+               center_x = new_x;
+               center_y = new_y;
+       }
+
+       new_x = Units::quantize(new_x, 0.001);
+       new_y = Units::quantize(new_y, 0.001);
+
+       plugin->config.hue_x[section] = new_x;
+       plugin->config.hue_y[section] = new_y;
+       plugin->config.boundaries();
+       if(plugin->copy_to_all[section]) plugin->config.copy_to_all(section);
+       plugin->send_configure_change();
+
+       
+       gui->update();
+
+       return 1;
+}
+
+
+
+
+
+
+
+
+