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);
111 BC_ThemeSet *result = new BC_ThemeSet(total, 0, title);
112 add_image_set(result);
113 for( int i=0; i<total; ++i ) {
114 result->data[i] = va_arg(list, VFrame*);
120 VFrame** BC_Theme::new_image_set(const char *title, int total, ...)
123 va_start(list, total);
124 VFrame **result = new_image_set(title, total, &list);
130 VFrame** BC_Theme::new_image_set(int total, ...)
133 va_start(list, total);
134 VFrame **result = new_image_set("", total, &list);
140 void BC_Theme::add_image_set(BC_ThemeSet *image_set)
142 image_sets.append(image_set);
143 if( image_sets_start >= 0 ) {
144 printf("BC_Theme::add_image_set image_sets unsorted, lookups degraded\n");
145 image_sets_start = -1;
149 int BC_Theme::image_set_cmpr(const void *ap, const void *bp)
151 BC_ThemeSet*a = *(BC_ThemeSet**)ap, *b = *(BC_ThemeSet**)bp;
152 return strcmp(a->title, b->title);
155 void BC_Theme::sort_image_sets()
157 if( image_sets_start >= 0 ) return;
158 qsort(&image_sets[0], image_sets.size(), sizeof(image_sets[0]), image_set_cmpr);
159 // skip over un-titled image sets
160 int i = 0, n = image_sets.size();
161 while( i<n && !image_sets[i]->title[0] ) ++i;
162 image_sets_start = i;
165 BC_ThemeSet* BC_Theme::get_image_set_object(const char *title)
167 if( last_image_set && !strcmp(title,last_image_set->title) )
168 return last_image_set;
170 if( image_sets_start >= 0 ) {
171 // binary search for image set
172 int r = image_sets.size(), l = image_sets_start-1;
176 BC_ThemeSet *image_set = image_sets[m];
177 if( !(v=strcmp(title, image_set->title)) )
178 return last_image_set = image_set;
179 if( v > 0 ) l = m; else r = m;
183 // compare title[0],title[1] for faster prefix test
184 const unsigned char *tp = (const unsigned char*)title;
185 unsigned short tval = tp[0];
186 if( tval ) tval |= (tp[1] << 8);
188 for( int i=0; i<image_sets.size(); ++i ) {
189 tp = (const unsigned char *)image_sets[i]->title;
190 unsigned short val = tp[0];
191 if( val ) val |= (tp[1] << 8);
192 if( val != tval ) continue;
193 if( !strcmp((const char *)tp, title) )
194 return last_image_set = image_sets[i];
201 VFrame* BC_Theme::get_image(const char *title, int use_default)
203 BC_ThemeSet* tsp = get_image_set_object(title);
204 if( tsp ) return tsp->data[0];
207 // Return the first image it can find. This should always work.
209 printf("BC_Theme::get_image: image \"%s\" not found.\n",
211 if( image_sets.size() )
212 return image_sets[0]->data[0];
215 // Give up and go to a movie.
219 VFrame** BC_Theme::get_image_set(const char *title, int use_default)
221 BC_ThemeSet* tsp = get_image_set_object(title);
222 if( tsp ) return tsp->data;
224 // Get the image set with the largest number of images.
226 printf("BC_Theme::get_image_set: image set \"%s\" not found.\n",
230 for( int i=0; i<image_sets.size(); ++i ) {
231 if( image_sets[i]->total > max_total ) {
232 max_total = image_sets[i]->total;
237 if( max_number >= 0 )
238 return image_sets[max_number]->data;
241 // Give up and go to a movie
255 VFrame** BC_Theme::new_button(const char *overlay_path,
261 VFramePng default_data(get_image_data(overlay_path));
262 BC_ThemeSet *result = new BC_ThemeSet(3, 1, title ? title : "");
263 if( title ) add_image_set(result);
265 result->data[0] = new_image(up_path);
266 result->data[1] = new_image(hi_path);
267 result->data[2] = new_image(dn_path);
268 for( int i=0; i<3; ++i ) {
269 overlay(result->data[i], &default_data, -1, -1, (i == 2));
275 VFrame** BC_Theme::new_button4(const char *overlay_path,
279 const char *disabled_path,
282 VFramePng default_data(get_image_data(overlay_path));
283 BC_ThemeSet *result = new BC_ThemeSet(4, 1, title ? title : "");
284 if( title ) add_image_set(result);
286 result->data[0] = new_image(up_path);
287 result->data[1] = new_image(hi_path);
288 result->data[2] = new_image(dn_path);
289 result->data[3] = new_image(disabled_path);
290 for( int i=0; i<4; ++i ) {
291 overlay(result->data[i], &default_data, -1, -1, (i == 2));
297 VFrame** BC_Theme::new_button(const char *overlay_path,
303 VFramePng default_data(get_image_data(overlay_path));
304 BC_ThemeSet *result = new BC_ThemeSet(3, 0, title ? title : "");
305 if( title ) add_image_set(result);
307 result->data[0] = new VFrame(*up);
308 result->data[1] = new VFrame(*hi);
309 result->data[2] = new VFrame(*dn);
310 for( int i=0; i<3; ++i )
311 overlay(result->data[i], &default_data, -1, -1, (i == 2));
316 VFrame** BC_Theme::new_toggle(const char *overlay_path,
319 const char *checked_path,
321 const char *checkedhi_path,
324 VFramePng default_data(get_image_data(overlay_path));
325 BC_ThemeSet *result = new BC_ThemeSet(5, 1, title ? title : "");
326 if( title ) add_image_set(result);
328 result->data[0] = new_image(up_path);
329 result->data[1] = new_image(hi_path);
330 result->data[2] = new_image(checked_path);
331 result->data[3] = new_image(dn_path);
332 result->data[4] = new_image(checkedhi_path);
333 for( int i=0; i<5; ++i )
334 overlay(result->data[i], &default_data, -1, -1, (i == 3));
338 VFrame** BC_Theme::new_toggle(const char *overlay_path,
346 VFramePng default_data(get_image_data(overlay_path));
347 BC_ThemeSet *result = new BC_ThemeSet(5, 0, title ? title : "");
348 if( title ) add_image_set(result);
350 result->data[0] = new VFrame(*up);
351 result->data[1] = new VFrame(*hi);
352 result->data[2] = new VFrame(*checked);
353 result->data[3] = new VFrame(*dn);
354 result->data[4] = new VFrame(*checkedhi);
355 for( int i=0; i<5; ++i )
356 overlay(result->data[i], &default_data, -1, -1, (i == 3));
360 void BC_Theme::overlay(VFrame *dst, VFrame *src, int in_x1, int in_x2, int shift)
364 unsigned char **in_rows;
365 unsigned char **out_rows;
368 w = MIN(src->get_w(), dst->get_w());
369 h = MIN(dst->get_h(), src->get_h());
375 h = MIN(dst->get_h(), src->get_h());
377 in_rows = src->get_rows();
378 out_rows = dst->get_rows();
380 switch( src->get_color_model() )
383 switch( dst->get_color_model() )
386 for( int i=shift; i<h; ++i ) {
387 unsigned char *in_row = 0;
388 unsigned char *out_row;
391 in_row = in_rows[i] + in_x1 * 4;
392 out_row = out_rows[i];
395 in_row = in_rows[i - 1] + in_x1 * 4;
396 out_row = out_rows[i] + 4;
399 for( int j=shift; j<w; ++j ) {
400 int opacity = in_row[3];
401 int transparency = 0xff - opacity;
403 out_row[0] = (in_row[0] * opacity + out_row[0] * transparency) / 0xff;
404 out_row[1] = (in_row[1] * opacity + out_row[1] * transparency) / 0xff;
405 out_row[2] = (in_row[2] * opacity + out_row[2] * transparency) / 0xff;
406 out_row[3] = MAX(in_row[3], out_row[3]);
414 for( int i=shift; i<h; ++i ) {
415 unsigned char *in_row;
416 unsigned char *out_row = out_rows[i];
419 in_row = in_rows[i] + in_x1 * 3;
420 out_row = out_rows[i];
423 in_row = in_rows[i - 1] + in_x1 * 3;
424 out_row = out_rows[i] + 3;
427 for( int j=shift; j<w; ++j ) {
428 int opacity = in_row[3];
429 int transparency = 0xff - opacity;
430 out_row[0] = (in_row[0] * opacity + out_row[0] * transparency) / 0xff;
431 out_row[1] = (in_row[1] * opacity + out_row[1] * transparency) / 0xff;
432 out_row[2] = (in_row[2] * opacity + out_row[2] * transparency) / 0xff;
443 void BC_Theme::set_data(unsigned char *ptr)
445 int hdr_sz = *(int*)ptr - sizeof(int);
446 unsigned char *cp = ptr + sizeof(int);
447 unsigned char *dp = cp + hdr_sz;
448 int start_item = images.size();
451 char *nm = (char *)cp;
452 while( cp < dp && *cp++ );
453 if( cp + sizeof(unsigned) > dp ) break;
455 for( int i=sizeof(unsigned); --i>=0; ofs|=cp[i] ) ofs <<= 8;
456 images.append(new BC_ImageData(nm, dp+ofs));
457 cp += sizeof(unsigned);
460 int items = images.size() - start_item;
461 data_items.append(items);
462 qsort(&images[start_item], items, sizeof(images[0]), images_cmpr);
465 int BC_Theme::images_cmpr(const void *ap, const void *bp)
467 BC_ImageData *a = *(BC_ImageData**)ap, *b = *(BC_ImageData**)bp;
468 return strcmp(a->name, b->name);
471 unsigned char* BC_Theme::get_image_data(const char *name, int log_errs)
473 // Image is the same as the last one
474 if( last_image_data && !strcmp(last_image_data->name, name) )
475 return last_image_data->data;
477 // look forwards thru data sets for name
479 for( int i=0,n=data_items.size(); i<n; ++i ) {
480 int end_item = start_item + data_items[i];
481 int r = end_item, l = start_item-1;
482 // binary search for image
486 BC_ImageData *image_data = images[m];
487 if( !(v=strcmp(name, image_data->name)) ) {
488 image_data->used = 1;
489 last_image_data = image_data;
490 return image_data->data;
492 if( v > 0 ) l = m; else r = m;
494 start_item = end_item;
498 fprintf(stderr, _("Theme::get_image: %s not found.\n"), name);
502 void BC_Theme::check_used()
504 // Can't use because some images are gotten the old fashioned way.
507 for( int i=0; i<images.size(); ++i ) {
508 if( !images[i]->used ) {
509 if( !got_it ) printf(_("BC_Theme::check_used: Images aren't used.\n"));
510 printf("%s ", images[i]->name);
514 if( got_it ) printf("\n");
518 BC_ThemeSet::BC_ThemeSet(int total, int is_reference, const char *title)
521 this->title = new char[strlen(title) + 1];
522 strcpy(this->title, title);
523 this->is_reference = is_reference;
524 data = new VFrame*[total];
527 BC_ThemeSet::~BC_ThemeSet()
530 if( !is_reference ) {
531 for( int i = 0; i < total; i++ )