1 /***********************************************************************
2     created:    Mon Jul 18 2005
3     author:     Paul D Turner <paul@cegui.org.uk>
4 *************************************************************************/
5 /***************************************************************************
6  *   Copyright (C) 2004 - 2012 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/falagard/FrameComponent.h"
28 #include "CEGUI/falagard/XMLEnumHelper.h"
29 #include "CEGUI/falagard/XMLHandler.h"
30 #include "CEGUI/Exceptions.h"
31 #include "CEGUI/ImageManager.h"
32 #include "CEGUI/Image.h"
33 #include "CEGUI/CoordConverter.h"
34 #include <iostream>
35 #include <cstdlib>
36 
37 namespace CEGUI
38 {
39 
40 //! Default values
41 const HorizontalFormatting FrameComponent::HorizontalFormattingDefault(HF_STRETCHED);
42 const VerticalFormatting FrameComponent::VerticalFormattingDefault(VF_STRETCHED);
43 
44 //----------------------------------------------------------------------------//
FrameComponent()45 FrameComponent::FrameComponent() :
46     d_leftEdgeFormatting(VerticalFormattingDefault),
47     d_rightEdgeFormatting(VerticalFormattingDefault),
48     d_topEdgeFormatting(HorizontalFormattingDefault),
49     d_bottomEdgeFormatting(HorizontalFormattingDefault),
50     d_backgroundVertFormatting(VerticalFormattingDefault),
51     d_backgroundHorzFormatting(HorizontalFormattingDefault)
52 {
53 }
54 
55 //----------------------------------------------------------------------------//
setLeftEdgeFormatting(VerticalFormatting fmt)56 void FrameComponent::setLeftEdgeFormatting(VerticalFormatting fmt)
57 {
58     d_leftEdgeFormatting.set(fmt);
59 }
60 
61 //----------------------------------------------------------------------------//
setRightEdgeFormatting(VerticalFormatting fmt)62 void FrameComponent::setRightEdgeFormatting(VerticalFormatting fmt)
63 {
64     d_rightEdgeFormatting.set(fmt);
65 }
66 
67 //----------------------------------------------------------------------------//
setTopEdgeFormatting(HorizontalFormatting fmt)68 void FrameComponent::setTopEdgeFormatting(HorizontalFormatting fmt)
69 {
70     d_topEdgeFormatting.set(fmt);
71 }
72 
73 //----------------------------------------------------------------------------//
setBottomEdgeFormatting(HorizontalFormatting fmt)74 void FrameComponent::setBottomEdgeFormatting(HorizontalFormatting fmt)
75 {
76     d_bottomEdgeFormatting.set(fmt);
77 }
78 
79 //----------------------------------------------------------------------------//
setBackgroundVerticalFormatting(VerticalFormatting fmt)80 void FrameComponent::setBackgroundVerticalFormatting(VerticalFormatting fmt)
81 {
82     d_backgroundVertFormatting.set(fmt);
83 }
84 
85 //----------------------------------------------------------------------------//
setBackgroundHorizontalFormatting(HorizontalFormatting fmt)86 void FrameComponent::setBackgroundHorizontalFormatting(HorizontalFormatting fmt)
87 {
88     d_backgroundHorzFormatting.set(fmt);
89 }
90 
91 //----------------------------------------------------------------------------//
setLeftEdgeFormattingPropertySource(const String & property_name)92 void FrameComponent::setLeftEdgeFormattingPropertySource(
93                                                     const String& property_name)
94 {
95     d_leftEdgeFormatting.setPropertySource(property_name);
96 }
97 
98 //----------------------------------------------------------------------------//
setRightEdgeFormattingPropertySource(const String & property_name)99 void FrameComponent::setRightEdgeFormattingPropertySource(
100                                                     const String& property_name)
101 {
102     d_rightEdgeFormatting.setPropertySource(property_name);
103 }
104 
105 //----------------------------------------------------------------------------//
setTopEdgeFormattingPropertySource(const String & property_name)106 void FrameComponent::setTopEdgeFormattingPropertySource(
107                                                     const String& property_name)
108 {
109     d_topEdgeFormatting.setPropertySource(property_name);
110 }
111 
112 //----------------------------------------------------------------------------//
setBottomEdgeFormattingPropertySource(const String & property_name)113 void FrameComponent::setBottomEdgeFormattingPropertySource(
114                                                     const String& property_name)
115 {
116     d_bottomEdgeFormatting.setPropertySource(property_name);
117 }
118 
119 //----------------------------------------------------------------------------//
setBackgroundVerticalFormattingPropertySource(const String & property_name)120 void FrameComponent::setBackgroundVerticalFormattingPropertySource(
121                                                     const String& property_name)
122 {
123     d_backgroundVertFormatting.setPropertySource(property_name);
124 }
125 
126 //----------------------------------------------------------------------------//
setBackgroundHorizontalFormattingPropertySource(const String & property_name)127 void FrameComponent::setBackgroundHorizontalFormattingPropertySource(
128                                                     const String& property_name)
129 {
130     d_backgroundHorzFormatting.setPropertySource(property_name);
131 }
132 
133 //----------------------------------------------------------------------------//
getLeftEdgeFormatting(const Window & wnd) const134 VerticalFormatting FrameComponent::getLeftEdgeFormatting(const Window& wnd) const
135 {
136     return d_leftEdgeFormatting.get(wnd);
137 }
138 
139 //----------------------------------------------------------------------------//
getRightEdgeFormatting(const Window & wnd) const140 VerticalFormatting FrameComponent::getRightEdgeFormatting(const Window& wnd) const
141 {
142     return d_rightEdgeFormatting.get(wnd);
143 }
144 
145 //----------------------------------------------------------------------------//
getTopEdgeFormatting(const Window & wnd) const146 HorizontalFormatting FrameComponent::getTopEdgeFormatting(const Window& wnd) const
147 {
148     return d_topEdgeFormatting.get(wnd);
149 }
150 
151 //----------------------------------------------------------------------------//
getBottomEdgeFormatting(const Window & wnd) const152 HorizontalFormatting FrameComponent::getBottomEdgeFormatting(const Window& wnd) const
153 {
154     return d_bottomEdgeFormatting.get(wnd);
155 }
156 
157 //----------------------------------------------------------------------------//
getBackgroundVerticalFormatting(const Window & wnd) const158 VerticalFormatting FrameComponent::getBackgroundVerticalFormatting(
159                                                     const Window& wnd) const
160 {
161     return d_backgroundVertFormatting.get(wnd);
162 }
163 
164 //----------------------------------------------------------------------------//
getBackgroundHorizontalFormatting(const Window & wnd) const165 HorizontalFormatting FrameComponent::getBackgroundHorizontalFormatting(
166                                                     const Window& wnd) const
167 {
168     return d_backgroundHorzFormatting.get(wnd);
169 }
170 
171 //----------------------------------------------------------------------------//
getImage(FrameImageComponent imageComponent,const Window & wnd) const172 const Image* FrameComponent::getImage(FrameImageComponent imageComponent,
173                                       const Window& wnd) const
174 {
175     assert(imageComponent < FIC_FRAME_IMAGE_COUNT);
176 
177     if (!d_frameImages[imageComponent].d_specified)
178         return 0;
179 
180     if (d_frameImages[imageComponent].d_propertyName.empty())
181         return d_frameImages[imageComponent].d_image;
182 
183     return wnd.getProperty<Image*>(d_frameImages[imageComponent].d_propertyName);
184 }
185 
186 //----------------------------------------------------------------------------//
getImage(FrameImageComponent imageComponent) const187 const Image* FrameComponent::getImage(FrameImageComponent imageComponent) const
188 {
189     assert(imageComponent < FIC_FRAME_IMAGE_COUNT);
190 
191     if (!d_frameImages[imageComponent].d_specified)
192         return 0;
193 
194     if (d_frameImages[imageComponent].d_propertyName.empty())
195         return d_frameImages[imageComponent].d_image;
196 
197     return 0;
198 }
199 
200 //----------------------------------------------------------------------------//
setImage(FrameImageComponent part,const Image * image)201 void FrameComponent::setImage(FrameImageComponent part, const Image* image)
202 {
203     assert(part < FIC_FRAME_IMAGE_COUNT);
204 
205     d_frameImages[part].d_image = image;
206     d_frameImages[part].d_specified = image != 0;
207     d_frameImages[part].d_propertyName.clear();
208 }
209 
210 //----------------------------------------------------------------------------//
setImage(FrameImageComponent part,const String & name)211 void FrameComponent::setImage(FrameImageComponent part, const String& name)
212 {
213     const Image* image;
214     CEGUI_TRY
215     {
216         image = &ImageManager::getSingleton().get(name);
217     }
218     CEGUI_CATCH (UnknownObjectException&)
219     {
220         image = 0;
221     }
222 
223     setImage(part, image);
224 }
225 
226 //----------------------------------------------------------------------------//
setImagePropertySource(FrameImageComponent part,const String & name)227 void FrameComponent::setImagePropertySource(FrameImageComponent part,
228                                             const String& name)
229 {
230     assert(part < FIC_FRAME_IMAGE_COUNT);
231 
232     d_frameImages[part].d_image = 0;
233     d_frameImages[part].d_specified = !name.empty();
234     d_frameImages[part].d_propertyName = name;
235 }
236 
237 //----------------------------------------------------------------------------//
isImageSpecified(FrameImageComponent part) const238 bool FrameComponent::isImageSpecified(FrameImageComponent part) const
239 {
240     assert(part < FIC_FRAME_IMAGE_COUNT);
241 
242     return d_frameImages[part].d_specified;
243 }
244 
245 //----------------------------------------------------------------------------//
isImageFetchedFromProperty(FrameImageComponent part) const246 bool FrameComponent::isImageFetchedFromProperty(FrameImageComponent part) const
247 {
248     assert(part < FIC_FRAME_IMAGE_COUNT);
249 
250     return d_frameImages[part].d_specified &&
251            !d_frameImages[part].d_propertyName.empty();
252 }
253 
254 //----------------------------------------------------------------------------//
getImagePropertySource(FrameImageComponent part) const255 const String& FrameComponent::getImagePropertySource(
256                                     FrameImageComponent part) const
257 {
258     assert(part < FIC_FRAME_IMAGE_COUNT);
259 
260     return d_frameImages[part].d_propertyName;
261 }
262 
263 //----------------------------------------------------------------------------//
render_impl(Window & srcWindow,Rectf & destRect,const CEGUI::ColourRect * modColours,const Rectf * clipper,bool clipToDisplay) const264 void FrameComponent::render_impl(Window& srcWindow, Rectf& destRect,
265                                  const CEGUI::ColourRect* modColours,
266                                  const Rectf* clipper, bool clipToDisplay) const
267 {
268     Rectf backgroundRect(destRect);
269     Rectf finalRect;
270     Sizef imageSize;
271     Vector2f imageOffsets;
272     ColourRect imageColours;
273     float leftfactor, rightfactor, topfactor, bottomfactor;
274     bool calcColoursPerImage;
275 
276     // vars we use to track what to do with the side pieces.
277     float topOffset = 0, bottomOffset = 0, leftOffset = 0, rightOffset = 0;
278     float topWidth, bottomWidth, leftHeight, rightHeight;
279     topWidth = bottomWidth = destRect.getWidth();
280     leftHeight = rightHeight = destRect.getHeight();
281 
282     // calculate final overall colours to be used
283     ColourRect finalColours;
284     initColoursRect(srcWindow, modColours, finalColours);
285 
286     if (finalColours.isMonochromatic())
287     {
288         calcColoursPerImage = false;
289         imageColours = finalColours;
290     }
291     else
292     {
293         calcColoursPerImage = true;
294     }
295 
296     // top-left image
297     if (const Image* const componentImage = getImage(FIC_TOP_LEFT_CORNER, srcWindow))
298     {
299         // calculate final destination area
300         imageSize = componentImage->getRenderedSize();
301         imageOffsets = componentImage->getRenderedOffset();
302         finalRect.d_min = destRect.d_min;
303         finalRect.setSize(imageSize);
304         finalRect = destRect.getIntersection(finalRect);
305 
306         // update adjustments required to edges do to presence of this element.
307         topOffset  += imageSize.d_width + imageOffsets.d_x;
308         leftOffset += imageSize.d_height + imageOffsets.d_y;
309         topWidth   -= topOffset;
310         leftHeight -= leftOffset;
311 
312         // calculate colours that are to be used to this component image
313         if (calcColoursPerImage)
314         {
315             leftfactor   = (finalRect.left() + imageOffsets.d_x) / destRect.getWidth();
316             rightfactor  = leftfactor + finalRect.getWidth() / destRect.getWidth();
317             topfactor    = (finalRect.top() + imageOffsets.d_y) / destRect.getHeight();
318             bottomfactor = topfactor + finalRect.getHeight() / destRect.getHeight();
319 
320             imageColours = finalColours.getSubRectangle( leftfactor, rightfactor, topfactor, bottomfactor);
321         }
322 
323         // draw this element.
324         componentImage->render(srcWindow.getGeometryBuffer(), finalRect, clipper, imageColours);
325     }
326 
327     // top-right image
328     if (const Image* const componentImage = getImage(FIC_TOP_RIGHT_CORNER, srcWindow))
329     {
330         // calculate final destination area
331         imageSize = componentImage->getRenderedSize();
332         imageOffsets = componentImage->getRenderedOffset();
333         finalRect.left(destRect.right() - imageSize.d_width);
334         finalRect.top(destRect.top());
335         finalRect.setSize(imageSize);
336         finalRect = destRect.getIntersection(finalRect);
337 
338         // update adjustments required to edges do to presence of this element.
339         rightOffset += imageSize.d_height + imageOffsets.d_y;
340         topWidth    -= imageSize.d_width - imageOffsets.d_x;
341         rightHeight -= rightOffset;
342 
343         // calculate colours that are to be used to this component image
344         if (calcColoursPerImage)
345         {
346             leftfactor   = (finalRect.left() + imageOffsets.d_x) / destRect.getWidth();
347             rightfactor  = leftfactor + finalRect.getWidth() / destRect.getWidth();
348             topfactor    = (finalRect.top() + imageOffsets.d_y) / destRect.getHeight();
349             bottomfactor = topfactor + finalRect.getHeight() / destRect.getHeight();
350 
351             imageColours = finalColours.getSubRectangle(leftfactor, rightfactor, topfactor, bottomfactor);
352         }
353 
354         // draw this element.
355         componentImage->render(srcWindow.getGeometryBuffer(), finalRect, clipper, imageColours);
356     }
357 
358     // bottom-left image
359     if (const Image* const componentImage = getImage(FIC_BOTTOM_LEFT_CORNER, srcWindow))
360     {
361         // calculate final destination area
362         imageSize = componentImage->getRenderedSize();
363         imageOffsets = componentImage->getRenderedOffset();
364         finalRect.left(destRect.left());
365         finalRect.top(destRect.bottom() - imageSize.d_height);
366         finalRect.setSize(imageSize);
367         finalRect = destRect.getIntersection(finalRect);
368 
369         // update adjustments required to edges do to presence of this element.
370         bottomOffset += imageSize.d_width + imageOffsets.d_x;
371         bottomWidth  -= bottomOffset;
372         leftHeight   -= imageSize.d_height - imageOffsets.d_y;
373 
374         // calculate colours that are to be used to this component image
375         if (calcColoursPerImage)
376         {
377             leftfactor   = (finalRect.left() + imageOffsets.d_x) / destRect.getWidth();
378             rightfactor  = leftfactor + finalRect.getWidth() / destRect.getWidth();
379             topfactor    = (finalRect.top() + imageOffsets.d_y) / destRect.getHeight();
380             bottomfactor = topfactor + finalRect.getHeight() / destRect.getHeight();
381 
382             imageColours = finalColours.getSubRectangle(leftfactor, rightfactor, topfactor, bottomfactor);
383         }
384 
385         // draw this element.
386         componentImage->render(srcWindow.getGeometryBuffer(), finalRect, clipper, imageColours);
387     }
388 
389     // bottom-right image
390     if (const Image* const componentImage = getImage(FIC_BOTTOM_RIGHT_CORNER, srcWindow))
391     {
392         // calculate final destination area
393         imageSize = componentImage->getRenderedSize();
394         imageOffsets = componentImage->getRenderedOffset();
395         finalRect.left(destRect.right() - imageSize.d_width);
396         finalRect.top(destRect.bottom() - imageSize.d_height);
397         finalRect.setSize(imageSize);
398         finalRect = destRect.getIntersection(finalRect);
399 
400         // update adjustments required to edges do to presence of this element.
401         bottomWidth -= imageSize.d_width - imageOffsets.d_x;
402         rightHeight -= imageSize.d_height - imageOffsets.d_y;
403 
404         // calculate colours that are to be used to this component image
405         if (calcColoursPerImage)
406         {
407             leftfactor   = (finalRect.left() + componentImage->getRenderedOffset().d_x) / destRect.getWidth();
408             rightfactor  = leftfactor + finalRect.getWidth() / destRect.getWidth();
409             topfactor    = (finalRect.top() + componentImage->getRenderedOffset().d_y) / destRect.getHeight();
410             bottomfactor = topfactor + finalRect.getHeight() / destRect.getHeight();
411 
412             imageColours = finalColours.getSubRectangle( leftfactor, rightfactor, topfactor, bottomfactor);
413         }
414 
415         // draw this element.
416         componentImage->render(srcWindow.getGeometryBuffer(), finalRect, clipper, imageColours);
417     }
418 
419     // top image
420     if (const Image* const componentImage = getImage(FIC_TOP_EDGE, srcWindow))
421     {
422         // calculate final destination area
423         imageSize = componentImage->getRenderedSize();
424         finalRect.left(destRect.left() + topOffset);
425         finalRect.right(finalRect.left() + topWidth);
426         finalRect.top(destRect.top());
427         finalRect.bottom(finalRect.top() + imageSize.d_height);
428         finalRect = destRect.getIntersection(finalRect);
429 
430         // adjust background area to miss this edge
431         backgroundRect.d_min.d_y += imageSize.d_height + componentImage->getRenderedOffset().d_y;
432 
433         // calculate colours that are to be used to this component image
434         if (calcColoursPerImage)
435         {
436             leftfactor   = (finalRect.left() + componentImage->getRenderedOffset().d_x) / destRect.getWidth();
437             rightfactor  = leftfactor + finalRect.getWidth() / destRect.getWidth();
438             topfactor    = (finalRect.top() + componentImage->getRenderedOffset().d_y) / destRect.getHeight();
439             bottomfactor = topfactor + finalRect.getHeight() / destRect.getHeight();
440 
441             imageColours = finalColours.getSubRectangle( leftfactor, rightfactor, topfactor, bottomfactor);
442         }
443 
444         // draw this element.
445         renderImage(srcWindow.getGeometryBuffer(), componentImage,
446                     VF_TOP_ALIGNED, d_topEdgeFormatting.get(srcWindow),
447                     finalRect, imageColours, clipper, clipToDisplay);
448     }
449 
450     // bottom image
451     if (const Image* const componentImage = getImage(FIC_BOTTOM_EDGE, srcWindow))
452     {
453         // calculate final destination area
454         imageSize = componentImage->getRenderedSize();
455         finalRect.left(destRect.left() + bottomOffset);
456         finalRect.right(finalRect.left() + bottomWidth);
457         finalRect.bottom(destRect.bottom());
458         finalRect.top(finalRect.bottom() - imageSize.d_height);
459         finalRect = destRect.getIntersection (finalRect);
460 
461         // adjust background area to miss this edge
462         backgroundRect.d_max.d_y -= imageSize.d_height - componentImage->getRenderedOffset().d_y;
463 
464         // calculate colours that are to be used to this component image
465         if (calcColoursPerImage)
466         {
467             leftfactor   = (finalRect.left() + componentImage->getRenderedOffset().d_x) / destRect.getWidth();
468             rightfactor  = leftfactor + finalRect.getWidth() / destRect.getWidth();
469             topfactor    = (finalRect.top() + componentImage->getRenderedOffset().d_y) / destRect.getHeight();
470             bottomfactor = topfactor + finalRect.getHeight() / destRect.getHeight();
471 
472             imageColours = finalColours.getSubRectangle(leftfactor, rightfactor, topfactor, bottomfactor);
473         }
474 
475         // draw this element.
476         renderImage(srcWindow.getGeometryBuffer(), componentImage,
477                     VF_BOTTOM_ALIGNED, d_bottomEdgeFormatting.get(srcWindow),
478                     finalRect, imageColours, clipper, clipToDisplay);
479     }
480 
481     // left image
482     if (const Image* const componentImage = getImage(FIC_LEFT_EDGE, srcWindow))
483     {
484         // calculate final destination area
485         imageSize = componentImage->getRenderedSize();
486         finalRect.left(destRect.left());
487         finalRect.right(finalRect.left() + imageSize.d_width);
488         finalRect.top(destRect.top() + leftOffset);
489         finalRect.bottom(finalRect.top() + leftHeight);
490         finalRect = destRect.getIntersection(finalRect);
491 
492         // adjust background area to miss this edge
493         backgroundRect.d_min.d_x += imageSize.d_width + componentImage->getRenderedOffset().d_x;
494 
495         // calculate colours that are to be used to this component image
496         if (calcColoursPerImage)
497         {
498             leftfactor   = (finalRect.left() + componentImage->getRenderedOffset().d_x) / destRect.getWidth();
499             rightfactor  = leftfactor + finalRect.getWidth() / destRect.getWidth();
500             topfactor    = (finalRect.top() + componentImage->getRenderedOffset().d_y) / destRect.getHeight();
501             bottomfactor = topfactor + finalRect.getHeight() / destRect.getHeight();
502 
503             imageColours = finalColours.getSubRectangle( leftfactor, rightfactor, topfactor, bottomfactor);
504         }
505 
506         // draw this element.
507         renderImage(srcWindow.getGeometryBuffer(), componentImage,
508                     d_leftEdgeFormatting.get(srcWindow), HF_LEFT_ALIGNED,
509                     finalRect, imageColours, clipper, clipToDisplay);
510     }
511 
512     // right image
513     if (const Image* const componentImage = getImage(FIC_RIGHT_EDGE, srcWindow))
514     {
515         // calculate final destination area
516         imageSize = componentImage->getRenderedSize();
517         finalRect.top(destRect.top() + rightOffset);
518         finalRect.bottom(finalRect.top() + rightHeight);
519         finalRect.right(destRect.right());
520         finalRect.left(finalRect.right() - imageSize.d_width);
521         finalRect = destRect.getIntersection (finalRect);
522 
523         // adjust background area to miss this edge
524         backgroundRect.d_max.d_x -= imageSize.d_width - componentImage->getRenderedOffset().d_x;
525 
526         // calculate colours that are to be used to this component image
527         if (calcColoursPerImage)
528         {
529             leftfactor   = (finalRect.left() + componentImage->getRenderedOffset().d_x) / destRect.getWidth();
530             rightfactor  = leftfactor + finalRect.getWidth() / destRect.getWidth();
531             topfactor    = (finalRect.top() + componentImage->getRenderedOffset().d_y) / destRect.getHeight();
532             bottomfactor = topfactor + finalRect.getHeight() / destRect.getHeight();
533 
534             imageColours = finalColours.getSubRectangle( leftfactor, rightfactor, topfactor, bottomfactor);
535         }
536 
537         // draw this element.
538         renderImage(srcWindow.getGeometryBuffer(), componentImage,
539                     d_rightEdgeFormatting.get(srcWindow), HF_RIGHT_ALIGNED,
540                     finalRect, imageColours, clipper, clipToDisplay);
541     }
542 
543     if (const Image* const componentImage = getImage(FIC_BACKGROUND, srcWindow))
544     {
545         // calculate colours that are to be used to this component image
546         if (calcColoursPerImage)
547         {
548             leftfactor   = (backgroundRect.left() + componentImage->getRenderedOffset().d_x) / destRect.getWidth();
549             rightfactor  = leftfactor + backgroundRect.getWidth() / destRect.getWidth();
550             topfactor    = (backgroundRect.top() + componentImage->getRenderedOffset().d_y) / destRect.getHeight();
551             bottomfactor = topfactor + backgroundRect.getHeight() / destRect.getHeight();
552 
553             imageColours = finalColours.getSubRectangle( leftfactor, rightfactor, topfactor, bottomfactor);
554         }
555 
556         const HorizontalFormatting horzFormatting =
557             d_backgroundHorzFormatting.get(srcWindow);
558 
559         const VerticalFormatting vertFormatting =
560             d_backgroundVertFormatting.get(srcWindow);
561 
562         renderImage(srcWindow.getGeometryBuffer(), componentImage,
563                     vertFormatting, horzFormatting,
564                     backgroundRect, imageColours, clipper, clipToDisplay);
565     }
566 }
567 
568 //----------------------------------------------------------------------------//
renderImage(GeometryBuffer & buffer,const Image * image,VerticalFormatting vertFmt,HorizontalFormatting horzFmt,Rectf & destRect,const ColourRect & colours,const Rectf * clipper,bool) const569 void FrameComponent::renderImage(GeometryBuffer& buffer, const Image* image,
570                                  VerticalFormatting vertFmt,
571                                  HorizontalFormatting horzFmt,
572                                  Rectf& destRect, const ColourRect& colours,
573                                  const Rectf* clipper, bool /*clipToDisplay*/) const
574 {
575     uint horzTiles, vertTiles;
576     float xpos, ypos;
577 
578     Sizef imgSz(image->getRenderedSize());
579 
580     // calculate initial x co-ordinate and horizontal tile count according to formatting options
581     switch (horzFmt)
582     {
583         case HF_STRETCHED:
584             imgSz.d_width = destRect.getWidth();
585             xpos = destRect.left();
586             horzTiles = 1;
587             break;
588 
589         case HF_TILED:
590             xpos = destRect.left();
591             horzTiles = std::abs(static_cast<int>(
592                 (destRect.getWidth() + (imgSz.d_width - 1)) / imgSz.d_width));
593             break;
594 
595         case HF_LEFT_ALIGNED:
596             xpos = destRect.left();
597             horzTiles = 1;
598             break;
599 
600         case HF_CENTRE_ALIGNED:
601             xpos = destRect.left() + CoordConverter::alignToPixels((destRect.getWidth() - imgSz.d_width) * 0.5f);
602             horzTiles = 1;
603             break;
604 
605         case HF_RIGHT_ALIGNED:
606             xpos = destRect.right() - imgSz.d_width;
607             horzTiles = 1;
608             break;
609 
610         default:
611             CEGUI_THROW(InvalidRequestException(
612                 "An unknown HorizontalFormatting value was specified."));
613     }
614 
615     // calculate initial y co-ordinate and vertical tile count according to formatting options
616     switch (vertFmt)
617     {
618         case VF_STRETCHED:
619             imgSz.d_height = destRect.getHeight();
620             ypos = destRect.top();
621             vertTiles = 1;
622             break;
623 
624         case VF_TILED:
625             ypos = destRect.top();
626             vertTiles = std::abs(static_cast<int>(
627                 (destRect.getHeight() + (imgSz.d_height - 1)) / imgSz.d_height));
628             break;
629 
630         case VF_TOP_ALIGNED:
631             ypos = destRect.top();
632             vertTiles = 1;
633             break;
634 
635         case VF_CENTRE_ALIGNED:
636             ypos = destRect.top() + CoordConverter::alignToPixels((destRect.getHeight() - imgSz.d_height) * 0.5f);
637             vertTiles = 1;
638             break;
639 
640         case VF_BOTTOM_ALIGNED:
641             ypos = destRect.bottom() - imgSz.d_height;
642             vertTiles = 1;
643             break;
644 
645         default:
646             CEGUI_THROW(InvalidRequestException(
647                 "An unknown VerticalFormatting value was specified."));
648     }
649 
650     // perform final rendering (actually is now a caching of the images which will be drawn)
651     Rectf finalRect;
652     Rectf finalClipper;
653     const Rectf* clippingRect;
654     finalRect.d_min.d_y = ypos;
655     finalRect.d_max.d_y = ypos + imgSz.d_height;
656 
657     for (uint row = 0; row < vertTiles; ++row)
658     {
659         finalRect.d_min.d_x = xpos;
660         finalRect.d_max.d_x = xpos + imgSz.d_width;
661 
662         for (uint col = 0; col < horzTiles; ++col)
663         {
664             // use custom clipping for right and bottom edges when tiling the imagery
665             if (((vertFmt == VF_TILED) && row == vertTiles - 1) ||
666                 ((horzFmt == HF_TILED) && col == horzTiles - 1))
667             {
668                 finalClipper = clipper ? clipper->getIntersection(destRect) : destRect;
669                 clippingRect = &finalClipper;
670             }
671             // not tiliing, or not on far edges, just used passed in clipper (if any).
672             else
673                 clippingRect = clipper;
674 
675             image->render(buffer, finalRect, clippingRect, colours);
676 
677             finalRect.d_min.d_x += imgSz.d_width;
678             finalRect.d_max.d_x += imgSz.d_width;
679         }
680 
681         finalRect.d_min.d_y += imgSz.d_height;
682         finalRect.d_max.d_y += imgSz.d_height;
683     }
684 }
685 
686 //----------------------------------------------------------------------------//
writeXMLToStream(XMLSerializer & xml_stream) const687 void FrameComponent::writeXMLToStream(XMLSerializer& xml_stream) const
688 {
689     // opening tag
690     xml_stream.openTag(Falagard_xmlHandler::FrameComponentElement);
691     // write out area
692     d_area.writeXMLToStream(xml_stream);
693 
694     // write images
695     for (int i = 0; i < FIC_FRAME_IMAGE_COUNT; ++i)
696     {
697         if (d_frameImages[i].d_specified)
698         {
699             if (d_frameImages[i].d_propertyName.empty())
700                 xml_stream.openTag(Falagard_xmlHandler::ImageElement)
701                     .attribute(Falagard_xmlHandler::ComponentAttribute, FalagardXMLHelper<FrameImageComponent>::toString(static_cast<FrameImageComponent>(i)))
702                     .attribute(Falagard_xmlHandler::NameAttribute, d_frameImages[i].d_image->getName())
703                     .closeTag();
704             else
705                 xml_stream.openTag(Falagard_xmlHandler::ImagePropertyElement)
706                     .attribute(Falagard_xmlHandler::ComponentAttribute, FalagardXMLHelper<FrameImageComponent>::toString(static_cast<FrameImageComponent>(i)))
707                     .attribute(Falagard_xmlHandler::NameAttribute, d_frameImages[i].d_propertyName)
708                     .closeTag();
709         }
710     }
711 
712     // get base class to write colours
713     writeColoursXML(xml_stream);
714 
715     if(d_leftEdgeFormatting.getValue() != VerticalFormattingDefault)
716     {
717         d_leftEdgeFormatting.writeXMLTagToStream(xml_stream);
718         xml_stream.attribute(Falagard_xmlHandler::ComponentAttribute, FalagardXMLHelper<FrameImageComponent>::LeftEdge);
719         d_leftEdgeFormatting.writeXMLAttributesToStream(xml_stream);
720         xml_stream.closeTag();
721     }
722 
723     if(d_rightEdgeFormatting.getValue() != VerticalFormattingDefault)
724     {
725         d_rightEdgeFormatting.writeXMLTagToStream(xml_stream);
726         xml_stream.attribute(Falagard_xmlHandler::ComponentAttribute, FalagardXMLHelper<FrameImageComponent>::RightEdge);
727         d_rightEdgeFormatting.writeXMLAttributesToStream(xml_stream);
728         xml_stream.closeTag();
729     }
730 
731     if(d_backgroundHorzFormatting.getValue() != HorizontalFormattingDefault)
732     {
733         d_backgroundHorzFormatting.writeXMLTagToStream(xml_stream);
734         xml_stream.attribute(Falagard_xmlHandler::ComponentAttribute, FalagardXMLHelper<FrameImageComponent>::Background);
735         d_backgroundHorzFormatting.writeXMLAttributesToStream(xml_stream);
736         xml_stream.closeTag();
737     }
738 
739     if(d_topEdgeFormatting.getValue() != HorizontalFormattingDefault)
740     {
741         d_topEdgeFormatting.writeXMLTagToStream(xml_stream);
742         xml_stream.attribute(Falagard_xmlHandler::ComponentAttribute, FalagardXMLHelper<FrameImageComponent>::TopEdge);
743         d_topEdgeFormatting.writeXMLAttributesToStream(xml_stream);
744         xml_stream.closeTag();
745     }
746 
747     if(d_bottomEdgeFormatting.getValue() != HorizontalFormattingDefault)
748     {
749         d_bottomEdgeFormatting.writeXMLTagToStream(xml_stream);
750         xml_stream.attribute(Falagard_xmlHandler::ComponentAttribute, FalagardXMLHelper<FrameImageComponent>::BottomEdge);
751         d_bottomEdgeFormatting.writeXMLAttributesToStream(xml_stream);
752         xml_stream.closeTag();
753     }
754 
755     if(d_backgroundVertFormatting.getValue() != VerticalFormattingDefault)
756     {
757         d_backgroundVertFormatting.writeXMLTagToStream(xml_stream);
758         xml_stream.attribute(Falagard_xmlHandler::ComponentAttribute, FalagardXMLHelper<FrameImageComponent>::Background);
759         d_backgroundVertFormatting.writeXMLAttributesToStream(xml_stream);
760         xml_stream.closeTag();
761     }
762 
763     // closing tag
764     xml_stream.closeTag();
765 }
766 
767 //----------------------------------------------------------------------------//
operator ==(const FrameComponent & rhs) const768 bool FrameComponent::operator==(const FrameComponent& rhs) const
769 {
770     if (d_backgroundVertFormatting != rhs.d_backgroundVertFormatting ||
771         d_backgroundHorzFormatting != rhs.d_backgroundHorzFormatting)
772             return false;
773 
774     for (int i = 0; i < FIC_FRAME_IMAGE_COUNT; ++i)
775         if (d_frameImages[i] != rhs.d_frameImages[i])
776             return false;
777 
778     return true;
779 }
780 
781 //----------------------------------------------------------------------------//
782 
783 }
784 
785