r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / guicast / bcmeter.C
blob2aa85fa2152c0b3485f35ab6b42309fa00aa6b4d
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 #define METER_NORMAL 0
12 #define METER_GREEN 1
13 #define METER_RED 2
14 #define METER_YELLOW 3
15 #define METER_OVER 4
17 #define METER_LEFT 0
18 #define METER_MID 1
19 #define METER_RIGHT 3
22 BC_Meter::BC_Meter(int x, 
23         int y, 
24         int orientation, 
25         int pixels, 
26         float min, 
27         int mode, 
28         int use_titles,
29         long over_delay,
30         long peak_delay)
31  : BC_SubWindow(x, y, -1, -1)
33         this->use_titles = use_titles;
34         this->over_delay = over_delay;
35         this->peak_delay = peak_delay;
36         this->min = min;
37         this->mode = mode;
38         this->orientation = orientation;
39         this->pixels = pixels;
40         for(int i = 0; i < TOTAL_METER_IMAGES; i++) images[i] = 0;
41         title_pixel = 0;
42         db_titles = 0;
43         meter_titles = 0;
46 BC_Meter::~BC_Meter()
48         if(db_titles)
49         {
50                 for(int i = 0; i < meter_titles; i++) delete [] db_titles[i];
51                 delete [] db_titles;
52         }
53         if(title_pixel) delete [] title_pixel;
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, float min)
166         this->mode = mode;
167         this->min = min;
168         reposition_window(get_x(), get_y(), pixels);
169         return 0;
172 int BC_Meter::level_to_pixel(float level)
174         int result;
175         if(mode == METER_DB)
176         {
177                 result = pixels - 4 - (int)((level / min) * (pixels - 4));
178                 if(level == 0) result = pixels;
179         }
180         else
181         {
182                 result = (int)(level * (pixels - 4));
183         }
184         
185         return result;
189 void BC_Meter::get_divisions()
191         int i;
192         float j, j_step;
193         float division, division_step;
194         char string[1024];
196         if(db_titles)
197         {
198                 for(int i = 0; i < meter_titles; i++) delete [] db_titles[i];
199                 delete [] db_titles;
200         }
201         if(title_pixel) delete [] title_pixel;
203         meter_titles = labs((int)(min / 5)) + 1;
204         title_pixel = new int[meter_titles];
206         if(use_titles)
207         {
208                 db_titles = new char*[meter_titles];
209                 for(i = 0; i < meter_titles; i++) db_titles[i] = 0;
210         }
212         division = METER_MARGIN;
213         division_step = (float)(pixels - METER_MARGIN * 3) / (meter_titles - 1);
214         j = 0;     // number for title
215         j_step = min / (meter_titles - 1);
217         for(i = 0; i < meter_titles; i++)
218         {
220                 if(use_titles)
221                 {
222                         sprintf(string, "%.0f", fabs(-j));
223                         db_titles[i] = new char[strlen(string) + 1];
224                         strcpy(db_titles[i], string);
225                 }
227                 title_pixel[i] = (int)(division); 
229                 division += division_step;
230                 j += j_step;
231         }
233         medium_division = pixels - title_pixel[(meter_titles-1)*1/6];
234         low_division = pixels - title_pixel[(meter_titles-1)*2/5];
237 void BC_Meter::draw_titles()
239         if(!use_titles) return;
241         set_font(get_resources()->meter_font);
243         if(orientation == METER_HORIZ)
244         {
245                 draw_top_background(parent_window, 0, 0, get_w(), get_title_w());
247                 for(int i = 0; i < meter_titles; i++)
248                 {
249                         draw_text(0, title_pixel[i], db_titles[i]);
250                 }
252                 flash(0, 0, get_w(), get_title_w());
253         }
254         else
255         if(orientation == METER_VERT)
256         {
257                 draw_top_background(parent_window, 0, 0, get_title_w(), get_h());
260                 for(int i = 0; i < meter_titles; i++)
261                 {
262 // Tick marks
263                         if(i < meter_titles - 1)
264                         {
265                                 for(int j = 0; j < 6; j++)
266                                 {
267                                         int y1;
268                                         int y2;
269                                         int y;
271                                         y1 = title_pixel[i];
272                                         y2 = title_pixel[i + 1];
273                                         y = (int)((float)(y2 - y1) * j / 5 + 0.5) + y1;
275                                         if(j == 0 || j == 5)
276                                         {
277                                                 set_color(get_resources()->meter_font_color);
278                                                 draw_line(get_title_w() - 10 - 1, y, get_title_w() - 1, y);
279                                                 if(get_resources()->meter_3d)
280                                                 {
281                                                         set_color(BLACK);
282                                                         draw_line(get_title_w() - 10, y + 1, get_title_w(), y + 1);
283                                                 }
284                                         }
285                                         else
286                                         {
287                                                 set_color(get_resources()->meter_font_color);
288                                                 draw_line(get_title_w() - 5 - 1, y, get_title_w() - 1, y);
289                                                 if(get_resources()->meter_3d)
290                                                 {
291                                                         set_color(BLACK);
292                                                         draw_line(get_title_w() - 5, y + 1, get_title_w(), y + 1);
293                                                 }
294                                         }
295                                 }
296                         }
298                         set_color(get_resources()->meter_font_color);
299                         if(i == 0)
300                                 draw_text(0, title_pixel[i] + get_text_height(SMALLFONT_3D) / 2, db_titles[i]);
301                         else
302                                 draw_text(0, title_pixel[i] + get_text_height(SMALLFONT_3D) / 2, db_titles[i]);
303                 }
305                 flash(0, 0, get_title_w(), get_h());
306         }
309 int BC_Meter::region_pixel(int region)
311         VFrame **reference_images = get_resources()->xmeter_images;
312         int result;
314         if(region == METER_RIGHT) 
315                 result = region * reference_images[0]->get_w() / 4;
316         else
317                 result = region * reference_images[0]->get_w() / 4;
319         return result;
322 int BC_Meter::region_pixels(int region)
324         int x1;
325         int x2;
326         int result;
327         VFrame **reference_images = get_resources()->xmeter_images;
328         
329         x1 = region * reference_images[0]->get_w() / 4;
330         x2 = (region + 1) * reference_images[0]->get_w() / 4;
331         if(region == METER_MID) 
332                 result = (x2 - x1) * 2;
333         else 
334                 result = x2 - x1;
335         return result;
338 void BC_Meter::draw_face()
340         VFrame **reference_images = get_resources()->xmeter_images;
341         int level_pixel = level_to_pixel(level);
342         int peak_pixel2 = level_to_pixel(peak);
343         int peak_pixel1 = peak_pixel2 - 2;
344         int left_pixel = region_pixel(METER_MID);
345         int right_pixel = pixels - region_pixels(METER_RIGHT);
346         int pixel = 0;
347         int image_number = 0, region = 0;
348         int in_span, in_start;
349         int x = use_titles ? get_title_w() : 0;
350         int w = use_titles ? this->w - get_title_w() : this->w;
352         draw_top_background(parent_window, x, 0, w, h);
353 //printf("BC_Meter::draw_face %d %d\n", w, h);
355         while(pixel < pixels)
356         {
357 // Select image to draw
358                 if(pixel < level_pixel ||
359                         (pixel >= peak_pixel1 && pixel < peak_pixel2))
360                 {
361                         if(pixel < low_division)
362                                 image_number = METER_GREEN;
363                         else
364                         if(pixel < medium_division)
365                                 image_number = METER_YELLOW;
366                         else
367                                 image_number = METER_RED;
368                 }
369                 else
370                 {
371                         image_number = METER_NORMAL;
372                 }
374 // Select region of image to duplicate
375                 if(pixel < left_pixel)
376                 {
377                         region = METER_LEFT;
378                         in_start = pixel + region_pixel(region);
379                         in_span = region_pixels(region) - (in_start - region_pixel(region));
380                 }
381                 else
382                 if(pixel < right_pixel)
383                 {
384                         region = METER_MID;
385                         in_start = region_pixel(region);
386                         in_span = region_pixels(region);
387                 }
388                 else
389                 {
390                         region = METER_RIGHT;
391                         in_start = (pixel - right_pixel) + region_pixel(region);
392                         in_span = region_pixels(region) - (in_start - region_pixel(region));;
393                 }
395 //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);
396                 if(in_span > 0)
397                 {
398 // Clip length to peaks
399                         if(pixel < level_pixel && pixel + in_span > level_pixel)
400                                 in_span = level_pixel - pixel;
401                         else
402                         if(pixel < peak_pixel1 && pixel + in_span > peak_pixel1)
403                                 in_span = peak_pixel1 - pixel;
404                         else
405                         if(pixel < peak_pixel2 && pixel + in_span > peak_pixel2) 
406                                 in_span = peak_pixel2 - pixel;
408 // Clip length to color changes
409                         if(image_number == METER_GREEN && pixel + in_span > low_division)
410                                 in_span = low_division - pixel;
411                         else
412                         if(image_number == METER_YELLOW && pixel + in_span > medium_division)
413                                 in_span = medium_division - pixel;
415 // Clip length to regions
416                         if(pixel < left_pixel && pixel + in_span > left_pixel)
417                                 in_span = left_pixel - pixel;
418                         else
419                         if(pixel < right_pixel && pixel + in_span > right_pixel)
420                                 in_span = right_pixel - pixel;
422 //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);
423 //printf("BC_Meter::draw_face %d %d %d %d\n", orientation, region, images[image_number]->get_h() - in_start - in_span);
424                         if(orientation == METER_HORIZ)
425                                 draw_pixmap(images[image_number], 
426                                         pixel, 
427                                         x, 
428                                         in_span + 1, 
429                                         get_h(), 
430                                         in_start, 
431                                         0);
432                         else
433                                 draw_pixmap(images[image_number],
434                                         x,
435                                         get_h() - pixel - in_span,
436                                         get_w(),
437                                         in_span + 1,
438                                         0,
439                                         images[image_number]->get_h() - in_start - in_span);
441                         pixel += in_span;
442                 }
443         }
445         if(over_timer)
446         {
447                 if(orientation == METER_HORIZ)
448                         draw_pixmap(images[METER_OVER], 
449                                 10, 
450                                 2);
451                 else
452                         draw_pixmap(images[METER_OVER],
453                                 x + 2,
454                                 get_h() - 100);
456                 over_timer--;
457         }
459         if(orientation == METER_HORIZ)
460                 flash(0, 0, pixels, get_h());
461         else
462                 flash(x, 0, w, pixels);
465 int BC_Meter::update(float new_value, int over)
467         peak_timer++;
469         if(mode == METER_DB)
470         {
471                 if(new_value == 0) 
472                         level = min;
473                 else
474                         level = db.todb(new_value);        // db value
475         }
477         if(level > peak || peak_timer > peak_delay)
478         {
479                 peak = level;
480                 peak_timer = 0;
481         }
483 //printf("BC_Meter::update %f\n", level);
484         if(over) over_timer = over_delay;       
485 // only draw if window is visible
487         draw_face();
488         return 0;