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