1 // Copyright 2006-2012 Asger Feldthaus
\r
2 // This file is part of the "Irrlicht Engine".
\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
\r
6 Originally Klasker's but I've messed around with it lots - Gaz
\r
9 #include "CGUIPanel.h"
\r
10 #include "IGUIEnvironment.h"
\r
11 #include "IGUIScrollBar.h"
\r
12 #include "IGUITabControl.h"
\r
13 #include "IVideoDriver.h"
\r
15 const int SCROLL_BAR_SIZE = 16; // Scroll bars are 16 pixels wide
\r
16 const int BORDER_WIDTH = 2;
\r
23 CGUIPanel::CGUIPanel(IGUIEnvironment* environment, IGUIElement* parent, s32 id, const core::rect<s32>& rectangle,
\r
24 bool border, E_SCROLL_BAR_MODE vMode, E_SCROLL_BAR_MODE hMode)
\r
25 : IGUIElement(EGUIET_ELEMENT, environment, parent, id, rectangle),
\r
26 VScrollBar(0), HScrollBar(0), ClipPane(0), InnerPane(0),
\r
27 VScrollBarMode(vMode), HScrollBarMode(hMode), NeedsUpdate(true), Border(border)
\r
30 setDebugName("CGUIPanel");
\r
33 s32 width = rectangle.getWidth();
\r
34 s32 height = rectangle.getHeight();
\r
36 core::rect<s32> rct = core::rect<s32>(width - SCROLL_BAR_SIZE,0, width, height);
\r
38 VScrollBar = environment->addScrollBar(false, rct, 0, id);
\r
39 VScrollBar->setSubElement(true);
\r
40 VScrollBar->setTabStop(false);
\r
41 VScrollBar->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
\r
43 IGUIElement::addChild(VScrollBar);
\r
45 rct = core::rect<s32>(0, height - SCROLL_BAR_SIZE, width - SCROLL_BAR_SIZE,height );
\r
47 HScrollBar = environment->addScrollBar(true, rct, 0, id);
\r
48 HScrollBar->setSubElement(true);
\r
49 HScrollBar->setTabStop(false);
\r
50 HScrollBar->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT);
\r
52 IGUIElement::addChild(HScrollBar);
\r
54 rct = core::rect<s32>(0,0, width - SCROLL_BAR_SIZE, height - SCROLL_BAR_SIZE);
\r
56 ClipPane = environment->addTab( rct, 0, -1);
\r
57 ClipPane->setSubElement(true);
\r
58 ClipPane->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
\r
60 IGUIElement::addChild(ClipPane);
\r
62 InnerPane = environment->addTab(rct, ClipPane, -1);
\r
63 InnerPane->setSubElement(true);
\r
66 calculateClientArea();
\r
70 CGUIPanel::~CGUIPanel()
\r
72 // because the inner pane has the list of children, we need to remove the outer ones manually
\r
73 IGUIElement::removeChild(VScrollBar);
\r
74 IGUIElement::removeChild(HScrollBar);
\r
75 IGUIElement::removeChild(ClipPane);
\r
77 // now we can drop the others
\r
85 void CGUIPanel::draw()
\r
89 calculateClientArea();
\r
91 NeedsUpdate = false;
\r
94 IGUISkin* skin = Environment->getSkin();
\r
97 skin->draw3DSunkenPane( this, skin->getColor( EGDC_APP_WORKSPACE), false, true, AbsoluteRect, &AbsoluteClippingRect );
\r
100 IGUIElement::draw();
\r
103 void CGUIPanel::addChild(IGUIElement *child)
\r
105 // add the child to the inner pane
\r
106 InnerPane->addChild(child);
\r
108 NeedsUpdate = true;
\r
111 void CGUIPanel::removeChild(IGUIElement *child)
\r
113 InnerPane->removeChild(child);
\r
115 NeedsUpdate = true;
\r
118 //! returns children of the inner pane
\r
119 const core::list<IGUIElement*>& CGUIPanel::getChildren()
\r
121 return InnerPane->getChildren();
\r
124 bool CGUIPanel::hasBorder() const
\r
129 void CGUIPanel::setBorder( bool enabled )
\r
134 IGUIScrollBar* CGUIPanel::getVScrollBar() const
\r
139 IGUIScrollBar* CGUIPanel::getHScrollBar() const
\r
144 E_SCROLL_BAR_MODE CGUIPanel::getVScrollBarMode() const
\r
146 return VScrollBarMode;
\r
149 void CGUIPanel::setVScrollBarMode( E_SCROLL_BAR_MODE mode )
\r
151 VScrollBarMode = mode;
\r
152 NeedsUpdate = true;
\r
155 E_SCROLL_BAR_MODE CGUIPanel::getHScrollBarMode() const
\r
157 return HScrollBarMode;
\r
160 void CGUIPanel::setHScrollBarMode(E_SCROLL_BAR_MODE mode)
\r
162 HScrollBarMode = mode;
\r
163 NeedsUpdate = true;
\r
166 bool CGUIPanel::OnEvent(const SEvent &event)
\r
168 // Redirect mouse wheel to scrollbar
\r
169 if (event.EventType == EET_MOUSE_INPUT_EVENT && event.MouseInput.Event == EMIE_MOUSE_WHEEL)
\r
171 if (VScrollBar->isVisible())
\r
173 Environment->setFocus(VScrollBar);
\r
174 VScrollBar->OnEvent(event);
\r
177 else if (VScrollBar->isVisible())
\r
179 Environment->setFocus(HScrollBar);
\r
180 HScrollBar->OnEvent(event);
\r
186 if (event.EventType == EET_GUI_EVENT && event.GUIEvent.EventType == EGET_SCROLL_BAR_CHANGED &&
\r
187 (event.GUIEvent.Caller == HScrollBar || event.GUIEvent.Caller == VScrollBar) )
\r
195 return IGUIElement::OnEvent(event);
\r
198 void CGUIPanel::moveInnerPane()
\r
200 core::dimension2d<s32> dim = InnerPane->getAbsolutePosition().getSize();
\r
201 core::position2d<s32> newpos(HScrollBar->isVisible() ? -HScrollBar->getPos() : 0 , VScrollBar->isVisible() ? -VScrollBar->getPos() : 0);
\r
202 core::rect<s32> r(newpos, newpos + dim);
\r
203 InnerPane->setRelativePosition(r);
\r
207 void CGUIPanel::updateAbsolutePosition()
\r
209 IGUIElement::updateAbsolutePosition();
\r
210 calculateClientArea();
\r
215 void CGUIPanel::resizeInnerPane()
\r
217 if (!HScrollBar || !VScrollBar || !InnerPane || !ClipPane)
\r
220 // get outer pane size
\r
221 core::rect<s32> outerRect = ClipPane->getRelativePosition();
\r
223 // resize flexible children depending on outer pane
\r
224 InnerPane->setRelativePosition(outerRect);
\r
226 // get desired size (total size of all children)
\r
227 core::rect<s32> totalRect(0, 0, 0, 0);
\r
229 core::list<IGUIElement*>::ConstIterator it;
\r
231 for (it = InnerPane->getChildren().begin();
\r
232 it != InnerPane->getChildren().end(); ++it)
\r
234 core::rect<s32> rct = (*it)->getRelativePosition();
\r
235 totalRect.addInternalPoint(rct.UpperLeftCorner);
\r
236 totalRect.addInternalPoint(rct.LowerRightCorner);
\r
239 // move children if pane needs to grow
\r
240 core::position2di adjustedMovement(0,0);
\r
242 if (totalRect.UpperLeftCorner.X < 0)
\r
243 adjustedMovement.X = -totalRect.UpperLeftCorner.X;
\r
244 if (totalRect.UpperLeftCorner.Y < 0)
\r
245 adjustedMovement.Y = -totalRect.UpperLeftCorner.Y;
\r
247 if (adjustedMovement.X > 0 || adjustedMovement.Y > 0)
\r
249 totalRect += adjustedMovement;
\r
251 for (it = InnerPane->getChildren().begin();
\r
252 it != InnerPane->getChildren().end(); ++it )
\r
254 (*it)->move(adjustedMovement);
\r
258 // make sure the inner pane is at least as big as the outer
\r
259 if (totalRect.getWidth() < outerRect.getWidth())
\r
261 totalRect.UpperLeftCorner.X = 0;
\r
262 totalRect.LowerRightCorner.X = outerRect.getWidth();
\r
264 if (totalRect.getHeight() < outerRect.getHeight())
\r
266 totalRect.UpperLeftCorner.Y = 0;
\r
267 totalRect.LowerRightCorner.Y = outerRect.getHeight();
\r
270 InnerPane->setRelativePosition(totalRect);
\r
273 if ( HScrollBarMode != ESBM_ALWAYS_INVISIBLE &&
\r
274 (totalRect.getWidth() > outerRect.getWidth() || HScrollBarMode == ESBM_ALWAYS_VISIBLE) )
\r
276 HScrollBar->setVisible(true);
\r
277 HScrollBar->setMax(totalRect.getWidth() - outerRect.getWidth());
\r
278 bringToFront(HScrollBar);
\r
281 HScrollBar->setVisible(false);
\r
283 if ( VScrollBarMode != ESBM_ALWAYS_INVISIBLE &&
\r
284 (totalRect.getHeight() > outerRect.getHeight() || VScrollBarMode == ESBM_ALWAYS_VISIBLE) )
\r
286 VScrollBar->setVisible(true);
\r
287 VScrollBar->setMax(totalRect.getHeight() - outerRect.getHeight());
\r
288 bringToFront(VScrollBar);
\r
291 VScrollBar->setVisible(false);
\r
293 // move to adjust for scrollbar pos
\r
297 void CGUIPanel::calculateClientArea()
\r
299 core::rect<s32> ClientArea(0,0, AbsoluteRect.getWidth(),AbsoluteRect.getHeight());
\r
301 if (VScrollBar->isVisible())
\r
302 ClientArea.LowerRightCorner.X -= VScrollBar->getRelativePosition().getWidth();
\r
304 if (HScrollBar->isVisible())
\r
305 ClientArea.LowerRightCorner.Y -= HScrollBar->getRelativePosition().getHeight();
\r
309 ClientArea.UpperLeftCorner += core::position2d<s32>( BORDER_WIDTH, BORDER_WIDTH );
\r
310 ClientArea.LowerRightCorner -= core::position2d<s32>( BORDER_WIDTH, BORDER_WIDTH );
\r
313 ClipPane->setRelativePosition(ClientArea);
\r
316 core::rect<s32> CGUIPanel::getClientArea() const
\r
318 return ClipPane->getRelativePosition();
\r
321 void CGUIPanel::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options)
\r
323 IGUIElement::serializeAttributes(out, options);
\r
325 out->addBool("border", Border);
\r
326 out->addEnum("horizontalScrollBar", HScrollBarMode, GUIScrollBarModeNames );
\r
327 out->addEnum("verticalScrollBar", VScrollBarMode, GUIScrollBarModeNames );
\r
330 void CGUIPanel::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
\r
332 IGUIElement::deserializeAttributes(in, options);
\r
334 setBorder(in->getAttributeAsBool("border"));
\r
335 setHScrollBarMode((E_SCROLL_BAR_MODE)in->getAttributeAsEnumeration("horizontalScrollBar", GUIScrollBarModeNames));
\r
336 setVScrollBarMode((E_SCROLL_BAR_MODE)in->getAttributeAsEnumeration("verticalScrollBar", GUIScrollBarModeNames));
\r