1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013-2014 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "nel/gui/group_table.h"
23 #include "nel/gui/widget_manager.h"
24 #include "nel/gui/interface_element.h"
25 #include "nel/gui/view_bitmap.h"
26 #include "nel/gui/view_text_id.h"
27 #include "nel/gui/group_container.h"
28 #include "nel/misc/i_xml.h"
29 #include "nel/misc/i18n.h"
30 #include "nel/misc/xml_auto_ptr.h"
31 #include "nel/gui/css_border_renderer.h"
32 #include "nel/gui/css_background_renderer.h"
35 using namespace NLMISC
;
44 bool CGroupCell::DebugUICell
= false;
46 // ----------------------------------------------------------------------------
47 CGroupCell::CGroupCell(const TCtorParam
¶m
)
48 : CInterfaceGroup(param
)
57 Group
= new CInterfaceGroup(CViewBase::TCtorParam());
58 // TODO: only initialize if border is set
59 Border
= new CSSBorderRenderer();
60 Background
= new CSSBackgroundRenderer();
61 PaddingTop
= PaddingRight
= PaddingBottom
= PaddingLeft
= 0;
66 IgnoreMaxWidth
= false;
67 IgnoreMinWidth
= false;
69 setEnclosedGroupDefaultParams();
73 // ----------------------------------------------------------------------------
74 CGroupCell::~CGroupCell()
88 // ----------------------------------------------------------------------------
89 void CGroupCell::setEnclosedGroupDefaultParams()
92 // Cells are moved and resized by the table
93 Group
->setParent(this);
94 Group
->setParentPos(this);
95 Group
->setPosRef(Hotspot_TL
);
96 Group
->setParentPosRef(Hotspot_TL
);
97 Group
->setResizeFromChildW(false);
98 Group
->setResizeFromChildH(true);
101 std::string
CGroupCell::getProperty( const std::string
&name
) const
103 if( name
== "align" )
122 if( name
== "valign" )
141 if( name
== "left_margin" )
143 return toString( LeftMargin
);
146 if( name
== "nowrap" )
148 return toString( NoWrap
);
151 if( name
== "bgcolor" )
154 return toString( Background
->getColor() );
155 return toString(CRGBA::Transparent
);
158 if( name
== "width" )
160 if( WidthWanted
!= 0 )
161 return toString( WidthWanted
);
163 return toString( TableRatio
* 100.0f
);
166 if( name
== "height" )
168 return toString( Height
);
171 if( name
== "ignore_max_width" )
173 return toString( IgnoreMaxWidth
);
176 if( name
== "ignore_min_width" )
178 return toString( IgnoreMinWidth
);
181 if( name
== "add_child_w" )
183 return toString( AddChildW
);
186 return CInterfaceGroup::getProperty( name
);
189 void CGroupCell::setProperty( const std::string
&name
, const std::string
&value
)
191 if( name
== "align" )
193 if( value
== "right" )
196 if( value
== "center" )
199 if( value
== "left" )
205 if( name
== "valign" )
210 if( value
== "middle" )
213 if( value
== "bottom" )
219 if( name
== "left_margin" )
222 if( fromString( value
, i
) )
227 if( name
== "nowrap" )
230 if( fromString( value
, b
) )
235 if( name
== "bgcolor" )
238 Background
= new CSSBackgroundRenderer();
241 if( fromString( value
, c
) )
242 Background
->setColor(c
);
246 if( name
== "width" )
248 convertPixelsOrRatio( value
.c_str(), WidthWanted
, TableRatio
);
252 if( name
== "height" )
255 if( fromString( value
, i
) )
260 if( name
== "ignore_max_width" )
263 if( fromString( value
, b
) )
268 if( name
== "ignore_min_width" )
271 if( fromString( value
, b
) )
276 if( name
== "add_child_w" )
279 if( fromString( value
, b
) )
284 if (name
== "colspan" )
287 if (fromString( value
, i
) )
288 ColSpan
= std::max(1, i
);
292 if (name
== "rowspan" )
295 if (fromString( value
, i
) )
296 RowSpan
= std::max(1, i
);
300 CInterfaceGroup::setProperty( name
, value
);
303 xmlNodePtr
CGroupCell::serialize( xmlNodePtr parentNode
, const char *type
) const
305 xmlNodePtr node
= CInterfaceGroup::serialize( parentNode
, type
);
309 xmlSetProp( node
, BAD_CAST
"type", BAD_CAST
"cell" );
345 xmlSetProp( node
, BAD_CAST
"align", BAD_CAST
"" );
346 xmlSetProp( node
, BAD_CAST
"valign", BAD_CAST
"" );
347 xmlSetProp( node
, BAD_CAST
"left_margin", BAD_CAST
toString( LeftMargin
).c_str() );
348 xmlSetProp( node
, BAD_CAST
"nowrap", BAD_CAST
toString( NoWrap
).c_str() );
350 xmlSetProp( node
, BAD_CAST
"bgcolor", BAD_CAST
toString( Background
->getColor() ).c_str() );
352 if( WidthWanted
!= 0 )
353 xmlSetProp( node
, BAD_CAST
"width", BAD_CAST
toString( WidthWanted
).c_str() );
355 xmlSetProp( node
, BAD_CAST
"width", BAD_CAST
toString( TableRatio
* 100.0f
).c_str() );
357 xmlSetProp( node
, BAD_CAST
"height", BAD_CAST
toString( Height
).c_str() );
358 xmlSetProp( node
, BAD_CAST
"ignore_max_width", BAD_CAST
toString( IgnoreMaxWidth
).c_str() );
359 xmlSetProp( node
, BAD_CAST
"ignore_min_width", BAD_CAST
toString( IgnoreMinWidth
).c_str() );
360 xmlSetProp( node
, BAD_CAST
"add_child_w", BAD_CAST
toString( AddChildW
).c_str() );
361 xmlSetProp( node
, BAD_CAST
"colspan", BAD_CAST
toString( ColSpan
).c_str() );
362 xmlSetProp( node
, BAD_CAST
"rowspan", BAD_CAST
toString( RowSpan
).c_str() );
367 // ----------------------------------------------------------------------------
368 bool CGroupCell::parseCell(xmlNodePtr cur
, CInterfaceGroup
* parentGroup
, uint columnIndex
, uint rowIndex
)
371 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"id");
374 // no id was given, so create one
375 std::string newId
= NLMISC::toString("cell_%d_%d", (int) columnIndex
, (int) rowIndex
);
376 xmlSetProp(cur
, (const xmlChar
*) "id", (const xmlChar
*) newId
.c_str());
378 // parse enclosed group
379 if (!Group
->parse(cur
, this)) return false;
380 Group
->setId(parentGroup
->getId() + Group
->getId());
381 setEnclosedGroupDefaultParams();
382 // parse the children
383 bool ok
= CWidgetManager::getInstance()->getParser()->parseGroupChildren(cur
, Group
, false);
384 if (!ok
) return false;
386 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"align" );
389 if (strcmp((const char *) ptr
, "left") == 0)
393 else if (strcmp((const char *) ptr
, "right") == 0)
397 else if (strcmp((const char *) ptr
, "center") == 0)
403 nlwarning("<CGroupCell::parse> Unknwown or unsupported align mode : %s", (const char *) ptr
);
407 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"valign" );
410 if (strcmp((const char *) ptr
, "top") == 0)
414 else if (strcmp((const char *) ptr
, "middle") == 0)
418 else if (strcmp((const char *) ptr
, "bottom") == 0)
424 nlwarning("<CGroupCell::parse> Unknwown or unsupported valign mode : %s", (const char *) ptr
);
428 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"left_margin" );
431 fromString((const char*)ptr
, LeftMargin
);
434 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"nowrap" );
437 NoWrap
= convertBool(ptr
);
440 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"bgcolor" );
444 Background
= new CSSBackgroundRenderer();
445 Background
->setColor(convertColor(ptr
));
448 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"width" );
451 convertPixelsOrRatio((const char *) ptr
, WidthWanted
, TableRatio
);
454 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"height" );
457 fromString((const char*)ptr
, Height
);
460 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"ignore_max_width" );
463 IgnoreMaxWidth
= convertBool(ptr
);
466 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"ignore_min_width" );
469 IgnoreMinWidth
= convertBool(ptr
);
472 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"add_child_w" );
475 AddChildW
= convertBool(ptr
);
478 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"colspan" );
482 if (fromString((const char*)ptr
, i
))
483 ColSpan
= std::max(1, i
);
486 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"rowspan" );
490 if (fromString((const char*)ptr
, i
))
491 RowSpan
= std::max(1, i
);
498 // ----------------------------------------------------------------------------
499 void CGroupCell::draw ()
501 if ( CGroupCell::DebugUICell
)
504 CViewRenderer
&rVR
= *CViewRenderer::getInstance();
505 rVR
.drawRotFlipBitmap (_RenderLayer
, _XReal
, _YReal
, _WReal
, 1, 0, false, rVR
.getBlankTextureId(), CRGBA(0,255,255,255) );
506 rVR
.drawRotFlipBitmap (_RenderLayer
, _XReal
, _YReal
, 1, _HReal
, 0, false, rVR
.getBlankTextureId(), CRGBA(0,255,255,255) );
507 rVR
.drawRotFlipBitmap (_RenderLayer
, _XReal
, _YReal
+_HReal
-1, _WReal
, 1, 0, false, rVR
.getBlankTextureId(), CRGBA(0,255,255,255) );
508 rVR
.drawRotFlipBitmap (_RenderLayer
, _XReal
+_WReal
-1, _YReal
, 1, _HReal
, 0, false, rVR
.getBlankTextureId(), CRGBA(0,255,255,255) );
512 CViewRenderer
&rVR
= *CViewRenderer::getInstance();
513 // flush draw queue to force correct draw order
518 uint8 CurrentAlpha
= 255;
519 CGroupTable
*table
= NULL
;
522 table
= static_cast<CGroupTable
*> (getParent ());
523 CurrentAlpha
= table
->CurrentAlpha
;
525 if (CurrentAlpha
> 0)
527 Background
->CurrentAlpha
= CurrentAlpha
;
528 Background
->setModulateGlobalColor(_ModulateGlobalColor
);
536 Border
->CurrentAlpha
= CWidgetManager::getInstance()->getGlobalColorForContent().A
;
537 if (Border
->CurrentAlpha
> 0)
539 Border
->setRenderLayer(_RenderLayer
);
540 Border
->setModulateGlobalColor(_ModulateGlobalColor
);
547 CInterfaceGroup::draw ();
550 // ----------------------------------------------------------------------------
551 sint32
CGroupCell::getMaxUsedW() const
553 sint32 result
= getPaddingLeftRight() + Group
->getMaxUsedW();
555 result
+= Border
->getLeftRightWidth();
559 // ------------------------------------------------------------------------------------------------
560 sint32
CGroupCell::getMinUsedW() const
562 sint32 result
= getPaddingLeftRight() + Group
->getMinUsedW();
564 result
+= Border
->getLeftRightWidth();
569 // ----------------------------------------------------------------------------
570 void CGroupCell::setTexture(const std::string
& TxName
)
573 Background
->setImage(TxName
);
576 // ----------------------------------------------------------------------------
577 void CGroupCell::setTextureTile(bool tiled
)
580 Background
->setImageRepeat(tiled
);
583 // ----------------------------------------------------------------------------
584 void CGroupCell::setTextureScale(bool scaled
)
587 Background
->setImageCover(scaled
);
590 // ----------------------------------------------------------------------------
591 void CGroupCell::updateCoords()
593 CInterfaceGroup::updateCoords();
596 // ----------------------------------------------------------------------------
597 NLMISC_REGISTER_OBJECT(CViewBase
, CGroupTable
, std::string
, "table");
599 CGroupTable::CGroupTable(const TCtorParam
¶m
)
600 : CInterfaceGroup(param
)
602 _ContentValidated
= false;
606 // TODO: only initialize when needed
607 Border
= new CSSBorderRenderer();
608 Background
= new CSSBackgroundRenderer();
613 ContinuousUpdate
= false;
616 // ----------------------------------------------------------------------------
617 void CGroupTable::addChild (CGroupCell
* child
)
622 child
->NewLine
= true;
624 // Cells are moved and resized by the table
625 child
->setParent(this);
626 child
->setParentPos(this);
627 child
->setPosRef(Hotspot_TL
);
628 child
->setParentPosRef(Hotspot_TL
);
629 child
->setResizeFromChildW(false);
631 // Child resize H for cells
632 child
->setResizeFromChildH(false);
640 child->setParentPos(NULL);
641 child->setPosRef(Hotspot_TL);
642 child->setParentPosRef(Hotspot_TL);
647 // Look for previous new line
649 for (i=_Cells.size()-1; i>0; i--)
650 if (_Cells[i]->NewLine)
653 child->setParentPos(_Cells[i]);
654 child->setPosRef(Hotspot_TL);
655 child->setParentPosRef(Hotspot_BL);
660 nlassert(!_Cells.empty());
661 child->setParentPos(_Cells.back());
662 child->setPosRef(Hotspot_TL);
663 child->setParentPosRef(Hotspot_TR);
668 _Cells
.push_back(child
);
672 // ----------------------------------------------------------------------------
673 CGroupTable::~CGroupTable()
688 for (i=0; i<_Cells.size(); i++)
693 // ----------------------------------------------------------------------------
694 void CGroupTable::setTexture(const std::string
& TxName
)
697 Background
->setImage(TxName
);
700 // ----------------------------------------------------------------------------
701 void CGroupTable::setTextureTile(bool tiled
)
704 Background
->setImageRepeat(tiled
);
707 // ----------------------------------------------------------------------------
708 void CGroupTable::setTextureScale(bool scaled
)
711 Background
->setImageCover(scaled
);
714 // ----------------------------------------------------------------------------
715 void CGroupTable::updateCoords()
719 if (ContinuousUpdate
)
721 sint parentWidth
= _Parent
->getInnerWidth();
722 if (_LastParentW
!= (sint
) parentWidth
)
724 _LastParentW
= parentWidth
;
725 _ContentValidated
= false;
728 if (!_ContentValidated
)
730 // Update W and XReal
731 CInterfaceElement::updateCoords();
733 // *** For each children, update coords, gets min and max values
734 // *** Get the column sizes, we need to know min for the table
739 for (i
=0; i
<_Cells
.size(); i
++)
741 // Update coords to get XReal
742 CGroupCell
*cell
= _Cells
[i
];
744 cell
->updateCoords();
746 sint32 additionnalWidth
= 0;
750 cell
->Group
->evalChildrenBBox(true, false, width
, height
);
751 additionnalWidth
= (sint32
) width
;
754 // Get width min and max
755 if( !cell
->IgnoreMaxWidth
)
756 cell
->WidthMax
= cell
->getMaxUsedW() + cell
->LeftMargin
;
758 cell
->WidthMax
= cell
->WidthWanted
+ additionnalWidth
+ cell
->LeftMargin
;
761 if(!cell
->IgnoreMinWidth
)
762 cellWidth
= cell
->NoWrap
? cell
->WidthMax
: cell
->getMinUsedW() + cell
->LeftMargin
;
764 cellWidth
= cell
->NoWrap
? cell
->WidthMax
: cell
->LeftMargin
;
767 sint32 cellBorderPadding
= cell
->getPaddingLeftRight();
769 cellBorderPadding
+= cell
->Border
->getLeftRightWidth();
770 if (cellWidth
< cellBorderPadding
)
771 cellWidth
= cellBorderPadding
;
777 while (column
< _Columns
.size())
779 if (_Columns
[column
].RowSpan
> 1)
780 _Columns
[column
].RowSpan
--;
787 if (column
>= _Columns
.size())
788 _Columns
.resize(column
+1);
790 // Handle rowspan from previous row
791 while (_Columns
[column
].RowSpan
> 1)
793 _Columns
[column
].RowSpan
--;
795 // if previous row had less <TD> elements, then we missing columns
796 if (column
>= _Columns
.size())
797 _Columns
.resize(column
+1);
800 // remember column index for later use
801 cell
->TableColumnIndex
= column
;
803 // new column, set rowspan from current <TD>
804 _Columns
[column
].RowSpan
= cell
->RowSpan
;
805 float colspan
= 1.f
/ cell
->ColSpan
;
808 if (cellWidth
*colspan
> _Columns
[column
].Width
)
809 _Columns
[column
].Width
= (sint32
)(cellWidth
*colspan
);
810 if (cell
->WidthMax
*colspan
> _Columns
[column
].WidthMax
)
811 _Columns
[column
].WidthMax
= (sint32
)(cell
->WidthMax
*colspan
);
812 if (cell
->TableRatio
*colspan
> _Columns
[column
].TableRatio
)
813 _Columns
[column
].TableRatio
= cell
->TableRatio
*colspan
;
814 if ((cell
->WidthWanted
+ additionnalWidth
)*colspan
> _Columns
[column
].WidthWanted
)
815 _Columns
[column
].WidthWanted
= (sint32
)((cell
->WidthWanted
+ additionnalWidth
)*colspan
);
817 if (_Columns
[column
].WidthWanted
> _Columns
[column
].WidthMax
)
818 _Columns
[column
].WidthMax
= _Columns
[column
].WidthWanted
;
819 if (_Columns
[column
].WidthWanted
> _Columns
[column
].Width
)
820 _Columns
[column
].Width
= _Columns
[column
].WidthWanted
;
822 if (cell
->ColSpan
> 1)
824 // copy this info to all spanned columns, create new columns as needed
825 uint newsize
= column
+ cell
->ColSpan
- 1;
826 if (newsize
>= _Columns
.size())
827 _Columns
.resize(newsize
+1);
829 for(sint span
= 0; span
< cell
->ColSpan
-1; ++span
)
832 _Columns
[column
].RowSpan
= _Columns
[column
-1].RowSpan
;
840 // Additional space contributing to table width
841 sint32 tableBorderSpacing
= 0;
843 tableBorderSpacing
+= Border
->getLeftRightWidth();
844 tableBorderSpacing
+= ((sint32
)_Columns
.size()+1) * CellSpacing
;;
846 sint32 innerForceWidthMin
= ForceWidthMin
;
847 if (innerForceWidthMin
< tableBorderSpacing
)
848 innerForceWidthMin
= 0;
850 innerForceWidthMin
-= tableBorderSpacing
;
853 sint32 tableWidthMax
= innerForceWidthMin
? innerForceWidthMin
: _LastParentW
- tableBorderSpacing
; // getWReal();
854 sint32 tableWidthMin
= std::max(innerForceWidthMin
, (sint32
)((float)tableWidthMax
*TableRatio
));
855 tableWidthMax
= std::max ((sint32
)0, tableWidthMax
);
856 tableWidthMin
= std::max ((sint32
)0, tableWidthMin
);
858 // Get the width of the table and normalize percent of the cell (sum of TableRatio must == 1)
859 sint32 tableWidth
= 0;
860 sint32 tableMaxContentWidth
= 0;
862 for (i
=0; i
<_Columns
.size(); i
++)
864 tableWidth
+= _Columns
[i
].Width
;
865 tableMaxContentWidth
+= _Columns
[i
].WidthMax
;
866 _Columns
[i
].TableRatio
= std::min(_Columns
[i
].TableRatio
, ratio
);
867 ratio
-= _Columns
[i
].TableRatio
;
870 // force table width to fit all columns
871 // if width is set, then use column min width
872 if (innerForceWidthMin
> 0)
873 tableWidthMax
= std::min(_LastParentW
- tableBorderSpacing
, std::max(tableWidthMax
, tableWidth
));
875 tableWidthMax
= std::min(_LastParentW
- tableBorderSpacing
, std::max(tableWidthMax
, tableMaxContentWidth
));
877 if (tableWidthMax
< 0)
880 if (tableWidthMax
< tableWidthMin
)
881 std::swap(tableWidthMin
, tableWidthMax
);
883 // Eval table size with all percent cells resized
884 // TODO: _Columns[i].TableRatio is for outer width
885 sint32 tableWidthSizeAfterPercent
= tableWidth
;
886 for (i
=0; i
<_Columns
.size(); i
++)
888 if (_Columns
[i
].TableRatio
> 0)
890 // Size of the cell with its percent
891 sint32 me
= (sint32
)((float)_Columns
[i
].Width
/ _Columns
[i
].TableRatio
);
893 tableWidthSizeAfterPercent
= std::min(tableWidthMax
, std::max(tableWidthSizeAfterPercent
, me
));
896 for (i
=0; i
<_Columns
.size(); i
++)
898 if (_Columns
[i
].TableRatio
> 0)
900 // Size of the other cells
902 if (_Columns
[i
].TableRatio
< 1.f
)
903 cellSize
= (sint32
)((float)tableWidthSizeAfterPercent
*_Columns
[i
].TableRatio
) + 1;
907 sint32 diff
= std::min(tableWidthMax
, (std::max(_Columns
[i
].Width
, cellSize
) - _Columns
[i
].Width
)+tableWidth
) - tableWidth
;
909 _Columns
[i
].Width
+= diff
;
910 // tableMaxContentWidth = std::max(tableMaxContentWidth, (sint32)((float)_Columns[i].WidthMax / _Columns[i].TableRatio));
913 sint32 space
= tableWidthMax
- tableWidth
;
915 // Normalize percent window
916 for (i
=0; i
<_Columns
.size(); i
++)
918 // Width for the cell
919 sint32 diff
= (sint32
)((float)tableWidth
*_Columns
[i
].TableRatio
) - _Columns
[i
].Width
;
920 diff
= std::min(diff
, space
);
923 _Columns
[i
].Width
+= diff
;
929 // Ok, now percent window are nomralized
930 // Evaluate space to put in windows
931 sint32 finalWidth
= std::max(tableWidthMin
, std::min(std::max(tableWidth
, tableMaxContentWidth
), tableWidthMax
));
932 space
= finalWidth
- tableWidth
;
935 // First give to percent cells
936 for (i
=0; i
<_Columns
.size(); i
++)
938 // Width for the cell
939 sint32 dif
= (sint32
)((float)space
*_Columns
[i
].TableRatio
);
940 _Columns
[i
].Width
+= dif
;
945 space
= finalWidth
- tableWidth
;
948 // Then add in wanted Width cells
949 for (i
=0; i
<_Columns
.size(); i
++)
951 // Width for the cell
952 if (_Columns
[i
].Width
< _Columns
[i
].WidthWanted
)
954 sint32 dif
= std::min(space
, _Columns
[i
].WidthWanted
-_Columns
[i
].Width
);
955 _Columns
[i
].Width
+= dif
;
962 // All cells with sizewanted are full
963 // Distribute remaining space in resizable cells that have a WidthMax
964 sint32 sumDeltaWidth
= 0;
965 for (i
=0; i
<_Columns
.size(); i
++)
967 if ((_Columns
[i
].TableRatio
== 0) && (_Columns
[i
].WidthWanted
== 0))
968 sumDeltaWidth
+= std::max ((sint32
)0, _Columns
[i
].WidthMax
- _Columns
[i
].Width
);
972 sint32 toDistribute
= space
;
973 for (i
=0; i
<_Columns
.size(); i
++)
975 if ((_Columns
[i
].TableRatio
== 0) && (_Columns
[i
].WidthWanted
== 0))
977 sint32 marge
= std::max ((sint32
)0, _Columns
[i
].WidthMax
- _Columns
[i
].Width
);
978 sint32 cellPart
= std::min(marge
, std::min(space
, 1 + marge
* toDistribute
/ sumDeltaWidth
));
981 _Columns
[i
].Width
+= cellPart
;
990 // All cells with sizemax are full
991 // Distribute remaining space in others resizable cells
993 for (i
=0; i
<_Columns
.size(); i
++)
995 if ((_Columns
[i
].TableRatio
== 0) && (_Columns
[i
].WidthWanted
== 0))
1000 sint32 toDistribute
= space
;
1001 for (i
=0; i
<_Columns
.size(); i
++)
1003 if ((_Columns
[i
].TableRatio
== 0) && (_Columns
[i
].WidthWanted
== 0))
1005 sint32 cellPart
= std::min(space
, 1 + toDistribute
/ sumDeltaWidth
);
1006 _Columns
[i
].Width
+= cellPart
;
1014 // No cells with sizemax not sizewanted, resize size wanted
1015 // Distribute remaining space in others resizable cells
1017 for (i
=0; i
<_Columns
.size(); i
++)
1019 if ((_Columns
[i
].TableRatio
== 0) && (_Columns
[i
].WidthWanted
!= 0))
1024 sint32 toDistribute
= space
;
1025 for (i
=0; i
<_Columns
.size(); i
++)
1027 if ((_Columns
[i
].TableRatio
== 0) && (_Columns
[i
].WidthWanted
!= 0))
1029 sint32 cellPart
= std::min(space
, 1 + toDistribute
/ sumDeltaWidth
);
1030 _Columns
[i
].Width
+= cellPart
;
1036 // If there is still space left, then sum up column widths
1037 // and add all the remaining space to final column.
1040 sint32 innerWidth
= 0;
1041 for(i
=0;i
<_Columns
.size();i
++)
1042 innerWidth
+= _Columns
[i
].Width
;
1044 if (innerWidth
> 0 && finalWidth
> innerWidth
)
1045 _Columns
[_Columns
.size()-1].Width
+= finalWidth
- innerWidth
;
1053 // *** Now we know each column width, resize cells and get the height for each row
1057 sint32 currentX
= 0;
1060 for (i
=0; i
<_Cells
.size(); i
++)
1062 CGroupCell
*cell
= _Cells
[i
];
1067 currentX
= CellSpacing
;
1069 currentX
+= Border
->getLeftWidth();
1071 _Rows
.push_back(CRow());
1074 if (cell
->TableColumnIndex
> 0)
1076 // we have active rowspan, must add up 'skipped' columns
1077 for( ; column
< (uint
)cell
->TableColumnIndex
; ++column
)
1078 currentX
+= _Columns
[column
].Width
+ CellSpacing
;
1081 // Set the x and width
1084 sint32 alignmentX
= 0;
1085 sint32 widthReduceX
= 0;
1086 sint32 columnWidth
= _Columns
[column
].Width
;
1087 sint32 cellBorderPaddingLeft
= cell
->PaddingLeft
;
1088 sint32 cellBorderPaddingRight
= cell
->PaddingRight
;
1091 cellBorderPaddingLeft
+= cell
->Border
->getLeftWidth();
1092 cellBorderPaddingRight
+= cell
->Border
->getRightWidth();
1095 if (cell
->ColSpan
> 1)
1097 // scan ahead and add up column widths as they might be different
1098 for(int j
= 1; j
<cell
->ColSpan
; j
++)
1099 columnWidth
+= CellSpacing
+ _Columns
[column
+j
].Width
;
1102 if (cell
->WidthMax
< columnWidth
)
1104 switch (cell
->Align
)
1106 case CGroupCell::Center
:
1107 alignmentX
= (columnWidth
- cell
->WidthMax
) / 2;
1108 widthReduceX
= alignmentX
* 2;
1110 case CGroupCell::Right
:
1111 alignmentX
= columnWidth
- cell
->WidthMax
;
1112 widthReduceX
= alignmentX
;
1120 cell
->setX(currentX
);
1121 cell
->setW(columnWidth
);
1124 cell
->Group
->setX(cellBorderPaddingLeft
+ alignmentX
+ cell
->LeftMargin
);
1125 cell
->Group
->setW(columnWidth
- widthReduceX
- cellBorderPaddingLeft
- cellBorderPaddingRight
);
1126 cell
->Group
->CInterfaceElement::updateCoords();
1128 // Update coords to get H
1129 cell
->Group
->checkCoords();
1130 cell
->Group
->updateCoords();
1132 // Resize the row array
1133 float rowspan
= 1.f
/ (float)cell
->RowSpan
;
1134 uint cellBorderPadding
= cell
->getPaddingTopBottom();
1136 cellBorderPadding
+= cell
->Border
->getTopBottomWidth();
1137 sint32 cellHeight
= std::max((sint32
)(cell
->Height
*rowspan
), (sint32
)(cell
->Group
->getH()*rowspan
+ cellBorderPadding
));
1138 _Rows
.back().Height
= std::max(_Rows
.back().Height
, (sint32
)cellHeight
);
1141 currentX
+= columnWidth
+ CellSpacing
;
1142 column
+= cell
->ColSpan
;
1147 sint32 currentY
= -CellSpacing
;
1149 currentY
-= Border
->getTopWidth();
1151 for (i
=0; i
<_Cells
.size(); i
++)
1154 CGroupCell
*cell
= _Cells
[i
];
1155 if ((i
!= 0) && (cell
->NewLine
))
1157 if (_Rows
[row
].Height
!= 0)
1159 currentY
-= _Rows
[row
].Height
+ CellSpacing
;
1165 sint32 alignmentY
= 0;
1166 sint32 rowHeight
= _Rows
[row
].Height
;
1167 sint32 cellBorderPaddingTop
= cell
->PaddingTop
;
1168 sint32 cellBorderPaddingBottom
= cell
->PaddingBottom
;
1171 cellBorderPaddingTop
+= cell
->Border
->getTopWidth();
1172 cellBorderPaddingBottom
+= cell
->Border
->getBottomWidth();
1174 if (cell
->RowSpan
> 1)
1176 // we need to scan down and add up row heights
1177 int k
= std::min((sint32
)_Rows
.size(), row
+ cell
->RowSpan
);
1178 for(int j
=row
+1; j
<k
; j
++)
1179 rowHeight
+= CellSpacing
+ _Rows
[j
].Height
;
1181 if ((sint32
)cell
->Group
->getH() < rowHeight
)
1183 switch (cell
->VAlign
)
1185 case CGroupCell::Middle
:
1186 alignmentY
= (rowHeight
- (sint32
)cell
->Group
->getH()) / 2;
1188 case CGroupCell::Bottom
:
1189 alignmentY
= rowHeight
- (sint32
)cell
->Group
->getH();
1197 cell
->setY(currentY
);
1198 cell
->setH (rowHeight
);
1200 cell
->Group
->setY(-(alignmentY
+ cellBorderPaddingTop
- cellBorderPaddingBottom
));
1205 currentY
-= _Rows
.back().Height
;
1206 currentY
-= CellSpacing
;
1207 finalWidth
+= ((sint
)_Columns
.size() + 1) * CellSpacing
;
1210 currentY
-= Border
->getBottomWidth();
1211 finalWidth
+= Border
->getLeftRightWidth();
1215 setW(finalWidth
-_LastParentW
);
1223 CInterfaceGroup::updateCoords();
1225 // update borders if present
1228 Border
->setRect(_XReal
+ _MarginLeft
, _YReal
, _WReal
, _HReal
);
1233 sint32 l
= _XReal
+ _MarginLeft
;
1237 Background
->setBorderArea(l
, b
, w
, h
);
1239 l
+= Border
->getLeftWidth();
1240 b
+= Border
->getBottomWidth();
1241 w
-= Border
->getLeftRightWidth();
1242 h
-= Border
->getTopBottomWidth();
1244 Background
->setPaddingArea(l
, b
, w
, h
);
1246 //CSSRect<sint32> Padding;
1247 //l += Padding.Left;
1248 //b += Padding.Bottom;
1249 //w -= Padding.Left - Padding.Right;
1250 //h -= Padding.Top - Padding.Bottom;
1251 Background
->setContentArea(l
, b
, w
, h
);
1254 // update cell borders if present
1255 for (uint32 i
=0; i
<_Cells
.size(); i
++)
1257 if (_Cells
[i
]->Border
)
1259 _Cells
[i
]->Border
->setRect(_Cells
[i
]->_XReal
, _Cells
[i
]->_YReal
, _Cells
[i
]->_WReal
, _Cells
[i
]->_HReal
);
1261 if (_Cells
[i
]->Background
)
1263 sint32 l
= _Cells
[i
]->_XReal
;
1264 sint32 b
= _Cells
[i
]->_YReal
;
1265 sint32 w
= _Cells
[i
]->_WReal
;
1266 sint32 h
= _Cells
[i
]->_HReal
;
1267 _Cells
[i
]->Background
->setBorderArea(l
, b
, w
, h
);
1268 if (_Cells
[i
]->Border
) {
1269 l
+= Border
->getLeftWidth();
1270 b
+= Border
->getBottomWidth();
1271 w
-= Border
->getLeftRightWidth();
1272 h
-= Border
->getTopBottomWidth();
1274 _Cells
[i
]->Background
->setPaddingArea(l
, b
, w
, h
);
1276 //CSSRect<sint32> Padding;
1277 //l += Padding.Left;
1278 //b += Padding.Bottom;
1279 //w -= Padding.Left - Padding.Right;
1280 //h -= Padding.Top - Padding.Bottom;
1281 _Cells
[i
]->Background
->setContentArea(l
, b
, w
, h
);
1286 _ContentValidated
= true;
1289 // ----------------------------------------------------------------------------
1290 void CGroupTable::checkCoords ()
1292 if (_Parent
!= NULL
)
1294 sint parentWidth
= _Parent
->getInnerWidth();
1295 if (_LastParentW
!= (sint
) parentWidth
)
1297 if (ContinuousUpdate
)
1299 _LastParentW
= parentWidth
;
1300 invalidateContent();
1305 CCtrlBase
*pCB
= CWidgetManager::getInstance()->getCapturePointerLeft();
1308 CCtrlResizer
*pCR
= dynamic_cast<CCtrlResizer
*>(pCB
);
1311 // We are resizing !!!!
1315 _LastParentW
= parentWidth
;
1316 invalidateContent();
1321 _LastParentW
= parentWidth
;
1322 invalidateContent();
1327 CInterfaceGroup::checkCoords();
1330 // ----------------------------------------------------------------------------
1331 void CGroupTable::onInvalidateContent()
1333 _ContentValidated
= false;
1337 // ----------------------------------------------------------------------------
1338 sint32
CGroupTable::getMaxUsedW() const
1340 // Return table width if its requested by user.
1341 // Need to do this because width of long line of text in here is calculated
1342 // differently than final cell width in updateCoords()
1343 // This will break tables with too narrow width set by user.
1344 if (ForceWidthMin
> 0)
1345 return ForceWidthMin
;
1349 vector
<sint32
> columns
;
1351 for (i
=0; i
<_Cells
.size(); i
++)
1353 // Update coords to get XReal
1354 CGroupCell
*cell
= _Cells
[i
];
1355 cell
->checkCoords();
1356 cell
->updateCoords();
1358 // Get width min and max
1359 sint32 cellWidthMax
= cell
->getMaxUsedW();
1366 if (column
>=columns
.size())
1367 columns
.resize(column
+1, 0);
1370 if (cellWidthMax
> columns
[column
])
1371 columns
[column
] = cellWidthMax
;
1372 if (cell
->WidthWanted
)
1373 columns
[column
] = cell
->WidthWanted
;
1375 // Hack to force a table with ratio to be large
1376 sint32 cellRatio
= (sint32
)ceil(cell
->TableRatio
* 1024.f
);
1377 if (cellRatio
> columns
[column
])
1378 columns
[column
] = cellRatio
;
1385 sint32 maxWidth
= 0;
1386 for (i
=0; i
<columns
.size(); i
++)
1387 maxWidth
+= columns
[i
];
1389 maxWidth
+= ((sint32
)columns
.size()+1) * CellSpacing
;
1391 maxWidth
+= Border
->getLeftRightWidth();
1396 // ----------------------------------------------------------------------------
1397 sint32
CGroupTable::getMinUsedW() const
1401 vector
<sint32
> columns
;
1403 for (i
=0; i
<_Cells
.size(); i
++)
1405 // Update coords to get XReal
1406 CGroupCell
*cell
= _Cells
[i
];
1407 cell
->checkCoords();
1408 cell
->updateCoords();
1410 // Get width min and max
1411 sint32 cellWidthMin
= cell
->getMinUsedW();
1418 if (column
>=columns
.size())
1419 columns
.resize(column
+1, 0);
1422 if (cellWidthMin
> columns
[column
])
1423 columns
[column
] = cellWidthMin
;
1424 if (cell
->WidthWanted
)
1425 columns
[column
] = cell
->WidthWanted
;
1432 sint32 maxWidth
= 0;
1433 for (i
=0; i
<columns
.size(); i
++)
1434 maxWidth
+= columns
[i
];
1436 maxWidth
+= ((sint32
)columns
.size()+1) * CellSpacing
;
1438 maxWidth
+= Border
->getLeftRightWidth();
1443 // ----------------------------------------------------------------------------
1444 void CGroupTable::draw ()
1446 // move X for clip and borders
1447 _XReal
+= _MarginLeft
;
1449 // search a parent container
1450 CInterfaceGroup
*gr
= getParent();
1453 if (gr
->isGroupContainer())
1455 CGroupContainer
*gc
= static_cast<CGroupContainer
*>(gr
);
1456 CurrentAlpha
= gc
->getCurrentContainerAlpha();
1459 gr
= gr
->getParent();
1466 if (!_Columns
.empty() && !_Rows
.empty())
1469 CViewRenderer
&rVR
= *CViewRenderer::getInstance();
1471 // TODO: monitor these in checkCoords and update when changed
1472 uint8 contentAlpha
= CWidgetManager::getInstance()->getGlobalColorForContent().A
;
1473 if (contentAlpha
> 0)
1477 Background
->CurrentAlpha
= CurrentAlpha
;
1478 Background
->setModulateGlobalColor(_ModulateGlobalColor
);
1484 Border
->CurrentAlpha
= CurrentAlpha
;
1485 Border
->setRenderLayer(_RenderLayer
);
1486 Border
->setModulateGlobalColor(_ModulateGlobalColor
);
1493 CInterfaceGroup::draw ();
1496 _XReal
-= _MarginLeft
;
1499 std::string
CGroupTable::getProperties( const std::string
&name
) const
1501 if( name
== "border" )
1504 return toString( Border
->getTopWidth() );
1508 if( name
== "bordercolor" )
1511 return toString( Border
->getTopColor() );
1512 return toString(CRGBA::Transparent
);
1515 if( name
== "cellpadding" )
1517 return toString( CellPadding
);
1520 if( name
== "cellspacing" )
1522 return toString( CellSpacing
);
1525 if( name
== "bgcolor" )
1528 return toString( Background
->getColor() );
1529 return toString( CRGBA::Transparent
);
1532 if( name
== "width" )
1534 if( ForceWidthMin
!= 0 )
1535 return toString( ForceWidthMin
);
1537 return toString( TableRatio
* 100.0f
);
1540 return CInterfaceGroup::getProperty( name
);
1543 void CGroupTable::setProperty( const std::string
&name
, const std::string
&value
)
1545 if( name
== "border" )
1548 if( fromString( value
, i
) )
1551 Border
= new CSSBorderRenderer();
1552 Border
->setWidth(i
);
1557 if( name
== "bordercolor" )
1560 if( fromString( value
, c
) )
1563 Border
= new CSSBorderRenderer();
1564 Border
->setColor(c
);
1569 if( name
== "cellpadding" )
1572 if( fromString( value
, i
) )
1577 if( name
== "cellspacing" )
1580 if( fromString( value
, i
) )
1585 if( name
== "bgcolor" )
1588 Background
= new CSSBackgroundRenderer();
1591 if( fromString( value
, c
) )
1592 Background
->setColor(c
);
1596 if( name
== "width" )
1598 convertPixelsOrRatio( value
.c_str(), ForceWidthMin
, TableRatio
);
1602 CInterfaceGroup::setProperty( name
, value
);
1606 xmlNodePtr
CGroupTable::serialize( xmlNodePtr parentNode
, const char *type
) const
1608 xmlNodePtr node
= CInterfaceGroup::serialize( parentNode
, type
);
1612 xmlSetProp( node
, BAD_CAST
"type", BAD_CAST
"table" );
1615 xmlSetProp( node
, BAD_CAST
"border", BAD_CAST
toString( Border
->getTopWidth() ).c_str() );
1616 xmlSetProp( node
, BAD_CAST
"bordercolor", BAD_CAST
toString( Border
->getTopColor() ).c_str() );
1618 xmlSetProp( node
, BAD_CAST
"cellpadding", BAD_CAST
toString( CellPadding
).c_str() );
1619 xmlSetProp( node
, BAD_CAST
"cellspacing", BAD_CAST
toString( CellSpacing
).c_str() );
1622 xmlSetProp( node
, BAD_CAST
"bgcolor", BAD_CAST
toString( Background
->getColor() ).c_str() );
1626 if( ForceWidthMin
!= 0 )
1627 xmlSetProp( node
, BAD_CAST
"width", BAD_CAST
toString( ForceWidthMin
).c_str() );
1629 xmlSetProp( node
, BAD_CAST
"width", BAD_CAST
toString( TableRatio
* 100.0f
).c_str() );
1634 // ------------------------------------------------------------------------------------------------
1635 bool CGroupTable::parse (xmlNodePtr cur
, CInterfaceGroup
* parentGroup
)
1637 if (!CInterfaceGroup::parse(cur
, parentGroup
)) return false;
1640 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"border" );
1644 fromString((const char*)ptr
, w
);
1646 Border
= new CSSBorderRenderer();
1647 Border
->setWidth(w
);
1650 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"bordercolor" );
1653 CRGBA c
= convertColor((const char*)ptr
);
1655 Border
= new CSSBorderRenderer();
1656 Border
->setColor(c
);
1659 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"cellpadding" );
1662 fromString((const char*)ptr
, CellPadding
);
1665 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"cellspacing" );
1668 fromString((const char*)ptr
, CellSpacing
);
1671 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"bgcolor" );
1675 Background
= new CSSBackgroundRenderer();
1677 Background
->setColor(convertColor((const char *) ptr
));
1680 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"width" );
1683 convertPixelsOrRatio(ptr
, ForceWidthMin
, TableRatio
);
1686 ptr
= (char*) xmlGetProp( cur
, (xmlChar
*)"continuous_update" );
1689 ContinuousUpdate
= convertBool(ptr
);
1693 xmlNodePtr currRow
= cur
->children
;
1694 while (currRow
!= NULL
)
1696 // look for 'TR' markup
1697 if (strcmp((char*)currRow
->name
,"TR") == 0)
1699 // found a row, parse cells inside
1700 xmlNodePtr currCol
= currRow
->children
;
1701 bool newLine
= true;
1703 while (currCol
!= NULL
)
1705 // look for 'TR' markup
1706 if (strcmp((char*)currCol
->name
,"TD") == 0)
1708 CGroupCell
*cell
= new CGroupCell(CViewBase::TCtorParam());
1709 if (cell
->parseCell(currCol
, this, column
, row
))
1711 cell
->NewLine
= newLine
;
1721 currCol
= currCol
->next
;
1725 currRow
= currRow
->next
;