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