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