/* * CINELERRA * Copyright (C) 1997-2011 Adam Williams * * 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 Color3WayWindow::Color3WayWindow(Color3WayMain *plugin) : PluginClientWindow(plugin, plugin->w, plugin->h, 680, 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") }; int w1 = w - (CLEAR_BTN_WIDTH + margin * 2); gui->add_tool(title = new BC_Title(x + w1 / 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, w1 / 2, section)); gui->add_tool(pointClr = new Color3WaySliderClrSection(plugin, gui, x + w1 + margin, y, CLEAR_BTN_WIDTH, RESET_POINT, 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, w1, section)); gui->add_tool(valueClr = new Color3WaySliderClrSection(plugin, gui, x + w1 + margin, y, CLEAR_BTN_WIDTH, RESET_VALUE, 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, w1, section)); gui->add_tool(saturationClr = new Color3WaySliderClrSection(plugin, gui, x + w1 + margin, y, CLEAR_BTN_WIDTH, RESET_SATURATION, 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; int w1 = w - (CLEAR_BTN_WIDTH + margin * 2); title->reposition_window(x + w1 / 2 - title->get_w() / 2, title->get_y()); point->reposition_window(x, point->get_y(), w1 / 2); pointClr->reposition_window(x + w1 + margin, point->get_y()); 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, w1, value->get_h()); value->set_pointer_motion_range(w1); valueClr->reposition_window(x + w1 + margin, y); y += value->get_h() + margin; sat_title->reposition_window(x, y); y += sat_title->get_h() + margin; saturation->reposition_window(x, y, w1, saturation->get_h()); saturation->set_pointer_motion_range(w1); saturationClr->reposition_window(x + w1 + margin, y); 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; } Color3WaySliderClrSection::Color3WaySliderClrSection(Color3WayMain *plugin, Color3WayWindow *gui, int x, int y, int w, int clear, int section) : BC_Button(x, y, w, plugin->get_theme()->get_image_set("reset_button")) { this->plugin = plugin; this->gui = gui; this->clear = clear; this->section = section; } Color3WaySliderClrSection::~Color3WaySliderClrSection() { } int Color3WaySliderClrSection::handle_event() { switch(clear) { case RESET_POINT : plugin->config.hue_x[section] = 0; plugin->config.hue_y[section] = 0; break; case RESET_VALUE : plugin->config.value[section] = 0; break; case RESET_SATURATION : plugin->config.saturation[section] = 0; break; } 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; }