themes: Workaround for bug where a background color of RGB 0,0,0 in Black color schem...
[ntk.git] / src / Fl_Shared_Image.cxx
blob13598a9e2a9d222632e4e3c5662d06ca6649bb83
1 //
2 // "$Id: Fl_Shared_Image.cxx 8306 2011-01-24 17:04:22Z matt $"
3 //
4 // Shared image code for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2010 by Bill Spitzak and others.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 // USA.
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <FL/fl_utf8.h>
31 #include "flstring.h"
33 #include <FL/Fl.H>
34 #include <FL/Fl_Shared_Image.H>
35 #include <FL/Fl_XBM_Image.H>
36 #include <FL/Fl_XPM_Image.H>
40 // Global class vars...
43 Fl_Shared_Image **Fl_Shared_Image::images_ = 0; // Shared images
44 int Fl_Shared_Image::num_images_ = 0; // Number of shared images
45 int Fl_Shared_Image::alloc_images_ = 0; // Allocated shared images
47 Fl_Shared_Handler *Fl_Shared_Image::handlers_ = 0;// Additional format handlers
48 int Fl_Shared_Image::num_handlers_ = 0; // Number of format handlers
49 int Fl_Shared_Image::alloc_handlers_ = 0; // Allocated format handlers
53 // Typedef the C API sort function type the only way I know how...
56 extern "C" {
57 typedef int (*compare_func_t)(const void *, const void *);
61 /** Returns the Fl_Shared_Image* array */
62 Fl_Shared_Image **Fl_Shared_Image::images() {
63 return images_;
65 /** Returns the total number of shared images in the array. */
66 int Fl_Shared_Image::num_images() {
67 return num_images_;
72 // 'Fl_Shared_Image::compare()' - Compare two shared images...
75 int
76 Fl_Shared_Image::compare(Fl_Shared_Image **i0, // I - First image
77 Fl_Shared_Image **i1) { // I - Second image
78 int i = strcmp((*i0)->name(), (*i1)->name());
80 if (i) return i;
81 else if (((*i0)->w() == 0 && (*i1)->original_) ||
82 ((*i1)->w() == 0 && (*i0)->original_)) return 0;
83 else if ((*i0)->w() != (*i1)->w()) return (*i0)->w() - (*i1)->w();
84 else return (*i0)->h() - (*i1)->h();
88 /**
89 Creates an empty shared image.
90 The constructors create a new shared image record in the image cache.
92 <P>The constructors are protected and cannot be used directly
93 from a program. Use the get() method instead.
95 Fl_Shared_Image::Fl_Shared_Image() : Fl_Image(0,0,0) {
96 name_ = 0;
97 refcount_ = 1;
98 original_ = 0;
99 image_ = 0;
100 alloc_image_ = 0;
104 /**
105 Creates a shared image from its filename and its corresponding Fl_Image* img.
106 The constructors create a new shared image record in the image cache.
108 <P>The constructors are protected and cannot be used directly
109 from a program. Use the get() method instead.
111 Fl_Shared_Image::Fl_Shared_Image(const char *n, // I - Filename
112 Fl_Image *img) // I - Image
113 : Fl_Image(0,0,0) {
114 name_ = new char[strlen(n) + 1];
115 strcpy((char *)name_, n);
117 refcount_ = 1;
118 image_ = img;
119 alloc_image_ = !img;
120 original_ = 1;
122 if (!img) reload();
123 else update();
128 // 'Fl_Shared_Image::add()' - Add a shared image to the array.
131 void
132 Fl_Shared_Image::add() {
133 Fl_Shared_Image **temp; // New image pointer array...
135 if (num_images_ >= alloc_images_) {
136 // Allocate more memory...
137 temp = new Fl_Shared_Image *[alloc_images_ + 32];
139 if (alloc_images_) {
140 memcpy(temp, images_, alloc_images_ * sizeof(Fl_Shared_Image *));
142 delete[] images_;
145 images_ = temp;
146 alloc_images_ += 32;
149 images_[num_images_] = this;
150 num_images_ ++;
152 if (num_images_ > 1) {
153 qsort(images_, num_images_, sizeof(Fl_Shared_Image *),
154 (compare_func_t)compare);
160 // 'Fl_Shared_Image::update()' - Update the dimensions of the shared images.
163 void
164 Fl_Shared_Image::update() {
165 if (image_) {
166 w(image_->w());
167 h(image_->h());
168 d(image_->d());
169 data(image_->data(), image_->count());
174 The destructor free all memory and server resources that are
175 used by the image. The destructor is protected and cannot be
176 used directly from a program. Use the Fl_Shared_Image::release() method
177 instead.
179 Fl_Shared_Image::~Fl_Shared_Image() {
180 if (name_) delete[] (char *)name_;
181 if (alloc_image_) delete image_;
186 /**
187 Releases and possibly destroys (if refcount <=0) a shared image.
188 In the latter case, it will reorganize the shared image array so that no hole will occur.
190 void Fl_Shared_Image::release() {
191 int i; // Looping var...
193 refcount_ --;
194 if (refcount_ > 0) return;
196 for (i = 0; i < num_images_; i ++)
197 if (images_[i] == this) {
198 num_images_ --;
200 if (i < num_images_) {
201 memmove(images_ + i, images_ + i + 1,
202 (num_images_ - i) * sizeof(Fl_Shared_Image *));
205 break;
208 delete this;
210 if (num_images_ == 0 && images_) {
211 delete[] images_;
213 images_ = 0;
214 alloc_images_ = 0;
220 /** Reloads the shared image from disk */
221 void Fl_Shared_Image::reload() {
222 // Load image from disk...
223 int i; // Looping var
224 FILE *fp; // File pointer
225 uchar header[64]; // Buffer for auto-detecting files
226 Fl_Image *img; // New image
228 if (!name_) return;
230 if ((fp = fl_fopen(name_, "rb")) != NULL) {
231 if (fread(header, 1, sizeof(header), fp)==0) { /* ignore */ }
232 fclose(fp);
233 } else {
234 return;
237 // Load the image as appropriate...
238 if (memcmp(header, "#define", 7) == 0) // XBM file
239 img = new Fl_XBM_Image(name_);
240 else if (memcmp(header, "/* XPM */", 9) == 0) // XPM file
241 img = new Fl_XPM_Image(name_);
242 else {
243 // Not a standard format; try an image handler...
244 for (i = 0, img = 0; i < num_handlers_; i ++) {
245 img = (handlers_[i])(name_, header, sizeof(header));
247 if (img) break;
251 if (img) {
252 if (alloc_image_) delete image_;
254 alloc_image_ = 1;
256 if ((img->w() != w() && w()) || (img->h() != h() && h())) {
257 // Make sure the reloaded image is the same size as the existing one.
258 Fl_Image *temp = img->copy(w(), h());
259 delete img;
260 image_ = temp;
261 } else {
262 image_ = img;
265 update();
271 // 'Fl_Shared_Image::copy()' - Copy and resize a shared image...
274 Fl_Image *
275 Fl_Shared_Image::copy(int W, int H) {
276 Fl_Image *temp_image; // New image file
277 Fl_Shared_Image *temp_shared; // New shared image
279 // Make a copy of the image we're sharing...
280 if (!image_) temp_image = 0;
281 else temp_image = image_->copy(W, H);
283 // Then make a new shared image...
284 temp_shared = new Fl_Shared_Image();
286 temp_shared->name_ = new char[strlen(name_) + 1];
287 strcpy((char *)temp_shared->name_, name_);
289 temp_shared->refcount_ = 1;
290 temp_shared->image_ = temp_image;
291 temp_shared->alloc_image_ = 1;
293 temp_shared->update();
295 return temp_shared;
300 // 'Fl_Shared_Image::color_average()' - Blend colors...
303 void
304 Fl_Shared_Image::color_average(Fl_Color c, // I - Color to blend with
305 float i) { // I - Blend fraction
306 if (!image_) return;
308 image_->color_average(c, i);
309 update();
314 // 'Fl_Shared_Image::desaturate()' - Convert the image to grayscale...
317 void
318 Fl_Shared_Image::desaturate() {
319 if (!image_) return;
321 image_->desaturate();
322 update();
327 // 'Fl_Shared_Image::draw()' - Draw a shared image...
330 void
331 Fl_Shared_Image::draw(int X, int Y, int W, int H, int cx, int cy) {
332 if (image_) image_->draw(X, Y, W, H, cx, cy);
333 else Fl_Image::draw(X, Y, W, H, cx, cy);
338 // 'Fl_Shared_Image::uncache()' - Uncache the shared image...
341 void Fl_Shared_Image::uncache()
343 if (image_) image_->uncache();
348 /** Finds a shared image from its named and size specifications */
349 Fl_Shared_Image* Fl_Shared_Image::find(const char *n, int W, int H) {
350 Fl_Shared_Image *key, // Image key
351 **match; // Matching image
353 if (num_images_) {
354 key = new Fl_Shared_Image();
355 key->name_ = new char[strlen(n) + 1];
356 strcpy((char *)key->name_, n);
357 key->w(W);
358 key->h(H);
360 match = (Fl_Shared_Image **)bsearch(&key, images_, num_images_,
361 sizeof(Fl_Shared_Image *),
362 (compare_func_t)compare);
364 delete key;
366 if (match) {
367 (*match)->refcount_ ++;
368 return *match;
372 return 0;
376 /**
377 \brief Find or load an image that can be shared by multiple widgets.
379 Gets a shared image, if it exists already ; it will return it.
380 If it does not exist or if it exist but with other size,
381 then the existing image is deleted and replaced
382 by a new image from the n filename of the proper dimension.
383 If n is not a valid image filename, then get() will return NULL.
385 Shared JPEG and PNG images can also be created from memory by using their
386 named memory access constructor.
388 \param n name of the image
389 \param W, H desired size
391 \see Fl_Shared_Image::find(const char *n, int W, int H)
392 \see Fl_Shared_Image::release()
393 \see Fl_JPEG_Image::Fl_JPEG_Image(const char *name, const unsigned char *data)
394 \see Fl_PNG_Image::Fl_PNG_Image (const char *name_png, const unsigned char *buffer, int maxsize)
396 Fl_Shared_Image* Fl_Shared_Image::get(const char *n, int W, int H) {
397 Fl_Shared_Image *temp; // Image
399 if ((temp = find(n, W, H)) != NULL) return temp;
401 if ((temp = find(n)) == NULL) {
402 temp = new Fl_Shared_Image(n);
404 if (!temp->image_) {
405 delete temp;
406 return NULL;
409 temp->add();
412 if ((temp->w() != W || temp->h() != H) && W && H) {
413 temp = (Fl_Shared_Image *)temp->copy(W, H);
414 temp->add();
417 return temp;
422 /** Adds a shared image handler, which is basically a test function for adding new formats */
423 void Fl_Shared_Image::add_handler(Fl_Shared_Handler f) {
424 int i; // Looping var...
425 Fl_Shared_Handler *temp; // New image handler array...
427 // First see if we have already added the handler...
428 for (i = 0; i < num_handlers_; i ++) {
429 if (handlers_[i] == f) return;
432 if (num_handlers_ >= alloc_handlers_) {
433 // Allocate more memory...
434 temp = new Fl_Shared_Handler [alloc_handlers_ + 32];
436 if (alloc_handlers_) {
437 memcpy(temp, handlers_, alloc_handlers_ * sizeof(Fl_Shared_Handler));
439 delete[] handlers_;
442 handlers_ = temp;
443 alloc_handlers_ += 32;
446 handlers_[num_handlers_] = f;
447 num_handlers_ ++;
452 /** Removes a shared image handler */
453 void Fl_Shared_Image::remove_handler(Fl_Shared_Handler f) {
454 int i; // Looping var...
456 // First see if the handler has been added...
457 for (i = 0; i < num_handlers_; i ++) {
458 if (handlers_[i] == f) break;
461 if (i >= num_handlers_) return;
463 // OK, remove the handler from the array...
464 num_handlers_ --;
466 if (i < num_handlers_) {
467 // Shift later handlers down 1...
468 memmove(handlers_ + i, handlers_ + i + 1,
469 (num_handlers_ - i) * sizeof(Fl_Shared_Handler ));
475 // End of "$Id: Fl_Shared_Image.cxx 8306 2011-01-24 17:04:22Z matt $".