diff options
author | Mark Tiefenbruck <mark@fluxbox.org> | 2007-12-28 05:47:55 (GMT) |
---|---|---|
committer | Mark Tiefenbruck <mark@fluxbox.org> | 2007-12-28 05:47:55 (GMT) |
commit | e8a2f155e8d5a082a8c04f291e65c137c20a05cb (patch) | |
tree | 4107154a6c73d518b604aab43371c994ae172624 /src/FbTk/Container.cc | |
parent | 00ceefd8846bda6f4dc43a5a990086545ea28727 (diff) | |
download | fluxbox-e8a2f155e8d5a082a8c04f291e65c137c20a05cb.zip fluxbox-e8a2f155e8d5a082a8c04f291e65c137c20a05cb.tar.bz2 |
moved Container to FbTk
Diffstat (limited to 'src/FbTk/Container.cc')
-rw-r--r-- | src/FbTk/Container.cc | 524 |
1 files changed, 524 insertions, 0 deletions
diff --git a/src/FbTk/Container.cc b/src/FbTk/Container.cc new file mode 100644 index 0000000..9da25c6 --- /dev/null +++ b/src/FbTk/Container.cc | |||
@@ -0,0 +1,524 @@ | |||
1 | // Container.cc | ||
2 | // Copyright (c) 2003 - 2006 Henrik Kinnunen (fluxgen at fluxbox dot org) | ||
3 | // and Simon Bowden (rathnor at users.sourceforge.net) | ||
4 | // | ||
5 | // Permission is hereby granted, free of charge, to any person obtaining a | ||
6 | // copy of this software and associated documentation files (the "Software"), | ||
7 | // to deal in the Software without restriction, including without limitation | ||
8 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
9 | // and/or sell copies of the Software, and to permit persons to whom the | ||
10 | // Software is furnished to do so, subject to the following conditions: | ||
11 | // | ||
12 | // The above copyright notice and this permission notice shall be included in | ||
13 | // all copies or substantial portions of the Software. | ||
14 | // | ||
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | // DEALINGS IN THE SOFTWARE. | ||
22 | |||
23 | #include "Container.hh" | ||
24 | |||
25 | #include "Button.hh" | ||
26 | #include "EventManager.hh" | ||
27 | #include "CompareEqual.hh" | ||
28 | |||
29 | #include <algorithm> | ||
30 | |||
31 | namespace FbTk { | ||
32 | |||
33 | typedef CompareEqual_base<FbWindow, Window> CompareWindow; | ||
34 | |||
35 | Container::Container(const FbWindow &parent): | ||
36 | FbWindow(parent, 0, 0, 1, 1, ExposureMask), | ||
37 | m_orientation(ROT0), | ||
38 | m_align(RELATIVE), | ||
39 | m_max_size_per_client(60), | ||
40 | m_max_total_size(0), | ||
41 | m_update_lock(false) { | ||
42 | EventManager::instance()->add(*this, *this); | ||
43 | } | ||
44 | |||
45 | Container::~Container() { | ||
46 | // ~FbWindow cleans event manager | ||
47 | } | ||
48 | |||
49 | void Container::resize(unsigned int width, unsigned int height) { | ||
50 | // do we need to resize? | ||
51 | if (FbWindow::width() == width && | ||
52 | FbWindow::height() == height) | ||
53 | return; | ||
54 | |||
55 | FbWindow::resize(width, height); | ||
56 | repositionItems(); | ||
57 | } | ||
58 | |||
59 | void Container::moveResize(int x, int y, | ||
60 | unsigned int width, unsigned int height) { | ||
61 | FbWindow::moveResize(x, y, width, height); | ||
62 | repositionItems(); | ||
63 | } | ||
64 | |||
65 | #ifdef NOT_USED | ||
66 | void Container::insertItems(ItemList &item_list, int pos) { | ||
67 | |||
68 | // make sure all items have parent == this | ||
69 | ItemList::iterator it = m_item_list.begin(); | ||
70 | ItemList::iterator it_end = m_item_list.end(); | ||
71 | for (; it != it_end; ++it) { | ||
72 | if ((*it)->parent() != this) | ||
73 | return; | ||
74 | } | ||
75 | |||
76 | if (pos > size() || pos < 0) { | ||
77 | // insert last | ||
78 | m_item_list.splice(m_item_list.end(), item_list); | ||
79 | } else if (pos == 0) { | ||
80 | // insert first | ||
81 | m_item_list.splice(m_item_list.begin(), item_list); | ||
82 | } else { | ||
83 | // find insert point | ||
84 | for (it = m_item_list.begin(); pos != 0; ++it, --pos) | ||
85 | continue; | ||
86 | m_item_list.splice(it, item_list); | ||
87 | } | ||
88 | |||
89 | m_item_list.unique(); | ||
90 | |||
91 | // update position | ||
92 | repositionItems(); | ||
93 | } | ||
94 | #endif | ||
95 | |||
96 | void Container::insertItem(Item item, int pos) { | ||
97 | if (find(item) != -1) | ||
98 | return; | ||
99 | |||
100 | // it must be a child of this window | ||
101 | if (item->parent() != this) | ||
102 | return; | ||
103 | |||
104 | item->setOrientation(m_orientation); | ||
105 | if (pos >= size() || pos < 0) { | ||
106 | m_item_list.push_back(item); | ||
107 | } else if (pos == 0) { | ||
108 | m_item_list.push_front(item); | ||
109 | } else { | ||
110 | ItemList::iterator it = m_item_list.begin(); | ||
111 | for (; pos != 0; ++it, --pos) | ||
112 | continue; | ||
113 | |||
114 | m_item_list.insert(it, item); | ||
115 | } | ||
116 | |||
117 | // make sure we dont have duplicate items | ||
118 | m_item_list.unique(); | ||
119 | |||
120 | repositionItems(); | ||
121 | } | ||
122 | |||
123 | void Container::moveItem(Item item, int movement) { | ||
124 | |||
125 | int index = find(item); | ||
126 | const size_t size = m_item_list.size(); | ||
127 | |||
128 | if (index < 0 || (movement % static_cast<signed>(size)) == 0) { | ||
129 | return; | ||
130 | } | ||
131 | |||
132 | int newindex = (index + movement) % static_cast<signed>(size); | ||
133 | if (newindex < 0) // neg wrap | ||
134 | newindex += size; | ||
135 | |||
136 | ItemList::iterator it = std::find(m_item_list.begin(), | ||
137 | m_item_list.end(), | ||
138 | item); | ||
139 | m_item_list.erase(it); | ||
140 | |||
141 | for (it = m_item_list.begin(); newindex >= 0; ++it, --newindex) { | ||
142 | if (newindex == 0) { | ||
143 | break; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | m_item_list.insert(it, item); | ||
148 | repositionItems(); | ||
149 | } | ||
150 | |||
151 | // returns true if something was done | ||
152 | bool Container::moveItemTo(Item item, int x, int y) { | ||
153 | Window parent_return=0, | ||
154 | root_return=0, | ||
155 | *children_return = NULL; | ||
156 | |||
157 | unsigned int nchildren_return; | ||
158 | |||
159 | // get the root window | ||
160 | if (!XQueryTree(display(), window(), | ||
161 | &root_return, &parent_return, &children_return, &nchildren_return)) | ||
162 | parent_return = parent_return; | ||
163 | |||
164 | if (children_return != NULL) | ||
165 | XFree(children_return); | ||
166 | |||
167 | int dest_x = 0, dest_y = 0; | ||
168 | Window itemwin = 0; | ||
169 | if (!XTranslateCoordinates(display(), | ||
170 | root_return, window(), | ||
171 | x, y, &dest_x, &dest_y, | ||
172 | &itemwin)) | ||
173 | return false; | ||
174 | |||
175 | ItemList::iterator it = find_if(m_item_list.begin(), | ||
176 | m_item_list.end(), | ||
177 | CompareWindow(&FbWindow::window, | ||
178 | itemwin)); | ||
179 | // not found :( | ||
180 | if (it == m_item_list.end()) | ||
181 | return false; | ||
182 | |||
183 | Window child_return = 0; | ||
184 | //make x and y relative to our item | ||
185 | if (!XTranslateCoordinates(display(), | ||
186 | window(), itemwin, | ||
187 | dest_x, dest_y, &x, &y, | ||
188 | &child_return)) | ||
189 | return false; | ||
190 | return true; | ||
191 | } | ||
192 | |||
193 | bool Container::removeItem(Item item) { | ||
194 | ItemList::iterator it = m_item_list.begin(); | ||
195 | ItemList::iterator it_end = m_item_list.end(); | ||
196 | for (; it != it_end && (*it) != item; ++it); | ||
197 | |||
198 | if (it == it_end) | ||
199 | return false; | ||
200 | |||
201 | m_item_list.erase(it); | ||
202 | repositionItems(); | ||
203 | return true; | ||
204 | } | ||
205 | |||
206 | bool Container::removeItem(int index) { | ||
207 | if (index < 0 || index > size()) | ||
208 | return false; | ||
209 | |||
210 | ItemList::iterator it = m_item_list.begin(); | ||
211 | for (; index != 0; ++it, --index) | ||
212 | continue; | ||
213 | |||
214 | m_item_list.erase(it); | ||
215 | |||
216 | repositionItems(); | ||
217 | return true; | ||
218 | } | ||
219 | |||
220 | void Container::removeAll() { | ||
221 | m_item_list.clear(); | ||
222 | if (!m_update_lock) { | ||
223 | clear(); | ||
224 | } | ||
225 | |||
226 | } | ||
227 | |||
228 | int Container::find(ConstItem item) { | ||
229 | ItemList::iterator it = m_item_list.begin(); | ||
230 | ItemList::iterator it_end = m_item_list.end(); | ||
231 | int index = 0; | ||
232 | for (; it != it_end; ++it, ++index) { | ||
233 | if ((*it) == item) | ||
234 | break; | ||
235 | } | ||
236 | |||
237 | if (it == it_end) | ||
238 | return -1; | ||
239 | |||
240 | return index; | ||
241 | } | ||
242 | |||
243 | void Container::setMaxSizePerClient(unsigned int size) { | ||
244 | if (size != m_max_size_per_client) { | ||
245 | m_max_size_per_client = size; | ||
246 | repositionItems(); | ||
247 | } | ||
248 | } | ||
249 | |||
250 | void Container::setMaxTotalSize(unsigned int size) { | ||
251 | if (m_max_total_size == size) | ||
252 | return; | ||
253 | |||
254 | m_max_total_size = size; | ||
255 | |||
256 | repositionItems(); | ||
257 | return; | ||
258 | } | ||
259 | |||
260 | void Container::setAlignment(Container::Alignment a) { | ||
261 | m_align = a; | ||
262 | } | ||
263 | |||
264 | void Container::exposeEvent(XExposeEvent &event) { | ||
265 | if (!m_update_lock) { | ||
266 | clearArea(event.x, event.y, event.width, event.height); | ||
267 | } | ||
268 | } | ||
269 | |||
270 | bool Container::tryExposeEvent(XExposeEvent &event) { | ||
271 | if (event.window == window()) { | ||
272 | exposeEvent(event); | ||
273 | return true; | ||
274 | } | ||
275 | |||
276 | ItemList::iterator it = find_if(m_item_list.begin(), | ||
277 | m_item_list.end(), | ||
278 | CompareWindow(&FbWindow::window, | ||
279 | event.window)); | ||
280 | // not found :( | ||
281 | if (it == m_item_list.end()) | ||
282 | return false; | ||
283 | |||
284 | (*it)->exposeEvent(event); | ||
285 | return true; | ||
286 | } | ||
287 | |||
288 | bool Container::tryButtonPressEvent(XButtonEvent &event) { | ||
289 | if (event.window == window()) { | ||
290 | // we don't have a buttonrelease event atm | ||
291 | return true; | ||
292 | } | ||
293 | |||
294 | ItemList::iterator it = find_if(m_item_list.begin(), | ||
295 | m_item_list.end(), | ||
296 | CompareWindow(&FbWindow::window, | ||
297 | event.window)); | ||
298 | // not found :( | ||
299 | if (it == m_item_list.end()) | ||
300 | return false; | ||
301 | |||
302 | (*it)->buttonPressEvent(event); | ||
303 | return true; | ||
304 | } | ||
305 | |||
306 | bool Container::tryButtonReleaseEvent(XButtonEvent &event) { | ||
307 | if (event.window == window()) { | ||
308 | // we don't have a buttonrelease event atm | ||
309 | return true; | ||
310 | } | ||
311 | |||
312 | ItemList::iterator it = find_if(m_item_list.begin(), | ||
313 | m_item_list.end(), | ||
314 | CompareWindow(&FbWindow::window, | ||
315 | event.window)); | ||
316 | // not found :( | ||
317 | if (it == m_item_list.end()) | ||
318 | return false; | ||
319 | |||
320 | (*it)->buttonReleaseEvent(event); | ||
321 | return true; | ||
322 | } | ||
323 | |||
324 | void Container::repositionItems() { | ||
325 | if (empty() || m_update_lock) | ||
326 | return; | ||
327 | |||
328 | /** | ||
329 | NOTE: all calculations here are done in non-rotated space | ||
330 | */ | ||
331 | |||
332 | unsigned int max_width_per_client = maxWidthPerClient(); | ||
333 | unsigned int borderW = m_item_list.front()->borderWidth(); | ||
334 | size_t num_items = m_item_list.size(); | ||
335 | |||
336 | unsigned int total_width; | ||
337 | unsigned int cur_width; | ||
338 | unsigned int height; | ||
339 | |||
340 | // unrotate | ||
341 | if (m_orientation == ROT0 || m_orientation == ROT180) { | ||
342 | total_width = cur_width = width(); | ||
343 | height = this->height(); | ||
344 | } else { | ||
345 | total_width = cur_width = this->height(); | ||
346 | height = width(); | ||
347 | } | ||
348 | |||
349 | // if we have a max total size, then we must also resize ourself | ||
350 | // within that bound | ||
351 | Alignment align = alignment(); | ||
352 | if (m_max_total_size && (align == RIGHT || align == LEFT)) { | ||
353 | total_width = (max_width_per_client + borderW) * num_items - borderW; | ||
354 | if (total_width > m_max_total_size) { | ||
355 | total_width = m_max_total_size; | ||
356 | if (m_max_total_size > ((num_items - 1)*borderW)) { // don't go negative with unsigned nums | ||
357 | max_width_per_client = ( m_max_total_size - (num_items - 1)*borderW ) / num_items; | ||
358 | } else | ||
359 | max_width_per_client = 1; | ||
360 | } | ||
361 | if (total_width != cur_width) { | ||
362 | // calling Container::resize here risks infinite loops | ||
363 | unsigned int neww = total_width, newh = height; | ||
364 | translateSize(m_orientation, neww, newh); | ||
365 | if (align == RIGHT && m_orientation != ROT270 || align == LEFT && m_orientation == ROT270) { | ||
366 | int deltax = 0; | ||
367 | int deltay = 0; | ||
368 | if (m_orientation == ROT0 || m_orientation == ROT180) | ||
369 | deltax = - (total_width - cur_width); | ||
370 | else | ||
371 | deltay = - (total_width - cur_width); | ||
372 | |||
373 | FbWindow::moveResize(x() + deltax, y() + deltay, neww, newh); | ||
374 | } else { | ||
375 | FbWindow::resize(neww, newh); | ||
376 | } | ||
377 | } | ||
378 | } | ||
379 | |||
380 | |||
381 | ItemList::iterator it = m_item_list.begin(); | ||
382 | const ItemList::iterator it_end = m_item_list.end(); | ||
383 | |||
384 | int rounding_error = 0; | ||
385 | |||
386 | if (align == RELATIVE || total_width == m_max_total_size) { | ||
387 | rounding_error = total_width - ((max_width_per_client + borderW)* num_items - borderW); | ||
388 | } | ||
389 | |||
390 | int next_x = -borderW; // zero so the border of the first shows | ||
391 | int extra = 0; | ||
392 | int direction = 1; | ||
393 | if (align == RIGHT) { | ||
394 | direction = -1; | ||
395 | next_x = total_width - max_width_per_client - borderW; | ||
396 | } | ||
397 | |||
398 | int tmpx, tmpy; | ||
399 | unsigned int tmpw, tmph; | ||
400 | for (; it != it_end; ++it, next_x += direction*(max_width_per_client + borderW + extra)) { | ||
401 | // we only need to do error stuff with alignment RELATIVE | ||
402 | // OR with max_total_size triggered | ||
403 | if (rounding_error) { | ||
404 | --rounding_error; | ||
405 | extra = 1; | ||
406 | //counter for different direction | ||
407 | if (align == RIGHT && !extra) | ||
408 | --next_x; | ||
409 | } else { | ||
410 | if (extra && align == RIGHT) // last extra | ||
411 | ++next_x; | ||
412 | extra = 0; | ||
413 | } | ||
414 | // rotate the x and y coords | ||
415 | tmpx = next_x; | ||
416 | tmpy = -borderW; | ||
417 | tmpw = max_width_per_client + extra; | ||
418 | tmph = height; | ||
419 | |||
420 | translateCoords(m_orientation, tmpx, tmpy, total_width, height); | ||
421 | translatePosition(m_orientation, tmpx, tmpy, tmpw, tmph, borderW); | ||
422 | translateSize(m_orientation, tmpw, tmph); | ||
423 | |||
424 | // resize each clients including border in size | ||
425 | (*it)->moveResize(tmpx, tmpy, | ||
426 | tmpw, tmph); | ||
427 | |||
428 | // moveresize does a clear | ||
429 | } | ||
430 | |||
431 | } | ||
432 | |||
433 | |||
434 | unsigned int Container::maxWidthPerClient() const { | ||
435 | switch (alignment()) { | ||
436 | case RIGHT: | ||
437 | case LEFT: | ||
438 | return m_max_size_per_client; | ||
439 | break; | ||
440 | case RELATIVE: | ||
441 | if (size() == 0) | ||
442 | return width(); | ||
443 | else { | ||
444 | unsigned int borderW = m_item_list.front()->borderWidth(); | ||
445 | // there're count-1 borders to fit in with the windows | ||
446 | // -> 1 per window plus end | ||
447 | unsigned int w = width(), h = height(); | ||
448 | translateSize(m_orientation, w, h); | ||
449 | if (w < (size()-1)*borderW) | ||
450 | return 1; | ||
451 | else | ||
452 | return (w - (size() - 1) * borderW) / size(); | ||
453 | } | ||
454 | break; | ||
455 | } | ||
456 | |||
457 | // this will never happen anyway | ||
458 | return 1; | ||
459 | } | ||
460 | |||
461 | void Container::for_each(std::mem_fun_t<void, FbWindow> function) { | ||
462 | std::for_each(m_item_list.begin(), | ||
463 | m_item_list.end(), | ||
464 | function); | ||
465 | } | ||
466 | |||
467 | void Container::setAlpha(unsigned char alpha) { | ||
468 | FbWindow::setAlpha(alpha); | ||
469 | ItemList::iterator it = m_item_list.begin(); | ||
470 | ItemList::iterator it_end = m_item_list.end(); | ||
471 | for (; it != it_end; ++it) | ||
472 | (*it)->setAlpha(alpha); | ||
473 | } | ||
474 | |||
475 | void Container::parentMoved() { | ||
476 | FbWindow::parentMoved(); | ||
477 | ItemList::iterator it = m_item_list.begin(); | ||
478 | ItemList::iterator it_end = m_item_list.end(); | ||
479 | for (; it != it_end; ++it) | ||
480 | (*it)->parentMoved(); | ||
481 | } | ||
482 | |||
483 | void Container::invalidateBackground() { | ||
484 | FbWindow::invalidateBackground(); | ||
485 | ItemList::iterator it = m_item_list.begin(); | ||
486 | ItemList::iterator it_end = m_item_list.end(); | ||
487 | for (; it != it_end; ++it) | ||
488 | (*it)->invalidateBackground(); | ||
489 | } | ||
490 | |||
491 | void Container::clear() { | ||
492 | ItemList::iterator it = m_item_list.begin(); | ||
493 | ItemList::iterator it_end = m_item_list.end(); | ||
494 | for (; it != it_end; ++it) | ||
495 | (*it)->clear(); | ||
496 | |||
497 | } | ||
498 | |||
499 | void Container::setOrientation(Orientation orient) { | ||
500 | if (m_orientation == orient) | ||
501 | return; | ||
502 | |||
503 | FbWindow::invalidateBackground(); | ||
504 | |||
505 | ItemList::iterator it = m_item_list.begin(); | ||
506 | ItemList::iterator it_end = m_item_list.end(); | ||
507 | for (; it != it_end; ++it) | ||
508 | (*it)->setOrientation(orient); | ||
509 | |||
510 | if ((m_orientation == ROT0 || m_orientation == ROT180) && | ||
511 | (orient == ROT90 || orient == ROT270) || | ||
512 | (m_orientation == ROT90 || m_orientation == ROT270) && | ||
513 | (orient == ROT0 || orient == ROT180)) { | ||
514 | // flip width and height | ||
515 | m_orientation = orient; | ||
516 | resize(height(), width()); | ||
517 | } else { | ||
518 | m_orientation = orient; | ||
519 | repositionItems(); | ||
520 | } | ||
521 | |||
522 | } | ||
523 | |||
524 | }; // end namespace FbTk | ||