r701: Jean-Luc Coulon has gettextized [tm] 2 more strings in the time average effect.
[cinelerra_cv.git] / guicast / bcmeter.C
blobc6e65e13e2f105afb122bef19ad1493960dd6891
1 #include "bcbutton.h"
2 #include "bcmeter.h"
3 #include "bcpixmap.h"
4 #include "bcresources.h"
5 #include "bcwindow.h"
6 #include "colors.h"
7 #include "fonts.h"
8 #include "vframe.h"
9 #include <string.h>
11 // Which source image to replicate
12 #define METER_NORMAL 0
13 #define METER_GREEN 1
14 #define METER_RED 2
15 #define METER_YELLOW 3
16 #define METER_WHITE 4
17 #define METER_OVER 5
19 // Region of source image to replicate
20 #define METER_LEFT 0
21 #define METER_MID 1
22 #define METER_RIGHT 3
25 BC_Meter::BC_Meter(int x, 
26         int y, 
27         int orientation, 
28         int pixels, 
29         int min, 
30         int max,
31         int mode, 
32         int use_titles,
33         long over_delay,
34         long peak_delay)
35  : BC_SubWindow(x, y, -1, -1)
37         this->use_titles = use_titles;
38         this->over_delay = over_delay;
39         this->peak_delay = peak_delay;
40         this->min = min;
41         this->max = max;
42         this->mode = mode;
43         this->orientation = orientation;
44         this->pixels = pixels;
45         for(int i = 0; i < TOTAL_METER_IMAGES; i++) images[i] = 0;
46         db_titles.set_array_delete();
49 BC_Meter::~BC_Meter()
51         db_titles.remove_all_objects();
52         title_pixels.remove_all();
53         tick_pixels.remove_all();
54         for(int i = 0; i < TOTAL_METER_IMAGES; i++) delete images[i];
57 int BC_Meter::get_title_w()
59         return get_resources()->meter_title_w;
62 int BC_Meter::get_meter_w()
64         return get_resources()->ymeter_images[0]->get_w() + 2;
68 int BC_Meter::set_delays(int over_delay, int peak_delay)
70         this->over_delay = over_delay;
71         this->peak_delay = peak_delay;
72         return 0;
75 int BC_Meter::initialize()
77         peak_timer = 0;
78         level_pixel = peak_pixel = 0;
79         over_timer = 0;
80         over_count = 0;
81         peak = level = -100;
83         if(orientation == METER_VERT)
84         {
85                 set_images(get_resources()->ymeter_images);
86                 h = pixels;
87                 w = images[0]->get_w();
88                 if(use_titles) w += get_title_w();
89         }
90         else
91         {
92                 set_images(get_resources()->xmeter_images);
93                 h = images[0]->get_h();
94                 w = pixels;
95                 if(use_titles) h += get_title_w();
96         }
98 // calibrate the db titles
99         get_divisions();
101         BC_SubWindow::initialize();
102         draw_titles();
103         draw_face();
104         return 0;
107 void BC_Meter::set_images(VFrame **data)
109         for(int i = 0; i < TOTAL_METER_IMAGES; i++) delete images[i];
110         for(int i = 0; i < TOTAL_METER_IMAGES; i++) 
111                 images[i] = new BC_Pixmap(parent_window, data[i], PIXMAP_ALPHA);
114 int BC_Meter::reposition_window(int x, int y, int pixels)
116         if(pixels < 0) pixels = this->pixels;
117         this->pixels = pixels;
118         if(orientation == METER_VERT)
119                 BC_SubWindow::reposition_window(x, y, get_w(), pixels);
120         else
121                 BC_SubWindow::reposition_window(x, y, pixels, get_h());
123 //printf("BC_Meter::reposition_window 1 %d %d %d %d\n", x, y, w, h);
124         get_divisions();
126 //set_color(WHITE);
127 //draw_box(0, 0, w, h);
128 //flash();      
129 //return 0;
130         draw_titles();
131         draw_face();
132         return 0;
135 int BC_Meter::reset()
137         level = min;
138         peak = min;
139         level_pixel = peak_pixel = 0;
140         peak_timer = 0;
141         over_timer = 0;
142         over_count = 0;
143         draw_face();
144         return 0;
147 int BC_Meter::button_press_event()
149         if(cursor_inside() && is_event_win())
150         {
151                 reset_over();
152                 return 1;
153         }
154         return 0;
158 int BC_Meter::reset_over()
160         over_timer = 0;
161         return 0;
164 int BC_Meter::change_format(int mode, int min, int max)
166         this->mode = mode;
167         this->min = min;
168         this->max = max;
169         reposition_window(get_x(), get_y(), pixels);
170         return 0;
173 int BC_Meter::level_to_pixel(float level)
175         int result;
176         if(mode == METER_DB)
177         {
178                 result = (int)(pixels * 
179                         (level - min) / 
180                         (max - min));
181                 if(level <= min) result = 0;
182         }
183         else
184         {
185 // Not implemented anymore
186                 result = 0;
187         }
188         
189         return result;
193 void BC_Meter::get_divisions()
195         int i;
196         int j, j_step;
197         int division, division_step;
198         char string[BCTEXTLEN];
199         char *new_string;
202         db_titles.remove_all_objects();
203         title_pixels.remove_all();
204         tick_pixels.remove_all();
206         low_division = 0;
207         medium_division = 0;
208         high_division = pixels;
210         int current_pixel;
211 // Create tick marks and titles in one pass
212         for(int current = min; current <= max; current++)
213         {
214                 if(orientation == METER_VERT)
215                 {
216 // Create tick mark
217                         current_pixel = (pixels - METER_MARGIN * 2 - 2) * 
218                                 (current - min) /
219                                 (max - min) + 2;
220                         tick_pixels.append(current_pixel);
222 // Create titles in selected positions
223                         if(current == min || 
224                                 current == max ||
225                                 current == 0 ||
226                                 (current - min > 4 && max - current > 4 && !(current % 5)))
227                         {
228                                 int title_pixel = (pixels - 
229                                         METER_MARGIN * 2) * 
230                                         (current - min) /
231                                         (max - min);
232                                 sprintf(string, "%d", labs(current));
233                                 new_string = new char[strlen(string) + 1];
234                                 strcpy(new_string, string);
235                                 db_titles.append(new_string);
236                                 title_pixels.append(title_pixel);
237                         }
238                 }
239                 else
240                 {
241                         current_pixel = (pixels - METER_MARGIN * 2) *
242                                 (current - min) /
243                                 (max - min);
244                         tick_pixels.append(current_pixel);
245 // Titles not supported for horizontal
246                 }
248 // Create color divisions
249                 if(current == -20)
250                 {
251                         low_division = current_pixel;
252                 }
253                 else
254                 if(current == -5)
255                 {
256                         medium_division = current_pixel;
257                 }
258                 else
259                 if(current == 0)
260                 {
261                         high_division = current_pixel;
262                 }
263         }
264 // if(orientation == METER_VERT)
265 // printf("BC_Meter::get_divisions %d %d %d %d\n",
266 // low_division, medium_division, high_division, pixels);
269 void BC_Meter::draw_titles()
271         if(!use_titles) return;
273         set_font(get_resources()->meter_font);
275         if(orientation == METER_HORIZ)
276         {
277                 draw_top_background(parent_window, 0, 0, get_w(), get_title_w());
279                 for(int i = 0; i < db_titles.total; i++)
280                 {
281                         draw_text(0, title_pixels.values[i], db_titles.values[i]);
282                 }
284                 flash(0, 0, get_w(), get_title_w());
285         }
286         else
287         if(orientation == METER_VERT)
288         {
289                 draw_top_background(parent_window, 0, 0, get_title_w(), get_h());
291 // Titles
292                 for(int i = 0; i < db_titles.total; i++)
293                 {
294                         int title_y = pixels - 
295                                 title_pixels.values[i];
296                         if(i == 0) 
297                                 title_y -= get_text_descent(SMALLFONT_3D);
298                         else
299                         if(i == db_titles.total - 1)
300                                 title_y += get_text_ascent(SMALLFONT_3D);
301                         else
302                                 title_y += get_text_ascent(SMALLFONT_3D) / 2;
304                         set_color(get_resources()->meter_font_color);
305                         draw_text(0, 
306                                 title_y,
307                                 db_titles.values[i]);
308                 }
310                 for(int i = 0; i < tick_pixels.total; i++)
311                 {
312 // Tick marks
313                         int tick_y = pixels - tick_pixels.values[i] - METER_MARGIN;
314                         set_color(get_resources()->meter_font_color);
315                         draw_line(get_title_w() - 10 - 1, tick_y, get_title_w() - 1, tick_y);
316                         if(get_resources()->meter_3d)
317                         {
318                                 set_color(BLACK);
319                                 draw_line(get_title_w() - 10, tick_y + 1, get_title_w(), tick_y + 1);
320                         }
321                 }
323                 flash(0, 0, get_title_w(), get_h());
324         }
327 int BC_Meter::region_pixel(int region)
329         VFrame **reference_images = get_resources()->xmeter_images;
330         int result;
332         if(region == METER_RIGHT) 
333                 result = region * reference_images[0]->get_w() / 4;
334         else
335                 result = region * reference_images[0]->get_w() / 4;
337         return result;
340 int BC_Meter::region_pixels(int region)
342         int x1;
343         int x2;
344         int result;
345         VFrame **reference_images = get_resources()->xmeter_images;
346         
347         x1 = region * reference_images[0]->get_w() / 4;
348         x2 = (region + 1) * reference_images[0]->get_w() / 4;
349         if(region == METER_MID) 
350                 result = (x2 - x1) * 2;
351         else 
352                 result = x2 - x1;
353         return result;
356 void BC_Meter::draw_face()
358         VFrame **reference_images = get_resources()->xmeter_images;
359         int level_pixel = level_to_pixel(level);
360         int peak_pixel2 = level_to_pixel(peak);
361         int peak_pixel1 = peak_pixel2 - 2;
362         int left_pixel = region_pixel(METER_MID);
363         int right_pixel = pixels - region_pixels(METER_RIGHT);
364         int pixel = 0;
365         int image_number = 0, region = 0;
366         int in_span, in_start;
367         int x = use_titles ? get_title_w() : 0;
368         int w = use_titles ? this->w - get_title_w() : this->w;
370         draw_top_background(parent_window, x, 0, w, h);
371 //printf("BC_Meter::draw_face %d %d\n", w, h);
373         while(pixel < pixels)
374         {
375 // Select image to draw
376                 if(pixel < level_pixel ||
377                         (pixel >= peak_pixel1 && pixel < peak_pixel2))
378                 {
379                         if(pixel < low_division)
380                                 image_number = METER_GREEN;
381                         else
382                         if(pixel < medium_division)
383                                 image_number = METER_YELLOW;
384                         else
385                         if(pixel < high_division)
386                                 image_number = METER_RED;
387                         else
388                                 image_number = METER_WHITE;
389                 }
390                 else
391                 {
392                         image_number = METER_NORMAL;
393                 }
395 // Select region of image to duplicate
396                 if(pixel < left_pixel)
397                 {
398                         region = METER_LEFT;
399                         in_start = pixel + region_pixel(region);
400                         in_span = region_pixels(region) - (in_start - region_pixel(region));
401                 }
402                 else
403                 if(pixel < right_pixel)
404                 {
405                         region = METER_MID;
406                         in_start = region_pixel(region);
407                         in_span = region_pixels(region);
408                 }
409                 else
410                 {
411                         region = METER_RIGHT;
412                         in_start = (pixel - right_pixel) + region_pixel(region);
413                         in_span = region_pixels(region) - (in_start - region_pixel(region));;
414                 }
416 //printf("BC_Meter::draw_face region %d pixel %d pixels %d in_start %d in_span %d\n", region, pixel, pixels, in_start, in_span);
417                 if(in_span > 0)
418                 {
419 // Clip length to peaks
420                         if(pixel < level_pixel && pixel + in_span > level_pixel)
421                                 in_span = level_pixel - pixel;
422                         else
423                         if(pixel < peak_pixel1 && pixel + in_span > peak_pixel1)
424                                 in_span = peak_pixel1 - pixel;
425                         else
426                         if(pixel < peak_pixel2 && pixel + in_span > peak_pixel2) 
427                                 in_span = peak_pixel2 - pixel;
429 // Clip length to color changes
430                         if(image_number == METER_GREEN && pixel + in_span > low_division)
431                                 in_span = low_division - pixel;
432                         else
433                         if(image_number == METER_YELLOW && pixel + in_span > medium_division)
434                                 in_span = medium_division - pixel;
435                         else
436                         if(image_number == METER_RED && pixel + in_span > high_division)
437                                 in_span = high_division - pixel;
439 // Clip length to regions
440                         if(pixel < left_pixel && pixel + in_span > left_pixel)
441                                 in_span = left_pixel - pixel;
442                         else
443                         if(pixel < right_pixel && pixel + in_span > right_pixel)
444                                 in_span = right_pixel - pixel;
446 //printf("BC_Meter::draw_face image_number %d pixel %d pixels %d in_start %d in_span %d\n", image_number, pixel, pixels, in_start, in_span);
447 //printf("BC_Meter::draw_face %d %d %d %d\n", orientation, region, images[image_number]->get_h() - in_start - in_span);
448                         if(orientation == METER_HORIZ)
449                                 draw_pixmap(images[image_number], 
450                                         pixel, 
451                                         x, 
452                                         in_span + 1, 
453                                         get_h(), 
454                                         in_start, 
455                                         0);
456                         else
457                                 draw_pixmap(images[image_number],
458                                         x,
459                                         get_h() - pixel - in_span,
460                                         get_w(),
461                                         in_span + 1,
462                                         0,
463                                         images[image_number]->get_h() - in_start - in_span);
465                         pixel += in_span;
466                 }
467                 else
468                 {
469 // Sanity check
470                         break;
471                 }
472         }
474         if(over_timer)
475         {
476                 if(orientation == METER_HORIZ)
477                         draw_pixmap(images[METER_OVER], 
478                                 10, 
479                                 2);
480                 else
481                         draw_pixmap(images[METER_OVER],
482                                 x + 2,
483                                 get_h() - 100);
485                 over_timer--;
486         }
488         if(orientation == METER_HORIZ)
489                 flash(0, 0, pixels, get_h());
490         else
491                 flash(x, 0, w, pixels);
492         flush();
495 int BC_Meter::update(float new_value, int over)
497         peak_timer++;
499         if(mode == METER_DB)
500         {
501                 if(new_value == 0) 
502                         level = min;
503                 else
504                         level = db.todb(new_value);        // db value
505         }
507         if(level > peak || peak_timer > peak_delay)
508         {
509                 peak = level;
510                 peak_timer = 0;
511         }
513 // if(orientation == METER_HORIZ)
514 // printf("BC_Meter::update %f\n", level);
515         if(over) over_timer = over_delay;       
516 // only draw if window is visible
518         draw_face();
519         return 0;