openscenegraph
Window
Go to the documentation of this file.
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2008 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version. The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14// Code by: Jeremy Moles (cubicool) 2007-2008
15
16#ifndef OSGWIDGET_WINDOW
17#define OSGWIDGET_WINDOW
18
19#include <osg/Scissor>
20#include <osg/MatrixTransform>
21#include <osg/Geode>
22#include <osg/ClipNode>
23#include <osgWidget/Types>
24#include <osgWidget/Util>
25#include <osgWidget/Widget>
26
27namespace osgWidget {
28
29// These are helper callbacks you can attach to Windows that will make them moveable,
30// rotatable, and scalable respectively.
31bool OSGWIDGET_EXPORT callbackWindowMove (Event&);
32bool OSGWIDGET_EXPORT callbackWindowRotate (Event&);
33bool OSGWIDGET_EXPORT callbackWindowScale (Event&);
34
35// These are helper callbacks you can attach to Windows to that will make various
36// keyboard events behave as you might imagine.
37bool OSGWIDGET_EXPORT callbackWindowTabFocus(Event&);
38
39class OSGWIDGET_EXPORT Window:
40 public osg::MatrixTransform,
41 public UIObjectParent<Widget>,
42 public EventInterface,
43 public StyleInterface
44{
45 public:
46 typedef std::list<osg::observer_ptr<Window> > WindowList;
47
48 struct Sizes
49 {
50 point_type current;
51 point_type minimum;
52
53 Sizes(point_type c = -1.0f, point_type m = -1.0f):
54 current(c),
55 minimum(m) {}
56 };
57
58 // TODO: This is a class that puts (embeds) the Window inside of a Widget
59 // interface, to help assemble Windows with Windows, and what have you.
60 class OSGWIDGET_EXPORT EmbeddedWindow: public Widget {
61 osg::ref_ptr<Window> _window;
62
63 public:
64 META_Object (osgWidget::Window, EmbeddedWindow);
65
66 EmbeddedWindow (const std::string& = "", point_type = 0.0f, point_type = 0.0f);
67 EmbeddedWindow (const EmbeddedWindow&, const osg::CopyOp&);
68
69 virtual void parented (Window*);
70 virtual void unparented (Window*);
71 virtual void managed (WindowManager*);
72 virtual void unmanaged (WindowManager*);
73 virtual void positioned ();
74
75 bool setWindow (Window*);
76 void updateSizeFromWindow ();
77
78 Window* getWindow() {
79 return _window.get();
80 }
81
82 const Window* getWindow() const {
83 return _window.get();
84 }
85 };
86
87 // These correspond to special regions honored by the WindowManager. Most Windows
88 // will want to be NONE, unless they need to exist in the foreground or background
89 // for some reason.
90 enum Strata {
91 STRATA_NONE,
92 STRATA_BACKGROUND,
93 STRATA_FOREGROUND
94 };
95
96 // If you only want to display a portion of a Window (such as when it is embedded),
97 // you will need to set the VisibilityMode to WM_PARTIAL. Otherwise, the entire
98 // Window is visible by default. The final enum, VM_ENTIRE, says that no Scissoring
99 // should take place at all, and is useful in cases where you want to properly
100 // scale or rotate Windows.
101 enum VisibilityMode {
102 VM_FULL,
103 VM_PARTIAL,
104 VM_ENTIRE
105 };
106
107 // Anchors are very similar in that they allow us to pre-apply transformations in the
108 // call to Window::update() that allow us to position a Window somewhere relative
109 // to the WindowManger's viewable area. However, unlike the ALIGNMENT enums, these
110 // are totally optional (whereas a Widget must always have some ALIGNMENT value set.
111 enum VerticalAnchor {
112 VA_NONE,
113 VA_CENTER,
114 VA_TOP,
115 VA_BOTTOM
116 };
117
118 enum HorizontalAnchor {
119 HA_NONE,
120 HA_CENTER,
121 HA_LEFT,
122 HA_RIGHT
123 };
124
125 Window (const std::string& = "");
126 Window (const Window&, const osg::CopyOp&);
127
128 bool resize (point_type = 0.0f, point_type = 0.0f);
129 bool resizeAdd (point_type = 0.0f, point_type = 0.0f);
130 bool resizePercent (point_type = 0.0f, point_type = 0.0f);
131
132 virtual void update ();
133 virtual void managed (WindowManager*);
134 virtual void unmanaged (WindowManager*);
135 virtual bool addWidget (Widget*);
136 virtual bool insertWidget (Widget*, unsigned int);
137 virtual bool removeWidget (Widget*);
138 virtual bool replaceWidget (Widget*, Widget*);
139
140 // This method wraps our Geode's addDrawable() method and returns the index of
141 // the newly-added Drawable.
142 unsigned int addDrawableAndGetIndex (osg::Drawable*);
143 unsigned int addChildAndGetIndex (osg::Node*);
144
145 bool isVisible () const;
146 bool isXYWithinVisible (float, float) const;
147 void setVisibleArea (int = 0, int = 0, int = 0, int = 0);
148 void addVisibleArea (int = 0, int = 0, int = 0, int = 0);
149 bool setFocused (const Widget*);
150 bool setFocused (const std::string&);
151 bool grabFocus ();
152 bool setFirstFocusable ();
153 bool setNextFocusable ();
154 bool getFocusList (WidgetList&) const;
155 bool getEmbeddedList (WindowList&) const;
156 void getParentList (WindowList&) const;
157
158 XYCoord localXY (double, double) const;
159 XYCoord getAbsoluteOrigin () const;
160
161 // This method wraps the current Window in a EmbeddedWindow object and returns it.
162 EmbeddedWindow* embed(
163 const std::string& = "",
164 Widget::Layer = Widget::LAYER_MIDDLE,
165 unsigned int = 0
166 );
167
168 Widget* getFocused() {
169 return _focused.get();
170 }
171
172 const Widget* getFocused() const {
173 return _focused.get();
174 }
175
176 bool show() {
177 return _setVisible(true);
178 }
179
180 bool hide() {
181 return _setVisible(false);
182 }
183
184 bool isPointerXYWithinVisible(float x, float y) const {
185 XYCoord xy = localXY(x, y);
186
187 return isXYWithinVisible(xy.x(), xy.y());
188 }
189
190 osg::Geode* getGeode() {
191 return _geode();
192 }
193
194 const osg::Geode* getGeode() const {
195 return _geode();
196 }
197
198 Widget* getBackground() {
199 return _bg();
200 }
201
202 const Widget* getBackground() const {
203 return _bg();
204 }
205
206 WindowManager* getWindowManager() {
207 return _wm;
208 }
209
210 const WindowManager* getWindowManager() const {
211 return _wm;
212 }
213
214 Window* getParent() {
215 return _parent;
216 }
217
218 const Window* getParent() const {
219 return _parent;
220 }
221
222 Window* getTopmostParent() {
223 return _getTopmostParent();
224 }
225
226 const Window* getTopmostParent() const {
227 return _getTopmostParent();
228 }
229
230 unsigned int getIndex() const {
231 return _index;
232 }
233
234 matrix_type getX() const {
235 return _x;
236 }
237
238 matrix_type getY() const {
239 return _y;
240 }
241
242 matrix_type getZ() const {
243 return _z;
244 }
245
246 point_type getWidth() const {
247 return _width.current;
248 }
249
250 point_type getHeight() const {
251 return _height.current;
252 }
253
254 point_type getMinWidth() const {
255 return _width.minimum;
256 }
257
258 point_type getMinHeight() const {
259 return _height.minimum;
260 }
261
262 VerticalAnchor getAnchorVertical() const {
263 return _vAnchor;
264 }
265
266 HorizontalAnchor getAnchorHorizontal() const {
267 return _hAnchor;
268 }
269
270 XYCoord getOrigin() const {
271 return XYCoord(_x, _y);
272 }
273
274 XYCoord getSize() const {
275 return XYCoord(_width.current, _height.current);
276 }
277
278 XYCoord getMinSize() const {
279 return XYCoord(_width.minimum, _height.minimum);
280 }
281
282 matrix_type getZRange() const {
283 return _zRange;
284 }
285
286 Strata getStrata() const {
287 return _strata;
288 }
289
290 const Quad& getVisibleArea() const {
291 return _visibleArea;
292 }
293
294 VisibilityMode getVisibilityMode() const {
295 return _vis;
296 }
297
298 Point getPosition() const {
299 return Point(_x, _y, _z);
300 }
301
302 matrix_type getRotate() const {
303 return _r;
304 }
305
306 matrix_type getScale() const {
307 return _s;
308 }
309
310 matrix_type getScaleDenominator() const {
311 return _scaleDenom;
312 }
313
314 void setX(matrix_type x) {
315 _x = x;
316 }
317
318 void setY(matrix_type y) {
319 _y = y;
320 }
321
322 void setZ(matrix_type z) {
323 _z = z;
324 }
325
326 void setZRange(matrix_type zRange) {
327 _zRange = zRange;
328 }
329
330 void setPosition(matrix_type x, matrix_type y, matrix_type z) {
331 _x = x;
332 _y = y;
333 _z = z;
334 }
335
336 void setPosition(const Point& p) {
337 setPosition(p.x(), p.y(), p.z());
338 }
339
340 void setOrigin(matrix_type x, matrix_type y) {
341 _x = x;
342 _y = y;
343 }
344
345 void setOrigin(const XYCoord& xy) {
346 setOrigin(xy.x(), xy.y());
347 }
348
349 void setRotate(matrix_type r) {
350 _r = r;
351 }
352
353 void setScale(matrix_type s) {
354 _s = s;
355 }
356
357 void setScaleDenominator(matrix_type sd) {
358 _scaleDenom = sd;
359 }
360
361 void setAnchorVertical(VerticalAnchor va) {
362 _vAnchor = va;
363 }
364
365 void setAnchorHorizontal(HorizontalAnchor ha) {
366 _hAnchor = ha;
367 }
368
369 void setStrata(Strata s) {
370 _strata = s;
371 }
372
373 void setVisibilityMode(VisibilityMode v) {
374 _vis = v;
375 }
376
377 void addX(matrix_type x) {
378 _x += x;
379 }
380
381 void addY(matrix_type y) {
382 _y += y;
383 }
384
385 void addZ(matrix_type z) {
386 _z += z;
387 }
388
389 void addRotate(matrix_type r) {
390 _r += r;
391 }
392
393 void addScale(matrix_type s) {
394 _s += s / (_scaleDenom != 0.0f ? _scaleDenom : 1.0f);
395 }
396
397 void addOrigin(matrix_type x, matrix_type y) {
398 _x += x;
399 _y += y;
400 }
401
402 void attachMoveCallback() {
403 addCallback(new Callback(&callbackWindowMove, EVENT_MOUSE_DRAG));
404 }
405
406 void attachRotateCallback() {
407 addCallback(new Callback(&callbackWindowRotate, EVENT_MOUSE_DRAG));
408 }
409
410 void attachScaleCallback() {
411 addCallback(new Callback(&callbackWindowScale, EVENT_MOUSE_DRAG));
412 }
413
414 void attachTabFocusCallback() {
415 addCallback(new Callback(&callbackWindowTabFocus, EVENT_KEY_DOWN));
416 }
417
418 typedef point_type (Widget::*Getter)() const;
419
420 protected:
421
422 typedef std::less<point_type> Less;
423 typedef std::greater<point_type> Greater;
424 typedef std::plus<point_type> Plus;
425
426 friend class WindowManager;
427
428 // The (optional) Window that this Window is parented inside.
429 Window* _parent;
430
431 // The WindowManger to which this window is attached.
432 WindowManager* _wm;
433
434 // The positional index this Node holds within it's parent WindowManager.
435 unsigned int _index;
436
437 // The X and Y values of the Window (origin).
438 matrix_type _x;
439 matrix_type _y;
440
441 // A pair of values representing the currently calculated Z value and the
442 // depth range for all children to be used during the call to update().
443 matrix_type _z;
444 matrix_type _zRange;
445
446 // This is a special value that can be used to "force" a Window not to be
447 // focusable and instead always exist in the foreground or background.
448 Strata _strata;
449
450 // A flag determining whether our visible area is the full Window or rather
451 // a portion of the Window.
452 VisibilityMode _vis;
453
454 // A rotation value in degrees.
455 matrix_type _r;
456
457 // This will also need to adjust geom internally so that picking is correct.
458 matrix_type _s;
459
460 matrix_type _scaleDenom;
461
462 Sizes _width;
463 Sizes _height;
464
465 VerticalAnchor _vAnchor;
466 HorizontalAnchor _hAnchor;
467
468 // Not all windows have widgets that can focus, but if they do this should
469 // be a pointer to it.
470 osg::observer_ptr<Widget> _focused;
471
472 // The "visible" area that will define both the glScissor bounds AND will
473 // be used to make sure our pick is valid. The values herein correspond to
474 // X, Y, W, and H--in that order.
475 Quad _visibleArea;
476
477 // This helper method is used by _compare<>() and _accumulate<>(), so ignore this
478 // function and go see the docs for those instead. This thing is huge and unwieldy
479 // and not to be triffled with! :)
480 template<typename T>
481 point_type _forEachAssignOrApply(
482 Getter get,
483 int begin,
484 int end,
485 int add,
486 bool assign
487 ) const {
488 point_type val = 0.0f;
489 unsigned int c = begin;
490
491 ConstIterator e = end > 0 ? _objects.begin() + end : _objects.end() + end;
492
493 // I WARNED YOU! If you try and understand what this does your head will
494 // explode! But let me say a few things: in MSVC you can't add to an iterator
495 // such that the add will cause it to increment past the end of the container.
496 // This appears to be safe in GCC, where it will just return the last
497 // item therein, but causes an assertion error in other compilers. I'm not
498 // sure if there is a cleaner remedy for this, so what we do for now is keep a
499 // count variable called "c" that makes sure our iterator's opterator+()
500 // method is safe to call.
501 for(
502 ConstIterator i = _objects.begin() + begin;
503 i < e;
504 c += add
505 ) {
506 point_type v = 0.0f;
507
508 if(i->valid()) v = (i->get()->*get)();
509
510 // If you want to assign to val, and NOT add a sequence of them...
511 if(assign) {
512 if(T()(v, val)) val = v;
513 }
514
515 // If you want to accumulate a value INTO val...
516 else val = T()(v, val);
517
518 // Make sure our iterator is safe to increment. Otherwise, set it to
519 // whatever end is.
520 // TODO: This isn't 100% accurate, as it does not YET take into account
521 // our requested end in any way other than implicitly. It should, however,
522 // work okay for now.
523 if((c + add) < _objects.size()) i += add;
524
525 else i = e;
526 }
527
528 return val;
529 }
530
531 void _setWidthAndHeightUnknownSizeError (const std::string&, point_type);
532 void _setWidthAndHeightNotPAError (const std::string&, point_type);
533 void _setWidthAndHeight ();
534 void _removeFromGeode (Widget*);
535
536 Widget* _getBackground() const;
537 Window* _getTopmostParent() const;
538
539 // This method will return the T'th value returned by applying the Getter member function
540 // pointer to each iterator in the range of iterators defined by offset and add. In
541 // plain language, this helper method will apply some standard Widget::get* function
542 // to a range of objects in the _objects Vector, and will return the T'th of that.
543 // The template T can be any functor accepting two point_type values that return
544 // a bool. For example, this is commonly used with std::less to find the smallest
545 // width in a range of Widgets.
546 template<typename T>
547 point_type _compare(
548 Getter get,
549 int begin = 0,
550 int end = 0,
551 int add = 1
552 ) const {
553 return _forEachAssignOrApply<T>(get, begin, end, add, true);
554 }
555
556 // This method will return the T'th value accumulated by applying the Getter member
557 // function to each iterator in the range of iterators defined by offset and add (similar
558 // to above). For example, this method can be used to apply std::plus to every
559 // width in a range of Widgets, and return the total.
560 template<typename T>
561 point_type _accumulate(
562 Getter get,
563 int begin = 0,
564 int end = 0,
565 int add = 1
566 ) const {
567 return _forEachAssignOrApply<T>(get, begin, end, add, false);
568 }
569
570 osg::Geode* _geode() {
571 return dynamic_cast<osg::Geode*>(getChild(0));
572 }
573
574 const osg::Geode* _geode() const {
575 return dynamic_cast<const osg::Geode*>(getChild(0));
576 }
577
578 Widget* _bg() {
579 return _getBackground();
580 }
581
582 const Widget* _bg() const {
583 return _getBackground();
584 }
585
586 osg::Scissor* _scissor() {
587 return dynamic_cast<osg::Scissor*>(
588 getStateSet()->getAttribute(osg::StateAttribute::SCISSOR)
589 );
590 }
591
592 bool _setWidget (Widget*, int = -1);
593 bool _setVisible (bool);
594 void _setFocused (Widget*);
595 void _setStyled (Widget*);
596 void _setParented (Widget*, bool=false);
597 void _setManaged (Widget*, bool=false);
598
599 void _positionWidget(Widget*, point_type, point_type);
600
601 // These return the smallest and largest width and height values for the given
602 // range of Widgets.
603 point_type _getMinWidgetWidth (int = 0, int = 0, int = 1) const;
604 point_type _getMinWidgetHeight (int = 0, int = 0, int = 1) const;
605 point_type _getMaxWidgetWidth (int = 0, int = 0, int = 1) const;
606 point_type _getMaxWidgetHeight (int = 0, int = 0, int = 1) const;
607
608 // These return the smallest and largest minWidth and minHeight values for
609 // the given range of Widgets.
610 point_type _getMinWidgetMinWidth (int = 0, int = 0, int = 1) const;
611 point_type _getMinWidgetMinHeight (int = 0, int = 0, int = 1) const;
612 point_type _getMaxWidgetMinWidth (int = 0, int = 0, int = 1) const;
613 point_type _getMaxWidgetMinHeight (int = 0, int = 0, int = 1) const;
614
615 // These return the smallest and largest width and height total (width + pad)
616 // values for the given range of Widgets.
617 point_type _getMinWidgetWidthTotal (int = 0, int = 0, int = 1) const;
618 point_type _getMinWidgetHeightTotal (int = 0, int = 0, int = 1) const;
619 point_type _getMaxWidgetWidthTotal (int = 0, int = 0, int = 1) const;
620 point_type _getMaxWidgetHeightTotal (int = 0, int = 0, int = 1) const;
621
622 // These return the smallest and largest minWidth and minHeight total
623 // (width + pad) values for the given range of Widgets.
624 point_type _getMinWidgetMinWidthTotal (int = 0, int = 0, int = 1) const;
625 point_type _getMinWidgetMinHeightTotal (int = 0, int = 0, int = 1) const;
626 point_type _getMaxWidgetMinWidthTotal (int = 0, int = 0, int = 1) const;
627 point_type _getMaxWidgetMinHeightTotal (int = 0, int = 0, int = 1) const;
628
629 // These return the smallest and largest horizontal and vertical padding
630 // values for the given range of Widgets.
631 point_type _getMinWidgetPadHorizontal (int = 0, int = 0, int = 1) const;
632 point_type _getMinWidgetPadVertical (int = 0, int = 0, int = 1) const;
633 point_type _getMaxWidgetPadHorizontal (int = 0, int = 0, int = 1) const;
634 point_type _getMaxWidgetPadVertical (int = 0, int = 0, int = 1) const;
635
636 point_type _getNumFill(int = 0, int = 0, int = 1) const;
637
638 // This method is passed the additional values by which width and height should be
639 // modified as calculed by the parent method, Window::resize. Keep in mind that these
640 // values can be negative (indicating a potential "shrink" request) or positive (which
641 // would indicate a "grow" request).
642 virtual void _resizeImplementation(point_type, point_type) = 0;
643
644 // These are made into implementation functions since getting the width or height
645 // of a window can potentially be an expensive operation, and we'll want to cache
646 // results if possible (which is handled transparently by the actual Window::resize
647 // method). They return a Sizes struct which contains two members: cur (for current)
648 // and min (minimum). It's important that the Window know it's minimum possible
649 // size so that it can ignore invalid requests to resize.
650 //
651 // Default versions using BoundingBox calculations are provided, but some Windows
652 // override this (Table, Box).
653 virtual Sizes _getWidthImplementation () const;
654 virtual Sizes _getHeightImplementation () const;
655
656};
657
658typedef Window::WindowList WindowList;
659
660}
661
662#endif