1 /* 2 * This file is part of Dune Legacy. 3 * 4 * Dune Legacy is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * Dune Legacy is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with Dune Legacy. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #ifndef HBOX_H 19 #define HBOX_H 20 21 #include "Container.h" 22 23 #include <algorithm> 24 25 class HBox_WidgetData { 26 public: HBox_WidgetData()27 HBox_WidgetData() : pWidget(nullptr), fixedWidth(0), weight(0.0) { }; HBox_WidgetData(Widget * _pWidget,Sint32 _fixedWidth)28 HBox_WidgetData(Widget* _pWidget, Sint32 _fixedWidth) : pWidget(_pWidget), fixedWidth(_fixedWidth), weight(0.0) { }; HBox_WidgetData(Widget * _pWidget,double _weight)29 HBox_WidgetData(Widget* _pWidget, double _weight) : pWidget(_pWidget), fixedWidth(-1), weight(_weight) { }; 30 31 Widget* pWidget; 32 Sint32 fixedWidth; 33 double weight; 34 }; 35 36 /// A container class for horizontal aligned widgets. 37 class HBox : public Container<HBox_WidgetData> { 38 public: 39 /// default constructor HBox()40 HBox() : Container<HBox_WidgetData>() { 41 ; 42 } 43 44 /// destructor ~HBox()45 virtual ~HBox() { 46 ; 47 } 48 49 /** 50 This method adds a new widget to this container. 51 \param newWidget Widget to add 52 \param fixedWidth a fixed width for this widget (must be greater than the minimum size) 53 */ addWidget(Widget * newWidget,Sint32 fixedWidth)54 virtual void addWidget(Widget* newWidget, Sint32 fixedWidth) { 55 if(newWidget != nullptr) { 56 containedWidgets.push_back(HBox_WidgetData(newWidget, fixedWidth)); 57 newWidget->setParent(this); 58 Widget::resizeAll(); 59 } 60 } 61 62 /** 63 This method adds a new widget to this container. 64 \param newWidget Widget to add 65 \param weight The weight for this widget (default=1.0) 66 */ 67 virtual void addWidget(Widget* newWidget, double weight = 1.0) { 68 if(newWidget != nullptr) { 69 containedWidgets.push_back(HBox_WidgetData(newWidget, weight)); 70 newWidget->setParent(this); 71 Widget::resizeAll(); 72 } 73 } 74 75 /** 76 Returns the minimum size of this container. The container should not 77 resized to a size smaller than this. If the container is not resizeable 78 in a direction this method returns the size in that direction. 79 \return the minimum size of this container 80 */ getMinimumSize()81 virtual Point getMinimumSize() const { 82 Point p(0,0); 83 for(const HBox_WidgetData& widgetData : containedWidgets) { 84 if(widgetData.fixedWidth > 0) { 85 p.x += widgetData.fixedWidth; 86 } else { 87 p.x += widgetData.pWidget->getMinimumSize().x; 88 } 89 p.y = std::max(p.y,widgetData.pWidget->getMinimumSize().y); 90 } 91 return p; 92 } 93 94 /** 95 This method resizes the container. This method should only 96 called if the new size is a valid size for this container (See getMinumumSize). 97 \param newSize the new size of this progress bar 98 */ resize(Point newSize)99 virtual void resize(Point newSize) { 100 resize(newSize.x,newSize.y); 101 } 102 103 /** 104 This method resizes the container to width and height. This method should only be 105 called if the new size is a valid size for this container (See resizingXAllowed, 106 resizingYAllowed, getMinumumSize). It also resizes all child widgets. 107 \param width the new width of this container 108 \param height the new height of this container 109 */ resize(Uint32 width,Uint32 height)110 virtual void resize(Uint32 width, Uint32 height) { 111 Sint32 availableWidth = width; 112 113 int numRemainingWidgets = containedWidgets.size(); 114 115 // Find objects that are not allowed to be resized or have a fixed width 116 // also find the sum of all weights 117 double weightSum = 0.0; 118 for(const HBox_WidgetData& widgetData : containedWidgets) { 119 if(widgetData.pWidget->resizingXAllowed() == false) { 120 availableWidth = availableWidth - widgetData.pWidget->getSize().x; 121 numRemainingWidgets--; 122 } else if(widgetData.fixedWidth > 0) { 123 availableWidth = availableWidth - widgetData.fixedWidth; 124 numRemainingWidgets--; 125 } else { 126 weightSum += widgetData.weight; 127 } 128 } 129 130 // Under the resizeable widgets find all objects that are oversized (minimum size > availableWidth*weight) 131 // also calculate the weight sum of all the resizeable widgets that are not oversized 132 Sint32 neededOversizeWidth = 0; 133 double notOversizedWeightSum = 0.0; 134 for(const HBox_WidgetData& widgetData : containedWidgets) { 135 if(widgetData.pWidget->resizingXAllowed() == true && widgetData.fixedWidth <= 0) { 136 if((double) widgetData.pWidget->getMinimumSize().x > availableWidth * (widgetData.weight/weightSum)) { 137 neededOversizeWidth += widgetData.pWidget->getMinimumSize().x; 138 } else { 139 notOversizedWeightSum += widgetData.weight; 140 } 141 } 142 } 143 144 Sint32 totalAvailableWidth = availableWidth; 145 for(const HBox_WidgetData& widgetData : containedWidgets) { 146 Sint32 widgetHeight; 147 if(widgetData.pWidget->resizingYAllowed() == true) { 148 widgetHeight = height; 149 } else { 150 widgetHeight = widgetData.pWidget->getMinimumSize().y; 151 } 152 153 if(widgetData.pWidget->resizingXAllowed() == true) { 154 Sint32 widgetWidth = 0; 155 156 if(widgetData.fixedWidth <= 0) { 157 if(numRemainingWidgets <= 1) { 158 widgetWidth = availableWidth; 159 } else if((double) widgetData.pWidget->getMinimumSize().x > totalAvailableWidth * (widgetData.weight/weightSum)) { 160 widgetWidth = widgetData.pWidget->getMinimumSize().x; 161 } else { 162 widgetWidth = (Sint32) ((totalAvailableWidth-neededOversizeWidth) * (widgetData.weight/notOversizedWeightSum)); 163 } 164 availableWidth -= widgetWidth; 165 numRemainingWidgets--; 166 } else { 167 widgetWidth = widgetData.fixedWidth; 168 } 169 170 widgetData.pWidget->resize(widgetWidth,widgetHeight); 171 } else { 172 widgetData.pWidget->resize(widgetData.pWidget->getSize().x,widgetHeight); 173 } 174 } 175 176 Container<HBox_WidgetData>::resize(width,height); 177 } 178 179 /** 180 This static method creates a dynamic HBox object. 181 The idea behind this method is to simply create a new HBox on the fly and 182 add it to a container. If the container gets destroyed also this HBox will be freed. 183 \return The new created HBox (will be automatically destroyed when it's parent widget is destroyed) 184 */ create()185 static HBox* create() { 186 HBox* hbox = new HBox(); 187 hbox->pAllocated = true; 188 return hbox; 189 } 190 191 protected: 192 /** 193 This method must be overwritten by all container classes. It should return 194 the position of the specified widget. 195 \param widgetData the widget data to get the position from. 196 \return The position of the left upper corner 197 */ getPosition(const HBox_WidgetData & widgetData)198 virtual Point getPosition(const HBox_WidgetData& widgetData) const { 199 Point p(0,0); 200 for(const HBox_WidgetData& tmpWidgetData : containedWidgets) { 201 if(widgetData.pWidget == tmpWidgetData.pWidget) { 202 p.y = (getSize().y - tmpWidgetData.pWidget->getSize().y)/2; 203 return p; 204 } else { 205 p.x = p.x + tmpWidgetData.pWidget->getSize().x; 206 } 207 } 208 209 //should not happen 210 return Point(0,0); 211 } 212 }; 213 214 #endif // HBOX_H 215 216