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

Revision 10489, 27.9 kB (checked in by robert, 5 years ago)

From Stephan Lamoliatte, "The vertical anchor is inverted in the osgWidget::Window::update function.
Here is a small patch to fix that."

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