1 /***********************************************************************
2 created: 1/3/2005
3 author: Paul D Turner
4 *************************************************************************/
5 /***************************************************************************
6 * Copyright (C) 2004 - 2009 Paul D Turner & The CEGUI Development Team
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining
9 * a copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be
17 * included in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 ***************************************************************************/
27 #include "CEGUI/widgets/ScrolledContainer.h"
28 #include "CEGUI/CoordConverter.h"
29 #include "CEGUI/RenderingSurface.h"
30
31 #if defined(_MSC_VER)
32 # pragma warning(push)
33 # pragma warning(disable : 4355)
34 #endif
35
36 // Start of CEGUI namespace section
37 namespace CEGUI
38 {
39 //----------------------------------------------------------------------------//
40 const String ScrolledContainer::WidgetTypeName("ScrolledContainer");
41 const String ScrolledContainer::EventNamespace("ScrolledContainer");
42 const String ScrolledContainer::EventContentChanged("ContentChanged");
43 const String ScrolledContainer::EventAutoSizeSettingChanged("AutoSizeSettingChanged");
44
45 //----------------------------------------------------------------------------//
ScrolledContainer(const String & type,const String & name)46 ScrolledContainer::ScrolledContainer(const String& type, const String& name) :
47 Window(type, name),
48 d_contentArea(0, 0, 0, 0),
49 d_autosizePane(true),
50
51 d_clientChildContentArea(this, static_cast<Element::CachedRectf::DataGenerator>(&ScrolledContainer::getClientChildContentArea_impl))
52 {
53 addScrolledContainerProperties();
54 setMouseInputPropagationEnabled(true);
55 }
56
57 //----------------------------------------------------------------------------//
~ScrolledContainer(void)58 ScrolledContainer::~ScrolledContainer(void)
59 {
60 }
61
62 //----------------------------------------------------------------------------//
isContentPaneAutoSized(void) const63 bool ScrolledContainer::isContentPaneAutoSized(void) const
64 {
65 return d_autosizePane;
66 }
67
68 //----------------------------------------------------------------------------//
setContentPaneAutoSized(bool setting)69 void ScrolledContainer::setContentPaneAutoSized(bool setting)
70 {
71 if (d_autosizePane != setting)
72 {
73 d_autosizePane = setting;
74
75 // Fire events
76 WindowEventArgs args1(this);
77 onAutoSizeSettingChanged(args1);
78 }
79 }
80
81 //----------------------------------------------------------------------------//
getContentArea(void) const82 const Rectf& ScrolledContainer::getContentArea(void) const
83 {
84 return d_contentArea;
85 }
86
87 //----------------------------------------------------------------------------//
setContentArea(const Rectf & area)88 void ScrolledContainer::setContentArea(const Rectf& area)
89 {
90 if (!d_autosizePane)
91 {
92 d_contentArea = area;
93
94 // Fire event
95 WindowEventArgs args(this);
96 onContentChanged(args);
97 }
98
99 }
100
101 //----------------------------------------------------------------------------//
getClientChildContentArea() const102 const Element::CachedRectf& ScrolledContainer::getClientChildContentArea() const
103 {
104 return d_clientChildContentArea;
105 }
106
107 //----------------------------------------------------------------------------//
getNonClientChildContentArea() const108 const Element::CachedRectf& ScrolledContainer::getNonClientChildContentArea() const
109 {
110 return d_clientChildContentArea;
111 }
112
113 //----------------------------------------------------------------------------//
notifyScreenAreaChanged(bool recursive)114 void ScrolledContainer::notifyScreenAreaChanged(bool recursive)
115 {
116 d_clientChildContentArea.invalidateCache();
117
118 Window::notifyScreenAreaChanged(recursive);
119 }
120
121 //----------------------------------------------------------------------------//
getChildExtentsArea(void) const122 Rectf ScrolledContainer::getChildExtentsArea(void) const
123 {
124 Rectf extents(0, 0, 0, 0);
125
126 const size_t childCount = getChildCount();
127 if (childCount == 0)
128 return extents;
129
130 for (size_t i = 0; i < childCount; ++i)
131 {
132 const Window* const wnd = getChildAtIdx(i);
133 Rectf area(
134 CoordConverter::asAbsolute(wnd->getPosition(), d_pixelSize),
135 wnd->getPixelSize());
136
137 if (wnd->getHorizontalAlignment() == HA_CENTRE)
138 area.setPosition(area.getPosition() - CEGUI::Vector2f(area.getWidth() * 0.5f - d_pixelSize.d_width * 0.5f, 0.0f));
139 if (wnd->getVerticalAlignment() == VA_CENTRE)
140 area.setPosition(area.getPosition() - CEGUI::Vector2f(0.0f, area.getHeight() * 0.5f - d_pixelSize.d_height * 0.5f));
141
142 if (area.d_min.d_x < extents.d_min.d_x)
143 extents.d_min.d_x = area.d_min.d_x;
144
145 if (area.d_min.d_y < extents.d_min.d_y)
146 extents.d_min.d_y = area.d_min.d_y;
147
148 if (area.d_max.d_x > extents.d_max.d_x)
149 extents.d_max.d_x = area.d_max.d_x;
150
151 if (area.d_max.d_y > extents.d_max.d_y)
152 extents.d_max.d_y = area.d_max.d_y;
153 }
154
155 return extents;
156 }
157
158 //----------------------------------------------------------------------------//
onContentChanged(WindowEventArgs & e)159 void ScrolledContainer::onContentChanged(WindowEventArgs& e)
160 {
161 if (d_autosizePane)
162 {
163 d_contentArea = getChildExtentsArea();
164 }
165
166 fireEvent(EventContentChanged, e, EventNamespace);
167 }
168
169 //----------------------------------------------------------------------------//
onAutoSizeSettingChanged(WindowEventArgs & e)170 void ScrolledContainer::onAutoSizeSettingChanged(WindowEventArgs& e)
171 {
172 fireEvent(EventAutoSizeSettingChanged, e, EventNamespace);
173
174 if (d_autosizePane)
175 {
176 WindowEventArgs args(this);
177 onContentChanged(args);
178 }
179 }
180
181 //----------------------------------------------------------------------------//
handleChildSized(const EventArgs &)182 bool ScrolledContainer::handleChildSized(const EventArgs&)
183 {
184 // Fire event that notifies that a child's area has changed.
185 WindowEventArgs args(this);
186 onContentChanged(args);
187 return true;
188 }
189
190 //----------------------------------------------------------------------------//
handleChildMoved(const EventArgs &)191 bool ScrolledContainer::handleChildMoved(const EventArgs&)
192 {
193 // Fire event that notifies that a child's area has changed.
194 WindowEventArgs args(this);
195 onContentChanged(args);
196 return true;
197 }
198
199 //----------------------------------------------------------------------------//
getUnclippedInnerRect_impl(bool skipAllPixelAlignment) const200 Rectf ScrolledContainer::getUnclippedInnerRect_impl(bool skipAllPixelAlignment) const
201 {
202 return d_parent ?
203 (skipAllPixelAlignment ? d_parent->getUnclippedInnerRect().getFresh(true) : d_parent->getUnclippedInnerRect().get()) :
204 Window::getUnclippedInnerRect_impl(skipAllPixelAlignment);
205 }
206
207 //----------------------------------------------------------------------------//
getInnerRectClipper_impl() const208 Rectf ScrolledContainer::getInnerRectClipper_impl() const
209 {
210 return d_parent ?
211 getParent()->getInnerRectClipper() :
212 Window::getInnerRectClipper_impl();
213 }
214
215 //----------------------------------------------------------------------------//
getHitTestRect_impl() const216 Rectf ScrolledContainer::getHitTestRect_impl() const
217 {
218 return d_parent ? getParent()->getHitTestRect() :
219 Window::getHitTestRect_impl();
220 }
221
222 //----------------------------------------------------------------------------//
getClientChildContentArea_impl(bool skipAllPixelAlignment) const223 Rectf ScrolledContainer::getClientChildContentArea_impl(bool skipAllPixelAlignment) const
224 {
225 if (!d_parent)
226 {
227 return skipAllPixelAlignment ? Window::getUnclippedInnerRect().getFresh(true) : Window::getUnclippedInnerRect().get();
228 }
229 else
230 {
231 if (skipAllPixelAlignment)
232 {
233 return Rectf(getUnclippedOuterRect().getFresh(true).getPosition(),
234 getParent()->getUnclippedInnerRect().getFresh(true).getSize());
235 }
236 else
237 {
238 return Rectf(getUnclippedOuterRect().get().getPosition(),
239 getParent()->getUnclippedInnerRect().get().getSize());
240 }
241 }
242 }
243
244 //----------------------------------------------------------------------------//
onChildAdded(ElementEventArgs & e)245 void ScrolledContainer::onChildAdded(ElementEventArgs& e)
246 {
247 Window::onChildAdded(e);
248
249 // subscribe to some events on this child
250 d_eventConnections.insert(std::make_pair(static_cast<Window*>(e.element),
251 static_cast<Window*>(e.element)->subscribeEvent(Window::EventSized,
252 Event::Subscriber(&ScrolledContainer::handleChildSized, this))));
253 d_eventConnections.insert(std::make_pair(static_cast<Window*>(e.element),
254 static_cast<Window*>(e.element)->subscribeEvent(Window::EventMoved,
255 Event::Subscriber(&ScrolledContainer::handleChildMoved, this))));
256
257 // force window to update what it thinks it's screen / pixel areas are.
258 static_cast<Window*>(e.element)->notifyScreenAreaChanged(false);
259
260 // perform notification.
261 WindowEventArgs args(this);
262 onContentChanged(args);
263 }
264
265 //----------------------------------------------------------------------------//
onChildRemoved(ElementEventArgs & e)266 void ScrolledContainer::onChildRemoved(ElementEventArgs& e)
267 {
268 Window::onChildRemoved(e);
269
270 // disconnect from events for this window.
271 ConnectionTracker::iterator conn;
272 while ((conn = d_eventConnections.find(static_cast<Window*>(e.element))) != d_eventConnections.end())
273 {
274 conn->second->disconnect();
275 d_eventConnections.erase(conn);
276 }
277
278 // perform notification only if we're not currently being destroyed
279 if (!d_destructionStarted)
280 {
281 WindowEventArgs args(this);
282 onContentChanged(args);
283 }
284 }
285
286 //----------------------------------------------------------------------------//
onParentSized(ElementEventArgs & e)287 void ScrolledContainer::onParentSized(ElementEventArgs& e)
288 {
289 Window::onParentSized(e);
290
291 // perform notification.
292 WindowEventArgs args(this);
293 onContentChanged(args);
294 }
295
296 //----------------------------------------------------------------------------//
addScrolledContainerProperties(void)297 void ScrolledContainer::addScrolledContainerProperties(void)
298 {
299 const String& propertyOrigin = WidgetTypeName;
300
301 CEGUI_DEFINE_PROPERTY(ScrolledContainer, bool,
302 "ContentPaneAutoSized", "Property to get/set the setting which controls whether the content pane will auto-size itself."
303 " Value is either \"true\" or \"false\".",
304 &ScrolledContainer::setContentPaneAutoSized, &ScrolledContainer::isContentPaneAutoSized, true
305 );
306
307 CEGUI_DEFINE_PROPERTY(ScrolledContainer, Rectf,
308 "ContentArea", "Property to get/set the current content area rectangle of the content pane."
309 " Value is \"l:[float] t:[float] r:[float] b:[float]\" (where l is left, t is top, r is right, and b is bottom).",
310 &ScrolledContainer::setContentArea, &ScrolledContainer::getContentArea, Rectf::zero()
311 );
312
313 CEGUI_DEFINE_PROPERTY(ScrolledContainer, Rectf,
314 "ChildExtentsArea", "Property to get the current content extents rectangle."
315 " Value is \"l:[float] t:[float] r:[float] b:[float]\" (where l is left, t is top, r is right, and b is bottom).",
316 0, &ScrolledContainer::getChildExtentsArea, Rectf::zero()
317 );
318 }
319
320 //----------------------------------------------------------------------------//
setArea_impl(const UVector2 & pos,const USize & size,bool topLeftSizing,bool fireEvents)321 void ScrolledContainer::setArea_impl(const UVector2& pos, const USize& size,
322 bool topLeftSizing, bool fireEvents)
323 {
324 d_clientChildContentArea.invalidateCache();
325 Window::setArea_impl(pos, size, topLeftSizing, fireEvents);
326 }
327
328 //----------------------------------------------------------------------------//
329
330 #if defined(_MSC_VER)
331 # pragma warning(pop)
332 #endif
333
334 } // End of CEGUI namespace section
335