root/OpenSceneGraph/trunk/src/osgWidget/Window.cpp @ 13041

Revision 13041, 28.1 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
Line 
1// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008
2// $Id: Window.cpp 66 2008-07-14 21:54:09Z cubicool $
3
4#include <algorithm>
5#include <osgGA/GUIEventAdapter>
6#include <osgWidget/WindowManager>
7
8namespace osgWidget {
9
10bool callbackWindowMove(Event& ev) {
11    if(!ev.getWindow() || !ev.getWindowManager()->isLeftMouseButtonDown()) return false;
12
13    ev.getWindow()->addOrigin(ev.x, ev.y);
14    ev.getWindow()->update();
15
16    return true;
17}
18
19bool callbackWindowRotate(Event& ev) {
20    if(!ev.getWindow() || !ev.getWindowManager()->isRightMouseButtonDown()) return false;
21
22    ev.getWindow()->addRotate(ev.y);
23    ev.getWindow()->update();
24
25    return true;
26}
27
28bool callbackWindowScale(Event& ev) {
29    if(!ev.getWindow() || !ev.getWindowManager()->isMiddleMouseButtonDown()) return false;
30
31    ev.getWindow()->addScale(ev.y);
32    ev.getWindow()->update();
33
34    return true;
35}
36
37bool callbackWindowTabFocus(Event& ev) {
38    if(!ev.getWindow() || ev.key != osgGA::GUIEventAdapter::KEY_Tab) return false;
39
40    return ev.getWindow()->setNextFocusable();
41}
42
43Window::EmbeddedWindow::EmbeddedWindow(const std::string& name, point_type w, point_type h):
44Widget(name, w, h) {
45}
46
47Window::EmbeddedWindow::EmbeddedWindow(const EmbeddedWindow& wiw, const osg::CopyOp& co):
48Widget(wiw, co) {
49    // TODO: Get this!
50    // _window = 0;
51}
52
53void Window::EmbeddedWindow::parented(Window* parent) {
54    if(!_window.valid()) return;
55
56    if(!_window->_parent) {
57        _window->_parent = parent;
58
59        // Add this Window to the Window, on the same level as a Window's
60        // internal Geode. This will require special handling of events!
61        parent->addChild(_window.get());
62    }
63
64    else warn()
65        << "EmbeddedWindow Widget [" << _name
66        << "] cannot embed itself in Window [" << _window->getName()
67        << "], since it is already a child of [" << _window->_parent->getName()
68        << "]" << std::endl
69    ;
70}
71
72void Window::EmbeddedWindow::unparented(Window*) {
73    if(_window.valid()) {
74        _window->_parent = 0;
75
76        if(_parent) _parent->removeChild(_window.get());
77    }
78}
79
80void Window::EmbeddedWindow::managed(WindowManager* wm) {
81    if(!_window.valid()) return;
82
83    _window->setNodeMask(wm->getNodeMask());
84    _window->managed(wm);
85}
86
87void Window::EmbeddedWindow::unmanaged(WindowManager* wm) {
88    _window->unmanaged(wm);
89}
90
91void Window::EmbeddedWindow::positioned() {
92    if(!_window.valid()) return;
93
94    point_type x = getX();
95    point_type y = getY();
96    point_type w = getWidth();
97    point_type h = getHeight();
98
99    // If the widget is fillable, ask the internal Window to resize itself.
100    // Whether or not the Window honors this reqest will be up to it.
101    _window->setOrigin(x, y);
102    _window->setZ(_calculateZ(getLayer() + 1));
103    _window->setZRange(_calculateZ(LAYER_TOP - (getLayer() + 1)));
104    _window->setVisibleArea(0, 0, static_cast<int>(w), static_cast<int>(h));
105    _window->resize(w, h);
106}
107
108bool Window::EmbeddedWindow::setWindow(Window* win) {
109    if(!win) {
110        warn()
111            << "EmbeddedWindow [" << _name
112            << "] attempted to set a NULL Window." << std::endl
113        ;
114
115        return false;
116    }
117
118    if (_window.valid() && _parent)
119        unparented(_parent);
120
121    _window = win;
122
123    _window->resize();
124    _window->setVisibilityMode(VM_PARTIAL);
125
126    if(_parent) parented(_parent);
127
128    WindowManager* wm = _getWindowManager();
129
130    if(wm) managed(wm);
131
132    return true;
133}
134
135void Window::EmbeddedWindow::updateSizeFromWindow() {
136    setSize(_window->getSize());
137
138    if(_parent) _parent->resize();
139}
140
141Window::Window(const std::string& name):
142    _parent     (0),
143    _wm         (0),
144    _index      (0),
145    _x          (0.0f),
146    _y          (0.0f),
147    _z          (0.0f),
148    _zRange     (0.0f),
149    _strata     (STRATA_NONE),
150    _vis        (VM_FULL),
151    _r          (0.0f),
152    _s          (1.0f),
153    _scaleDenom (100.0f),
154    _vAnchor    (VA_NONE),
155    _hAnchor    (HA_NONE)
156{
157    _name = name.size() ? name : generateRandomName("Window");
158
159    // TODO: Fix the "bg" name.
160    osg::Geode* geode = new osg::Geode();
161    Widget*     bg    = new Widget(name + "bg", 0.0f, 0.0f);
162
163    bg->setLayer(Widget::LAYER_BG);
164    bg->setColor(1.0f, 1.0f, 1.0f, 1.0f);
165
166    _setParented(bg);
167
168    geode->addDrawable(bg);
169
170    addChild(geode);
171    setDataVariance(osg::Object::DYNAMIC);
172    setEventMask(EVENT_ALL);
173
174    getOrCreateStateSet()->setAttributeAndModes(
175        new osg::Scissor(0, 0, 0, 0),
176        osg::StateAttribute::ON
177    );
178}
179
180Window::Window(const Window& window, const osg::CopyOp& co):
181    MatrixTransform (window, co),
182    EventInterface  (window),
183    StyleInterface  (window),
184    _parent         (0),
185    _wm             (0),
186    _index          (0),
187    _x              (window._x),
188    _y              (window._y),
189    _z              (window._z),
190    _zRange         (window._zRange),
191    _strata         (window._strata),
192    _vis            (window._vis),
193    _r              (window._r),
194    _s              (window._s),
195    _scaleDenom     (window._scaleDenom),
196    _width          (window._width),
197    _height         (window._height),
198    _vAnchor        (window._vAnchor),
199    _hAnchor        (window._hAnchor),
200    _visibleArea    (window._visibleArea)
201{
202    // Construct our vector of Widgets for easier use. :)
203    // TODO: I almost certainly will need to use the getPosition() thing here eventually
204    // for things to work 100% properly. For example, some Geodes may contain labels,
205    // etc. Also, any widget that doesn't support simple addWidget probably won't
206    // work (Table?)
207    osg::Geode* geode = _geode();
208
209    Widget* bg = dynamic_cast<Widget*>(geode->getDrawable(0));
210
211    if(bg) {
212        _setParented(bg);
213
214        // TODO: This is silly...
215        bg->setName(_name + "bg");
216    }
217
218    for(unsigned int i = 1; i < geode->getNumDrawables(); i++) {
219        Widget* widget = dynamic_cast<Widget*>(geode->getDrawable(i));
220
221        if(!widget) continue;
222
223        // TODO: Properly test this...
224        if(!widget->canClone()) {
225            // geode->removeDrawable(widget);
226
227            continue;
228        }
229
230        _setParented(widget);
231
232        _objects.push_back(widget);
233    }
234
235    geode->setName(_name);
236}
237
238// This is the method by which all Windows are redrawn/resized. Keep in mind that not all
239// Windows are required to absolutely honor a resize request, which is why we call the
240// _getWidthImplementation() and _getHeightImplementation() functions instead of using the
241// values passed in.
242bool Window::resize(point_type width, point_type height) {
243    // First, we query and store what sizes the Window currently is.
244    _setWidthAndHeight();
245
246    // Second, we determine if there is a difference between what the size currently
247    // is and what the user has requested.
248    point_type diffWidth  = width > 0.0f ? width - _width.current : 0.0f;
249    point_type diffHeight = height > 0.0f ? height - _height.current : 0.0f;
250
251    return resizeAdd(diffWidth, diffHeight);
252}
253
254bool Window::resizeAdd(point_type diffWidth, point_type diffHeight) {
255    if(
256        _width.current + diffWidth < _width.minimum ||
257        _height.current + diffHeight < _height.minimum
258    ) {
259        warn()
260            << "Window [" << _name << "] can't call resizeAdd() with the "
261            << "values " << diffWidth << " and " << diffHeight << std::endl
262        ;
263
264        return false;
265    }
266
267    // Now we initiate the resize, which may or may not succeed.
268    _resizeImplementation(diffWidth, diffHeight);
269
270    // Inform each widget that it has been positioned.
271    for(Iterator i = begin(); i != end(); i++) if(i->valid()) {
272        i->get()->dirtyBound();
273        i->get()->setDimensions();
274        i->get()->positioned();
275    }
276
277    _setWidthAndHeight();
278
279    Widget* bg = _bg();
280
281    bg->setSize(_width.current, _height.current);
282    bg->dirtyBound();
283    bg->positioned();
284
285    update();
286
287    return true;
288}
289
290bool Window::resizePercent(point_type width, point_type height) {
291    if(!_parent && !_wm) {
292        warn()
293            << "Window [" << _name
294            << "] cannot resizePercent without being managed or parented."
295            << std::endl
296        ;
297
298        return false;
299    }
300
301    if(!_parent) return resize(
302        _wm->getWidth() * (width / 100.0f),
303        _wm->getHeight() * (height / 100.0f)
304    );
305
306    else return resize(
307        _parent->getWidth() * (width / 100.0f),
308        _parent->getHeight() * (height / 100.0f)
309    );
310}
311
312void Window::update() {
313    WindowList wl;
314
315    getEmbeddedList(wl);
316
317    for(WindowList::iterator w = wl.begin(); w != wl.end(); w++) w->get()->update();
318
319    matrix_type x  = _x;
320    matrix_type y  = _y;
321    XYCoord     xy = getAbsoluteOrigin();
322
323    // We only honor ANCHOR requests on topmost Windows, not embedded ones.
324    if((_vAnchor != VA_NONE || _hAnchor != HA_NONE) && !_parent && _wm) {
325        if(_vAnchor == VA_TOP) y = _wm->getHeight() - _height.current;
326        else if(_vAnchor == VA_CENTER) y = osg::round(_wm->getHeight() / 2.0f);
327        else if(_vAnchor == VA_BOTTOM) y = 0.0f;
328
329        if(_hAnchor == HA_LEFT) x = 0.0f;
330        else if(_hAnchor == HA_CENTER) x = osg::round((_wm->getWidth() - _width.current)/ 2.0f);
331        else if(_hAnchor == HA_RIGHT) x = _wm->getWidth() - _width.current + _visibleArea[2];
332
333        xy.set(x, y);
334    }
335
336    matrix_type z = _z;
337
338    // We can't do proper scissoring until we have access to our parent WindowManager, and
339    // we need to determine the sorting method we want to use.
340    if(_wm) {
341        if(_wm->isUsingRenderBins()) {
342            getOrCreateStateSet()->setRenderBinDetails(
343                static_cast<int>((1.0f - fabs(_z)) * OSGWIDGET_RENDERBIN_MOD),
344                "RenderBin"
345            );
346
347            z = 0.0f;
348        }
349
350        int sx = static_cast<int>(xy.x());
351        int sy = static_cast<int>(xy.y());
352        int sw = static_cast<int>(_width.current);
353        int sh = static_cast<int>(_height.current);
354
355        // This sets the Scissor area to some offset defined by the user.
356        if(_vis == VM_PARTIAL) {
357            sw = static_cast<int>(_visibleArea[2]);
358            sh = static_cast<int>(_visibleArea[3]);
359        }
360
361        // Otherwise, use the size of the WindowManager itself.
362        else if(_vis == VM_ENTIRE) {
363            sx = 0;
364            sy = 0;
365            sw = static_cast<int>(_wm->getWidth());
366            sh = static_cast<int>(_wm->getHeight());
367        }
368
369        _scissor()->setScissor(sx, sy, sw, sh);
370    }
371
372    // Update the Window itself, setting it's matrix according to translate, rotate, and
373    // scale values.
374    osg::Matrix r = osg::Matrix::rotate(
375        osg::DegreesToRadians(_r),
376        osg::Vec3d(0.0f, 0.0f, 1.0f)
377    );
378
379    osg::Matrix s = osg::Matrix::scale(_s, _s, 1.0f);
380    osg::Matrix t = osg::Matrix::translate(x - _visibleArea[0], y - _visibleArea[1], z);
381
382    setMatrix(r * s * t);
383}
384
385void Window::_setWidthAndHeightUnknownSizeError(const std::string& size, point_type val) {
386    warn()
387        << "Window [" << _name << "] doesn't know its " << size
388        << " (" << val << ")." << std::endl
389    ;
390}
391
392void Window::_setWidthAndHeightNotPAError(const std::string& size, point_type val) {
393    warn()
394        << "Window [" << _name
395        << "] should be pixel-aligned, but a remainder was detected for it's "
396        << size << " (" << val << ")." << std::endl
397    ;
398}
399
400// Since there is so much error-checking associated with setting the width and height properly
401// of a Window, this function attempts to abstract some of that tedium.
402void Window::_setWidthAndHeight() {
403    _width  = _getWidthImplementation();
404    _height = _getHeightImplementation();
405
406    if(_width.current < 0.0f) _setWidthAndHeightUnknownSizeError("current width", _width.current);
407
408    if(_width.minimum < 0.0f) _setWidthAndHeightUnknownSizeError("minimum width", _width.minimum);
409
410    if(_height.current < 0.0f) _setWidthAndHeightUnknownSizeError("current height", _height.current);
411
412    if(_height.minimum < 0.0f) _setWidthAndHeightUnknownSizeError("minimum height", _height.minimum);
413
414    if(hasDecimal(_width.current)) _setWidthAndHeightNotPAError("current width", _width.current);
415
416    if(hasDecimal(_width.minimum)) _setWidthAndHeightNotPAError("minimum width", _width.minimum);
417
418    if(hasDecimal(_height.current)) _setWidthAndHeightNotPAError("current height", _height.current);
419
420    if(hasDecimal(_height.minimum)) _setWidthAndHeightNotPAError("minimum height", _height.minimum);
421}
422
423void Window::_removeFromGeode(Widget* widget) {
424    if(!widget) return;
425
426    widget->_index = 0;
427
428    _setParented(widget, true);
429
430    _geode()->removeDrawable(widget);
431}
432
433// This is a somewhat complicated function designed to only be called by derived classes,
434// allowing them to insert Widgets (which can be added to the Window in any way the derived
435// class sees fit) into the REAL internal _objects container.
436// TODO: This doesn't handle insertion properly!!!
437bool Window::_setWidget(Widget* widget, int index) {
438    if(!widget) {
439        warn() << "Window [" << _name << "] called addWidget with NULL." << std::endl;
440
441        return false;
442    }
443
444    if(widget->_parent) {
445        warn()
446            << "Window [" << _name
447            << "] attempted to parent Widget [" << widget->getName()
448            << "], which is already parented by [" << widget->_parent->getName()
449            << "]." << std::endl
450        ;
451
452        return false;
453    }
454
455    if(index >= 0 && index >= static_cast<int>(size())) {
456        warn()
457            << "Window [" << _name
458            << "] attempted to manually insert the Widget [" << widget->getName()
459            << "] at position " << index
460            << ", but there is not enough space available."
461            << std::endl
462        ;
463
464        return false;
465    }
466
467    // If we're just appending another widget...
468    if(index < 0) _objects.push_back(widget);
469
470    // Otherwise, we're inserting and need to call removeWidget on the old
471    // one (if valid)...
472    else {
473        if(_objects[index].valid()) _removeFromGeode(_objects[index].get());
474
475        _objects[index] = widget;
476    }
477
478    osg::Geode* geode = _geode();
479
480    widget->_index = geode->getNumDrawables();
481
482    geode->addDrawable(widget);
483
484    _setParented(widget);
485    _setManaged(widget);
486    _setStyled(widget);
487
488    // We make sure and resize after every added Widget. This ensures the most
489    // accurate geometry...
490    resize();
491
492    return true;
493}
494
495bool Window::_setVisible(bool visible) {
496    if(!_wm) return false;
497
498    _wm->setValue(_index, visible);
499
500    return true;
501}
502
503void Window::_setFocused(Widget* widget) {
504    if(widget && _wm) {
505        Event ev(_wm);
506
507        ev._window = this;
508
509        if(_focused.valid()) {
510            ev._widget = _focused.get();
511
512            _focused->callMethodAndCallbacks(ev.makeType(EVENT_UNFOCUS));
513        }
514
515        _focused   = widget;
516        ev._widget = widget;
517
518        _focused->callMethodAndCallbacks(ev.makeType(EVENT_FOCUS));
519    }
520}
521
522void Window::_setStyled(Widget* widget) {
523    if(!widget || !_wm) return;
524
525    if(!widget->_isStyled) return;
526
527    widget->_isStyled = true;
528
529    _wm->getStyleManager()->applyStyles(widget);
530}
531
532void Window::_setParented(Widget* widget, bool setUnparented) {
533    if(!widget) return;
534
535    if(!setUnparented) {
536        widget->_parent = this;
537
538        widget->parented(this);
539    }
540
541    else {
542        widget->unparented(this);
543
544        widget->_parent = 0;
545    }
546}
547
548void Window::_setManaged(Widget* widget, bool setUnmanaged) {
549    if(!widget || !_wm) return;
550
551    // Tell the widget it's managed if it isn't already...
552    if(!setUnmanaged) {
553        if(widget->_isManaged) return;
554
555        widget->_isManaged = true;
556
557        widget->managed(_wm);
558    }
559
560    // Otherwise, make sure it IS managed and tell it that it no longer will be. :)
561    else {
562        if(!widget->_isManaged) return;
563
564        widget->_isManaged = false;
565
566        widget->unmanaged(_wm);
567    }
568}
569
570Widget* Window::_getBackground() const {
571    const osg::Geode* geode = _geode();
572
573    // lol...
574    if(geode) return dynamic_cast<Widget*>(const_cast<osg::Drawable*>(geode->getDrawable(0)));
575
576    return 0;
577}
578
579Window* Window::_getTopmostParent() const {
580    WindowList windowList;
581
582    getParentList(windowList);
583
584    return windowList.back().get();
585}
586
587// This will position a widget based on the amount of width and height it has
588// to fill. The x/y values should already be set, since we will be adding here.
589// However, the width and height can be anything and will be adjusted accordingly.
590void Window::_positionWidget(Widget* widget, point_type width, point_type height) {
591    point_type w  = widget->getWidth();
592    point_type h  = widget->getHeight();
593    point_type pl = widget->getPadLeft();
594    point_type pr = widget->getPadRight();
595    point_type pt = widget->getPadTop();
596    point_type pb = widget->getPadBottom();
597
598    if(widget->canFill()) {
599        point_type nw = osg::round(width - pr - pl);
600        point_type nh = osg::round(height - pt - pb);
601
602        widget->addOrigin(pl, pb);
603
604        if(w != nw) widget->setWidth(nw);
605        if(h != nh) widget->setHeight(nh);
606
607        return;
608    }
609
610    point_type ha = osg::round((width - w - pl - pr) / 2.0f);
611    point_type va = osg::round((height - h - pt - pb) / 2.0f);
612
613    // Handle HORIZONTAL alignment.
614    if(widget->getAlignHorizontal() == Widget::HA_LEFT) widget->addX(pl);
615
616    else if(widget->getAlignHorizontal() == Widget::HA_RIGHT) widget->addX(width - w - pr);
617
618    else widget->addX(ha + pl);
619
620    // Handle VERTICAL alignment.
621    if(widget->getAlignVertical() == Widget::VA_BOTTOM) widget->addY(height - h - pt);
622
623    else if(widget->getAlignVertical() == Widget::VA_TOP) widget->addY(pb);
624
625    else widget->addY(va + pb);
626}
627
628bool Window::isVisible() const {
629    if(!_wm) return false;
630
631    return _wm->getValue(_index);
632}
633
634bool Window::isXYWithinVisible(float x, float y) const {
635    return
636        (x >= _visibleArea[0] && x <= (_visibleArea[0] + _visibleArea[2])) &&
637        (y >= _visibleArea[1] && y <= (_visibleArea[1] + _visibleArea[3]))
638    ;
639}
640
641void Window::setVisibleArea(int x, int y, int w, int h) {
642    _visibleArea[0] = x;
643    _visibleArea[1] = y;
644    _visibleArea[2] = w;
645    _visibleArea[3] = h;
646}
647
648void Window::addVisibleArea(int x, int y, int w, int h) {
649    _visibleArea[0] += x;
650    _visibleArea[1] += y;
651    _visibleArea[2] += w;
652    _visibleArea[3] += h;
653}
654
655// The topmost Window always has this method called, instead of the embedded window directly.
656bool Window::setFocused(const Widget* widget) {
657    // TODO: I've turned on the warn() here, but perhaps I shouldn't? I need to define
658    // the conditions under which it's okay to call setFocus() with a NULL widget.
659    if(!widget) {
660        warn() << "Window [" << _name << "] can't focus a NULL Widget." << std::endl;
661
662        return false;
663    }
664
665    ConstIterator i = std::find(begin(), end(), widget);
666
667    bool found = false;
668
669    if(i == end()) {
670        // We couldn't find the widget in the toplevel, so lets see if one of our
671        // EmbeddedWindow objects has it.
672        WindowList wl;
673
674        getEmbeddedList(wl);
675
676        for(WindowList::iterator w = wl.begin(); w != wl.end(); w++) {
677            ConstIterator ii = std::find(w->get()->begin(), w->get()->end(), widget);
678
679            if(ii != w->get()->end()) {
680                found = true;
681                i     = ii;
682            }
683        }
684    }
685
686    else found = true;
687
688    if(!found) {
689        warn()
690            << "Window [" << _name
691            << "] couldn't find the Widget [" << widget->getName()
692            << "] in it's object list." << std::endl
693        ;
694
695        return false;
696    }
697
698    _setFocused(i->get());
699
700    return true;
701}
702
703bool Window::setFocused(const std::string& name) {
704    Widget* w1 = getByName(name);
705
706    bool found = false;
707
708    if(!w1) {
709        // Just like above, we couldn't find the widget in the toplevel, so lets see if
710        // one of our EmbeddedWindow objects has it. The difference here is that we
711        // search by name.
712        WindowList wl;
713
714        getEmbeddedList(wl);
715
716        for(WindowList::iterator w = wl.begin(); w != wl.end(); w++) {
717            Widget* w2 = w->get()->getByName(name);
718
719            if(w2) {
720                found = true;
721                w1    = w2;
722            }
723        }
724    }
725
726    else found = true;
727
728    if(!found) {
729        warn()
730            << "Window [" << _name
731            << "] couldn't find a Widget named [" << name
732            << "] to set as it's focus." << std::endl
733        ;
734
735        return false;
736    }
737
738    _setFocused(w1);
739
740    return true;
741}
742
743bool Window::grabFocus() {
744    if(!_wm) return false;
745
746    return _wm->setFocused(this);
747}
748
749bool Window::setFirstFocusable() {
750    WidgetList focusList;
751
752    if(getFocusList(focusList)) {
753        _setFocused(focusList.front().get());
754
755        return true;
756    }
757
758    return false;
759}
760
761bool Window::setNextFocusable() {
762    WidgetList focusList;
763
764    if(!getFocusList(focusList)) return false;
765
766    WidgetList::iterator w = focusList.begin();
767
768    // TODO: This needs to be a more complicated object, since the focus may be
769    // in a child Window instead of a Widget.
770    unsigned int focusedIndex = 0;
771
772    for(unsigned int i = 0; w != focusList.end(); w++, i++) if(*w == _focused) {
773        focusedIndex = i;
774
775        break;
776    }
777
778    if(focusedIndex < focusList.size() - 1) _setFocused((++w)->get());
779
780    else _setFocused(focusList.front().get());
781
782    return true;
783}
784
785XYCoord Window::localXY(double absx, double absy) const {
786    XYCoord xy = getAbsoluteOrigin();
787    double  x  = absx - xy.x();
788    double  y  = absy - xy.y();
789
790    return XYCoord(x + _visibleArea[0], y + _visibleArea[1]);
791}
792
793XYCoord Window::getAbsoluteOrigin() const {
794    XYCoord xy(0, 0);
795
796    WindowList windowList;
797
798    getParentList(windowList);
799
800    for(WindowList::iterator i = windowList.begin(); i != windowList.end(); i++) {
801        if(!i->valid()) continue;
802
803        xy.x() += static_cast<int>(i->get()->getX());
804        xy.y() += static_cast<int>(i->get()->getY());
805    }
806
807    return xy;
808}
809
810Window::EmbeddedWindow* Window::embed(
811    const std::string& newName,
812    Widget::Layer      layer,
813    unsigned int       layerOffset
814) {
815    EmbeddedWindow* ew = new EmbeddedWindow(
816        newName.size() > 0 ? newName : _name + "Embedded",
817        getWidth(),
818        getHeight()
819    );
820
821    ew->setWindow(this);
822    ew->setSize(getWidth(), getHeight());
823    ew->setCanFill(true);
824    ew->setLayer(layer, layerOffset);
825
826    return ew;
827}
828
829bool Window::getFocusList(WidgetList& wl) const {
830    for(ConstIterator i = begin(); i != end(); i++) if(i->valid()) {
831        EmbeddedWindow* ew = dynamic_cast<EmbeddedWindow*>(i->get());
832
833        if(!ew) {
834            if(i->get()->canFocus()) wl.push_back(i->get());
835        }
836
837        else {
838            if(ew->getWindow()) ew->getWindow()->getFocusList(wl);
839        }
840    }
841
842    return wl.size() != 0;
843}
844
845bool Window::getEmbeddedList(WindowList& wl) const {
846    for(ConstIterator i = begin(); i != end(); i++) if(i->valid()) {
847        EmbeddedWindow* ew = dynamic_cast<EmbeddedWindow*>(i->get());
848
849        if(!ew || !ew->getWindow()) continue;
850
851        else {
852            wl.push_back(ew->getWindow());
853
854            ew->getWindow()->getEmbeddedList(wl);
855        }
856    }
857
858    return wl.size() != 0;
859}
860
861void Window::getParentList(WindowList& wl) const {
862    const Window* current = this;
863
864    while(current) {
865        wl.push_back(const_cast<Window*>(current));
866
867        if(current->_parent) current = current->_parent;
868
869        else current = 0;
870    }
871}
872
873void Window::managed(WindowManager* wm) {
874    _wm = wm;
875
876    for(Iterator i = begin(); i != end(); i++) {
877        _setManaged(i->get());
878        _setStyled(i->get());
879    }
880
881    setFirstFocusable();
882    resize();
883    update();
884}
885
886void Window::unmanaged(WindowManager* wm) {
887    for(Iterator i = begin(); i != end(); i++) _setManaged(i->get(), true);
888
889    _wm = 0;
890}
891
892bool Window::addWidget(Widget* widget) {
893    return _setWidget(widget);
894}
895
896bool Window::insertWidget(Widget* widget, unsigned int pos) {
897    return _setWidget(widget, pos);
898}
899
900bool Window::removeWidget(Widget* widget) {
901    if(!widget) return false;
902
903    if(_remove(widget)) {
904        _removeFromGeode(widget);
905
906        resize();
907
908        return true;
909    }
910
911    return false;
912}
913
914bool Window::replaceWidget(Widget* oldWidget, Widget* newWidget) {
915    return false;
916}
917
918unsigned int Window::addDrawableAndGetIndex(osg::Drawable* drawable) {
919    osg::Geode* geode = _geode();
920
921    if(geode->addDrawable(drawable)) return geode->getDrawableIndex(drawable);
922
923    // 0 is a valid error return code here, since our background widget should be
924    // the first child.
925    return 0;
926}
927
928unsigned int Window::addChildAndGetIndex(osg::Node* node) {
929    if(addChild(node)) return getChildIndex(node);
930
931    return 0;
932}
933
934// All of the subsequent functions are very boring and uninteresting, although hopefully
935// self-explanatory. They simply wrap calls to _compare<>() with the proper templates, and
936// forward the optional iteration ranges...
937
938point_type Window::_getMinWidgetWidth(int begin, int end, int add) const {
939    return _compare<Less>(&Widget::getWidth, begin, end, add);
940}
941
942point_type Window::_getMinWidgetHeight(int begin, int end, int add) const {
943    return _compare<Less>(&Widget::getHeight, begin, end, add);
944}
945
946point_type Window::_getMaxWidgetWidth(int begin, int end, int add) const {
947    return _compare<Greater>(&Widget::getWidth, begin, end, add);
948}
949
950point_type Window::_getMaxWidgetHeight(int begin, int end, int add) const {
951    return _compare<Greater>(&Widget::getHeight, begin, end, add);
952}
953
954point_type Window::_getMinWidgetMinWidth(int begin, int end, int add) const {
955    return _compare<Less>(&Widget::getMinWidth, begin, end, add);
956}
957
958point_type Window::_getMinWidgetMinHeight(int begin, int end, int add) const {
959    return _compare<Less>(&Widget::getMinHeight, begin, end, add);
960}
961
962point_type Window::_getMaxWidgetMinWidth(int begin, int end, int add) const {
963    return _compare<Greater>(&Widget::getMinWidth, begin, end, add);
964}
965
966point_type Window::_getMaxWidgetMinHeight(int begin, int end, int add) const {
967    return _compare<Greater>(&Widget::getMinHeight, begin, end, add);
968}
969
970point_type Window::_getMinWidgetWidthTotal(int begin, int end, int add) const {
971    return _compare<Less>(&Widget::getWidthTotal, begin, end, add);
972}
973
974point_type Window::_getMinWidgetHeightTotal(int begin, int end, int add) const {
975    return _compare<Less>(&Widget::getHeightTotal, begin, end, add);
976}
977
978point_type Window::_getMaxWidgetWidthTotal(int begin, int end, int add) const {
979    return _compare<Greater>(&Widget::getWidthTotal, begin, end, add);
980}
981
982point_type Window::_getMaxWidgetHeightTotal(int begin, int end, int add) const {
983    return _compare<Greater>(&Widget::getHeightTotal, begin, end, add);
984}
985
986point_type Window::_getMinWidgetMinWidthTotal(int begin, int end, int add) const {
987    return _compare<Less>(&Widget::getMinWidthTotal, begin, end, add);
988}
989
990point_type Window::_getMinWidgetMinHeightTotal(int begin, int end, int add) const {
991    return _compare<Less>(&Widget::getMinHeightTotal, begin, end, add);
992}
993
994point_type Window::_getMaxWidgetMinWidthTotal(int begin, int end, int add) const {
995    return _compare<Greater>(&Widget::getMinWidthTotal, begin, end, add);
996}
997
998point_type Window::_getMaxWidgetMinHeightTotal(int begin, int end, int add) const {
999    return _compare<Greater>(&Widget::getMinHeightTotal, begin, end, add);
1000}
1001
1002point_type Window::_getMinWidgetPadHorizontal(int begin, int end, int add) const {
1003    return _compare<Less>(&Widget::getPadHorizontal, begin, end, add);
1004}
1005
1006point_type Window::_getMinWidgetPadVertical(int begin, int end, int add) const {
1007    return _compare<Less>(&Widget::getPadVertical, begin, end, add);
1008}
1009
1010point_type Window::_getMaxWidgetPadHorizontal(int begin, int end, int add) const {
1011    return _compare<Greater>(&Widget::getPadHorizontal, begin, end, add);
1012}
1013
1014point_type Window::_getMaxWidgetPadVertical(int begin, int end, int add) const {
1015    return _compare<Greater>(&Widget::getPadVertical, begin, end, add);
1016}
1017
1018point_type Window::_getNumFill(int begin, int end, int add) const {
1019    return _accumulate<Plus>(&Widget::getFillAsNumeric, begin, end, add);
1020}
1021
1022Window::Sizes Window::_getWidthImplementation() const {
1023    osg::BoundingBox bb = getGeode()->getBoundingBox();
1024
1025    point_type w = osg::round(bb.xMax() - bb.xMin());
1026
1027    return Sizes(w, 0.0f);
1028}
1029
1030Window::Sizes Window::_getHeightImplementation() const {
1031    osg::BoundingBox bb = getGeode()->getBoundingBox();
1032
1033    point_type h = osg::round(bb.yMax() - bb.yMin());
1034
1035    return Sizes(h, 0.0f);
1036}
1037
1038}
Note: See TracBrowser for help on using the browser.