version update
[goodguy/cinelerra.git] / cinelerra-5.1 / guicast / bcpan.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 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 "bcpan.h"
23 #include "bcpixmap.h"
24 #include "bcpopup.h"
25 #include "bcresources.h"
26 #include "clip.h"
27 #include "bccolors.h"
28 #include "fonts.h"
29 #include "rotateframe.h"
30 #include "units.h"
31 #include "vframe.h"
32
33 #include <math.h>
34 #include <string.h>
35
36 BC_Pan::BC_Pan(int x, int y, int virtual_r,
37                 float maxvalue, int total_values, int *value_positions,
38                 int stick_x, int stick_y, float *values)
39  : BC_SubWindow(x, y, -1, -1, -1)
40 {
41         this->virtual_r = virtual_r;
42         this->maxvalue = maxvalue;
43         this->total_values = total_values;
44         this->values = new float[total_values];
45         memcpy(this->values, values, sizeof(float) * total_values);
46         this->value_positions = new int[total_values];
47         memcpy(this->value_positions, value_positions, sizeof(int) * total_values);
48         this->value_x = new int[total_values];
49         this->value_y = new int[total_values];
50         this->stick_x = stick_x;
51         this->stick_y = stick_y;
52         get_channel_positions(value_x,
53                 value_y,
54                 value_positions,
55                 virtual_r,
56                 total_values);
57         if(stick_x < 0 || stick_y < 0)
58                 calculate_stick_position(total_values,
59                         value_positions,
60                         values,
61                         maxvalue,
62                         virtual_r,
63                         this->stick_x,
64                         this->stick_y);
65         highlighted = 0;
66         active = 0;
67         temp_channel = 0;
68         rotater = 0;
69         popup = 0;
70         memset(images, 0, sizeof(BC_Pixmap*) * PAN_IMAGES);
71 }
72
73 BC_Pan::~BC_Pan()
74 {
75         delete [] values;
76         delete [] value_positions;
77         delete [] value_x;
78         delete [] value_y;
79         delete popup;
80         delete temp_channel;
81         delete rotater;
82         for( int i=0; i<PAN_IMAGES; ++i )
83                 delete images[i];
84 //printf("BC_Pan::~BC_Pan 2\n");
85 }
86
87 int BC_Pan::initialize()
88 {
89         set_images(get_resources()->pan_data);
90
91         BC_SubWindow::initialize();
92         temp_channel = new VFrame;
93         temp_channel->set_use_shm(0);
94         temp_channel->reallocate(0, -1, 0, 0, 0,
95                 get_resources()->pan_data[PAN_CHANNEL]->get_w(),
96                 get_resources()->pan_data[PAN_CHANNEL]->get_h(),
97                 get_resources()->pan_data[PAN_CHANNEL]->get_color_model(),
98                 -1);
99         draw(1, 0);
100         return 0;
101 }
102
103 void BC_Pan::set_images(VFrame **data)
104 {
105         for(int i = 0; i < PAN_IMAGES; i++)
106         {
107                 if(images[i]) delete images[i];
108                 images[i] = new BC_Pixmap(parent_window, data[i], PIXMAP_ALPHA);
109         }
110         w = images[PAN_UP]->get_w();
111         h = images[PAN_UP]->get_h();
112 }
113
114 int BC_Pan::button_press_event()
115 {
116         // there are two modes of operation...
117         if (popup)
118         {       if (popup->is_event_win() && get_button_down() && get_buttonpress() == 1)
119                 {
120                         active = 1;
121                         x_origin = popup->get_cursor_x();
122                         y_origin = popup->get_cursor_y();
123                         stick_x_origin = stick_x;
124                         stick_y_origin = stick_y;
125                         return 1;
126                 } else
127                 {
128                         deactivate();
129                         return 0;
130                 }
131         }
132         if(is_event_win() && get_button_down() && get_buttonpress() == 1)
133         {
134                 hide_tooltip();
135                 activate();
136                 active = 1;
137                 x_origin = get_cursor_x();
138                 y_origin = get_cursor_y();
139                 stick_x_origin = stick_x;
140                 stick_y_origin = stick_y;
141                 draw_popup();
142                 return 1;
143         }
144         return 0;
145 }
146
147 int BC_Pan::cursor_motion_event()
148 {
149         if(popup && get_button_down() && get_buttonpress() == 1)
150         {
151                 stick_x = stick_x_origin + get_cursor_x() - x_origin;
152                 stick_y = stick_y_origin + get_cursor_y() - y_origin;
153                 CLAMP(stick_x, 0, virtual_r * 2);
154                 CLAMP(stick_y, 0, virtual_r * 2);
155                 stick_to_values();
156                 draw_popup();
157                 handle_event();
158                 return 1;
159         }
160         return 0;
161 }
162
163 int BC_Pan::button_release_event()
164 {
165         if(popup)
166         {
167                 hide_tooltip();
168                 deactivate();
169                 draw(1, 1);
170                 return 1;
171         }
172         return 0;
173 }
174
175 int BC_Pan::repeat_event(int64_t duration)
176 {
177         if( highlighted && !active &&
178                 tooltip_text && tooltip_text[0] != 0 &&
179                 duration == top_level->get_resources()->tooltip_delay )
180         {
181                 show_tooltip();
182                 return 1;
183         }
184         return 0;
185 }
186
187 int BC_Pan::cursor_enter_event()
188 {
189         if(is_event_win() && !highlighted)
190         {
191                 highlighted = 1;
192                 draw(1, 1);
193         }
194         return 0;
195 }
196
197 int BC_Pan::cursor_leave_event()
198 {
199         if(highlighted)
200         {
201                 highlighted = 0;
202                 hide_tooltip();
203                 draw(1, 1);
204         }
205         return 0;
206 }
207
208
209
210 int BC_Pan::deactivate()
211 {
212         delete popup;    popup = 0;
213         delete rotater;  rotater = 0;
214         active = 0;
215         return 0;
216 }
217
218 int BC_Pan::activate(int popup_x, int popup_y)
219 {
220         int x, y;
221         Window tempwin;
222
223         active = 0;
224         if (popup_x < 0 || popup_y < 0)
225         {
226                 XTranslateCoordinates(top_level->display, win,
227                         top_level->rootwin, 0, 0, &x, &y, &tempwin);
228
229                 x -= (images[PAN_POPUP]->get_w() - get_w()) / 2;
230                 y -= (images[PAN_POPUP]->get_h() - get_h()) / 2;
231                 if (x < 0) x = 0;
232         }
233         else {
234                 XTranslateCoordinates(top_level->display,
235                         top_level->win, top_level->rootwin,
236                         popup_x, popup_y, &x, &y, &tempwin);
237                 x -= images[PAN_POPUP]->get_w() / 2;
238                 y -= images[PAN_POPUP]->get_h() / 2;
239                 if (x < 0) x = 0;
240         }
241
242         rotater = new RotateFrame(1,
243                 get_resources()->pan_data[PAN_CHANNEL]->get_w(),
244                 get_resources()->pan_data[PAN_CHANNEL]->get_h());
245
246         delete popup;
247         popup = new BC_Popup(this, x, y,
248                                 images[PAN_POPUP]->get_w(),
249                                 images[PAN_POPUP]->get_h(),
250                                 0, 0, images[PAN_POPUP]);
251         draw_popup();
252         flush();
253         return 0;
254 }
255
256 int BC_Pan::update(int x, int y)
257 {
258         if(x != stick_x || y != stick_y)
259         {
260                 stick_x = x;
261                 stick_y = y;
262                 stick_to_values();
263                 draw(1, 1);
264         }
265         return 0;
266 }
267
268 void BC_Pan::draw_popup()
269 {
270         popup->draw_background(0, 0, popup->get_w(), popup->get_h());
271
272         int x1, y1;
273         float rotate_angle;
274         float scale = (float)(popup->get_w() -
275                 get_resources()->pan_data[PAN_CHANNEL]->get_w()) /
276                 (virtual_r * 2);
277         set_color(get_resources()->pan_text_color);
278         set_font(SMALLFONT);
279
280         for(int i = 0; i < total_values; i++)
281         {
282                 x1 = (int)(value_x[i] * scale);
283                 y1 = (int)(value_y[i] * scale);
284                 rotate_angle = value_positions[i];
285                 rotate_angle = -rotate_angle;
286                 while(rotate_angle < 0) rotate_angle += 360;
287                 rotater->rotate(temp_channel,
288                         get_resources()->pan_data[PAN_CHANNEL],
289                         rotate_angle,
290                         0);
291                 BC_Pixmap *temp_pixmap = new BC_Pixmap(popup,
292                         temp_channel,
293                         PIXMAP_ALPHA);
294                 popup->draw_pixmap(temp_pixmap, x1, y1);
295                 delete temp_pixmap;
296
297                 char string[BCTEXTLEN];
298                 float value = values[i] + 0.005;
299                 sprintf(string, "%.1f", value);
300                 popup->draw_text(x1, y1 + get_text_height(SMALLFONT), string);
301         }
302
303         x1 = (int)(stick_x * scale);
304         y1 = (int)(stick_y * scale);
305         popup->draw_pixmap(images[PAN_STICK], x1, y1);
306         popup->flash();
307 }
308
309 #define PICON_W xS(6)
310 #define PICON_H yS(6)
311
312 void BC_Pan::draw(int flash, int flush)
313 {
314         draw_top_background(parent_window, 0, 0, w, h);
315
316         draw_pixmap(images[highlighted ? PAN_HI : PAN_UP]);
317         get_channel_positions(value_x,
318                 value_y,
319                 value_positions,
320                 virtual_r,
321                 total_values);
322
323 // draw channels
324         int x1, y1;
325         float scale = (float)(get_w() - PICON_W) / (virtual_r * 2);
326         set_color(RED);
327
328         for(int i = 0; i < total_values; i++)
329         {
330 // printf("BC_Pan::draw 1 %d %d %d %d\n",
331 //      i,
332 //      value_positions[i],
333 //      value_x[i],
334 //      value_y[i]);
335                 x1 = (int)(value_x[i] * scale);
336                 y1 = (int)(value_y[i] * scale);
337 //printf("BC_Pan::draw 2 %d %d\n", x1, y1);
338                 CLAMP(x1, 0, get_w() - PICON_W);
339                 CLAMP(y1, 0, get_h() - PICON_H);
340                 draw_pixmap(images[PAN_CHANNEL_SMALL], x1, y1);
341 //              draw_box(x1, y1, PICON_W, PICON_H);
342         }
343
344 // draw stick
345         set_color(GREEN);
346         x1 = (int)(stick_x * scale);
347         y1 = (int)(stick_y * scale);
348
349 //printf("BC_Pan::draw 2 %d %d\n", x1, y1);
350         CLAMP(x1, 0, get_w() - PICON_W);
351         CLAMP(y1, 0, get_h() - PICON_H);
352
353         draw_pixmap(images[PAN_STICK_SMALL], x1, y1);
354 //      x2 = x1 + PICON_W;
355 //      y2 = y1 + PICON_H;
356 //      draw_line(x1, y1, x2, y2);
357 //      draw_line(x2, y1, x1, y2);
358
359         if(flash) this->flash(0);
360         if(flush) this->flush();
361 }
362
363 int BC_Pan::stick_to_values()
364 {
365         return stick_to_values(values,
366                 total_values,
367                 value_positions,
368                 stick_x,
369                 stick_y,
370                 virtual_r,
371                 maxvalue);
372 }
373
374 int BC_Pan::stick_to_values(float *values,
375                 int total_values,
376                 int *value_positions,
377                 int stick_x,
378                 int stick_y,
379                 int virtual_r,
380                 float maxvalue)
381 {
382 // find shortest distance to a channel
383         float shortest = 2 * virtual_r, test_distance;
384         int i;
385         int *value_x = new int[total_values];
386         int *value_y = new int[total_values];
387
388         get_channel_positions(value_x, value_y, value_positions, virtual_r, total_values);
389         for(i = 0; i < total_values; i++)
390         {
391                 if((test_distance = distance(stick_x,
392                         value_x[i],
393                         stick_y,
394                         value_y[i])) < shortest)
395                         shortest = test_distance;
396         }
397
398 // get values for channels
399         if(shortest == 0)
400         {
401                 for(i = 0; i < total_values; i++)
402                 {
403                         if(distance(stick_x, value_x[i], stick_y, value_y[i]) == shortest)
404                                 values[i] = maxvalue;
405                         else
406                                 values[i] = 0;
407                 }
408         }
409         else
410         {
411                 for(i = 0; i < total_values; i++)
412                 {
413                         values[i] = shortest;
414                         values[i] -= (float)(distance(stick_x,
415                                 value_x[i],
416                                 stick_y,
417                                 value_y[i]) - shortest);
418                         if(values[i] < 0) values[i] = 0;
419                         values[i] = values[i] / shortest * maxvalue;
420                 }
421         }
422
423         for(i = 0; i < total_values; i++)
424         {
425                 values[i] = Units::quantize10(values[i]);
426         }
427
428         delete [] value_x;
429         delete [] value_y;
430         return 0;
431 }
432
433
434 float BC_Pan::distance(int x1, int x2, int y1, int y2)
435 {
436         return hypot(x2 - x1, y2 - y1);
437 }
438
439 int BC_Pan::change_channels(int new_channels, int *value_positions)
440 {
441         delete values;
442         delete this->value_positions;
443         delete value_x;
444         delete value_y;
445
446         values = new float[new_channels];
447         this->value_positions = new int[new_channels];
448         value_x = new int[new_channels];
449         value_y = new int[new_channels];
450         total_values = new_channels;
451         for(int i = 0; i < new_channels; i++)
452         {
453                 this->value_positions[i] = value_positions[i];
454         }
455         get_channel_positions(value_x,
456                 value_y,
457                 value_positions,
458                 virtual_r,
459                 total_values);
460         stick_to_values();
461         draw(1, 1);
462         return 0;
463 }
464
465 int BC_Pan::get_channel_positions(int *value_x,
466         int *value_y,
467         int *value_positions,
468         int virtual_r,
469         int total_values)
470 {
471         for(int i = 0; i < total_values; i++)
472         {
473                 rdtoxy(value_x[i], value_y[i], value_positions[i], virtual_r);
474         }
475         return 0;
476 }
477
478 int BC_Pan::get_total_values()
479 {
480         return total_values;
481 }
482
483 float BC_Pan::get_value(int channel)
484 {
485         return values[channel];
486 }
487
488 int BC_Pan::get_stick_x()
489 {
490         return stick_x;
491 }
492
493 int BC_Pan::get_stick_y()
494 {
495         return stick_y;
496 }
497
498 float* BC_Pan::get_values()
499 {
500         return values;
501 }
502
503 int BC_Pan::rdtoxy(int &x, int &y, int a, int virtual_r)
504 {
505         float radians = (float)a / 360 * 2 * M_PI;
506
507         y = (int)(sin(radians) * virtual_r);
508         x = (int)(cos(radians) * virtual_r);
509         x += virtual_r;
510         y = virtual_r - y;
511         return 0;
512 }
513
514 void BC_Pan::calculate_stick_position(int total_values,
515         int *value_positions,
516         float *values,
517         float maxvalue,
518         int virtual_r,
519         int &stick_x,
520         int &stick_y)
521 {
522 // If 2 channels have positive values, use weighted average
523         int channel1 = -1;
524         int channel2 = -1;
525
526         for(int i = 0; i < total_values; i++)
527         {
528                 if(values[i] > 0.001)
529                 {
530                         if(channel1 < 0) channel1 = i;
531                         else
532                         if(channel2 < 0) channel2 = i;
533                         else
534                                 break;
535                 }
536         }
537
538         if(channel1 >= 0 && channel2 >= 0)
539         {
540                 int x1, y1, x2, y2;
541                 rdtoxy(x1, y1, value_positions[channel1], virtual_r);
542                 rdtoxy(x2, y2, value_positions[channel2], virtual_r);
543                 stick_x = (x1 + x2) / 2;
544                 stick_y = (y1 + y2) / 2;
545         }
546         else
547         {
548
549 // use highest value as location of stick
550                 float highest_value = 0;
551                 int angle = 0;
552
553                 for(int i = 0; i < total_values; i++)
554                 {
555                         if(values[i] > highest_value)
556                         {
557                                 highest_value = values[i];
558                                 angle = value_positions[i];
559                         }
560                 }
561                 rdtoxy(stick_x, stick_y, angle, virtual_r);
562         }
563
564 }
565