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"
40 image_sets.remove_all_objects();
41 images.remove_all_objects();
46 printf("BC_Theme::dump 1 image_sets=%d images=%d\n",
47 image_sets.size(), images.size());
48 for( int i=0; i<images.size(); ++i ) {
49 image_item *item = images[i];
50 printf(" %s %p\n", item->name, item->data);
54 BC_Resources* BC_Theme::get_resources()
56 return BC_WindowBase::get_resources();
59 // These create single images for storage in the image_sets table.
60 VFrame* BC_Theme::new_image(const char *title, const char *path)
62 VFrame *existing_image = title[0] ? get_image(title, 0) : 0;
63 if( existing_image ) return existing_image;
65 BC_ThemeSet *result = new BC_ThemeSet(1, 0, title);
66 result->data[0] = new VFramePng(get_image_data(path));
67 image_sets.append(result);
68 return result->data[0];
71 VFrame* BC_Theme::new_image(const char *path)
73 return new_image("", path);
76 // These create image sets which are stored in the image_sets table.
77 VFrame** BC_Theme::new_image_set(const char *title, int total, va_list *args)
80 printf("BC_Theme::new_image_set %d %s zero number of images\n",
84 VFrame **existing_image_set = title[0] ? get_image_set(title, 0) : 0;
85 if( existing_image_set ) return existing_image_set;
87 BC_ThemeSet *result = new BC_ThemeSet(total, 1, title);
88 image_sets.append(result);
89 for( int i=0; i<total; ++i ) {
90 char *path = va_arg(*args, char*);
91 result->data[i] = new_image(path);
96 VFrame** BC_Theme::new_image_set_images(const char *title, int total, ...)
99 va_start(list, total);
100 BC_ThemeSet *existing_image_set = title[0] ? get_image_set_object(title) : 0;
101 if( existing_image_set ) {
102 image_sets.remove_object(existing_image_set);
105 BC_ThemeSet *result = new BC_ThemeSet(total, 0, title);
106 image_sets.append(result);
107 for( int i=0; i<total; ++i ) {
108 result->data[i] = va_arg(list, VFrame*);
114 VFrame** BC_Theme::new_image_set(const char *title, int total, ...)
117 va_start(list, total);
118 VFrame **result = new_image_set(title, total, &list);
124 VFrame** BC_Theme::new_image_set(int total, ...)
127 va_start(list, total);
128 VFrame **result = new_image_set("", total, &list);
134 BC_ThemeSet* BC_Theme::get_image_set_object(const char *title)
136 // compare title[0],title[1] for faster prefix test
137 const unsigned char *bp = (const unsigned char*)title;
138 unsigned short tval = bp[0];
139 if( tval ) tval |= (bp[1] << 8);
141 for( int i=0; i<image_sets.size(); ++i ) {
142 const char *tp = image_sets[i]->title;
143 bp = (const unsigned char *) tp;
144 unsigned short val = bp[0];
145 if( val ) val |= (bp[1] << 8);
146 if( val != tval ) continue;
147 if( !strcmp(tp, title) ) return image_sets[i];
152 VFrame* BC_Theme::get_image(const char *title, int use_default)
154 BC_ThemeSet* tsp = get_image_set_object(title);
155 if( tsp ) return tsp->data[0];
158 // Return the first image it can find. This should always work.
160 printf("BC_Theme::get_image: image \"%s\" not found.\n",
162 if( image_sets.size() )
163 return image_sets[0]->data[0];
166 // Give up and go to a movie.
170 VFrame** BC_Theme::get_image_set(const char *title, int use_default)
172 BC_ThemeSet* tsp = get_image_set_object(title);
173 if( tsp ) return tsp->data;
175 // Get the image set with the largest number of images.
177 printf("BC_Theme::get_image_set: image set \"%s\" not found.\n",
181 for( int i=0; i<image_sets.size(); ++i ) {
182 if( image_sets[i]->total > max_total ) {
183 max_total = image_sets[i]->total;
188 if( max_number >= 0 )
189 return image_sets[max_number]->data;
192 // Give up and go to a movie
206 VFrame** BC_Theme::new_button(const char *overlay_path,
212 VFramePng default_data(get_image_data(overlay_path));
213 BC_ThemeSet *result = new BC_ThemeSet(3, 1, title ? title : "");
214 if( title ) image_sets.append(result);
216 result->data[0] = new_image(up_path);
217 result->data[1] = new_image(hi_path);
218 result->data[2] = new_image(dn_path);
219 for( int i=0; i<3; ++i ) {
220 overlay(result->data[i], &default_data, -1, -1, (i == 2));
226 VFrame** BC_Theme::new_button4(const char *overlay_path,
230 const char *disabled_path,
233 VFramePng default_data(get_image_data(overlay_path));
234 BC_ThemeSet *result = new BC_ThemeSet(4, 1, title ? title : "");
235 if( title ) image_sets.append(result);
237 result->data[0] = new_image(up_path);
238 result->data[1] = new_image(hi_path);
239 result->data[2] = new_image(dn_path);
240 result->data[3] = new_image(disabled_path);
241 for( int i=0; i<4; ++i ) {
242 overlay(result->data[i], &default_data, -1, -1, (i == 2));
248 VFrame** BC_Theme::new_button(const char *overlay_path,
254 VFramePng default_data(get_image_data(overlay_path));
255 BC_ThemeSet *result = new BC_ThemeSet(3, 0, title ? title : "");
256 if( title ) image_sets.append(result);
258 result->data[0] = new VFrame(*up);
259 result->data[1] = new VFrame(*hi);
260 result->data[2] = new VFrame(*dn);
261 for( int i=0; i<3; ++i )
262 overlay(result->data[i], &default_data, -1, -1, (i == 2));
267 VFrame** BC_Theme::new_toggle(const char *overlay_path,
270 const char *checked_path,
272 const char *checkedhi_path,
275 VFramePng default_data(get_image_data(overlay_path));
276 BC_ThemeSet *result = new BC_ThemeSet(5, 1, title ? title : "");
277 if( title ) image_sets.append(result);
279 result->data[0] = new_image(up_path);
280 result->data[1] = new_image(hi_path);
281 result->data[2] = new_image(checked_path);
282 result->data[3] = new_image(dn_path);
283 result->data[4] = new_image(checkedhi_path);
284 for( int i=0; i<5; ++i )
285 overlay(result->data[i], &default_data, -1, -1, (i == 3));
289 VFrame** BC_Theme::new_toggle(const char *overlay_path,
297 VFramePng default_data(get_image_data(overlay_path));
298 BC_ThemeSet *result = new BC_ThemeSet(5, 0, title ? title : "");
299 if( title ) image_sets.append(result);
301 result->data[0] = new VFrame(*up);
302 result->data[1] = new VFrame(*hi);
303 result->data[2] = new VFrame(*checked);
304 result->data[3] = new VFrame(*dn);
305 result->data[4] = new VFrame(*checkedhi);
306 for( int i=0; i<5; ++i )
307 overlay(result->data[i], &default_data, -1, -1, (i == 3));
311 void BC_Theme::overlay(VFrame *dst, VFrame *src, int in_x1, int in_x2, int shift)
315 unsigned char **in_rows;
316 unsigned char **out_rows;
319 w = MIN(src->get_w(), dst->get_w());
320 h = MIN(dst->get_h(), src->get_h());
326 h = MIN(dst->get_h(), src->get_h());
328 in_rows = src->get_rows();
329 out_rows = dst->get_rows();
331 switch( src->get_color_model() )
334 switch( dst->get_color_model() )
337 for( int i=shift; i<h; ++i ) {
338 unsigned char *in_row = 0;
339 unsigned char *out_row;
342 in_row = in_rows[i] + in_x1 * 4;
343 out_row = out_rows[i];
346 in_row = in_rows[i - 1] + in_x1 * 4;
347 out_row = out_rows[i] + 4;
350 for( int j=shift; j<w; ++j ) {
351 int opacity = in_row[3];
352 int transparency = 0xff - opacity;
354 out_row[0] = (in_row[0] * opacity + out_row[0] * transparency) / 0xff;
355 out_row[1] = (in_row[1] * opacity + out_row[1] * transparency) / 0xff;
356 out_row[2] = (in_row[2] * opacity + out_row[2] * transparency) / 0xff;
357 out_row[3] = MAX(in_row[3], out_row[3]);
365 for( int i=shift; i<h; ++i ) {
366 unsigned char *in_row;
367 unsigned char *out_row = out_rows[i];
370 in_row = in_rows[i] + in_x1 * 3;
371 out_row = out_rows[i];
374 in_row = in_rows[i - 1] + in_x1 * 3;
375 out_row = out_rows[i] + 3;
378 for( int j=shift; j<w; ++j ) {
379 int opacity = in_row[3];
380 int transparency = 0xff - opacity;
381 out_row[0] = (in_row[0] * opacity + out_row[0] * transparency) / 0xff;
382 out_row[1] = (in_row[1] * opacity + out_row[1] * transparency) / 0xff;
383 out_row[2] = (in_row[2] * opacity + out_row[2] * transparency) / 0xff;
394 void BC_Theme::set_data(unsigned char *ptr)
396 int hdr_sz = *(int*)ptr - sizeof(int);
397 unsigned char *cp = ptr + sizeof(int);
398 unsigned char *dp = cp + hdr_sz;
399 int start_item = images.size();
402 char *nm = (char *)cp;
403 while( cp < dp && *cp++ );
404 if( cp + sizeof(unsigned) > dp ) break;
406 for( int i=sizeof(unsigned); --i>=0; ofs|=cp[i] ) ofs <<= 8;
407 images.append(new image_item(nm, dp+ofs));
408 cp += sizeof(unsigned);
411 int items = images.size() - start_item;
412 data_items.append(items);
413 qsort(&images[start_item], items, sizeof(images[0]), images_cmpr);
416 int BC_Theme::images_cmpr(const void *ap, const void *bp)
418 image_item *a = *(image_item**)ap, *b = *(image_item**)bp;
419 return strcasecmp(a->name, b->name);
422 unsigned char* BC_Theme::get_image_data(const char *name, int log_errs)
424 // Image is the same as the last one
425 if( last_image && !strcasecmp(last_image->name, name) )
426 return last_image->data;
428 // look forwards thru data sets for name
430 for( int i=0,n=data_items.size(); i<n; ++i ) {
431 int end_item = start_item + data_items[i];
432 int r = end_item, l = start_item-1;
433 // binary search for image
437 image_item *item = images[m];
438 if( !(v=strcasecmp(name, item->name)) ) {
443 if( v > 0 ) l = m; else r = m;
445 start_item = end_item;
449 fprintf(stderr, _("Theme::get_image: %s not found.\n"), name);
453 void BC_Theme::check_used()
455 // Can't use because some images are gotten the old fashioned way.
458 for( int i=0; i<images.size(); ++i ) {
459 if( !images[i]->used ) {
460 if( !got_it ) printf(_("BC_Theme::check_used: Images aren't used.\n"));
461 printf("%s ", images[i]->name);
465 if( got_it ) printf("\n");
469 BC_ThemeSet::BC_ThemeSet(int total, int is_reference, const char *title)
472 this->title = new char[strlen(title) + 1];
473 strcpy(this->title, title);
474 this->is_reference = is_reference;
475 data = new VFrame*[total];
478 BC_ThemeSet::~BC_ThemeSet()
481 if( !is_reference ) {
482 for( int i = 0; i < total; i++ )