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