1 // Copyright 2006-2012 Asger Feldthaus
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
4 
5 /*
6 	Originally Klasker's but I've messed around with it lots - Gaz
7 */
8 
9 #include "CGUIPanel.h"
10 #include "IGUIEnvironment.h"
11 #include "IGUIScrollBar.h"
12 #include "IGUITabControl.h"
13 #include "IVideoDriver.h"
14 
15 const int SCROLL_BAR_SIZE = 16; // Scroll bars are 16 pixels wide
16 const int BORDER_WIDTH = 2;
17 
18 namespace irr
19 {
20 namespace gui
21 {
22 
CGUIPanel(IGUIEnvironment * environment,IGUIElement * parent,s32 id,const core::rect<s32> & rectangle,bool border,E_SCROLL_BAR_MODE vMode,E_SCROLL_BAR_MODE hMode)23 CGUIPanel::CGUIPanel(IGUIEnvironment* environment, IGUIElement* parent, s32 id, const core::rect<s32>& rectangle,
24 			bool border, E_SCROLL_BAR_MODE vMode, E_SCROLL_BAR_MODE hMode)
25 	: IGUIElement(EGUIET_ELEMENT, environment, parent, id, rectangle),
26 	VScrollBar(0), HScrollBar(0), ClipPane(0), InnerPane(0),
27 	VScrollBarMode(vMode), HScrollBarMode(hMode), NeedsUpdate(true), Border(border)
28 {
29 	#ifdef _DEBUG
30 	setDebugName("CGUIPanel");
31 	#endif
32 
33 	s32 width = rectangle.getWidth();
34 	s32 height = rectangle.getHeight();
35 
36 	core::rect<s32> rct = core::rect<s32>(width - SCROLL_BAR_SIZE,0, width, height);
37 
38 	VScrollBar = environment->addScrollBar(false, rct, 0, id);
39 	VScrollBar->setSubElement(true);
40 	VScrollBar->setTabStop(false);
41 	VScrollBar->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
42 	VScrollBar->grab();
43 	IGUIElement::addChild(VScrollBar);
44 
45 	rct = core::rect<s32>(0, height - SCROLL_BAR_SIZE, width - SCROLL_BAR_SIZE,height );
46 
47 	HScrollBar = environment->addScrollBar(true, rct, 0, id);
48 	HScrollBar->setSubElement(true);
49 	HScrollBar->setTabStop(false);
50 	HScrollBar->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT);
51 	HScrollBar->grab();
52 	IGUIElement::addChild(HScrollBar);
53 
54 	rct = core::rect<s32>(0,0, width - SCROLL_BAR_SIZE, height - SCROLL_BAR_SIZE);
55 
56 	ClipPane = environment->addTab( rct, 0, -1);
57 	ClipPane->setSubElement(true);
58 	ClipPane->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
59 	ClipPane->grab();
60 	IGUIElement::addChild(ClipPane);
61 
62 	InnerPane = environment->addTab(rct, ClipPane, -1);
63 	InnerPane->setSubElement(true);
64 	InnerPane->grab();
65 
66 	calculateClientArea();
67 	resizeInnerPane();
68 }
69 
~CGUIPanel()70 CGUIPanel::~CGUIPanel()
71 {
72 	// because the inner pane has the list of children, we need to remove the outer ones manually
73 	IGUIElement::removeChild(VScrollBar);
74 	IGUIElement::removeChild(HScrollBar);
75 	IGUIElement::removeChild(ClipPane);
76 
77 	// now we can drop the others
78 	VScrollBar->drop();
79 	HScrollBar->drop();
80 	ClipPane->drop();
81 	InnerPane->drop();
82 }
83 
84 
draw()85 void CGUIPanel::draw()
86 {
87 	if (NeedsUpdate)
88 	{
89 		calculateClientArea();
90 		resizeInnerPane();
91 		NeedsUpdate = false;
92 	}
93 
94 	IGUISkin* skin = Environment->getSkin();
95 	if (Border && skin)
96 	{
97 		skin->draw3DSunkenPane( this, skin->getColor( EGDC_APP_WORKSPACE), false, true, AbsoluteRect, &AbsoluteClippingRect );
98 	}
99 
100 	IGUIElement::draw();
101 }
102 
addChild(IGUIElement * child)103 void CGUIPanel::addChild(IGUIElement *child)
104 {
105 	// add the child to the inner pane
106 	InnerPane->addChild(child);
107 
108 	NeedsUpdate = true;
109 }
110 
removeChild(IGUIElement * child)111 void CGUIPanel::removeChild(IGUIElement *child)
112 {
113 	InnerPane->removeChild(child);
114 
115 	NeedsUpdate = true;
116 }
117 
118 //! returns children of the inner pane
getChildren()119 const core::list<IGUIElement*>& CGUIPanel::getChildren()
120 {
121 	return InnerPane->getChildren();
122 }
123 
hasBorder() const124 bool CGUIPanel::hasBorder() const
125 {
126 	return Border;
127 }
128 
setBorder(bool enabled)129 void CGUIPanel::setBorder( bool enabled )
130 {
131 	Border = enabled;
132 }
133 
getVScrollBar() const134 IGUIScrollBar* CGUIPanel::getVScrollBar() const
135 {
136 	return VScrollBar;
137 }
138 
getHScrollBar() const139 IGUIScrollBar* CGUIPanel::getHScrollBar() const
140 {
141 	return HScrollBar;
142 }
143 
getVScrollBarMode() const144 E_SCROLL_BAR_MODE CGUIPanel::getVScrollBarMode() const
145 {
146 	return VScrollBarMode;
147 }
148 
setVScrollBarMode(E_SCROLL_BAR_MODE mode)149 void CGUIPanel::setVScrollBarMode( E_SCROLL_BAR_MODE mode )
150 {
151 	VScrollBarMode = mode;
152 	NeedsUpdate = true;
153 }
154 
getHScrollBarMode() const155 E_SCROLL_BAR_MODE CGUIPanel::getHScrollBarMode() const
156 {
157 	return HScrollBarMode;
158 }
159 
setHScrollBarMode(E_SCROLL_BAR_MODE mode)160 void CGUIPanel::setHScrollBarMode(E_SCROLL_BAR_MODE mode)
161 {
162 	HScrollBarMode = mode;
163 	NeedsUpdate = true;
164 }
165 
OnEvent(const SEvent & event)166 bool CGUIPanel::OnEvent(const SEvent &event)
167 {
168 	// Redirect mouse wheel to scrollbar
169 	if (event.EventType == EET_MOUSE_INPUT_EVENT && event.MouseInput.Event == EMIE_MOUSE_WHEEL)
170 	{
171 		if (VScrollBar->isVisible())
172 		{
173 			Environment->setFocus(VScrollBar);
174 			VScrollBar->OnEvent(event);
175 			return true;
176 		}
177 		else if (VScrollBar->isVisible())
178 		{
179 			Environment->setFocus(HScrollBar);
180 			HScrollBar->OnEvent(event);
181 			return true;
182 		}
183 	}
184 	else
185 	{
186 		if (event.EventType == EET_GUI_EVENT && event.GUIEvent.EventType == EGET_SCROLL_BAR_CHANGED &&
187 			(event.GUIEvent.Caller == HScrollBar || event.GUIEvent.Caller == VScrollBar) )
188 		{
189 			moveInnerPane();
190 
191 			return true;
192 		}
193 	}
194 
195 	return IGUIElement::OnEvent(event);
196 }
197 
moveInnerPane()198 void CGUIPanel::moveInnerPane()
199 {
200 	core::dimension2d<s32> dim = InnerPane->getAbsolutePosition().getSize();
201 	core::position2d<s32> newpos(HScrollBar->isVisible() ? -HScrollBar->getPos() : 0 , VScrollBar->isVisible() ? -VScrollBar->getPos() : 0);
202 	core::rect<s32> r(newpos, newpos + dim);
203 	InnerPane->setRelativePosition(r);
204 }
205 
206 
updateAbsolutePosition()207 void CGUIPanel::updateAbsolutePosition()
208 {
209 	IGUIElement::updateAbsolutePosition();
210 	calculateClientArea();
211 	resizeInnerPane();
212 }
213 
214 
resizeInnerPane()215 void CGUIPanel::resizeInnerPane()
216 {
217 	if (!HScrollBar || !VScrollBar || !InnerPane || !ClipPane)
218 		return;
219 
220 	// get outer pane size
221 	core::rect<s32> outerRect = ClipPane->getRelativePosition();
222 
223 	// resize flexible children depending on outer pane
224 	InnerPane->setRelativePosition(outerRect);
225 
226 	// get desired size (total size of all children)
227 	core::rect<s32> totalRect(0, 0, 0, 0);
228 
229 	core::list<IGUIElement*>::ConstIterator it;
230 
231 	for (it  = InnerPane->getChildren().begin();
232          it != InnerPane->getChildren().end(); ++it)
233 	{
234 		core::rect<s32> rct = (*it)->getRelativePosition();
235 		totalRect.addInternalPoint(rct.UpperLeftCorner);
236 		totalRect.addInternalPoint(rct.LowerRightCorner);
237 	}
238 
239 	// move children if pane needs to grow
240 	core::position2di adjustedMovement(0,0);
241 
242 	if (totalRect.UpperLeftCorner.X < 0)
243 		adjustedMovement.X = -totalRect.UpperLeftCorner.X;
244 	if (totalRect.UpperLeftCorner.Y < 0)
245 		adjustedMovement.Y = -totalRect.UpperLeftCorner.Y;
246 
247 	if (adjustedMovement.X > 0 || adjustedMovement.Y > 0)
248 	{
249 		totalRect += adjustedMovement;
250 
251 		for (it = InnerPane->getChildren().begin();
252 			it != InnerPane->getChildren().end(); ++it )
253 		{
254 			(*it)->move(adjustedMovement);
255 		}
256 	}
257 
258 	// make sure the inner pane is at least as big as the outer
259 	if (totalRect.getWidth() < outerRect.getWidth())
260 	{
261 		totalRect.UpperLeftCorner.X = 0;
262 		totalRect.LowerRightCorner.X = outerRect.getWidth();
263 	}
264 	if (totalRect.getHeight() < outerRect.getHeight())
265 	{
266 		totalRect.UpperLeftCorner.Y = 0;
267 		totalRect.LowerRightCorner.Y = outerRect.getHeight();
268 	}
269 
270 	InnerPane->setRelativePosition(totalRect);
271 
272 	// scrollbars
273 	if ( HScrollBarMode != ESBM_ALWAYS_INVISIBLE &&
274 		(totalRect.getWidth() > outerRect.getWidth() || HScrollBarMode == ESBM_ALWAYS_VISIBLE) )
275 	{
276 		HScrollBar->setVisible(true);
277 		HScrollBar->setMax(totalRect.getWidth() - outerRect.getWidth());
278 		bringToFront(HScrollBar);
279 	}
280 	else
281 		HScrollBar->setVisible(false);
282 
283 	if ( VScrollBarMode != ESBM_ALWAYS_INVISIBLE &&
284 		(totalRect.getHeight() > outerRect.getHeight() || VScrollBarMode == ESBM_ALWAYS_VISIBLE) )
285 	{
286 		VScrollBar->setVisible(true);
287 		VScrollBar->setMax(totalRect.getHeight() - outerRect.getHeight());
288 		bringToFront(VScrollBar);
289 	}
290 	else
291 		VScrollBar->setVisible(false);
292 
293 	// move to adjust for scrollbar pos
294 	moveInnerPane();
295 }
296 
calculateClientArea()297 void CGUIPanel::calculateClientArea()
298 {
299 	core::rect<s32> ClientArea(0,0, AbsoluteRect.getWidth(),AbsoluteRect.getHeight());
300 
301 	if (VScrollBar->isVisible())
302 		ClientArea.LowerRightCorner.X -= VScrollBar->getRelativePosition().getWidth();
303 
304 	if (HScrollBar->isVisible())
305 		ClientArea.LowerRightCorner.Y -= HScrollBar->getRelativePosition().getHeight();
306 
307 	if (Border)
308 	{
309 		ClientArea.UpperLeftCorner += core::position2d<s32>( BORDER_WIDTH, BORDER_WIDTH );
310 		ClientArea.LowerRightCorner -= core::position2d<s32>( BORDER_WIDTH, BORDER_WIDTH );
311 	}
312 
313 	ClipPane->setRelativePosition(ClientArea);
314 }
315 
getClientArea() const316 core::rect<s32> CGUIPanel::getClientArea() const
317 {
318 	return ClipPane->getRelativePosition();
319 }
320 
serializeAttributes(io::IAttributes * out,io::SAttributeReadWriteOptions * options)321 void CGUIPanel::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options)
322 {
323 	IGUIElement::serializeAttributes(out, options);
324 
325 	out->addBool("border", Border);
326 	out->addEnum("horizontalScrollBar", HScrollBarMode, GUIScrollBarModeNames );
327 	out->addEnum("verticalScrollBar", VScrollBarMode, GUIScrollBarModeNames );
328 }
329 
deserializeAttributes(io::IAttributes * in,io::SAttributeReadWriteOptions * options)330 void CGUIPanel::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
331 {
332 	IGUIElement::deserializeAttributes(in, options);
333 
334 	setBorder(in->getAttributeAsBool("border"));
335 	setHScrollBarMode((E_SCROLL_BAR_MODE)in->getAttributeAsEnumeration("horizontalScrollBar", GUIScrollBarModeNames));
336 	setVScrollBarMode((E_SCROLL_BAR_MODE)in->getAttributeAsEnumeration("verticalScrollBar", GUIScrollBarModeNames));
337 }
338 
339 } // namespace gui
340 } // namespace irr
341