aboutsummaryrefslogtreecommitdiff
path: root/src/FbTk/Container.cc
diff options
context:
space:
mode:
authorMark Tiefenbruck <mark@fluxbox.org>2007-12-28 05:47:55 (GMT)
committerMark Tiefenbruck <mark@fluxbox.org>2007-12-28 05:47:55 (GMT)
commite8a2f155e8d5a082a8c04f291e65c137c20a05cb (patch)
tree4107154a6c73d518b604aab43371c994ae172624 /src/FbTk/Container.cc
parent00ceefd8846bda6f4dc43a5a990086545ea28727 (diff)
downloadfluxbox-e8a2f155e8d5a082a8c04f291e65c137c20a05cb.zip
fluxbox-e8a2f155e8d5a082a8c04f291e65c137c20a05cb.tar.bz2
moved Container to FbTk
Diffstat (limited to 'src/FbTk/Container.cc')
-rw-r--r--src/FbTk/Container.cc524
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
31namespace FbTk {
32
33typedef CompareEqual_base<FbWindow, Window> CompareWindow;
34
35Container::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
45Container::~Container() {
46 // ~FbWindow cleans event manager
47}
48
49void 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
59void 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
66void 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
96void 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
123void 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
152bool 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
193bool 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
206bool 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
220void Container::removeAll() {
221 m_item_list.clear();
222 if (!m_update_lock) {
223 clear();
224 }
225
226}
227
228int 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
243void 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
250void 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
260void Container::setAlignment(Container::Alignment a) {
261 m_align = a;
262}
263
264void Container::exposeEvent(XExposeEvent &event) {
265 if (!m_update_lock) {
266 clearArea(event.x, event.y, event.width, event.height);
267 }
268}
269
270bool 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
288bool 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
306bool 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
324void 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
434unsigned 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
461void 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
467void 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
475void 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
483void 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
491void 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
499void 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