vicon placement tweak, bclistbox select fixes, new ctrl-a/s shortcuts
[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,
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 &&
196                 tooltip_text && tooltip_text[0] != 0 &&
197                 duration == top_level->get_resources()->tooltip_delay )
198         {
199                 show_tooltip();
200                 return 1;
201         }
202         return 0;
203 }
204
205 int BC_Pan::cursor_enter_event()
206 {
207         if(is_event_win() && !highlighted)
208         {
209                 highlighted = 1;
210                 draw(1, 1);
211         }
212         return 0;
213 }
214
215 int BC_Pan::cursor_leave_event()
216 {
217         if(highlighted)
218         {
219                 highlighted = 0;
220                 hide_tooltip();
221                 draw(1, 1);
222         }
223         return 0;
224 }
225
226
227
228 int BC_Pan::deactivate()
229 {
230         if(popup) delete popup;
231         popup = 0;
232         active = 0;
233         return 0;
234 }
235
236 int BC_Pan::activate(int popup_x, int popup_y)
237 {
238         int x, y;
239         Window tempwin;
240
241         active = 0;
242         if (popup_x < 0 || popup_y < 0)
243         {
244                 XTranslateCoordinates(top_level->display,
245                         win,
246                         top_level->rootwin,
247                         0,
248                         0,
249                         &x,
250                         &y,
251                         &tempwin);
252
253                 x -= (images[PAN_POPUP]->get_w() - get_w()) / 2;
254                 y -= (images[PAN_POPUP]->get_h() - get_h()) / 2;
255                 if (x < 0) x = 0;
256         }
257         else {
258                 XTranslateCoordinates(top_level->display,
259                         top_level->win, top_level->rootwin,
260                         popup_x, popup_y, &x, &y, &tempwin);
261                 x -= images[PAN_POPUP]->get_w() / 2;
262                 y -= images[PAN_POPUP]->get_h() / 2;
263                 if (x < 0) x = 0;
264         }
265
266         delete popup;
267         popup = new BC_Popup(this, x, y,
268                                 images[PAN_POPUP]->get_w(),
269                                 images[PAN_POPUP]->get_h(),
270                                 0, 0, images[PAN_POPUP]);
271         draw_popup();
272         flush();
273         return 0;
274 }
275
276 int BC_Pan::update(int x, int y)
277 {
278         if(x != stick_x || y != stick_y)
279         {
280                 stick_x = x;
281                 stick_y = y;
282                 stick_to_values();
283                 draw(1, 1);
284         }
285         return 0;
286 }
287
288 void BC_Pan::draw_popup()
289 {
290         popup->draw_background(0, 0, popup->get_w(), popup->get_h());
291
292         int x1, y1;
293         float rotate_angle;
294         float scale = (float)(popup->get_w() -
295                 get_resources()->pan_data[PAN_CHANNEL]->get_w()) /
296                 (virtual_r * 2);
297         set_color(get_resources()->pan_text_color);
298         set_font(SMALLFONT);
299
300         for(int i = 0; i < total_values; i++)
301         {
302                 x1 = (int)(value_x[i] * scale);
303                 y1 = (int)(value_y[i] * scale);
304                 rotate_angle = value_positions[i];
305                 rotate_angle = -rotate_angle;
306                 while(rotate_angle < 0) rotate_angle += 360;
307                 rotater->rotate(temp_channel,
308                         get_resources()->pan_data[PAN_CHANNEL],
309                         rotate_angle,
310                         0);
311                 BC_Pixmap *temp_pixmap = new BC_Pixmap(popup,
312                         temp_channel,
313                         PIXMAP_ALPHA);
314                 popup->draw_pixmap(temp_pixmap, x1, y1);
315                 delete temp_pixmap;
316
317                 char string[BCTEXTLEN];
318                 float value = values[i] + 0.005;
319                 sprintf(string, "%.1f", value);
320                 popup->draw_text(x1, y1 + get_text_height(SMALLFONT), string);
321         }
322
323         x1 = (int)(stick_x * scale);
324         y1 = (int)(stick_y * scale);
325         popup->draw_pixmap(images[PAN_STICK], x1, y1);
326         popup->flash();
327 }
328
329 #define PICON_W 6
330 #define PICON_H 6
331
332 void BC_Pan::draw(int flash, int flush)
333 {
334         draw_top_background(parent_window, 0, 0, w, h);
335
336         draw_pixmap(images[highlighted ? PAN_HI : PAN_UP]);
337         get_channel_positions(value_x,
338                 value_y,
339                 value_positions,
340                 virtual_r,
341                 total_values);
342
343 // draw channels
344         int x1, y1;
345         float scale = (float)(get_w() - PICON_W) / (virtual_r * 2);
346         set_color(RED);
347
348         for(int i = 0; i < total_values; i++)
349         {
350 // printf("BC_Pan::draw 1 %d %d %d %d\n",
351 //      i,
352 //      value_positions[i],
353 //      value_x[i],
354 //      value_y[i]);
355                 x1 = (int)(value_x[i] * scale);
356                 y1 = (int)(value_y[i] * scale);
357 //printf("BC_Pan::draw 2 %d %d\n", x1, y1);
358                 CLAMP(x1, 0, get_w() - PICON_W);
359                 CLAMP(y1, 0, get_h() - PICON_H);
360                 draw_pixmap(images[PAN_CHANNEL_SMALL], x1, y1);
361 //              draw_box(x1, y1, PICON_W, PICON_H);
362         }
363
364 // draw stick
365         set_color(GREEN);
366         x1 = (int)(stick_x * scale);
367         y1 = (int)(stick_y * scale);
368
369 //printf("BC_Pan::draw 2 %d %d\n", x1, y1);
370         CLAMP(x1, 0, get_w() - PICON_W);
371         CLAMP(y1, 0, get_h() - PICON_H);
372
373         draw_pixmap(images[PAN_STICK_SMALL], x1, y1);
374 //      x2 = x1 + PICON_W;
375 //      y2 = y1 + PICON_H;
376 //      draw_line(x1, y1, x2, y2);
377 //      draw_line(x2, y1, x1, y2);
378
379         if(flash) this->flash(0);
380         if(flush) this->flush();
381 }
382
383 int BC_Pan::stick_to_values()
384 {
385         return stick_to_values(values,
386                 total_values,
387                 value_positions,
388                 stick_x,
389                 stick_y,
390                 virtual_r,
391                 maxvalue);
392 }
393
394 int BC_Pan::stick_to_values(float *values,
395                 int total_values,
396                 int *value_positions,
397                 int stick_x,
398                 int stick_y,
399                 int virtual_r,
400                 float maxvalue)
401 {
402 // find shortest distance to a channel
403         float shortest = 2 * virtual_r, test_distance;
404         int i;
405         int *value_x = new int[total_values];
406         int *value_y = new int[total_values];
407
408         get_channel_positions(value_x, value_y, value_positions, virtual_r, total_values);
409         for(i = 0; i < total_values; i++)
410         {
411                 if((test_distance = distance(stick_x,
412                         value_x[i],
413                         stick_y,
414                         value_y[i])) < shortest)
415                         shortest = test_distance;
416         }
417
418 // get values for channels
419         if(shortest == 0)
420         {
421                 for(i = 0; i < total_values; i++)
422                 {
423                         if(distance(stick_x, value_x[i], stick_y, value_y[i]) == shortest)
424                                 values[i] = maxvalue;
425                         else
426                                 values[i] = 0;
427                 }
428         }
429         else
430         {
431                 for(i = 0; i < total_values; i++)
432                 {
433                         values[i] = shortest;
434                         values[i] -= (float)(distance(stick_x,
435                                 value_x[i],
436                                 stick_y,
437                                 value_y[i]) - shortest);
438                         if(values[i] < 0) values[i] = 0;
439                         values[i] = values[i] / shortest * maxvalue;
440                 }
441         }
442
443         for(i = 0; i < total_values; i++)
444         {
445                 values[i] = Units::quantize10(values[i]);
446         }
447
448         delete [] value_x;
449         delete [] value_y;
450         return 0;
451 }
452
453
454 float BC_Pan::distance(int x1, int x2, int y1, int y2)
455 {
456         return hypot(x2 - x1, y2 - y1);
457 }
458
459 int BC_Pan::change_channels(int new_channels, int *value_positions)
460 {
461         delete values;
462         delete this->value_positions;
463         delete value_x;
464         delete value_y;
465
466         values = new float[new_channels];
467         this->value_positions = new int[new_channels];
468         value_x = new int[new_channels];
469         value_y = new int[new_channels];
470         total_values = new_channels;
471         for(int i = 0; i < new_channels; i++)
472         {
473                 this->value_positions[i] = value_positions[i];
474         }
475         get_channel_positions(value_x,
476                 value_y,
477                 value_positions,
478                 virtual_r,
479                 total_values);
480         stick_to_values();
481         draw(1, 1);
482         return 0;
483 }
484
485 int BC_Pan::get_channel_positions(int *value_x,
486         int *value_y,
487         int *value_positions,
488         int virtual_r,
489         int total_values)
490 {
491         for(int i = 0; i < total_values; i++)
492         {
493                 rdtoxy(value_x[i], value_y[i], value_positions[i], virtual_r);
494         }
495         return 0;
496 }
497
498 int BC_Pan::get_total_values()
499 {
500         return total_values;
501 }
502
503 float BC_Pan::get_value(int channel)
504 {
505         return values[channel];
506 }
507
508 int BC_Pan::get_stick_x()
509 {
510         return stick_x;
511 }
512
513 int BC_Pan::get_stick_y()
514 {
515         return stick_y;
516 }
517
518 float* BC_Pan::get_values()
519 {
520         return values;
521 }
522
523 int BC_Pan::rdtoxy(int &x, int &y, int a, int virtual_r)
524 {
525         float radians = (float)a / 360 * 2 * M_PI;
526
527         y = (int)(sin(radians) * virtual_r);
528         x = (int)(cos(radians) * virtual_r);
529         x += virtual_r;
530         y = virtual_r - y;
531         return 0;
532 }
533
534 void BC_Pan::calculate_stick_position(int total_values,
535         int *value_positions,
536         float *values,
537         float maxvalue,
538         int virtual_r,
539         int &stick_x,
540         int &stick_y)
541 {
542 // If 2 channels have positive values, use weighted average
543         int channel1 = -1;
544         int channel2 = -1;
545
546         for(int i = 0; i < total_values; i++)
547         {
548                 if(values[i] > 0.001)
549                 {
550                         if(channel1 < 0) channel1 = i;
551                         else
552                         if(channel2 < 0) channel2 = i;
553                         else
554                                 break;
555                 }
556         }
557
558         if(channel1 >= 0 && channel2 >= 0)
559         {
560                 int x1, y1, x2, y2;
561                 rdtoxy(x1, y1, value_positions[channel1], virtual_r);
562                 rdtoxy(x2, y2, value_positions[channel2], virtual_r);
563                 stick_x = (x1 + x2) / 2;
564                 stick_y = (y1 + y2) / 2;
565         }
566         else
567         {
568
569 // use highest value as location of stick
570                 float highest_value = 0;
571                 int angle = 0;
572
573                 for(int i = 0; i < total_values; i++)
574                 {
575                         if(values[i] > highest_value)
576                         {
577                                 highest_value = values[i];
578                                 angle = value_positions[i];
579                         }
580                 }
581                 rdtoxy(stick_x, stick_y, angle, virtual_r);
582         }
583
584 }
585