4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #include "bcresources.h"
24 #include "bcwindowbase.h"
37 image_sets_start = -1;
42 image_sets.remove_all_objects();
43 images.remove_all_objects();
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);
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]);
60 BC_Resources* BC_Theme::get_resources()
62 return BC_WindowBase::get_resources();
65 // These create single images for storage in the image_sets table.
66 VFrame* BC_Theme::new_image(const char *title, const char *path)
68 VFrame *existing_image = title[0] ? get_image(title, 0) : 0;
69 if( existing_image ) return existing_image;
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];
77 VFrame* BC_Theme::new_image(const char *path)
79 return new_image("", path);
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)
86 printf("BC_Theme::new_image_set %d %s zero number of images\n",
90 VFrame **existing_image_set = title[0] ? get_image_set(title, 0) : 0;
91 if( existing_image_set ) return existing_image_set;
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);
102 VFrame** BC_Theme::new_image_set_images(const char *title, int total, ...)
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);
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*);
122 VFrame** BC_Theme::new_image_set(const char *title, int total, ...)
125 va_start(list, total);
126 VFrame **result = new_image_set(title, total, &list);
132 VFrame** BC_Theme::new_image_set(int total, ...)
135 va_start(list, total);
136 VFrame **result = new_image_set("", total, &list);
142 void BC_Theme::add_image_set(BC_ThemeSet *image_set)
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;
151 int BC_Theme::image_set_cmpr(const void *ap, const void *bp)
153 BC_ThemeSet*a = *(BC_ThemeSet**)ap, *b = *(BC_ThemeSet**)bp;
154 return strcmp(a->title, b->title);
157 void BC_Theme::sort_image_sets()
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;
167 BC_ThemeSet* BC_Theme::get_image_set_object(const char *title)
169 if( last_image_set && !strcmp(title,last_image_set->title) )
170 return last_image_set;
172 if( image_sets_start >= 0 ) {
173 // binary search for image set
174 int r = image_sets.size(), l = image_sets_start-1;
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;
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);
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];
203 VFrame* BC_Theme::get_image(const char *title, int use_default)
205 BC_ThemeSet* tsp = get_image_set_object(title);
206 if( tsp ) return tsp->data[0];
209 // Return the first image it can find. This should always work.
211 printf("BC_Theme::get_image: image \"%s\" not found.\n",
213 if( image_sets.size() )
214 return image_sets[0]->data[0];
217 // Give up and go to a movie.
221 VFrame** BC_Theme::get_image_set(const char *title, int use_default)
223 BC_ThemeSet* tsp = get_image_set_object(title);
224 if( tsp ) return tsp->data;
226 // Get the image set with the largest number of images.
228 printf("BC_Theme::get_image_set: image set \"%s\" not found.\n",
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;
239 if( max_number >= 0 )
240 return image_sets[max_number]->data;
243 // Give up and go to a movie
257 VFrame** BC_Theme::new_button(const char *overlay_path,
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);
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));
277 VFrame** BC_Theme::new_button4(const char *overlay_path,
281 const char *disabled_path,
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);
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));
299 VFrame** BC_Theme::new_button(const char *overlay_path,
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);
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));
318 VFrame** BC_Theme::new_toggle(const char *overlay_path,
321 const char *checked_path,
323 const char *checkedhi_path,
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);
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));
340 VFrame** BC_Theme::new_toggle(const char *overlay_path,
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);
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));
362 void BC_Theme::overlay(VFrame *dst, VFrame *src, int in_x1, int in_x2, int shift)
366 unsigned char **in_rows;
367 unsigned char **out_rows;
370 w = MIN(src->get_w(), dst->get_w());
371 h = MIN(dst->get_h(), src->get_h());
377 h = MIN(dst->get_h(), src->get_h());
379 in_rows = src->get_rows();
380 out_rows = dst->get_rows();
382 switch( src->get_color_model() )
385 switch( dst->get_color_model() )
388 for( int i=shift; i<h; ++i ) {
389 unsigned char *in_row = 0;
390 unsigned char *out_row;
393 in_row = in_rows[i] + in_x1 * 4;
394 out_row = out_rows[i];
397 in_row = in_rows[i - 1] + in_x1 * 4;
398 out_row = out_rows[i] + 4;
401 for( int j=shift; j<w; ++j ) {
402 int opacity = in_row[3];
403 int transparency = 0xff - opacity;
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]);
416 for( int i=shift; i<h; ++i ) {
417 unsigned char *in_row;
418 unsigned char *out_row = out_rows[i];
421 in_row = in_rows[i] + in_x1 * 3;
422 out_row = out_rows[i];
425 in_row = in_rows[i - 1] + in_x1 * 3;
426 out_row = out_rows[i] + 3;
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;
445 void BC_Theme::set_data(unsigned char *ptr)
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();
453 char *nm = (char *)cp;
454 while( cp < dp && *cp++ );
455 if( cp + sizeof(unsigned) > dp ) break;
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);
462 int items = images.size() - start_item;
463 data_items.append(items);
464 qsort(&images[start_item], items, sizeof(images[0]), images_cmpr);
467 int BC_Theme::images_cmpr(const void *ap, const void *bp)
469 BC_ImageData *a = *(BC_ImageData**)ap, *b = *(BC_ImageData**)bp;
470 return strcmp(a->name, b->name);
473 unsigned char* BC_Theme::get_image_data(const char *name, int log_errs)
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;
479 // look forwards thru data sets for name
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
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;
494 if( v > 0 ) l = m; else r = m;
496 start_item = end_item;
500 fprintf(stderr, _("Theme::get_image: %s not found.\n"), name);
504 void BC_Theme::check_used()
506 // Can't use because some images are gotten the old fashioned way.
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);
516 if( got_it ) printf("\n");
520 BC_ThemeSet::BC_ThemeSet(int total, int is_reference, const char *title)
523 this->title = new char[strlen(title) + 1];
524 strcpy(this->title, title);
525 this->is_reference = is_reference;
526 data = new VFrame*[total];
529 BC_ThemeSet::~BC_ThemeSet()
532 if( !is_reference ) {
533 for( int i = 0; i < total; i++ )