--- /dev/null
+
+/*
+ * 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;
+}
+
+
+
+
+
+
+
+
+