diff options
Diffstat (limited to 'src/Fl_Tiled_Image.cxx')
| -rw-r--r-- | src/Fl_Tiled_Image.cxx | 115 |
1 files changed, 94 insertions, 21 deletions
diff --git a/src/Fl_Tiled_Image.cxx b/src/Fl_Tiled_Image.cxx index 4d88cf8bc..7dcfd2cbc 100644 --- a/src/Fl_Tiled_Image.cxx +++ b/src/Fl_Tiled_Image.cxx @@ -3,7 +3,7 @@ // // Tiled image code for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2010 by Bill Spitzak and others. +// Copyright 1998-2015 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -25,6 +25,36 @@ /** The constructors create a new tiled image containing the specified image. Use a width and height of 0 to tile the whole window/widget. + + \note Due to implementation constraints in FLTK 1.3.3 and later width + and height of 0 may not work as expected when used as background image + in widgets other than windows. + + You may need to center and clip the image (label) and set the label type + to FL_NORMAL_LABEL. Doing so will let the tiled image fill the whole + widget as its background image. Other combinations of label flags may + or may not work. + + \code + #include "bg.xpm" + Fl_Pixmap *bg_xpm = new Fl_Pixmap(bg_xpm); + Fl_Tiled_Image *bg_tiled = new Fl_Tiled_Image(bg_xpm,0,0); + + Fl_Box *box = new Fl_Box(40,40,300,100,""); + box->box(FL_UP_BOX); + box->labeltype(FL_NORMAL_LABEL); + box->align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER | FL_ALIGN_CLIP); + box->image(bg_tiled); + \endcode + + \note Setting an image (label) for a window may not work as expected due + to implementation constraints in FLTK 1.3.x and maybe later. The reason + is the way Fl::scheme() is initializing the window's label type and image. + A workaround is to use another Fl_Group as the only child widget and set + the background image for this group as described above. + + \todo Fix Fl_Tiled_Image as background image for widgets and windows, + and fix the implementation of Fl::scheme(const char *). */ Fl_Tiled_Image::Fl_Tiled_Image(Fl_Image *i, // I - Image to tile int W, // I - Width of tiled area @@ -32,10 +62,11 @@ Fl_Tiled_Image::Fl_Tiled_Image(Fl_Image *i, // I - Image to tile Fl_Image(W,H,0) { image_ = i; alloc_image_ = 0; - // giving to the tiled image the screen size may fail with multiscreen configurations - // so we leave it with w = h = 0 (STR #3106) - /* if (W == 0) w(Fl::w()); - if (H == 0) h(Fl::h());*/ + + // giving to the tiled image the screen size may fail with multiscreen + // configurations, so we leave it with w = h = 0 (STR #3106) + // if (W == 0) w(Fl::w()); + // if (H == 0) h(Fl::h()); } /** The destructor frees all memory and server resources that are used by @@ -90,9 +121,36 @@ Fl_Tiled_Image::desaturate() { // -// 'Fl_Tiled_Image::draw()' - Draw a shared image... +// 'Fl_Tiled_Image::draw()' - Draw a tiled image. // +/** + Draws a tiled image. + + Tiled images can be used as background images for widgets and windows. + However, due to some implementation constraints, you must take care when + setting label types and alignment flags. Only certain combinations work as + expected, others may yield unexpected results and undefined behavior. + + This draw method can draw multiple copies of one image in an area given + by \p X, \p Y, \p W, \p H. + The optional arguments \p cx and \p cy can be used to crop the image + starting at offsets (cx, cy). \p cx and \p cy must be \>= 0 (negative values + are ignored). If one of the values is greater than the image width or height + resp. (\b cx \>= image()->w() or \p cy \>= image()->h()) nothing is drawn, + because the resulting image would be empty. + + After calculating the resulting image size the image is drawn as often + as necessary to fill the given area, starting at the top left corner. + + If both \p X and \p Y are 0 the image is repeated as often as necessary + to fill the entire window, unless there is a valid clip region. If you + want to fill only one particular widget's background, make sure that you + either set a clip region in your draw() method or use the label alignment + flags \p FL_ALIGN_INSIDE|FL_ALIGN_CLIP to make sure the image is clipped. + + This may be improved in a later version of the library. +*/ void Fl_Tiled_Image::draw(int X, // I - Starting X position int Y, // I - Starting Y position @@ -100,28 +158,43 @@ Fl_Tiled_Image::draw(int X, // I - Starting X position int H, // I - Height of area to be filled int cx, // I - "Source" X position int cy) { // I - "Source" Y position - if (!image_->w() || !image_->h()) return; - if (W == 0 && H == 0 && Fl_Window::current()) { // W and H null means the image is potentially as large as the current window + + int iw = image_->w(); // effective image width + int ih = image_->h(); // effective image height + + if (!iw || !ih) return; + if (cx >= iw || cy >= ih) return; + + if (cx < 0) cx = 0; // ignore negative values + if (cy < 0) cy = 0; + + // W and H null means the image is potentially as large as the current window + // or widget. The latter can not be checked here, hence we use the whole + // window as well and rely on appropriate clipping. See comments above. + // This should be fixed! (AlbrechtS, 01 Mar 2015) + + if (W == 0 && H == 0 && Fl_Window::current()) { W = Fl_Window::current()->w(); H = Fl_Window::current()->h(); X = Y = 0; } - fl_push_clip(X, Y, W, H); - - X += cx; - Y += cy; - - X = X - (X % image_->w()); - Y = Y - (Y % image_->h()); - - W += X; - H += Y; + if (W == 0 || H == 0) return; - for (int yy = Y; yy < H; yy += image_->h()) - for (int xx = X; xx < W; xx += image_->w()) - image_->draw(xx, yy); + fl_push_clip(X, Y, W, H); + if (cx > 0) iw -= cx; // crop image + if (cy > 0) ih -= cy; + + for (int yy = Y; yy < H; yy += ih) { + if (fl_not_clipped(X,yy,W,ih)) { + for (int xx = X; xx < W; xx += iw) { + if (fl_not_clipped(xx,yy,iw,ih)) { + image_->draw(xx,yy,iw,ih,cx,cy); + } + } + } + } fl_pop_clip(); } |
