Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / gui / group_table.cpp
blob86d98ae8d4af810e90fb5185f7eeed961b889332
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013-2014 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 //
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/>.
21 #include "stdpch.h"
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"
34 using namespace std;
35 using namespace NLMISC;
37 #ifdef DEBUG_NEW
38 #define new DEBUG_NEW
39 #endif
41 namespace NLGUI
44 bool CGroupCell::DebugUICell = false;
46 // ----------------------------------------------------------------------------
47 CGroupCell::CGroupCell(const TCtorParam &param)
48 : CInterfaceGroup(param)
50 NewLine = false;
51 TableRatio = 0.f;
52 WidthWanted = 0;
53 Height = 0;
54 ColSpan = 1;
55 RowSpan = 1;
56 TableColumnIndex = 0;
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;
62 Align = Left;
63 VAlign = Middle;
64 LeftMargin = 0;
65 NoWrap = false;
66 IgnoreMaxWidth = false;
67 IgnoreMinWidth = false;
68 AddChildW = false;
69 setEnclosedGroupDefaultParams();
70 addGroup (Group);
73 // ----------------------------------------------------------------------------
74 CGroupCell::~CGroupCell()
76 if (Border)
78 delete Border;
79 Border = NULL;
81 if (Background)
83 delete Background;
84 Background = NULL;
88 // ----------------------------------------------------------------------------
89 void CGroupCell::setEnclosedGroupDefaultParams()
91 nlassert(Group);
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" )
105 switch( Align )
107 case Right:
108 return "right";
110 case Center:
111 return "center";
113 case Left:
114 return "left";
117 nlassert(false);
119 return "";
121 else
122 if( name == "valign" )
124 switch( VAlign )
126 case Middle:
127 return "middle";
129 case Bottom:
130 return "bottom";
132 case Top:
133 return "top";
136 nlassert(false);
138 return "";
140 else
141 if( name == "left_margin" )
143 return toString( LeftMargin );
145 else
146 if( name == "nowrap" )
148 return toString( NoWrap );
150 else
151 if( name == "bgcolor" )
153 if (Background)
154 return toString( Background->getColor() );
155 return toString(CRGBA::Transparent);
157 else
158 if( name == "width" )
160 if( WidthWanted != 0 )
161 return toString( WidthWanted );
162 else
163 return toString( TableRatio * 100.0f );
165 else
166 if( name == "height" )
168 return toString( Height );
170 else
171 if( name == "ignore_max_width" )
173 return toString( IgnoreMaxWidth );
175 else
176 if( name == "ignore_min_width" )
178 return toString( IgnoreMinWidth );
180 else
181 if( name == "add_child_w" )
183 return toString( AddChildW );
185 else
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" )
194 Align = Right;
195 else
196 if( value == "center" )
197 Align = Center;
198 else
199 if( value == "left" )
200 Align = Left;
202 return;
204 else
205 if( name == "valign" )
207 if( value == "top" )
208 VAlign = Top;
209 else
210 if( value == "middle" )
211 VAlign = Middle;
212 else
213 if( value == "bottom" )
214 VAlign = Bottom;
216 return;
218 else
219 if( name == "left_margin" )
221 sint32 i;
222 if( fromString( value, i ) )
223 LeftMargin = i;
224 return;
226 else
227 if( name == "nowrap" )
229 bool b;
230 if( fromString( value, b ) )
231 NoWrap = b;
232 return;
234 else
235 if( name == "bgcolor" )
237 if (!Background)
238 Background = new CSSBackgroundRenderer();
240 CRGBA c;
241 if( fromString( value, c ) )
242 Background->setColor(c);
243 return;
245 else
246 if( name == "width" )
248 convertPixelsOrRatio( value.c_str(), WidthWanted, TableRatio );
249 return;
251 else
252 if( name == "height" )
254 sint32 i;
255 if( fromString( value, i ) )
256 Height = i;
257 return;
259 else
260 if( name == "ignore_max_width" )
262 bool b;
263 if( fromString( value, b ) )
264 IgnoreMaxWidth = b;
265 return;
267 else
268 if( name == "ignore_min_width" )
270 bool b;
271 if( fromString( value, b ) )
272 IgnoreMinWidth = b;
273 return;
275 else
276 if( name == "add_child_w" )
278 bool b;
279 if( fromString( value, b ) )
280 AddChildW = b;
281 return;
283 else
284 if (name == "colspan" )
286 sint32 i;
287 if (fromString( value, i ) )
288 ColSpan = std::max(1, i);
289 return;
291 else
292 if (name == "rowspan" )
294 sint32 i;
295 if (fromString( value, i ) )
296 RowSpan = std::max(1, i);
297 return;
299 else
300 CInterfaceGroup::setProperty( name, value );
303 xmlNodePtr CGroupCell::serialize( xmlNodePtr parentNode, const char *type ) const
305 xmlNodePtr node = CInterfaceGroup::serialize( parentNode, type );
306 if( node == NULL )
307 return NULL;
309 xmlSetProp( node, BAD_CAST "type", BAD_CAST "cell" );
311 std::string align;
312 std::string valign;
314 switch( Align )
316 case Right:
317 align = "right";
318 break;
320 case Center:
321 align = "center";
322 break;
324 default:
325 align = "left";
326 break;
330 switch( VAlign )
332 case Middle:
333 valign = "middle";
334 break;
336 case Bottom:
337 valign = "bottom";
338 break;
340 default:
341 valign = "top";
342 break;
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() );
349 if (Background)
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() );
354 else
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() );
364 return node;
367 // ----------------------------------------------------------------------------
368 bool CGroupCell::parseCell(xmlNodePtr cur, CInterfaceGroup * parentGroup, uint columnIndex, uint rowIndex)
370 CXMLAutoPtr ptr;
371 ptr = (char*) xmlGetProp( cur, (xmlChar*)"id");
372 if (!ptr)
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;
385 // align
386 ptr = (char*) xmlGetProp( cur, (xmlChar*)"align" );
387 if (ptr)
389 if (strcmp((const char *) ptr, "left") == 0)
391 Align = Left;
393 else if (strcmp((const char *) ptr, "right") == 0)
395 Align = Right;
397 else if (strcmp((const char *) ptr, "center") == 0)
399 Align = Center;
401 else
403 nlwarning("<CGroupCell::parse> Unknwown or unsupported align mode : %s", (const char *) ptr);
406 // v-align
407 ptr = (char*) xmlGetProp( cur, (xmlChar*)"valign" );
408 if (ptr)
410 if (strcmp((const char *) ptr, "top") == 0)
412 VAlign = Top;
414 else if (strcmp((const char *) ptr, "middle") == 0)
416 VAlign = Middle;
418 else if (strcmp((const char *) ptr, "bottom") == 0)
420 VAlign = Bottom;
422 else
424 nlwarning("<CGroupCell::parse> Unknwown or unsupported valign mode : %s", (const char *) ptr);
427 // left margin
428 ptr = (char*) xmlGetProp( cur, (xmlChar*)"left_margin" );
429 if (ptr)
431 fromString((const char*)ptr, LeftMargin);
434 ptr = (char*) xmlGetProp( cur, (xmlChar*)"nowrap" );
435 if (ptr)
437 NoWrap = convertBool(ptr);
440 ptr = (char*) xmlGetProp( cur, (xmlChar*)"bgcolor" );
441 if (ptr)
443 if (!Background)
444 Background = new CSSBackgroundRenderer();
445 Background->setColor(convertColor(ptr));
448 ptr = (char*) xmlGetProp( cur, (xmlChar*)"width" );
449 if (ptr)
451 convertPixelsOrRatio((const char *) ptr, WidthWanted, TableRatio);
454 ptr = (char*) xmlGetProp( cur, (xmlChar*)"height" );
455 if (ptr)
457 fromString((const char*)ptr, Height);
460 ptr = (char*) xmlGetProp( cur, (xmlChar*)"ignore_max_width" );
461 if (ptr)
463 IgnoreMaxWidth = convertBool(ptr);
466 ptr = (char*) xmlGetProp( cur, (xmlChar*)"ignore_min_width" );
467 if (ptr)
469 IgnoreMinWidth = convertBool(ptr);
472 ptr = (char*) xmlGetProp( cur, (xmlChar*)"add_child_w" );
473 if (ptr)
475 AddChildW = convertBool(ptr);
478 ptr = (char*) xmlGetProp( cur, (xmlChar*)"colspan" );
479 if (ptr)
481 sint32 i;
482 if (fromString((const char*)ptr, i))
483 ColSpan = std::max(1, i);
486 ptr = (char*) xmlGetProp( cur, (xmlChar*)"rowspan" );
487 if (ptr)
489 sint32 i;
490 if (fromString((const char*)ptr, i))
491 RowSpan = std::max(1, i);
494 return true;
498 // ----------------------------------------------------------------------------
499 void CGroupCell::draw ()
501 if ( CGroupCell::DebugUICell )
503 // Draw cell
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
514 rVR.flush();
516 if (Background)
518 uint8 CurrentAlpha = 255;
519 CGroupTable *table = NULL;
520 if (getParent ())
522 table = static_cast<CGroupTable*> (getParent ());
523 CurrentAlpha = table->CurrentAlpha;
525 if (CurrentAlpha > 0)
527 Background->CurrentAlpha = CurrentAlpha;
528 Background->setModulateGlobalColor(_ModulateGlobalColor);
529 Background->draw();
530 rVR.flush();
534 if (Border)
536 Border->CurrentAlpha = CWidgetManager::getInstance()->getGlobalColorForContent().A;
537 if (Border->CurrentAlpha > 0)
539 Border->setRenderLayer(_RenderLayer);
540 Border->setModulateGlobalColor(_ModulateGlobalColor);
541 Border->draw();
542 rVR.flush();
547 CInterfaceGroup::draw ();
550 // ----------------------------------------------------------------------------
551 sint32 CGroupCell::getMaxUsedW() const
553 sint32 result = getPaddingLeftRight() + Group->getMaxUsedW();
554 if (Border)
555 result += Border->getLeftRightWidth();
556 return result;
559 // ------------------------------------------------------------------------------------------------
560 sint32 CGroupCell::getMinUsedW() const
562 sint32 result = getPaddingLeftRight() + Group->getMinUsedW();
563 if (Border)
564 result += Border->getLeftRightWidth();
565 return result;
569 // ----------------------------------------------------------------------------
570 void CGroupCell::setTexture(const std::string & TxName)
572 if (Background)
573 Background->setImage(TxName);
576 // ----------------------------------------------------------------------------
577 void CGroupCell::setTextureTile(bool tiled)
579 if (Background)
580 Background->setImageRepeat(tiled);
583 // ----------------------------------------------------------------------------
584 void CGroupCell::setTextureScale(bool scaled)
586 if (Background)
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 &param)
600 : CInterfaceGroup(param)
602 _ContentValidated = false;
603 TableRatio = 0.f;
604 ForceWidthMin = 0;
606 // TODO: only initialize when needed
607 Border = new CSSBorderRenderer();
608 Background = new CSSBackgroundRenderer();
610 CellBorder = false;
611 CellPadding=1;
612 CellSpacing=2;
613 ContinuousUpdate = false;
616 // ----------------------------------------------------------------------------
617 void CGroupTable::addChild (CGroupCell* child)
619 // Cell empty ?
620 if (_Cells.empty())
621 // New line
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);
634 /* // New line ?
635 if (child->NewLine)
637 // First element
638 if (_Cells.empty())
640 child->setParentPos(NULL);
641 child->setPosRef(Hotspot_TL);
642 child->setParentPosRef(Hotspot_TL);
644 // New line
645 else
647 // Look for previous new line
648 uint i;
649 for (i=_Cells.size()-1; i>0; i--)
650 if (_Cells[i]->NewLine)
651 break;
653 child->setParentPos(_Cells[i]);
654 child->setPosRef(Hotspot_TL);
655 child->setParentPosRef(Hotspot_BL);
658 else
660 nlassert(!_Cells.empty());
661 child->setParentPos(_Cells.back());
662 child->setPosRef(Hotspot_TL);
663 child->setParentPosRef(Hotspot_TR);
666 // Add the child
667 addGroup(child);
668 _Cells.push_back(child);
669 invalidateContent();
672 // ----------------------------------------------------------------------------
673 CGroupTable::~CGroupTable()
675 if (Border)
677 delete Border;
678 Border = NULL;
681 if (Background)
683 delete Background;
684 Background = NULL;
687 /* uint i;
688 for (i=0; i<_Cells.size(); i++)
689 delete _Cells[i];
690 _Cells.clear ();*/
693 // ----------------------------------------------------------------------------
694 void CGroupTable::setTexture(const std::string & TxName)
696 if (Background)
697 Background->setImage(TxName);
700 // ----------------------------------------------------------------------------
701 void CGroupTable::setTextureTile(bool tiled)
703 if (Background)
704 Background->setImageRepeat(tiled);
707 // ----------------------------------------------------------------------------
708 void CGroupTable::setTextureScale(bool scaled)
710 if (Background)
711 Background->setImageCover(scaled);
714 // ----------------------------------------------------------------------------
715 void CGroupTable::updateCoords()
717 if (_Parent)
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
736 uint i;
737 uint column = 0;
738 _Columns.clear ();
739 for (i=0; i<_Cells.size(); i++)
741 // Update coords to get XReal
742 CGroupCell *cell = _Cells[i];
743 cell->checkCoords();
744 cell->updateCoords();
746 sint32 additionnalWidth = 0;
747 if (cell->AddChildW)
749 sint width, height;
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;
757 else
758 cell->WidthMax = cell->WidthWanted + additionnalWidth + cell->LeftMargin;
760 sint32 cellWidth;
761 if(!cell->IgnoreMinWidth)
762 cellWidth = cell->NoWrap ? cell->WidthMax : cell->getMinUsedW() + cell->LeftMargin;
763 else
764 cellWidth = cell->NoWrap ? cell->WidthMax : cell->LeftMargin;
767 sint32 cellBorderPadding = cell->getPaddingLeftRight();
768 if (cell->Border)
769 cellBorderPadding += cell->Border->getLeftRightWidth();
770 if (cellWidth < cellBorderPadding)
771 cellWidth = cellBorderPadding;
774 // New cell ?
775 if (cell->NewLine)
777 while (column < _Columns.size())
779 if (_Columns[column].RowSpan > 1)
780 _Columns[column].RowSpan--;
781 column++;
783 column = 0;
786 // Resize the array
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--;
794 column++;
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;
807 // Update sizes
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)
831 ++column;
832 _Columns[column].RowSpan = _Columns[column-1].RowSpan;
836 // Next column
837 column++;
840 // Additional space contributing to table width
841 sint32 tableBorderSpacing = 0;
842 if (Border)
843 tableBorderSpacing += Border->getLeftRightWidth();
844 tableBorderSpacing += ((sint32)_Columns.size()+1) * CellSpacing;;
846 sint32 innerForceWidthMin = ForceWidthMin;
847 if (innerForceWidthMin < tableBorderSpacing)
848 innerForceWidthMin = 0;
849 else
850 innerForceWidthMin -= tableBorderSpacing;
852 // Get the width
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;
861 float ratio = 1;
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));
874 else
875 tableWidthMax = std::min(_LastParentW - tableBorderSpacing, std::max(tableWidthMax, tableMaxContentWidth));
877 if (tableWidthMax < 0)
878 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
901 sint32 cellSize;
902 if (_Columns[i].TableRatio < 1.f)
903 cellSize = (sint32)((float)tableWidthSizeAfterPercent*_Columns[i].TableRatio) + 1;
904 else
905 cellSize = 10000;
907 sint32 diff = std::min(tableWidthMax, (std::max(_Columns[i].Width, cellSize) - _Columns[i].Width)+tableWidth) - tableWidth;
908 tableWidth += diff;
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);
921 if (diff > 0)
923 _Columns[i].Width += diff;
924 tableWidth += diff;
925 space -= 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;
933 if (space > 0)
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;
941 tableWidth += dif;
944 // Some space ?
945 space = finalWidth - tableWidth;
946 if (space > 0)
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;
956 space -= dif;
960 if (space > 0)
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);
970 if (sumDeltaWidth)
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));
979 if (cellPart)
981 _Columns[i].Width += cellPart;
982 space -= cellPart;
988 if (space > 0)
990 // All cells with sizemax are full
991 // Distribute remaining space in others resizable cells
992 sumDeltaWidth = 0;
993 for (i=0; i<_Columns.size(); i++)
995 if ((_Columns[i].TableRatio == 0) && (_Columns[i].WidthWanted == 0))
996 sumDeltaWidth++;
998 if (sumDeltaWidth)
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;
1007 space -= cellPart;
1012 if (space > 0)
1014 // No cells with sizemax not sizewanted, resize size wanted
1015 // Distribute remaining space in others resizable cells
1016 sumDeltaWidth = 0;
1017 for (i=0; i<_Columns.size(); i++)
1019 if ((_Columns[i].TableRatio == 0) && (_Columns[i].WidthWanted != 0))
1020 sumDeltaWidth++;
1022 if (sumDeltaWidth)
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;
1031 space -= cellPart;
1036 // If there is still space left, then sum up column widths
1037 // and add all the remaining space to final column.
1038 if (space > 0)
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
1055 column = 0;
1056 sint32 row = 0;
1057 sint32 currentX = 0;
1059 _Rows.clear ();
1060 for (i=0; i<_Cells.size(); i++)
1062 CGroupCell *cell = _Cells[i];
1063 // New cell ?
1064 if (cell->NewLine)
1066 column = 0;
1067 currentX = CellSpacing;
1068 if (Border)
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
1083 // Check align
1084 sint32 alignmentX = 0;
1085 sint32 widthReduceX = 0;
1086 sint32 columnWidth = _Columns[column].Width;
1087 sint32 cellBorderPaddingLeft = cell->PaddingLeft;
1088 sint32 cellBorderPaddingRight = cell->PaddingRight;
1089 if (cell->Border)
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;
1109 break;
1110 case CGroupCell::Right:
1111 alignmentX = columnWidth - cell->WidthMax;
1112 widthReduceX = alignmentX;
1113 break;
1114 default:
1115 break;
1119 // outer
1120 cell->setX(currentX);
1121 cell->setW(columnWidth);
1123 // inner
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();
1135 if (cell->Border)
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);
1140 // Next column
1141 currentX += columnWidth + CellSpacing;
1142 column += cell->ColSpan;
1145 // Set cell Y
1146 row = 0;
1147 sint32 currentY = -CellSpacing;
1148 if (Border)
1149 currentY -= Border->getTopWidth();
1151 for (i=0; i<_Cells.size(); i++)
1153 // New cell ?
1154 CGroupCell *cell = _Cells[i];
1155 if ((i != 0) && (cell->NewLine))
1157 if (_Rows[row].Height != 0)
1159 currentY -= _Rows[row].Height + CellSpacing;
1161 row++;
1164 // Check align
1165 sint32 alignmentY = 0;
1166 sint32 rowHeight = _Rows[row].Height;
1167 sint32 cellBorderPaddingTop = cell->PaddingTop;
1168 sint32 cellBorderPaddingBottom = cell->PaddingBottom;
1169 if (cell->Border)
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;
1187 break;
1188 case CGroupCell::Bottom:
1189 alignmentY = rowHeight - (sint32)cell->Group->getH();
1190 break;
1191 default:
1192 break;
1196 // outer
1197 cell->setY(currentY);
1198 cell->setH (rowHeight);
1199 // inner
1200 cell->Group->setY(-(alignmentY + cellBorderPaddingTop - cellBorderPaddingBottom));
1203 // final row
1204 if (!_Rows.empty())
1205 currentY -= _Rows.back().Height;
1206 currentY -= CellSpacing;
1207 finalWidth += ((sint)_Columns.size() + 1) * CellSpacing;
1208 if (Border)
1210 currentY -= Border->getBottomWidth();
1211 finalWidth += Border->getLeftRightWidth();
1214 // Resize the table
1215 setW(finalWidth-_LastParentW);
1216 setH(-currentY);
1218 // All done
1223 CInterfaceGroup::updateCoords();
1225 // update borders if present
1226 if (Border)
1228 Border->setRect(_XReal + _MarginLeft, _YReal, _WReal, _HReal);
1231 if (Background)
1233 sint32 l = _XReal + _MarginLeft;
1234 sint32 b = _YReal;
1235 sint32 w = _WReal;
1236 sint32 h = _HReal;
1237 Background->setBorderArea(l, b, w, h);
1238 if (Border) {
1239 l += Border->getLeftWidth();
1240 b += Border->getBottomWidth();
1241 w -= Border->getLeftRightWidth();
1242 h -= Border->getTopBottomWidth();
1244 Background->setPaddingArea(l, b, w, h);
1245 // TODO: padding
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);
1275 // TODO: padding
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);
1285 // Validated
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();
1302 else
1305 CCtrlBase *pCB = CWidgetManager::getInstance()->getCapturePointerLeft();
1306 if (pCB != NULL)
1308 CCtrlResizer *pCR = dynamic_cast<CCtrlResizer*>(pCB);
1309 if (pCR != NULL)
1311 // We are resizing !!!!
1313 else
1315 _LastParentW = parentWidth;
1316 invalidateContent();
1319 else
1321 _LastParentW = parentWidth;
1322 invalidateContent();
1327 CInterfaceGroup::checkCoords();
1330 // ----------------------------------------------------------------------------
1331 void CGroupTable::onInvalidateContent()
1333 _ContentValidated = false;
1334 invalidateCoords();
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;
1347 uint i;
1348 uint column = 0;
1349 vector<sint32> columns;
1350 columns.clear ();
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();
1361 // New cell ?
1362 if (cell->NewLine)
1363 column = 0;
1365 // Resize the array
1366 if (column>=columns.size())
1367 columns.resize(column+1, 0);
1369 // Update sizes
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;
1380 // Next column
1381 column++;
1384 // Sum
1385 sint32 maxWidth = 0;
1386 for (i=0; i<columns.size(); i++)
1387 maxWidth += columns[i];
1389 maxWidth += ((sint32)columns.size()+1) * CellSpacing;
1390 if (Border)
1391 maxWidth += Border->getLeftRightWidth();
1393 return maxWidth;
1396 // ----------------------------------------------------------------------------
1397 sint32 CGroupTable::getMinUsedW() const
1399 uint i;
1400 uint column = 0;
1401 vector<sint32> columns;
1402 columns.clear ();
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();
1413 // New cell ?
1414 if (cell->NewLine)
1415 column = 0;
1417 // Resize the array
1418 if (column>=columns.size())
1419 columns.resize(column+1, 0);
1421 // Update sizes
1422 if (cellWidthMin > columns[column])
1423 columns[column] = cellWidthMin;
1424 if (cell->WidthWanted)
1425 columns[column] = cell->WidthWanted;
1427 // Next column
1428 column++;
1431 // Sum
1432 sint32 maxWidth = 0;
1433 for (i=0; i<columns.size(); i++)
1434 maxWidth += columns[i];
1436 maxWidth += ((sint32)columns.size()+1) * CellSpacing;
1437 if (Border)
1438 maxWidth += Border->getLeftRightWidth();
1440 return maxWidth;
1443 // ----------------------------------------------------------------------------
1444 void CGroupTable::draw ()
1446 // move X for clip and borders
1447 _XReal += _MarginLeft;
1449 // search a parent container
1450 CInterfaceGroup *gr = getParent();
1451 while (gr)
1453 if (gr->isGroupContainer())
1455 CGroupContainer *gc = static_cast<CGroupContainer *>(gr);
1456 CurrentAlpha = gc->getCurrentContainerAlpha();
1457 break;
1459 gr = gr->getParent();
1462 // Not found ?
1463 if (gr == NULL)
1464 CurrentAlpha = 255;
1466 if (!_Columns.empty() && !_Rows.empty())
1468 bool flush = false;
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)
1475 if (Background)
1477 Background->CurrentAlpha = CurrentAlpha;
1478 Background->setModulateGlobalColor(_ModulateGlobalColor);
1479 Background->draw();
1480 rVR.flush();
1482 if (Border)
1484 Border->CurrentAlpha = CurrentAlpha;
1485 Border->setRenderLayer(_RenderLayer);
1486 Border->setModulateGlobalColor(_ModulateGlobalColor);
1487 Border->draw();
1488 rVR.flush();
1493 CInterfaceGroup::draw ();
1495 // restore
1496 _XReal -= _MarginLeft;
1499 std::string CGroupTable::getProperties( const std::string &name ) const
1501 if( name == "border" )
1503 if (Border)
1504 return toString( Border->getTopWidth() );
1505 return "0";
1507 else
1508 if( name == "bordercolor" )
1510 if (Border)
1511 return toString( Border->getTopColor() );
1512 return toString(CRGBA::Transparent);
1514 else
1515 if( name == "cellpadding" )
1517 return toString( CellPadding );
1519 else
1520 if( name == "cellspacing" )
1522 return toString( CellSpacing );
1524 else
1525 if( name == "bgcolor" )
1527 if (Background)
1528 return toString( Background->getColor() );
1529 return toString( CRGBA::Transparent );
1531 else
1532 if( name == "width" )
1534 if( ForceWidthMin != 0 )
1535 return toString( ForceWidthMin );
1536 else
1537 return toString( TableRatio * 100.0f );
1539 else
1540 return CInterfaceGroup::getProperty( name );
1543 void CGroupTable::setProperty( const std::string &name, const std::string &value )
1545 if( name == "border" )
1547 sint32 i;
1548 if( fromString( value, i ) )
1550 if (!Border)
1551 Border = new CSSBorderRenderer();
1552 Border->setWidth(i);
1554 return;
1556 else
1557 if( name == "bordercolor" )
1559 CRGBA c;
1560 if( fromString( value, c ) )
1562 if (!Border)
1563 Border = new CSSBorderRenderer();
1564 Border->setColor(c);
1566 return;
1568 else
1569 if( name == "cellpadding" )
1571 sint32 i;
1572 if( fromString( value, i ) )
1573 CellPadding = i;
1574 return;
1576 else
1577 if( name == "cellspacing" )
1579 sint32 i;
1580 if( fromString( value, i ) )
1581 CellSpacing = i;
1582 return;
1584 else
1585 if( name == "bgcolor" )
1587 if (!Background)
1588 Background = new CSSBackgroundRenderer();
1590 CRGBA c;
1591 if( fromString( value, c ) )
1592 Background->setColor(c);
1593 return;
1595 else
1596 if( name == "width" )
1598 convertPixelsOrRatio( value.c_str(), ForceWidthMin, TableRatio );
1599 return;
1601 else
1602 CInterfaceGroup::setProperty( name, value );
1606 xmlNodePtr CGroupTable::serialize( xmlNodePtr parentNode, const char *type ) const
1608 xmlNodePtr node = CInterfaceGroup::serialize( parentNode, type );
1609 if( node == NULL )
1610 return NULL;
1612 xmlSetProp( node, BAD_CAST "type", BAD_CAST "table" );
1613 if (Border)
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() );
1620 if (Background)
1622 xmlSetProp( node, BAD_CAST "bgcolor", BAD_CAST toString( Background->getColor() ).c_str() );
1623 // TODO: Texture
1626 if( ForceWidthMin != 0 )
1627 xmlSetProp( node, BAD_CAST "width", BAD_CAST toString( ForceWidthMin ).c_str() );
1628 else
1629 xmlSetProp( node, BAD_CAST "width", BAD_CAST toString( TableRatio * 100.0f ).c_str() );
1631 return node;
1634 // ------------------------------------------------------------------------------------------------
1635 bool CGroupTable::parse (xmlNodePtr cur, CInterfaceGroup * parentGroup)
1637 if (!CInterfaceGroup::parse(cur, parentGroup)) return false;
1639 CXMLAutoPtr ptr;
1640 ptr = (char*) xmlGetProp( cur, (xmlChar*)"border" );
1641 if (ptr)
1643 uint32 w;
1644 fromString((const char*)ptr, w);
1645 if (!Border)
1646 Border = new CSSBorderRenderer();
1647 Border->setWidth(w);
1650 ptr = (char*) xmlGetProp( cur, (xmlChar*)"bordercolor" );
1651 if (ptr)
1653 CRGBA c = convertColor((const char*)ptr);
1654 if (!Border)
1655 Border = new CSSBorderRenderer();
1656 Border->setColor(c);
1659 ptr = (char*) xmlGetProp( cur, (xmlChar*)"cellpadding" );
1660 if (ptr)
1662 fromString((const char*)ptr, CellPadding);
1665 ptr = (char*) xmlGetProp( cur, (xmlChar*)"cellspacing" );
1666 if (ptr)
1668 fromString((const char*)ptr, CellSpacing);
1671 ptr = (char*) xmlGetProp( cur, (xmlChar*)"bgcolor" );
1672 if (ptr)
1674 if (!Background)
1675 Background = new CSSBackgroundRenderer();
1677 Background->setColor(convertColor((const char *) ptr));
1680 ptr = (char*) xmlGetProp( cur, (xmlChar*)"width" );
1681 if (ptr)
1683 convertPixelsOrRatio(ptr, ForceWidthMin, TableRatio);
1686 ptr = (char*) xmlGetProp( cur, (xmlChar*)"continuous_update" );
1687 if (ptr)
1689 ContinuousUpdate = convertBool(ptr);
1691 // parse cells
1692 uint row = 0;
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;
1702 uint column = 0;
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;
1712 newLine = false;
1713 addChild(cell);
1715 else
1717 delete cell;
1719 ++ column;
1721 currCol = currCol->next;
1723 ++ row;
1725 currRow = currRow->next;
1728 return true;