1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
|
//
// Tiled image code for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2022 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
// file is missing or damaged, see the license at:
//
// https://www.fltk.org/COPYING.php
//
// Please see the following page on how to report bugs and issues:
//
// https://www.fltk.org/bugs.php
//
#include <FL/Fl.H>
#include <FL/Fl_Tiled_Image.H>
#include <FL/Fl_Window.H>
#include <FL/fl_draw.H>
/**
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() initializes the window's label type and image.
A possible workaround is to use another Fl_Group as the only child widget
and to 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
int H) : // I - Height of tiled area
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());
}
/**
The destructor frees all memory and server resources that are used by
the tiled image.
*/
Fl_Tiled_Image::~Fl_Tiled_Image() {
if (alloc_image_) delete image_;
}
//
// 'Fl_Tiled_Image::copy()' - Copy and resize a tiled image...
//
Fl_Image * // O - New image
Fl_Tiled_Image::copy(int W, // I - New width
int H) const { // I - New height
return new Fl_Tiled_Image(image_, W, H);
}
//
// 'Fl_Tiled_Image::color_average()' - Blend colors...
//
void
Fl_Tiled_Image::color_average(Fl_Color c, // I - Color to blend with
float i) { // I - Blend fraction
if (!alloc_image_) {
int W = image_->w(), H = image_->h();
image_ = image_->copy(image_->data_w(), image_->data_h());
image_->scale(W, H, 0, 1);
alloc_image_ = 1;
}
image_->color_average(c, i);
}
//
// 'Fl_Tiled_Image::desaturate()' - Convert the image to grayscale...
//
void
Fl_Tiled_Image::desaturate() {
if (!alloc_image_) {
int W = image_->w(), H = image_->h();
image_ = image_->copy(image_->data_w(), image_->data_h());
image_->scale(W, H, 0, 1);
alloc_image_ = 1;
}
image_->desaturate();
}
//
// '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 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. (\p 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 W and \p H 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, then you should
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
int W, // I - Width of area to be filled
int H, // I - Height of area to be filled
int cx, // I - "Source" X position
int cy) { // I - "Source" Y position
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;
}
if (W == 0 || H == 0) return;
fl_push_clip(X, Y, W, H);
if (cx > 0) iw -= cx; // crop image
if (cy > 0) ih -= cy;
int yy;
for (yy = Y; yy < Y+H; yy += ih) {
if (fl_not_clipped(X,yy,W,ih)) {
int xx;
for (xx = X; xx < X+W; xx += iw) {
if (fl_not_clipped(xx,yy,iw,ih)) {
image_->draw(xx,yy,iw,ih,cx,cy);
}
}
}
}
fl_pop_clip();
}
|