// -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008 #include #include namespace osgWidget { Box::Box(const std::string& name, BoxType bt, bool uniform): Window (name), _boxType (bt), _uniform (uniform), _lastAdd (0) { } Box::Box(const Box& box, const osg::CopyOp& co): Window (box, co), _boxType (box._boxType), _uniform (box._uniform), _lastAdd (box._lastAdd) { } // TODO: Here's something to consider! If we resize the box by 1 every time, only the // first resizable Widget will continue to get larger. This is really silly. void Box::_resizeImplementation(point_type w, point_type h) { // Get the number of Widgets that agree to fill. Also perfom some casting to integers // in case we're being request to resize with pixel perfection. point_type numFill = _getNumFill(); int iw = static_cast(w); int ih = static_cast(h); int inumFill = static_cast(numFill); int wrem = 0; int hrem = 0; // If we have some widgets that fill, use these variables to keep a running count // of what needs to be added. if(inumFill) { wrem = iw % inumFill; hrem = ih % inumFill; } // If we have any widgets that agree to fill and there has been an honest resize // request, handle it here. The first case handles resizes where we have AT LEAST // as many pixels to fill as we have objects. if(numFill > 0.0f && (w != 0.0f || h != 0.0f)) { unsigned int cur = 0; for(Iterator i = begin(); i != end(); i++) if(i->valid() && i->get()->canFill()) { point_type addWidth = 0.0f; point_type addHeight = 0.0f; // If our last added-to Widget was the last one, reset it to 0. if(_lastAdd >= size()) _lastAdd = 0; // We EVENLY give any remaining space to all fillable Widgets. In the // future we may want to be able to specify a fill "percent", which // would be some portion of the total available space. if(_boxType == HORIZONTAL) { if(w) { addWidth += static_cast(iw / inumFill); if(cur >= _lastAdd && wrem) { _lastAdd++; addWidth++; wrem--; } } if(h) addHeight += h; } else { if(w) addWidth += w; if(h) { addHeight += static_cast(ih / inumFill); if(cur >= _lastAdd && hrem) { _lastAdd++; addHeight++; hrem--; } } } if(addWidth != 0.0f) i->get()->addWidth(addWidth); if(addHeight != 0.0f) i->get()->addHeight(addHeight); cur++; } } // Get the width and height of our largest widgets; these values take // into account the padding, and will be affected by any resizing that occured above. point_type maxWidth = _getMaxWidgetWidthTotal(); point_type maxHeight = _getMaxWidgetHeightTotal(); // Create counters for the various offsets as we position Widgets. point_type xoff = 0.0f; point_type yoff = 0.0f; point_type xadd = 0.0f; point_type yadd = 0.0f; for(Iterator i = begin(); i != end(); i++) { Widget* widget = i->get(); // This positioning works by setting each Widget's unmodified origin and then // letting Window::_positionWidget calculate the padding/fill. if(_boxType == HORIZONTAL) { // First, lets set it to the proper x offset, ignoring any padding. widget->setOrigin(xoff, 0.0f); // Immediately reset our xoff for the next iteration. if(_uniform) { _positionWidget(widget, maxWidth, maxHeight); xadd = maxWidth; } else { _positionWidget(widget, widget->getWidthTotal(), maxHeight); xadd = widget->getWidthTotal(); } } else { widget->setOrigin(0.0f, yoff); if(_uniform) { _positionWidget(widget, maxWidth, maxHeight); yadd = maxHeight; } else { _positionWidget(widget, maxWidth, widget->getHeightTotal()); yadd = widget->getHeightTotal(); } } xoff += xadd; yoff += yadd; } } Window::Sizes Box::_getWidthImplementation() const { // The width of a horizontal box is all of the widgets added together. if(_boxType == HORIZONTAL) { // If we're a uniformly sized box, our width is our largest width plus our // largest padding, multiplied times the number of widgets. Our minimum width // is the size of the largest minWidth times the number of widgets. if(_uniform) return Sizes( _getMaxWidgetWidthTotal() * size(), _getMaxWidgetMinWidthTotal() * size() ); // Othweriwse, our width is all of the widths added together, and our minWidth // is all of the minWidths added together. else return Sizes( _accumulate(&Widget::getWidthTotal), _accumulate(&Widget::getMinWidthTotal) ); } // If we're a vertical Box, our width is the width of the larget Widget in the group. // Our minWidth is the largest minWidth of the Widgets in the group. else return Sizes( _getMaxWidgetWidthTotal(), _getMaxWidgetMinWidthTotal() ); } Window::Sizes Box::_getHeightImplementation() const { if(_boxType == VERTICAL) { if(_uniform) return Sizes( _getMaxWidgetHeightTotal() * size(), _getMaxWidgetMinHeightTotal() * size() ); else return Sizes( _accumulate(&Widget::getHeightTotal), _accumulate(&Widget::getMinHeightTotal) ); } else return Sizes( _getMaxWidgetHeightTotal(), _getMaxWidgetMinHeightTotal() ); } }