1 |
/* packer.hh |
2 |
* This file is part of ndk library |
3 |
* Copyright (c) 2003,2004 by Stanislav Ievlev |
4 |
* |
5 |
* This file is covered by the GNU Library General Public License, |
6 |
* which should be included with libndk as the file COPYING. |
7 |
*/ |
8 |
#ifndef NDK_PACKER_HH__ |
9 |
#define NDK_PACKER_HH__ |
10 |
|
11 |
#include <algorithm> |
12 |
#include <functional> |
13 |
#include <vector> |
14 |
|
15 |
#include <ndk/align.hh> |
16 |
#include <ndk/panel.hh> |
17 |
#include <ndk/support.hh> |
18 |
|
19 |
namespace ndk |
20 |
{ |
21 |
namespace pack /**< packer strategies */ |
22 |
{ |
23 |
struct vertical /**< vertical packing strategy */ |
24 |
{ |
25 |
static int align_coord (panel *p) |
26 |
{ |
27 |
return p->x (); |
28 |
} |
29 |
|
30 |
static int align_size (panel *p) |
31 |
{ |
32 |
return p->width (); |
33 |
} |
34 |
|
35 |
static void align_move (panel *p, int pos) |
36 |
{ |
37 |
p->move (pos, p->y (), absolute); |
38 |
} |
39 |
|
40 |
static void align_resize (panel *p, int size) |
41 |
{ |
42 |
const bool need_update = (p->width () != size); |
43 |
|
44 |
p->resize (size, p->height ()); |
45 |
if (need_update) |
46 |
p->draw (); |
47 |
} |
48 |
|
49 |
static int line_coord (panel *p) |
50 |
{ |
51 |
return p->y (); |
52 |
} |
53 |
|
54 |
static int line_size (panel *p) |
55 |
{ |
56 |
return p->height (); |
57 |
} |
58 |
|
59 |
static void line_move (panel *p, int pos) |
60 |
{ |
61 |
p->move (p->x (), pos, absolute); |
62 |
} |
63 |
|
64 |
static void resize (panel *p, int align_size, int line_size) |
65 |
{ |
66 |
p->resize (align_size, line_size); |
67 |
} |
68 |
}; |
69 |
|
70 |
struct horizontal /**< horizontal packing strategy */ |
71 |
{ |
72 |
static int align_coord (panel *p) |
73 |
{ |
74 |
return p->y (); |
75 |
} |
76 |
|
77 |
static int align_size (panel *p) |
78 |
{ |
79 |
return p->height (); |
80 |
} |
81 |
|
82 |
static void align_move (panel *p, int pos) |
83 |
{ |
84 |
p->move (p->x (), pos, absolute); |
85 |
} |
86 |
|
87 |
static void align_resize (panel *p, int size) |
88 |
{ |
89 |
const bool need_update = (p->height () != size); |
90 |
|
91 |
p->resize (p->width (), size); |
92 |
if (need_update) |
93 |
p->draw (); |
94 |
} |
95 |
|
96 |
static int line_coord (panel *p) |
97 |
{ |
98 |
return p->x (); |
99 |
} |
100 |
|
101 |
static int line_size (panel *p) |
102 |
{ |
103 |
return p->width (); |
104 |
} |
105 |
|
106 |
static void line_move (panel *p, int pos) |
107 |
{ |
108 |
p->move (pos, p->y (), absolute); |
109 |
} |
110 |
|
111 |
static void resize (panel *p, int align_size, int line_size) |
112 |
{ |
113 |
p->resize (line_size, align_size); |
114 |
} |
115 |
}; |
116 |
|
117 |
template<class T> |
118 |
struct def_resizer /**< default resize policy for the packer object */ |
119 |
{ |
120 |
static void fix_item (panel *p, int, int pos) |
121 |
{ |
122 |
T::align_move (p, pos); |
123 |
} |
124 |
|
125 |
static void fix_panel (panel *p, int align_size, int line_size) |
126 |
{ |
127 |
T::resize (p, align_size, line_size); |
128 |
} |
129 |
|
130 |
static void draw (panel *p) |
131 |
{ |
132 |
p->draw (); |
133 |
} |
134 |
}; |
135 |
|
136 |
template<class T> |
137 |
struct no_resizer /**< * this policy don't made resize of the object */ |
138 |
{ |
139 |
static void fix_item (panel *p, int size, int pos) |
140 |
{ |
141 |
T::align_move (p, pos); |
142 |
T::align_resize (p, size); |
143 |
} |
144 |
|
145 |
static void fix_panel (panel *, int, int) |
146 |
{ |
147 |
} |
148 |
|
149 |
static void draw (panel *) |
150 |
{ |
151 |
} |
152 |
}; |
153 |
} |
154 |
|
155 |
template<class T> |
156 |
bool |
157 |
wider_panel (panel *p1, panel *p2) |
158 |
{ |
159 |
/**< compare panels, who is wider */ |
160 |
return T::align_size (p1) < T::align_size (p2); |
161 |
} |
162 |
|
163 |
/** |
164 |
* general template to the auto packer/aligner of widgets |
165 |
* packer algorithm: |
166 |
* with resizer: |
167 |
* 1. find widget with maximum size (max) |
168 |
* 2. main widget size is max + 2*padding |
169 |
* 3. align all widgets and place it with begining from padding |
170 |
* 4. resize main to size max + 2*padding, and total widgets length+2*padding |
171 |
* without resizer: |
172 |
* 1. find widget with maximum size |
173 |
* 2. align all widgets, according max widget size and with begining from padding |
174 |
* 3. resize all widgets to the "main - 2*padding" if we need it |
175 |
*/ |
176 |
template<class T, template<class> class resizer = pack::def_resizer> |
177 |
class packer |
178 |
{ |
179 |
typedef std::vector<panel *> widget_vector; |
180 |
typedef resizer<T> resizer_type; |
181 |
|
182 |
public: |
183 |
packer (panel *main, align::type alignment, int padding = 0) |
184 |
: main_ (main) |
185 |
, padding_ (padding) |
186 |
, align_ (alignment) |
187 |
{ |
188 |
} |
189 |
|
190 |
void add (panel *item) |
191 |
{ |
192 |
widgets_.push_back (item); |
193 |
resizer_type::draw (item); /* in auto resize method we need to draw widgets to know it's real sizes */ |
194 |
} |
195 |
|
196 |
void pack () /**< move and align widgets */ |
197 |
{ |
198 |
if (widgets_.empty ()) |
199 |
return; |
200 |
|
201 |
/* first made alignment */ |
202 |
widget_vector::const_iterator max_item = |
203 |
std::max_element (widgets_.begin (), widgets_.end (), wider_panel<T> ); |
204 |
const int align_size = T::align_size (*max_item) + main_->padding () * 2; |
205 |
foreach (panel *widget, widgets_) |
206 |
do_align (widget, T::align_size (*max_item)); |
207 |
|
208 |
int pos = main_->padding (); |
209 |
foreach (panel *widget, widgets_) |
210 |
do_move (widget, pos); |
211 |
const int line_size = pos - padding_ + main_->padding (); |
212 |
|
213 |
resizer_type::fix_panel (main_, align_size, line_size); /* try to fix size of the panel */ |
214 |
} |
215 |
|
216 |
private: |
217 |
void do_align (panel *p, int max) /**< align panel's possition according current aligment */ |
218 |
{ |
219 |
resizer_type::fix_item (p, T::align_size (main_) - 2 * main_->padding (), |
220 |
T::align_coord (main_) + |
221 |
main_->padding () + |
222 |
align::pos (T::align_size (p), max, align_)); |
223 |
} |
224 |
|
225 |
void do_move (panel *p, int &pos) /**< move next item according current packing */ |
226 |
{ |
227 |
T::line_move (p, T::line_coord (main_) + pos); |
228 |
pos += T::line_size (p) + padding_; |
229 |
} |
230 |
|
231 |
widget_vector widgets_; /**< widgets to pack */ |
232 |
panel *main_; /**< main widget, we will try to place all widgets under it*/ |
233 |
int padding_; /**< size of empty area between widgets on the line */ |
234 |
align::type align_; /**< aligment of the widgets */ |
235 |
}; |
236 |
|
237 |
typedef packer<pack::horizontal> horizontal_packer; |
238 |
typedef packer<pack::vertical> vertical_packer; |
239 |
} |
240 |
|
241 |
#endif |