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