plug leaks, leaker tweaks, lang for effect info, c41 spiffs, wm probe tweaks
[goodguy/history.git] / cinelerra-5.1 / guicast / bctheme.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 "bcresources.h"
23 #include "bctheme.h"
24 #include "bcwindowbase.h"
25 #include "clip.h"
26 #include "language.h"
27 #include "vframe.h"
28
29 #include <errno.h>
30 #include <stdio.h>
31 #include <string.h>
32
33 BC_Theme::BC_Theme()
34 {
35         data_ptr = 0;
36         contents_ptr = 0;
37         last_image = 0;
38         last_pointer = 0;
39 }
40
41 BC_Theme::~BC_Theme()
42 {
43         image_sets.remove_all_objects();
44         contents.remove_all();
45 }
46
47 void BC_Theme::dump()
48 {
49         printf("BC_Theme::dump 1 image_sets=%d contents=%d\n",
50                 image_sets.total,
51                 contents.total);
52         for(int i = 0; i < contents.total; i++)
53                 printf("    %s %p\n", contents.values[i], pointers.values[i]);
54 }
55
56 BC_Resources* BC_Theme::get_resources()
57 {
58         return BC_WindowBase::get_resources();
59 }
60
61 // These create single images for storage in the image_sets table.
62 VFrame* BC_Theme::new_image(const char *title, const char *path)
63 {
64         VFrame *existing_image = title[0] ? get_image(title, 0) : 0;
65         if(existing_image) return existing_image;
66
67         BC_ThemeSet *result = new BC_ThemeSet(1, 0, title);
68         result->data[0] = new VFramePng(get_image_data(path));
69         image_sets.append(result);
70         return result->data[0];
71 }
72
73 VFrame* BC_Theme::new_image(const char *path)
74 {
75         return new_image("", path);
76 }
77
78
79
80 // These create image sets which are stored in the image_sets table.
81 VFrame** BC_Theme::new_image_set(const char *title, int total, va_list *args)
82 {
83         if(!total)
84         {
85                 printf("BC_Theme::new_image_set %d %s zero number of images\n",
86                         __LINE__,
87                         title);
88         }
89
90         VFrame **existing_image_set = title[0] ? get_image_set(title, 0) : 0;
91         if(existing_image_set) return existing_image_set;
92
93         BC_ThemeSet *result = new BC_ThemeSet(total, 1, title);
94         image_sets.append(result);
95         for(int i = 0; i < total; i++)
96         {
97                 char *path = va_arg(*args, char*);
98                 result->data[i] = new_image(path);
99         }
100         return result->data;
101 }
102
103 VFrame** BC_Theme::new_image_set_images(const char *title, int total, ...)
104 {
105         va_list list;
106         va_start(list, total);
107         BC_ThemeSet *existing_image_set = title[0] ? get_image_set_object(title) : 0;
108         if(existing_image_set)
109         {
110                 image_sets.remove_object(existing_image_set);
111         }
112
113         BC_ThemeSet *result = new BC_ThemeSet(total, 0, title);
114         image_sets.append(result);
115         for(int i = 0; i < total; i++)
116         {
117                 result->data[i] = va_arg(list, VFrame*);
118         }
119         va_end(list);
120         return result->data;
121 }
122
123 VFrame** BC_Theme::new_image_set(const char *title, int total, ...)
124 {
125         va_list list;
126         va_start(list, total);
127         VFrame **result = new_image_set(title, total, &list);
128         va_end(list);
129
130         return result;
131 }
132
133 VFrame** BC_Theme::new_image_set(int total, ...)
134 {
135         va_list list;
136         va_start(list, total);
137         VFrame **result = new_image_set("", total, &list);
138         va_end(list);
139
140         return result;
141 }
142
143 BC_ThemeSet* BC_Theme::get_image_set_object(const char *title)
144 {
145 // compare title[0],title[1] for faster prefix test
146         const unsigned char *bp = (const unsigned char*)title;
147         unsigned short tval = bp[0];
148         if( tval ) tval |= (bp[1] << 8);
149
150         for( int i=0; i < image_sets.total; ++i ) {
151                 const char *tp = image_sets[i]->title;
152                 bp = (const unsigned char *) tp;
153                 unsigned short val = bp[0];
154                 if( val ) val |= (bp[1] << 8);
155                 if( val != tval ) continue;
156                 if( !strcmp(tp, title) ) return image_sets[i];
157         }
158         return 0;
159 }
160
161 VFrame* BC_Theme::get_image(const char *title, int use_default)
162 {
163         BC_ThemeSet* tsp = get_image_set_object(title);
164         if( tsp ) return tsp->data[0];
165
166
167 // Return the first image it can find.  This should always work.
168         if(use_default) {
169                 printf("BC_Theme::get_image: image \"%s\" not found.\n",
170                         title);
171                 if(image_sets.total)
172                         return image_sets[0]->data[0];
173         }
174
175 // Give up and go to a movie.
176         return 0;
177 }
178
179 VFrame** BC_Theme::get_image_set(const char *title, int use_default)
180 {
181         BC_ThemeSet* tsp = get_image_set_object(title);
182         if( tsp ) return tsp->data;
183
184 // Get the image set with the largest number of images.
185         if(use_default)
186         {
187                 printf("BC_Theme::get_image_set: image set \"%s\" not found.\n",
188                         title);
189                 int max_total = 0;
190                 int max_number = -1;
191                 for(int i = 0; i < image_sets.total; i++)
192                 {
193                         if(image_sets[i]->total > max_total)
194                         {
195                                 max_total = image_sets[i]->total;
196                                 max_number = i;
197                         }
198                 }
199
200                 if(max_number >= 0)
201                         return image_sets[max_number]->data;
202         }
203
204 // Give up and go to a movie
205         return 0;
206 }
207
208
209
210
211
212
213
214
215
216
217
218 VFrame** BC_Theme::new_button(const char *overlay_path,
219         const char *up_path,
220         const char *hi_path,
221         const char *dn_path,
222         const char *title)
223 {
224         VFramePng default_data(get_image_data(overlay_path));
225         BC_ThemeSet *result = new BC_ThemeSet(3, 1, title ? title : "");
226         if(title) image_sets.append(result);
227
228         result->data[0] = new_image(up_path);
229         result->data[1] = new_image(hi_path);
230         result->data[2] = new_image(dn_path);
231         for(int i = 0; i < 3; i++)
232         {
233                 overlay(result->data[i], &default_data, -1, -1, (i == 2));
234         }
235         return result->data;
236 }
237
238
239 VFrame** BC_Theme::new_button4(const char *overlay_path,
240         const char *up_path,
241         const char *hi_path,
242         const char *dn_path,
243         const char *disabled_path,
244         const char *title)
245 {
246         VFramePng default_data(get_image_data(overlay_path));
247         BC_ThemeSet *result = new BC_ThemeSet(4, 1, title ? title : "");
248         if(title) image_sets.append(result);
249
250         result->data[0] = new_image(up_path);
251         result->data[1] = new_image(hi_path);
252         result->data[2] = new_image(dn_path);
253         result->data[3] = new_image(disabled_path);
254         for(int i = 0; i < 4; i++)
255         {
256                 overlay(result->data[i], &default_data, -1, -1, (i == 2));
257         }
258         return result->data;
259 }
260
261
262 VFrame** BC_Theme::new_button(const char *overlay_path,
263         VFrame *up,
264         VFrame *hi,
265         VFrame *dn,
266         const char *title)
267 {
268         VFramePng default_data(get_image_data(overlay_path));
269         BC_ThemeSet *result = new BC_ThemeSet(3, 0, title ? title : "");
270         if(title) image_sets.append(result);
271
272         result->data[0] = new VFrame(*up);
273         result->data[1] = new VFrame(*hi);
274         result->data[2] = new VFrame(*dn);
275         for(int i = 0; i < 3; i++)
276                 overlay(result->data[i], &default_data, -1, -1, (i == 2));
277         return result->data;
278 }
279
280
281 VFrame** BC_Theme::new_toggle(const char *overlay_path,
282         const char *up_path,
283         const char *hi_path,
284         const char *checked_path,
285         const char *dn_path,
286         const char *checkedhi_path,
287         const char *title)
288 {
289         VFramePng default_data(get_image_data(overlay_path));
290         BC_ThemeSet *result = new BC_ThemeSet(5, 1, title ? title : "");
291         if(title) image_sets.append(result);
292
293         result->data[0] = new_image(up_path);
294         result->data[1] = new_image(hi_path);
295         result->data[2] = new_image(checked_path);
296         result->data[3] = new_image(dn_path);
297         result->data[4] = new_image(checkedhi_path);
298         for(int i = 0; i < 5; i++)
299                 overlay(result->data[i], &default_data, -1, -1, (i == 3));
300         return result->data;
301 }
302
303 VFrame** BC_Theme::new_toggle(const char *overlay_path,
304         VFrame *up,
305         VFrame *hi,
306         VFrame *checked,
307         VFrame *dn,
308         VFrame *checkedhi,
309         const char *title)
310 {
311         VFramePng default_data(get_image_data(overlay_path));
312         BC_ThemeSet *result = new BC_ThemeSet(5, 0, title ? title : "");
313         if(title) image_sets.append(result);
314
315         result->data[0] = new VFrame(*up);
316         result->data[1] = new VFrame(*hi);
317         result->data[2] = new VFrame(*checked);
318         result->data[3] = new VFrame(*dn);
319         result->data[4] = new VFrame(*checkedhi);
320         for(int i = 0; i < 5; i++)
321                 overlay(result->data[i], &default_data, -1, -1, (i == 3));
322         return result->data;
323 }
324
325 void BC_Theme::overlay(VFrame *dst, VFrame *src, int in_x1, int in_x2, int shift)
326 {
327         int w;
328         int h;
329         unsigned char **in_rows;
330         unsigned char **out_rows;
331
332         if(in_x1 < 0)
333         {
334                 w = MIN(src->get_w(), dst->get_w());
335                 h = MIN(dst->get_h(), src->get_h());
336                 in_x1 = 0;
337                 in_x2 = w;
338         }
339         else
340         {
341                 w = in_x2 - in_x1;
342                 h = MIN(dst->get_h(), src->get_h());
343         }
344         in_rows = src->get_rows();
345         out_rows = dst->get_rows();
346
347         switch(src->get_color_model())
348         {
349                 case BC_RGBA8888:
350                         switch(dst->get_color_model())
351                         {
352                                 case BC_RGBA8888:
353                                         for(int i = shift; i < h; i++)
354                                         {
355                                                 unsigned char *in_row = 0;
356                                                 unsigned char *out_row;
357
358                                                 if(!shift)
359                                                 {
360                                                         in_row = in_rows[i] + in_x1 * 4;
361                                                         out_row = out_rows[i];
362                                                 }
363                                                 else
364                                                 {
365                                                         in_row = in_rows[i - 1] + in_x1 * 4;
366                                                         out_row = out_rows[i] + 4;
367                                                 }
368
369                                                 for(int j = shift; j < w; j++)
370                                                 {
371                                                         int opacity = in_row[3];
372                                                         int transparency = 0xff - opacity;
373
374                                                         out_row[0] = (in_row[0] * opacity + out_row[0] * transparency) / 0xff;
375                                                         out_row[1] = (in_row[1] * opacity + out_row[1] * transparency) / 0xff;
376                                                         out_row[2] = (in_row[2] * opacity + out_row[2] * transparency) / 0xff;
377                                                         out_row[3] = MAX(in_row[3], out_row[3]);
378                                                         out_row += 4;
379                                                         in_row += 4;
380                                                 }
381                                         }
382                                         break;
383
384                                 case BC_RGB888:
385                                         for(int i = shift; i < h; i++)
386                                         {
387                                                 unsigned char *in_row;
388                                                 unsigned char *out_row = out_rows[i];
389
390                                                 if(!shift)
391                                                 {
392                                                         in_row = in_rows[i] + in_x1 * 3;
393                                                         out_row = out_rows[i];
394                                                 }
395                                                 else
396                                                 {
397                                                         in_row = in_rows[i - 1] + in_x1 * 3;
398                                                         out_row = out_rows[i] + 3;
399                                                 }
400
401                                                 for(int j = shift; j < w; j++)
402                                                 {
403                                                         int opacity = in_row[3];
404                                                         int transparency = 0xff - opacity;
405                                                         out_row[0] = (in_row[0] * opacity + out_row[0] * transparency) / 0xff;
406                                                         out_row[1] = (in_row[1] * opacity + out_row[1] * transparency) / 0xff;
407                                                         out_row[2] = (in_row[2] * opacity + out_row[2] * transparency) / 0xff;
408                                                         out_row += 3;
409                                                         in_row += 4;
410                                                 }
411                                         }
412                                         break;
413                         }
414                         break;
415         }
416 }
417
418 void BC_Theme::set_data(unsigned char *ptr)
419 {
420         contents_ptr = (char*)(ptr + sizeof(int));
421         int contents_size = *(int*)ptr - sizeof(int);
422         data_ptr = contents_ptr + contents_size;
423
424         for(int i = 0; i < contents_size; )
425         {
426                 used.append(0);
427                 contents.append(contents_ptr + i);
428                 while(contents_ptr[i] && i < contents_size)
429                         i++;
430                 if(i < contents_size)
431                 {
432                         i++;
433                         pointers.append((unsigned char*)data_ptr +
434                                 *(unsigned int*)(contents_ptr + i));
435                         i += 4;
436                 }
437                 else
438                 {
439                         pointers.append((unsigned char*)data_ptr);
440                         break;
441                 }
442         }
443 }
444
445 unsigned char* BC_Theme::get_image_data(const char *title)
446 {
447         if(!data_ptr)
448         {
449                 fprintf(stderr, "BC_Theme::get_image_data: no data set\n");
450                 return 0;
451         }
452
453 // Image is the same as the last one
454         if(last_image && !strcasecmp(last_image, title))
455         {
456                 return last_pointer;
457         }
458         else
459 // Search for image anew.
460         for(int i = 0; i < contents.total; i++)
461         {
462                 if(!strcasecmp(contents.values[i], title))
463                 {
464                         last_pointer = pointers.values[i];
465                         last_image = contents.values[i];
466                         used.values[i] = 1;
467                         return pointers.values[i];
468                 }
469         }
470
471         fprintf(stderr, _("Theme::get_image: %s not found.\n"), title);
472         return 0;
473 }
474
475 void BC_Theme::check_used()
476 {
477 // Can't use because some images are gotten the old fashioned way.
478 return;
479         int got_it = 0;
480         for(int i = 0; i < used.total; i++)
481         {
482                 if(!used.values[i])
483                 {
484                         if(!got_it)
485                                 printf(_("BC_Theme::check_used: Images aren't used.\n"));
486                         printf("%s ", contents.values[i]);
487                         got_it = 1;
488                 }
489         }
490         if(got_it) printf("\n");
491 }
492
493
494
495
496
497
498
499
500
501
502
503
504 BC_ThemeSet::BC_ThemeSet(int total, int is_reference, const char *title)
505 {
506         this->total = total;
507         this->title = new char[strlen(title) + 1];
508         strcpy(this->title, title);
509         this->is_reference = is_reference;
510         data = new VFrame*[total];
511 }
512
513 BC_ThemeSet::~BC_ThemeSet()
514 {
515         if(data)
516         {
517                 if(!is_reference)
518                 {
519                         for(int i = 0; i < total; i++)
520                                 delete data[i];
521                 }
522
523                 delete [] data;
524         }
525
526         delete [] title;
527 }
528
529
530
531
532