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