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