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 VFrame* BC_Theme::new_image1(const char *title, const char *path)
84 VFrame *existing_image = title[0] ? get_image(title, 0) : 0;
85 if( existing_image ) return existing_image;
87 BC_ThemeSet *result = new BC_ThemeSet(1, 0, title);
88 result->data[0] = new VFramePng(get_image_data(path), 1.);
89 add_image_set(result);
90 return result->data[0];
93 // These create image sets which are stored in the image_sets table.
94 VFrame** BC_Theme::new_image_set(const char *title, int total, va_list *args)
97 printf("BC_Theme::new_image_set %d %s zero number of images\n",
101 VFrame **existing_image_set = title[0] ? get_image_set(title, 0) : 0;
102 if( existing_image_set ) return existing_image_set;
104 BC_ThemeSet *result = new BC_ThemeSet(total, 1, title);
105 add_image_set(result);
106 for( int i=0; i<total; ++i ) {
107 char *path = va_arg(*args, char*);
108 result->data[i] = new_image(path);
113 VFrame** BC_Theme::new_image_set_images(const char *title, int total, ...)
116 va_start(list, total);
117 BC_ThemeSet *existing_image_set = title[0] ? get_image_set_object(title) : 0;
118 if( existing_image_set ) {
119 image_sets.remove_object(existing_image_set);
124 BC_ThemeSet *result = new BC_ThemeSet(total, 0, title);
125 add_image_set(result);
126 for( int i=0; i<total; ++i ) {
127 result->data[i] = va_arg(list, VFrame*);
133 VFrame** BC_Theme::new_image_set(const char *title, int total, ...)
136 va_start(list, total);
137 VFrame **result = new_image_set(title, total, &list);
143 VFrame** BC_Theme::new_image_set(int total, ...)
146 va_start(list, total);
147 VFrame **result = new_image_set("", total, &list);
153 void BC_Theme::add_image_set(BC_ThemeSet *image_set)
155 image_sets.append(image_set);
156 if( image_sets_start >= 0 ) {
157 printf("BC_Theme::add_image_set image_sets unsorted, lookups degraded\n");
158 image_sets_start = -1;
162 int BC_Theme::image_set_cmpr(const void *ap, const void *bp)
164 BC_ThemeSet*a = *(BC_ThemeSet**)ap, *b = *(BC_ThemeSet**)bp;
165 return strcmp(a->title, b->title);
168 void BC_Theme::sort_image_sets()
170 if( image_sets_start >= 0 ) return;
171 qsort(&image_sets[0], image_sets.size(), sizeof(image_sets[0]), image_set_cmpr);
172 // skip over un-titled image sets
173 int i = 0, n = image_sets.size();
174 while( i<n && !image_sets[i]->title[0] ) ++i;
175 image_sets_start = i;
178 BC_ThemeSet* BC_Theme::get_image_set_object(const char *title)
180 if( last_image_set && !strcmp(title,last_image_set->title) )
181 return last_image_set;
183 if( image_sets_start >= 0 ) {
184 // binary search for image set
185 int r = image_sets.size(), l = image_sets_start-1;
189 BC_ThemeSet *image_set = image_sets[m];
190 if( !(v=strcmp(title, image_set->title)) )
191 return last_image_set = image_set;
192 if( v > 0 ) l = m; else r = m;
196 // compare title[0],title[1] for faster prefix test
197 const unsigned char *tp = (const unsigned char*)title;
198 unsigned short tval = tp[0];
199 if( tval ) tval |= (tp[1] << 8);
201 for( int i=0; i<image_sets.size(); ++i ) {
202 tp = (const unsigned char *)image_sets[i]->title;
203 unsigned short val = tp[0];
204 if( val ) val |= (tp[1] << 8);
205 if( val != tval ) continue;
206 if( !strcmp((const char *)tp, title) )
207 return last_image_set = image_sets[i];
214 VFrame* BC_Theme::get_image(const char *title, int use_default)
216 BC_ThemeSet* tsp = get_image_set_object(title);
217 if( tsp ) return tsp->data[0];
220 // Return the first image it can find. This should always work.
222 printf("BC_Theme::get_image: image \"%s\" not found.\n",
224 if( image_sets.size() )
225 return image_sets[0]->data[0];
228 // Give up and go to a movie.
232 VFrame** BC_Theme::get_image_set(const char *title, int use_default)
234 BC_ThemeSet* tsp = get_image_set_object(title);
235 if( tsp ) return tsp->data;
237 // Get the image set with the largest number of images.
239 printf("BC_Theme::get_image_set: image set \"%s\" not found.\n",
243 for( int i=0; i<image_sets.size(); ++i ) {
244 if( image_sets[i]->total > max_total ) {
245 max_total = image_sets[i]->total;
250 if( max_number >= 0 )
251 return image_sets[max_number]->data;
254 // Give up and go to a movie
268 VFrame** BC_Theme::new_button(const char *overlay_path,
274 VFramePng default_data(get_image_data(overlay_path));
275 BC_ThemeSet *result = new BC_ThemeSet(3, 1, title ? title : "");
276 if( title ) add_image_set(result);
278 result->data[0] = new_image(up_path);
279 result->data[1] = new_image(hi_path);
280 result->data[2] = new_image(dn_path);
281 for( int i=0; i<3; ++i ) {
282 overlay(result->data[i], &default_data, -1, -1, (i == 2));
288 VFrame** BC_Theme::new_button4(const char *overlay_path,
292 const char *disabled_path,
295 VFramePng default_data(get_image_data(overlay_path));
296 BC_ThemeSet *result = new BC_ThemeSet(4, 1, title ? title : "");
297 if( title ) add_image_set(result);
299 result->data[0] = new_image(up_path);
300 result->data[1] = new_image(hi_path);
301 result->data[2] = new_image(dn_path);
302 result->data[3] = new_image(disabled_path);
303 for( int i=0; i<4; ++i ) {
304 overlay(result->data[i], &default_data, -1, -1, (i == 2));
310 VFrame** BC_Theme::new_button(const char *overlay_path,
316 VFramePng default_data(get_image_data(overlay_path));
317 BC_ThemeSet *result = new BC_ThemeSet(3, 0, title ? title : "");
318 if( title ) add_image_set(result);
320 result->data[0] = new VFrame(*up);
321 result->data[1] = new VFrame(*hi);
322 result->data[2] = new VFrame(*dn);
323 for( int i=0; i<3; ++i )
324 overlay(result->data[i], &default_data, -1, -1, (i == 2));
329 VFrame** BC_Theme::new_toggle(const char *overlay_path,
332 const char *checked_path,
334 const char *checkedhi_path,
337 VFramePng default_data(get_image_data(overlay_path));
338 BC_ThemeSet *result = new BC_ThemeSet(5, 1, title ? title : "");
339 if( title ) add_image_set(result);
341 result->data[0] = new_image(up_path);
342 result->data[1] = new_image(hi_path);
343 result->data[2] = new_image(checked_path);
344 result->data[3] = new_image(dn_path);
345 result->data[4] = new_image(checkedhi_path);
346 for( int i=0; i<5; ++i )
347 overlay(result->data[i], &default_data, -1, -1, (i == 3));
351 VFrame** BC_Theme::new_toggle(const char *overlay_path,
359 VFramePng default_data(get_image_data(overlay_path));
360 BC_ThemeSet *result = new BC_ThemeSet(5, 0, title ? title : "");
361 if( title ) add_image_set(result);
363 result->data[0] = new VFrame(*up);
364 result->data[1] = new VFrame(*hi);
365 result->data[2] = new VFrame(*checked);
366 result->data[3] = new VFrame(*dn);
367 result->data[4] = new VFrame(*checkedhi);
368 for( int i=0; i<5; ++i )
369 overlay(result->data[i], &default_data, -1, -1, (i == 3));
373 void BC_Theme::overlay(VFrame *dst, VFrame *src, int in_x1, int in_x2, int shift)
377 unsigned char **in_rows;
378 unsigned char **out_rows;
381 w = MIN(src->get_w(), dst->get_w());
382 h = MIN(dst->get_h(), src->get_h());
388 h = MIN(dst->get_h(), src->get_h());
390 in_rows = src->get_rows();
391 out_rows = dst->get_rows();
393 switch( src->get_color_model() )
396 switch( dst->get_color_model() )
399 for( int i=shift; i<h; ++i ) {
400 unsigned char *in_row = 0;
401 unsigned char *out_row;
404 in_row = in_rows[i] + in_x1 * 4;
405 out_row = out_rows[i];
408 in_row = in_rows[i - 1] + in_x1 * 4;
409 out_row = out_rows[i] + 4;
412 for( int j=shift; j<w; ++j ) {
413 int opacity = in_row[3];
414 int transparency = 0xff - opacity;
416 out_row[0] = (in_row[0] * opacity + out_row[0] * transparency) / 0xff;
417 out_row[1] = (in_row[1] * opacity + out_row[1] * transparency) / 0xff;
418 out_row[2] = (in_row[2] * opacity + out_row[2] * transparency) / 0xff;
419 out_row[3] = MAX(in_row[3], out_row[3]);
427 for( int i=shift; i<h; ++i ) {
428 unsigned char *in_row;
429 unsigned char *out_row = out_rows[i];
432 in_row = in_rows[i] + in_x1 * 3;
433 out_row = out_rows[i];
436 in_row = in_rows[i - 1] + in_x1 * 3;
437 out_row = out_rows[i] + 3;
440 for( int j=shift; j<w; ++j ) {
441 int opacity = in_row[3];
442 int transparency = 0xff - opacity;
443 out_row[0] = (in_row[0] * opacity + out_row[0] * transparency) / 0xff;
444 out_row[1] = (in_row[1] * opacity + out_row[1] * transparency) / 0xff;
445 out_row[2] = (in_row[2] * opacity + out_row[2] * transparency) / 0xff;
456 void BC_Theme::set_data(unsigned char *ptr)
458 //int hdr_sz = *(int*)ptr - sizeof(int);
460 memcpy(&hdr_sz, ptr, sizeof(int));
461 hdr_sz -= sizeof(int);
462 unsigned char *cp = ptr + sizeof(int);
463 unsigned char *dp = cp + hdr_sz;
464 int start_item = images.size();
467 char *nm = (char *)cp;
468 while( cp < dp && *cp++ );
469 if( cp + sizeof(unsigned) > dp ) break;
471 for( int i=sizeof(unsigned); --i>=0; ofs|=cp[i] ) ofs <<= 8;
472 images.append(new BC_ImageData(nm, dp+ofs));
473 cp += sizeof(unsigned);
476 int items = images.size() - start_item;
477 data_items.append(items);
478 qsort(&images[start_item], items, sizeof(images[0]), images_cmpr);
481 int BC_Theme::images_cmpr(const void *ap, const void *bp)
483 BC_ImageData *a = *(BC_ImageData**)ap, *b = *(BC_ImageData**)bp;
484 return strcmp(a->name, b->name);
487 unsigned char* BC_Theme::get_image_data(const char *name, int log_errs)
489 // Image is the same as the last one
490 if( last_image_data && !strcmp(last_image_data->name, name) )
491 return last_image_data->data;
493 // look forwards thru data sets for name
495 for( int i=0,n=data_items.size(); i<n; ++i ) {
496 int end_item = start_item + data_items[i];
497 int r = end_item, l = start_item-1;
498 // binary search for image
502 BC_ImageData *image_data = images[m];
503 if( !(v=strcmp(name, image_data->name)) ) {
504 image_data->used = 1;
505 last_image_data = image_data;
506 return image_data->data;
508 if( v > 0 ) l = m; else r = m;
510 start_item = end_item;
514 fprintf(stderr, _("Theme::get_image: %s not found.\n"), name);
518 void BC_Theme::check_used()
520 // Can't use because some images are gotten the old fashioned way.
523 for( int i=0; i<images.size(); ++i ) {
524 if( !images[i]->used ) {
525 if( !got_it ) printf(_("BC_Theme::check_used: Images aren't used.\n"));
526 printf("%s ", images[i]->name);
530 if( got_it ) printf("\n");
534 BC_ThemeSet::BC_ThemeSet(int total, int is_reference, const char *title)
537 this->title = new char[strlen(title) + 1];
538 strcpy(this->title, title);
539 this->is_reference = is_reference;
540 data = new VFrame*[total];
543 BC_ThemeSet::~BC_ThemeSet()
546 if( !is_reference ) {
547 for( int i = 0; i < total; i++ )