r370: Heroine Virutal's official release 1.2.1
[cinelerra_cv/mob.git] / hvirtual / guicast / bcmeter.C
blob5f34cca355c8b9d2a63d0ce5b9043fd7ef4c00a8
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;
48 BC_Meter::~BC_Meter()
50         db_titles.remove_all_objects();
51         title_pixels.remove_all();
52         tick_pixels.remove_all();
53         for(int i = 0; i < TOTAL_METER_IMAGES; i++) delete images[i];
56 int BC_Meter::get_title_w()
58         return get_resources()->meter_title_w;
61 int BC_Meter::get_meter_w()
63         return get_resources()->ymeter_images[0]->get_w() + 2;
67 int BC_Meter::set_delays(int over_delay, int peak_delay)
69         this->over_delay = over_delay;
70         this->peak_delay = peak_delay;
71         return 0;
74 int BC_Meter::initialize()
76         peak_timer = 0;
77         level_pixel = peak_pixel = 0;
78         over_timer = 0;
79         over_count = 0;
80         peak = level = -100;
82         if(orientation == METER_VERT)
83         {
84                 set_images(get_resources()->ymeter_images);
85                 h = pixels;
86                 w = images[0]->get_w();
87                 if(use_titles) w += get_title_w();
88         }
89         else
90         {
91                 set_images(get_resources()->xmeter_images);
92                 h = images[0]->get_h();
93                 w = pixels;
94                 if(use_titles) h += get_title_w();
95         }
97 // calibrate the db titles
98         get_divisions();
100         BC_SubWindow::initialize();
101         draw_titles();
102         draw_face();
103         return 0;
106 void BC_Meter::set_images(VFrame **data)
108         for(int i = 0; i < TOTAL_METER_IMAGES; i++) delete images[i];
109         for(int i = 0; i < TOTAL_METER_IMAGES; i++) 
110                 images[i] = new BC_Pixmap(parent_window, data[i], PIXMAP_ALPHA);
113 int BC_Meter::reposition_window(int x, int y, int pixels)
115         if(pixels < 0) pixels = this->pixels;
116         this->pixels = pixels;
117         if(orientation == METER_VERT)
118                 BC_SubWindow::reposition_window(x, y, get_w(), pixels);
119         else
120                 BC_SubWindow::reposition_window(x, y, pixels, get_h());
122 //printf("BC_Meter::reposition_window 1 %d %d %d %d\n", x, y, w, h);
123         get_divisions();
125 //set_color(WHITE);
126 //draw_box(0, 0, w, h);
127 //flash();      
128 //return 0;
129         draw_titles();
130         draw_face();
131         return 0;
134 int BC_Meter::reset()
136         level = min;
137         peak = min;
138         level_pixel = peak_pixel = 0;
139         peak_timer = 0;
140         over_timer = 0;
141         over_count = 0;
142         draw_face();
143         return 0;
146 int BC_Meter::button_press_event()
148         if(cursor_inside() && is_event_win())
149         {
150                 reset_over();
151                 return 1;
152         }
153         return 0;
157 int BC_Meter::reset_over()
159         over_timer = 0;
160         return 0;
163 int BC_Meter::change_format(int mode, int min, int max)
165         this->mode = mode;
166         this->min = min;
167         this->max = max;
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 = (int)(pixels * 
178                         (level - min) / 
179                         (max - min));
180                 if(level <= min) result = 0;
181         }
182         else
183         {
184 // Not implemented anymore
185                 result = 0;
186         }
187         
188         return result;
192 void BC_Meter::get_divisions()
194         int i;
195         int j, j_step;
196         int division, division_step;
197         char string[BCTEXTLEN];
198         char *new_string;
201         db_titles.remove_all_objects();
202         title_pixels.remove_all();
203         tick_pixels.remove_all();
205         low_division = 0;
206         medium_division = 0;
207         high_division = pixels;
209         int current_pixel;
210 // Create tick marks and titles in one pass
211         for(int current = min; current <= max; current++)
212         {
213                 if(orientation == METER_VERT)
214                 {
215 // Create tick mark
216                         current_pixel = (pixels - METER_MARGIN * 2 - 2) * 
217                                 (current - min) /
218                                 (max - min) + 2;
219                         tick_pixels.append(current_pixel);
221 // Create titles in selected positions
222                         if(current == min || 
223                                 current == max ||
224                                 current == 0 ||
225                                 (current - min > 4 && max - current > 4 && !(current % 5)))
226                         {
227                                 int title_pixel = (pixels - 
228                                         METER_MARGIN * 2) * 
229                                         (current - min) /
230                                         (max - min);
231                                 sprintf(string, "%d", labs(current));
232                                 new_string = new char[strlen(string) + 1];
233                                 strcpy(new_string, string);
234                                 db_titles.append(new_string);
235                                 title_pixels.append(title_pixel);
236                         }
237                 }
238                 else
239                 {
240                         current_pixel = (pixels - METER_MARGIN * 2) *
241                                 (current - min) /
242                                 (max - min);
243                         tick_pixels.append(current_pixel);
244 // Titles not supported for horizontal
245                 }
247 // Create color divisions
248                 if(current == -20)
249                 {
250                         low_division = current_pixel;
251                 }
252                 else
253                 if(current == -5)
254                 {
255                         medium_division = current_pixel;
256                 }
257                 else
258                 if(current == 0)
259                 {
260                         high_division = current_pixel;
261                 }
262         }
263 // if(orientation == METER_VERT)
264 // printf("BC_Meter::get_divisions %d %d %d %d\n",
265 // low_division, medium_division, high_division, pixels);
268 void BC_Meter::draw_titles()
270         if(!use_titles) return;
272         set_font(get_resources()->meter_font);
274         if(orientation == METER_HORIZ)
275         {
276                 draw_top_background(parent_window, 0, 0, get_w(), get_title_w());
278                 for(int i = 0; i < db_titles.total; i++)
279                 {
280                         draw_text(0, title_pixels.values[i], db_titles.values[i]);
281                 }
283                 flash(0, 0, get_w(), get_title_w());
284         }
285         else
286         if(orientation == METER_VERT)
287         {
288                 draw_top_background(parent_window, 0, 0, get_title_w(), get_h());
290 // Titles
291                 for(int i = 0; i < db_titles.total; i++)
292                 {
293                         int title_y = pixels - 
294                                 title_pixels.values[i];
295                         if(i == 0) 
296                                 title_y -= get_text_descent(SMALLFONT_3D);
297                         else
298                         if(i == db_titles.total - 1)
299                                 title_y += get_text_ascent(SMALLFONT_3D);
300                         else
301                                 title_y += get_text_ascent(SMALLFONT_3D) / 2;
303                         set_color(get_resources()->meter_font_color);
304                         draw_text(0, 
305                                 title_y,
306                                 db_titles.values[i]);
307                 }
309                 for(int i = 0; i < tick_pixels.total; i++)
310                 {
311 // Tick marks
312                         int tick_y = pixels - tick_pixels.values[i] - METER_MARGIN;
313                         set_color(get_resources()->meter_font_color);
314                         draw_line(get_title_w() - 10 - 1, tick_y, get_title_w() - 1, tick_y);
315                         if(get_resources()->meter_3d)
316                         {
317                                 set_color(BLACK);
318                                 draw_line(get_title_w() - 10, tick_y + 1, get_title_w(), tick_y + 1);
319                         }
320                 }
322                 flash(0, 0, get_title_w(), get_h());
323         }
326 int BC_Meter::region_pixel(int region)
328         VFrame **reference_images = get_resources()->xmeter_images;
329         int result;
331         if(region == METER_RIGHT) 
332                 result = region * reference_images[0]->get_w() / 4;
333         else
334                 result = region * reference_images[0]->get_w() / 4;
336         return result;
339 int BC_Meter::region_pixels(int region)
341         int x1;
342         int x2;
343         int result;
344         VFrame **reference_images = get_resources()->xmeter_images;
345         
346         x1 = region * reference_images[0]->get_w() / 4;
347         x2 = (region + 1) * reference_images[0]->get_w() / 4;
348         if(region == METER_MID) 
349                 result = (x2 - x1) * 2;
350         else 
351                 result = x2 - x1;
352         return result;
355 void BC_Meter::draw_face()
357         VFrame **reference_images = get_resources()->xmeter_images;
358         int level_pixel = level_to_pixel(level);
359         int peak_pixel2 = level_to_pixel(peak);
360         int peak_pixel1 = peak_pixel2 - 2;
361         int left_pixel = region_pixel(METER_MID);
362         int right_pixel = pixels - region_pixels(METER_RIGHT);
363         int pixel = 0;
364         int image_number = 0, region = 0;
365         int in_span, in_start;
366         int x = use_titles ? get_title_w() : 0;
367         int w = use_titles ? this->w - get_title_w() : this->w;
369         draw_top_background(parent_window, x, 0, w, h);
370 //printf("BC_Meter::draw_face %d %d\n", w, h);
372         while(pixel < pixels)
373         {
374 // Select image to draw
375                 if(pixel < level_pixel ||
376                         (pixel >= peak_pixel1 && pixel < peak_pixel2))
377                 {
378                         if(pixel < low_division)
379                                 image_number = METER_GREEN;
380                         else
381                         if(pixel < medium_division)
382                                 image_number = METER_YELLOW;
383                         else
384                         if(pixel < high_division)
385                                 image_number = METER_RED;
386                         else
387                                 image_number = METER_WHITE;
388                 }
389                 else
390                 {
391                         image_number = METER_NORMAL;
392                 }
394 // Select region of image to duplicate
395                 if(pixel < left_pixel)
396                 {
397                         region = METER_LEFT;
398                         in_start = pixel + region_pixel(region);
399                         in_span = region_pixels(region) - (in_start - region_pixel(region));
400                 }
401                 else
402                 if(pixel < right_pixel)
403                 {
404                         region = METER_MID;
405                         in_start = region_pixel(region);
406                         in_span = region_pixels(region);
407                 }
408                 else
409                 {
410                         region = METER_RIGHT;
411                         in_start = (pixel - right_pixel) + region_pixel(region);
412                         in_span = region_pixels(region) - (in_start - region_pixel(region));;
413                 }
415 //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);
416                 if(in_span > 0)
417                 {
418 // Clip length to peaks
419                         if(pixel < level_pixel && pixel + in_span > level_pixel)
420                                 in_span = level_pixel - pixel;
421                         else
422                         if(pixel < peak_pixel1 && pixel + in_span > peak_pixel1)
423                                 in_span = peak_pixel1 - pixel;
424                         else
425                         if(pixel < peak_pixel2 && pixel + in_span > peak_pixel2) 
426                                 in_span = peak_pixel2 - pixel;
428 // Clip length to color changes
429                         if(image_number == METER_GREEN && pixel + in_span > low_division)
430                                 in_span = low_division - pixel;
431                         else
432                         if(image_number == METER_YELLOW && pixel + in_span > medium_division)
433                                 in_span = medium_division - pixel;
434                         else
435                         if(image_number == METER_RED && pixel + in_span > high_division)
436                                 in_span = high_division - pixel;
438 // Clip length to regions
439                         if(pixel < left_pixel && pixel + in_span > left_pixel)
440                                 in_span = left_pixel - pixel;
441                         else
442                         if(pixel < right_pixel && pixel + in_span > right_pixel)
443                                 in_span = right_pixel - pixel;
445 //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);
446 //printf("BC_Meter::draw_face %d %d %d %d\n", orientation, region, images[image_number]->get_h() - in_start - in_span);
447                         if(orientation == METER_HORIZ)
448                                 draw_pixmap(images[image_number], 
449                                         pixel, 
450                                         x, 
451                                         in_span + 1, 
452                                         get_h(), 
453                                         in_start, 
454                                         0);
455                         else
456                                 draw_pixmap(images[image_number],
457                                         x,
458                                         get_h() - pixel - in_span,
459                                         get_w(),
460                                         in_span + 1,
461                                         0,
462                                         images[image_number]->get_h() - in_start - in_span);
464                         pixel += in_span;
465                 }
466                 else
467                 {
468 // Sanity check
469                         break;
470                 }
471         }
473         if(over_timer)
474         {
475                 if(orientation == METER_HORIZ)
476                         draw_pixmap(images[METER_OVER], 
477                                 10, 
478                                 2);
479                 else
480                         draw_pixmap(images[METER_OVER],
481                                 x + 2,
482                                 get_h() - 100);
484                 over_timer--;
485         }
487         if(orientation == METER_HORIZ)
488                 flash(0, 0, pixels, get_h());
489         else
490                 flash(x, 0, w, pixels);
491         flush();
494 int BC_Meter::update(float new_value, int over)
496         peak_timer++;
498         if(mode == METER_DB)
499         {
500                 if(new_value == 0) 
501                         level = min;
502                 else
503                         level = db.todb(new_value);        // db value
504         }
506         if(level > peak || peak_timer > peak_delay)
507         {
508                 peak = level;
509                 peak_timer = 0;
510         }
512 // if(orientation == METER_HORIZ)
513 // printf("BC_Meter::update %f\n", level);
514         if(over) over_timer = over_delay;       
515 // only draw if window is visible
517         draw_face();
518         return 0;