/* * CINELERRA * Copyright (C) 2008 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 "bcpan.h" #include "bcpixmap.h" #include "bcpopup.h" #include "bcresources.h" #include "clip.h" #include "bccolors.h" #include "fonts.h" #include "rotateframe.h" #include "units.h" #include "vframe.h" #include #include BC_Pan::BC_Pan(int x, int y, int virtual_r, float maxvalue, int total_values, int *value_positions, int stick_x, int stick_y, float *values) : BC_SubWindow(x, y, -1, -1, -1) { this->virtual_r = virtual_r; this->maxvalue = maxvalue; this->total_values = total_values; this->values = new float[total_values]; memcpy(this->values, values, sizeof(float) * total_values); this->value_positions = new int[total_values]; memcpy(this->value_positions, value_positions, sizeof(int) * total_values); this->value_x = new int[total_values]; this->value_y = new int[total_values]; this->stick_x = stick_x; this->stick_y = stick_y; get_channel_positions(value_x, value_y, value_positions, virtual_r, total_values); if(stick_x < 0 || stick_y < 0) calculate_stick_position(total_values, value_positions, values, maxvalue, virtual_r, this->stick_x, this->stick_y); highlighted = 0; popup = 0; active = 0; memset(images, 0, sizeof(BC_Pixmap*) * PAN_IMAGES); } BC_Pan::~BC_Pan() { //printf("BC_Pan::~BC_Pan 1\n"); delete [] values; //printf("BC_Pan::~BC_Pan 1\n"); delete [] value_positions; //printf("BC_Pan::~BC_Pan 1\n"); delete [] value_x; //printf("BC_Pan::~BC_Pan 1\n"); delete [] value_y; //printf("BC_Pan::~BC_Pan 1\n"); if(popup) delete popup; //printf("BC_Pan::~BC_Pan 1\n"); delete temp_channel; //printf("BC_Pan::~BC_Pan 1\n"); delete rotater; for(int i = 0; i < PAN_IMAGES; i++) if(images[i]) delete images[i]; //printf("BC_Pan::~BC_Pan 2\n"); } int BC_Pan::initialize() { set_images(get_resources()->pan_data); BC_SubWindow::initialize(); temp_channel = new VFrame; temp_channel->set_use_shm(0); temp_channel->reallocate(0, -1, 0, 0, 0, get_resources()->pan_data[PAN_CHANNEL]->get_w(), get_resources()->pan_data[PAN_CHANNEL]->get_h(), get_resources()->pan_data[PAN_CHANNEL]->get_color_model(), -1); rotater = new RotateFrame(1, get_resources()->pan_data[PAN_CHANNEL]->get_w(), get_resources()->pan_data[PAN_CHANNEL]->get_h()); draw(1, 0); return 0; } void BC_Pan::set_images(VFrame **data) { for(int i = 0; i < PAN_IMAGES; i++) { if(images[i]) delete images[i]; images[i] = new BC_Pixmap(parent_window, data[i], PIXMAP_ALPHA); } w = images[PAN_UP]->get_w(); h = images[PAN_UP]->get_h(); } int BC_Pan::button_press_event() { // there are two modes of operation... if (popup) { if (popup->is_event_win() && get_button_down() && get_buttonpress() == 1) { active = 1; x_origin = popup->get_cursor_x(); y_origin = popup->get_cursor_y(); stick_x_origin = stick_x; stick_y_origin = stick_y; return 1; } else { deactivate(); return 0; } } if(is_event_win() && get_button_down() && get_buttonpress() == 1) { hide_tooltip(); activate(); active = 1; x_origin = get_cursor_x(); y_origin = get_cursor_y(); stick_x_origin = stick_x; stick_y_origin = stick_y; draw_popup(); return 1; } return 0; } int BC_Pan::cursor_motion_event() { if(popup && get_button_down() && get_buttonpress() == 1) { stick_x = stick_x_origin + get_cursor_x() - x_origin; stick_y = stick_y_origin + get_cursor_y() - y_origin; CLAMP(stick_x, 0, virtual_r * 2); CLAMP(stick_y, 0, virtual_r * 2); stick_to_values(); draw_popup(); handle_event(); return 1; } return 0; } int BC_Pan::button_release_event() { if(popup) { hide_tooltip(); deactivate(); draw(1, 1); return 1; } return 0; } int BC_Pan::repeat_event(int64_t duration) { if( highlighted && !active && tooltip_text && tooltip_text[0] != 0 && duration == top_level->get_resources()->tooltip_delay ) { show_tooltip(); return 1; } return 0; } int BC_Pan::cursor_enter_event() { if(is_event_win() && !highlighted) { highlighted = 1; draw(1, 1); } return 0; } int BC_Pan::cursor_leave_event() { if(highlighted) { highlighted = 0; hide_tooltip(); draw(1, 1); } return 0; } int BC_Pan::deactivate() { if(popup) delete popup; popup = 0; active = 0; return 0; } int BC_Pan::activate(int popup_x, int popup_y) { int x, y; Window tempwin; active = 0; if (popup_x < 0 || popup_y < 0) { XTranslateCoordinates(top_level->display, win, top_level->rootwin, 0, 0, &x, &y, &tempwin); x -= (images[PAN_POPUP]->get_w() - get_w()) / 2; y -= (images[PAN_POPUP]->get_h() - get_h()) / 2; if (x < 0) x = 0; } else { XTranslateCoordinates(top_level->display, top_level->win, top_level->rootwin, popup_x, popup_y, &x, &y, &tempwin); x -= images[PAN_POPUP]->get_w() / 2; y -= images[PAN_POPUP]->get_h() / 2; if (x < 0) x = 0; } delete popup; popup = new BC_Popup(this, x, y, images[PAN_POPUP]->get_w(), images[PAN_POPUP]->get_h(), 0, 0, images[PAN_POPUP]); draw_popup(); flush(); return 0; } int BC_Pan::update(int x, int y) { if(x != stick_x || y != stick_y) { stick_x = x; stick_y = y; stick_to_values(); draw(1, 1); } return 0; } void BC_Pan::draw_popup() { popup->draw_background(0, 0, popup->get_w(), popup->get_h()); int x1, y1; float rotate_angle; float scale = (float)(popup->get_w() - get_resources()->pan_data[PAN_CHANNEL]->get_w()) / (virtual_r * 2); set_color(get_resources()->pan_text_color); set_font(SMALLFONT); for(int i = 0; i < total_values; i++) { x1 = (int)(value_x[i] * scale); y1 = (int)(value_y[i] * scale); rotate_angle = value_positions[i]; rotate_angle = -rotate_angle; while(rotate_angle < 0) rotate_angle += 360; rotater->rotate(temp_channel, get_resources()->pan_data[PAN_CHANNEL], rotate_angle, 0); BC_Pixmap *temp_pixmap = new BC_Pixmap(popup, temp_channel, PIXMAP_ALPHA); popup->draw_pixmap(temp_pixmap, x1, y1); delete temp_pixmap; char string[BCTEXTLEN]; float value = values[i] + 0.005; sprintf(string, "%.1f", value); popup->draw_text(x1, y1 + get_text_height(SMALLFONT), string); } x1 = (int)(stick_x * scale); y1 = (int)(stick_y * scale); popup->draw_pixmap(images[PAN_STICK], x1, y1); popup->flash(); } #define PICON_W 6 #define PICON_H 6 void BC_Pan::draw(int flash, int flush) { draw_top_background(parent_window, 0, 0, w, h); draw_pixmap(images[highlighted ? PAN_HI : PAN_UP]); get_channel_positions(value_x, value_y, value_positions, virtual_r, total_values); // draw channels int x1, y1; float scale = (float)(get_w() - PICON_W) / (virtual_r * 2); set_color(RED); for(int i = 0; i < total_values; i++) { // printf("BC_Pan::draw 1 %d %d %d %d\n", // i, // value_positions[i], // value_x[i], // value_y[i]); x1 = (int)(value_x[i] * scale); y1 = (int)(value_y[i] * scale); //printf("BC_Pan::draw 2 %d %d\n", x1, y1); CLAMP(x1, 0, get_w() - PICON_W); CLAMP(y1, 0, get_h() - PICON_H); draw_pixmap(images[PAN_CHANNEL_SMALL], x1, y1); // draw_box(x1, y1, PICON_W, PICON_H); } // draw stick set_color(GREEN); x1 = (int)(stick_x * scale); y1 = (int)(stick_y * scale); //printf("BC_Pan::draw 2 %d %d\n", x1, y1); CLAMP(x1, 0, get_w() - PICON_W); CLAMP(y1, 0, get_h() - PICON_H); draw_pixmap(images[PAN_STICK_SMALL], x1, y1); // x2 = x1 + PICON_W; // y2 = y1 + PICON_H; // draw_line(x1, y1, x2, y2); // draw_line(x2, y1, x1, y2); if(flash) this->flash(0); if(flush) this->flush(); } int BC_Pan::stick_to_values() { return stick_to_values(values, total_values, value_positions, stick_x, stick_y, virtual_r, maxvalue); } int BC_Pan::stick_to_values(float *values, int total_values, int *value_positions, int stick_x, int stick_y, int virtual_r, float maxvalue) { // find shortest distance to a channel float shortest = 2 * virtual_r, test_distance; int i; int *value_x = new int[total_values]; int *value_y = new int[total_values]; get_channel_positions(value_x, value_y, value_positions, virtual_r, total_values); for(i = 0; i < total_values; i++) { if((test_distance = distance(stick_x, value_x[i], stick_y, value_y[i])) < shortest) shortest = test_distance; } // get values for channels if(shortest == 0) { for(i = 0; i < total_values; i++) { if(distance(stick_x, value_x[i], stick_y, value_y[i]) == shortest) values[i] = maxvalue; else values[i] = 0; } } else { for(i = 0; i < total_values; i++) { values[i] = shortest; values[i] -= (float)(distance(stick_x, value_x[i], stick_y, value_y[i]) - shortest); if(values[i] < 0) values[i] = 0; values[i] = values[i] / shortest * maxvalue; } } for(i = 0; i < total_values; i++) { values[i] = Units::quantize10(values[i]); } delete [] value_x; delete [] value_y; return 0; } float BC_Pan::distance(int x1, int x2, int y1, int y2) { return hypot(x2 - x1, y2 - y1); } int BC_Pan::change_channels(int new_channels, int *value_positions) { delete values; delete this->value_positions; delete value_x; delete value_y; values = new float[new_channels]; this->value_positions = new int[new_channels]; value_x = new int[new_channels]; value_y = new int[new_channels]; total_values = new_channels; for(int i = 0; i < new_channels; i++) { this->value_positions[i] = value_positions[i]; } get_channel_positions(value_x, value_y, value_positions, virtual_r, total_values); stick_to_values(); draw(1, 1); return 0; } int BC_Pan::get_channel_positions(int *value_x, int *value_y, int *value_positions, int virtual_r, int total_values) { for(int i = 0; i < total_values; i++) { rdtoxy(value_x[i], value_y[i], value_positions[i], virtual_r); } return 0; } int BC_Pan::get_total_values() { return total_values; } float BC_Pan::get_value(int channel) { return values[channel]; } int BC_Pan::get_stick_x() { return stick_x; } int BC_Pan::get_stick_y() { return stick_y; } float* BC_Pan::get_values() { return values; } int BC_Pan::rdtoxy(int &x, int &y, int a, int virtual_r) { float radians = (float)a / 360 * 2 * M_PI; y = (int)(sin(radians) * virtual_r); x = (int)(cos(radians) * virtual_r); x += virtual_r; y = virtual_r - y; return 0; } void BC_Pan::calculate_stick_position(int total_values, int *value_positions, float *values, float maxvalue, int virtual_r, int &stick_x, int &stick_y) { // If 2 channels have positive values, use weighted average int channel1 = -1; int channel2 = -1; for(int i = 0; i < total_values; i++) { if(values[i] > 0.001) { if(channel1 < 0) channel1 = i; else if(channel2 < 0) channel2 = i; else break; } } if(channel1 >= 0 && channel2 >= 0) { int x1, y1, x2, y2; rdtoxy(x1, y1, value_positions[channel1], virtual_r); rdtoxy(x2, y2, value_positions[channel2], virtual_r); stick_x = (x1 + x2) / 2; stick_y = (y1 + y2) / 2; } else { // use highest value as location of stick float highest_value = 0; int angle = 0; for(int i = 0; i < total_values; i++) { if(values[i] > highest_value) { highest_value = values[i]; angle = value_positions[i]; } } rdtoxy(stick_x, stick_y, angle, virtual_r); } }