// Ryzom - MMORPG Framework
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
#include "stdpch.h"
#include "group_paragraph.h"
#include "group_html.h"
#include "interface_manager.h"
#include "interface_element.h"
#include "../client_chat_manager.h"
#include "view_bitmap.h"
#include "view_text_id.h"
#include "group_container.h"
#include "nel/misc/i_xml.h"
#include "nel/misc/i18n.h"
#include "game_share/xml_auto_ptr.h"
using namespace std;
using namespace NLMISC;
extern CClientChatManager ChatMngr;
NLMISC_REGISTER_OBJECT(CViewBase, CCtrlLink, std::string, "button_link");
// ----------------------------------------------------------------------------
CGroupParagraph::CGroupParagraph(const TCtorParam ¶m)
: CInterfaceGroup(param),
_Templ(TCtorParam())
{
_IdCounter = 0;
_AddElt = Bottom;
_Align = Left;
_Space = 0;
_MinW= 0;
_MinH= 0;
_Over = false;
_OverColor = CRGBA(255,255,255,32);
_OverElt = -1;
_LastW = 0;
invalidateContent();
_TopSpace = 0;
_Indent = 0;
_FirstViewIndentView = false;
_BrowseGroup = NULL;
}
// ----------------------------------------------------------------------------
void CGroupParagraph::addChild (CViewBase* child, bool deleteOnRemove)
{
if (!child)
{
nlwarning(" : tried to add a NULL view");
return;
}
// add child at last index
addChildAtIndex(child, _Elements.size(), deleteOnRemove);
if (_Elements.size() >= 2)
{
setOrder(_Elements.size() - 1, getOrder(_Elements.size() - 2) + 1);
}
invalidateContent();
}
// ----------------------------------------------------------------------------
CGroupParagraph::~CGroupParagraph()
{
deleteAllChildren();
}
// ----------------------------------------------------------------------------
// Set Hotspot of the first element in reference to the group
/*void CGroupParagraph::setHSGroup (CViewBase *child, EAlign addElt, EAlign align)
{
switch (addElt)
{
case Bottom:
if (align == Left)
{
child->_ParentPosRef = Hotspot_TL;
child->_PosRef = Hotspot_TL;
}
else // align == Right
{
child->_ParentPosRef = Hotspot_TR;
child->_PosRef = Hotspot_TR;
}
break;
case Left:
if (align == Top)
{
child->_ParentPosRef = Hotspot_TR;
child->_PosRef = Hotspot_TR;
}
else // align == Bottom
{
child->_ParentPosRef = Hotspot_BR;
child->_PosRef = Hotspot_BR;
}
break;
case Top:
if (align == Left)
{
child->_ParentPosRef = Hotspot_BL;
child->_PosRef = Hotspot_BL;
}
else // align == Right
{
child->_ParentPosRef = Hotspot_BR;
child->_PosRef = Hotspot_BR;
}
break;
case Right:
if (align == Top)
{
child->_ParentPosRef = Hotspot_TL;
child->_PosRef = Hotspot_TL;
}
else // align == Bottom
{
child->_ParentPosRef = Hotspot_BL;
child->_PosRef = Hotspot_BL;
}
break;
default:
nlassert(false);
break;
}
}*/
// ----------------------------------------------------------------------------
/** align an element towards its parent in the group
*/
/*void CGroupParagraph::setHSParent(CViewBase *view, EAlign addElt, EAlign align, uint space)
{
if ((addElt == Top) || (addElt == Bottom))
{
if (addElt == Bottom)
{
if (_Align == Left)
view->_ParentPosRef = Hotspot_BL;
else // align == Right
view->_ParentPosRef = Hotspot_BR;
view->_Y = -abs(space);
}
else if (addElt == Top)
{
if (_Align == Left)
view->_ParentPosRef = Hotspot_TL;
else // align == Right
view->_ParentPosRef = Hotspot_TR;
view->_Y = abs(space);
}
}
else
{
if (addElt == Left)
{
if (_Align == Top)
view->_ParentPosRef = Hotspot_TL;
else // align == Bottom
view->_ParentPosRef = Hotspot_BL;
view->_X = -abs(space);
}
else if (addElt == Right)
{
if (_Align == Top)
view->_ParentPosRef = Hotspot_TR;
else // align == Bottom
view->_ParentPosRef = Hotspot_BR;
view->_X = abs(space);
}
}
}*/
// ----------------------------------------------------------------------------
bool CGroupParagraph::parse (xmlNodePtr cur, CInterfaceGroup * parentGroup)
{
if (!CInterfaceGroup::parse(cur,parentGroup))
return false;
// Parse location. If these properties are not specified, set them to 0
CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"addelt" ));
_AddElt = Bottom;
if (ptr)
{
if (stricmp(ptr,"B") == 0)
_AddElt = Bottom;
else if (stricmp(ptr,"T") == 0)
_AddElt = Top;
else if (stricmp(ptr,"L") == 0)
_AddElt = Left;
else if (stricmp(ptr,"R") == 0)
_AddElt = Right;
}
ptr = (char*) xmlGetProp( cur, (xmlChar*)"align" );
_Align = Left;
if (ptr)
{
if (stricmp(ptr,"B") == 0)
_Align = Bottom;
else if (stricmp(ptr,"T") == 0)
_Align = Top;
else if (stricmp(ptr,"L") == 0)
_Align = Left;
else if (stricmp(ptr,"R") == 0)
_Align = Right;
}
ptr = (char*) xmlGetProp( cur, (xmlChar*)"space" );
_Space = 0;
if (ptr)
fromString((const char*)ptr, _Space);
EAlign addElt = _AddElt;
// EAlign align = _Align;
_GroupSizeRef = _SizeRef;
if ((addElt == Top) || (addElt == Bottom))
{
setMaxW (_W);
setMaxH(_H);
_H = 0;
_SizeRef = _SizeRef&(~2);
}
else
{
setMaxW (_W);
setMaxH (_H);
_W = 0;
_SizeRef = _SizeRef&(~1);
}
ptr = (char*) xmlGetProp( cur, (xmlChar*)"over" );
_Over = false;
if (ptr) _Over = convertBool(ptr);
ptr = (char*) xmlGetProp( cur, (xmlChar*)"col_over" );
_OverColor = CRGBA(255,255,255,32);
if (ptr) _OverColor = convertColor(ptr);
// TEMPLATE TEXT SETUP
// justification parameters
_Templ.parseTextOptions (cur);
// initial text
ptr = (char*) xmlGetProp( cur, (xmlChar*)"hardtext" );
if (ptr)
{
const char *propPtr = ptr;
ucstring Text = ucstring(propPtr);
if ((strlen(propPtr)>2) && (propPtr[0] == 'u') && (propPtr[1] == 'i'))
Text = CI18N::get (propPtr);
addTextChild(Text);
}
else
{
ptr = (char*) xmlGetProp( cur, (xmlChar*)"textid" );
if (ptr)
{
uint32 textId;
fromString((const char*)ptr, textId);
addTextChildID(textId);
}
}
return true;
}
// ----------------------------------------------------------------------------
void CGroupParagraph::addTextChild(const ucstring& line, bool multiLine /*= true*/)
{
const string elid = _Id + ":el" + toString(_IdCounter); ++_IdCounter;
CViewText *view= new CViewText (elid, string(""), _Templ.getFontSize(), _Templ.getColor(), _Templ.getShadow());
view->_Parent = this;
view->setMultiLine (multiLine);
view->setTextMode(_Templ.getTextMode());
if (multiLine) view->setMultiLineSpace (_Space);
view->setText (line);
// Herit global-coloring
view->setModulateGlobalColor(getModulateGlobalColor());
addChild (view);
invalidateCoords();
}
// ----------------------------------------------------------------------------
void CGroupParagraph::addTextChild(const ucstring& line, const CRGBA& textColor, bool multiLine /*= true*/)
{
const string elid = _Id + ":el" + toString(_IdCounter); ++_IdCounter;
CViewText *view= new CViewText (elid, string(""), _Templ.getFontSize(), _Templ.getColor(), _Templ.getShadow());
view->_Parent = this;
view->setMultiLine (multiLine);
if (multiLine) view->setMultiLineSpace (_Space);
view->setText (line);
view->setColor (textColor);
// Herit global-coloring
view->setModulateGlobalColor(getModulateGlobalColor());
addChild (view);
invalidateCoords();
}
// ----------------------------------------------------------------------------
void CGroupParagraph::addTextChildID (uint32 nID, bool multiLine)
{
const string elid = _Id + ":el" + toString(_IdCounter); ++_IdCounter;
CViewTextID *view= new CViewTextID (elid, nID, _Templ.getFontSize(), _Templ.getColor(), _Templ.getShadow());
view->_Parent = this;
view->setMultiLine (multiLine);
if (multiLine) view->setMultiLineSpace (_Space);
// Herit global-coloring
view->setModulateGlobalColor(getModulateGlobalColor());
addChild (view);
invalidateCoords();
}
// ----------------------------------------------------------------------------
void CGroupParagraph::addTextChildID(const std::string &dbPath,bool multiLine /*=true*/)
{
const string elid = _Id + ":el" + toString(_IdCounter); ++_IdCounter;
CViewTextID *view= new CViewTextID (elid, dbPath, _Templ.getFontSize(), _Templ.getColor(), _Templ.getShadow());
view->_Parent = this;
view->setMultiLine (multiLine);
if (multiLine) view->setMultiLineSpace (_Space);
// Herit global-coloring
view->setModulateGlobalColor(getModulateGlobalColor());
addChild (view);
invalidateCoords();
}
// ----------------------------------------------------------------------------
void CGroupParagraph::delChild (CViewBase* childToDel)
{
// Look for child
uint posChildToDel = 0;
for (posChildToDel = 0; posChildToDel < _Elements.size(); ++posChildToDel)
{
CElementInfo rEI = _Elements[posChildToDel];
if (rEI.Element == childToDel)
break;
}
if (posChildToDel == _Elements.size())
{
nlwarning("Can't del child %s, it does not exist in the list", childToDel->getId().c_str());
return;
}
delChild(posChildToDel);
}
// ----------------------------------------------------------------------------
void CGroupParagraph::delChild(uint posChildToDel)
{
if (posChildToDel >= (uint) _Elements.size())
{
nlwarning(" bad index");
return;
}
CViewBase* childToDel = _Elements[posChildToDel].Element;
bool ElementMustBeDeleted = _Elements[posChildToDel].EltDeleteOnRemove;
_Elements.erase (_Elements.begin()+posChildToDel);
// Remove from drawing
if (dynamic_cast(childToDel)) delGroup(static_cast(childToDel), !ElementMustBeDeleted);
else if (dynamic_cast(childToDel)) delCtrl(static_cast(childToDel), !ElementMustBeDeleted);
else delView(childToDel, !ElementMustBeDeleted);
// Bind the new first element
if (posChildToDel < _Elements.size())
{
CViewBase *pVB = _Elements[posChildToDel].Element;
if (posChildToDel == 0)
{
pVB->_ParentPos = NULL;
// setHSGroup (pVB, _AddElt, _Align);
if ((_AddElt == Top) || (_AddElt == Bottom))
pVB->setY (0);
else
pVB->setX (0);
}
else
pVB->_ParentPos = _Elements[posChildToDel-1].Element;
}
}
// ----------------------------------------------------------------------------
/*void CGroupParagraph::removeHead ()
{
if (_Elements.empty())
{
nlwarning(" Can't remove head, list is empty");
return;
}
delChild (_Elements.begin()->Element);*/
/*CViewBase *pVB = _Elements.begin()->Element;
if ((_AddElt == Top) || (_AddElt == Bottom))
{
sint32 shift = _H - (pVB->getH() + _Space);
_H = shift;
}
else
{
sint32 shift = _W - (pVB->getW() + _Space);
_W = shift;
}
bool FirstElementMustBeDeleted = _Elements.begin()->EltDeleteOnRemove;
if (FirstElementMustBeDeleted)
delete pVB;
_Elements.erase (_Elements.begin());
// Remove from drawing
for (vector::iterator itg = _ChildrenGroups.begin(); itg != _ChildrenGroups.end(); itg++)
if(*itg == pVB)
{
_ChildrenGroups.erase (itg);
break;
}
for (vector::iterator itc = _Controls.begin(); itc != _Controls.end(); itc++)
if(*itc == pVB)
{
_Controls.erase (itc);
break;
}
for (vector::iterator itv = _Views.begin(); itv != _Views.end(); itv++)
if(*itv == pVB)
{
_Views.erase (itv);
break;
}
delEltOrder (pVB);
// Bind the new first element
pVB = _Elements.begin()->Element;
pVB->_ParentPos = NULL;
setHSGroup (pVB, _AddElt, _Align);
if ((_AddElt == Top) || (_AddElt == Bottom))
pVB->setY (0);
else
pVB->setX (0);*/
//}
// ----------------------------------------------------------------------------
void CGroupParagraph::setTextTemplate(const CViewText& templ)
{
_Templ = templ;
}
// ----------------------------------------------------------------------------
void CGroupParagraph::updateCoords()
{
if (_Parent)
{
if (!_ContentValidated)
{
// Update W
CInterfaceElement::updateCoords();
// Current X and Y
sint32 x=_Indent;
sint32 y=-(sint32)_TopSpace;
// Current W
sint width = std::min(getMaxWReal(), getWReal());
// For each elements, place them
uint firstElementOnLine = 0;
const uint elmCount = _Elements.size();
uint i;
for (i = 0; i < elmCount+1; ++i)
{
// Force flush for the last element
bool changeLine = (i == elmCount);
uint lastLineElement = i+1;
// Not the end of the element
if (i < elmCount)
{
// Active element ?
if (_Elements[i].Element->getActive())
{
_Elements[i].Element->updateCoords();
// Is a view text ?
CViewText *viewText = dynamic_cast(_Elements[i].Element);
if (viewText)
{
viewText->setFirstLineX(x + ((i==0)?_FirstViewIndentView:0));
viewText->setX(0);
viewText->updateTextContext();
}
else
{
_Elements[i].Element->setX(x + ((i==0)?_FirstViewIndentView:0));
}
_Elements[i].Element->setPosRef(Hotspot_TL);
_Elements[i].Element->setParentPosRef(Hotspot_TL);
// Update coords for this element
_Elements[i].Element->updateCoords();
// Does we balance the last line height ?
if (viewText)
{
changeLine = viewText->getNumLine() > 1;
if (!viewText->getText().empty() && *(viewText->getText().rbegin()) == (ucchar) '\n')
{
changeLine = true;
}
}
else
{
// If this element is too big for the line, place it next time
if ((i!=firstElementOnLine) && ((_Elements[i].Element->getX() + _Elements[i].Element->getW()) > width))
{
lastLineElement--;
changeLine = true;
i--;
}
}
// New x coordinate
x = _Elements[i].Element->getX() + _Elements[i].Element->getWReal();
}
}
else
lastLineElement = i;
// Balance line height
if (changeLine)
{
// Eval line height
uint j;
uint lineHeight = 0;
uint multiLineHeight = 0;
uint legHeight = 0;
uint lastLineWidth = _Indent;
for (j=firstElementOnLine; j(_Elements[j].Element);
// Element height
if (viewTextOnLine)
{
// Height is just under the first line letter
newHeight = viewTextOnLine->getFontHeight() - viewTextOnLine->getFontLegHeight();
// Leg height for this view
legHeight = std::max(legHeight, viewTextOnLine->getFontLegHeight());
// Last element is a text multi line
if (j==(lastLineElement-1))
{
const uint numLine = viewTextOnLine->getNumLine();
if (numLine>1)
{
multiLineHeight = (numLine-2) * viewTextOnLine->getFontHeight() + (numLine-1) * viewTextOnLine->getMultiLineSpace();
lastLineWidth = _Indent + viewTextOnLine->getLastLineW ();
}
}
}
else
{
newHeight = _Elements[j].Element->getH();
CGroupHTMLInputOffset *inputOffset = dynamic_cast(_Elements[j].Element);
if (inputOffset && inputOffset->Offset < 0)
{
newHeight += inputOffset->Offset;
legHeight = max(-(inputOffset->Offset), sint32(legHeight));
}
}
if (lineHeight < newHeight)
lineHeight = newHeight;
}
// Repos element on the line
for (j=firstElementOnLine; j(_Elements[j].Element);
sint32 offsetY=0;
CGroupHTMLInputOffset *inputOffset = dynamic_cast(_Elements[j].Element);
if (inputOffset)
offsetY = inputOffset->Offset;
// Element height
if (viewTextOnLine)
newHeight = viewTextOnLine->getFontHeight() - viewTextOnLine->getFontLegHeight() - offsetY;
else
newHeight = _Elements[j].Element->getH();
sint32 posY = y-lineHeight+newHeight+offsetY;
_Elements[j].Element->setY(posY);
}
if (i < elmCount)
{
nlassert(lastLineElement>0);
nlassert(lastLineElement-1getNumLine());
// Number of line..
uint j;
for (j=0; j<3; j++)
{
if (jsetId(getId()+":"+"links"+toString(i)+"-"+toString(j));
ctrl->setParent (this);
ctrl->setParentSize (this);
ctrl->setParentPos (this);
ctrl->setParentPosRef (Hotspot_TL);
ctrl->setPosRef (Hotspot_TL);
ctrl->setActive(true);
if (_BrowseGroup)
{
ctrl->setActionOnLeftClick("browse");
ctrl->setParamsOnLeftClick("name="+_BrowseGroup->getId()+"|url="+link.Link->Link);
}
ctrl->setScale(true);
addCtrl(ctrl);
}
// Pos the links
int x, y, width, height;
int fontSize = link.Link->getFontHeight();
int fontLineSpace = link.Link->getMultiLineSpace();
// X
x = (j == 0) ? link.Link->getFirstLineX() : link.Link->getX();
// Y
if (j < 2)
y = link.Link->getY() - (fontSize+fontLineSpace) * j;
else
y = link.Link->getY() - ((fontSize+fontLineSpace) * (link.Link->getNumLine()-1));
// Width
// Last line ?
if (j == (links-1))
width = link.Link->getLastLineW ();
else
{
width = link.Link->getW();
// First line ?
if (j == 0)
width -= (link.Link->getFirstLineX() - link.Link->getX());
}
if ((j == 1) && (links==3))
height = (fontSize+fontLineSpace)*(link.Link->getNumLine()-2);
else
height = fontSize;
ctrl->setX(x);
ctrl->setY(y);
ctrl->setW(width);
ctrl->setH(height);
}
else
{
if (link.CtrlLink[j])
{
delCtrl (link.CtrlLink[j]);
link.CtrlLink[j] = NULL;
}
}
}
}
}
}
CInterfaceGroup::updateCoords();
// Validated
_ContentValidated = true;
}
// ----------------------------------------------------------------------------
void CGroupParagraph::checkCoords ()
{
if (_Parent != NULL)
{
sint parentWidth = std::min(_Parent->getMaxWReal(), _Parent->getWReal());
if (_LastW != (sint) parentWidth)
{
CInterfaceManager *pIM = CInterfaceManager::getInstance();
CCtrlBase *pCB = pIM->getCapturePointerLeft();
if (pCB != NULL)
{
CCtrlResizer *pCR = dynamic_cast(pCB);
if (pCR != NULL)
{
// We are resizing !!!!
}
else
{
_LastW = parentWidth;
invalidateContent();
}
}
else
{
_LastW = parentWidth;
invalidateContent();
}
}
}
CInterfaceGroup::checkCoords();
}
// ----------------------------------------------------------------------------
void CGroupParagraph::draw ()
{
// TEMP TEMP
//CViewRenderer &rVR = CInterfaceManager::getInstance()->getViewRenderer();
//rVR.drawRotFlipBitmap _RenderLayer, (_XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), CRGBA(0,255,0,255) );
if (_Over)
{
CInterfaceManager *pIM = CInterfaceManager::getInstance();
CViewRenderer &rVR = pIM->getViewRenderer();
if (pIM->getModalWindow() == NULL)
{
sint32 x = pIM->getPointer()->getX();
sint32 y = pIM->getPointer()->getY();
CInterfaceGroup *pIG = pIM->getWindowUnder(x,y);
CInterfaceGroup *pParent = this;
bool bFound = false;
while (pParent != NULL)
{
if (pParent == pIG)
{
bFound = true;
break;
}
pParent = pParent->getParent();
}
sint32 clipx,clipy,clipw,cliph;
getClip(clipx,clipy,clipw,cliph);
if ((x < clipx) ||
(x > (clipx + clipw)) ||
(y < clipy) ||
(y > (clipy + cliph)) || !bFound)
{
_OverElt = -1;
}
else
{
for (uint32 i = 0; i < _Elements.size(); ++i)
if (_Elements[i].Element->getActive())
{
CViewBase *pVB = _Elements[i].Element;
if ((x >= pVB->getXReal()) &&
(x < (pVB->getXReal() + pVB->getWReal()))&&
(y >= pVB->getYReal()) &&
(y < (pVB->getYReal() + pVB->getHReal())))
{
_OverElt = i;
}
}
}
}
if (_OverElt != -1)
{
CViewBase *pVB = _Elements[_OverElt].Element;
CRGBA col = _OverColor;
if(getModulateGlobalColor())
{
col.modulateFromColor (_OverColor, pIM->getGlobalColorForContent());
}
else
{
col= _OverColor;
col.A = (uint8)(((sint32)col.A*((sint32)pIM->getGlobalColorForContent().A+1))>>8);
}
rVR.drawRotFlipBitmap (_RenderLayer, pVB->getXReal(), pVB->getYReal(),
pVB->getWReal(), pVB->getHReal(), 0, false, rVR.getBlankTextureId(),
col );
}
}
CInterfaceGroup::draw ();
}
// ----------------------------------------------------------------------------
bool CGroupParagraph::handleEvent (const CEventDescriptor& event)
{
if (!_Active)
return false;
bool bReturn = CInterfaceGroup::handleEvent(event);
if (event.getType() == CEventDescriptor::mouse)
{
const CEventDescriptorMouse &eventDesc = (const CEventDescriptorMouse &)event;
_OverElt = -1;
if (!isIn(eventDesc.getX(), eventDesc.getY()))
return false;
for (uint32 i = 0; i < _Elements.size(); ++i)
if (_Elements[i].Element->getActive())
{
CViewBase *pVB = _Elements[i].Element;
if ((eventDesc.getX() >= pVB->getXReal()) &&
(eventDesc.getX() < (pVB->getXReal() + pVB->getWReal()))&&
(eventDesc.getY() >= pVB->getYReal()) &&
(eventDesc.getY() < (pVB->getYReal() + pVB->getHReal())))
{
_OverElt = i;
}
}
}
return bReturn;
}
// predicate to remove a view from the list of element
struct CRemoveViewPred
{
bool operator()(const CGroupParagraph::CElementInfo &info) const { return dynamic_cast(info.Element) != NULL; }
};
// predicate to remove a ctrl from the list of element
struct CRemoveCtrlPred
{
bool operator()(const CGroupParagraph::CElementInfo &info) const { return dynamic_cast(info.Element) != NULL; }
};
// predicate to remove a group from the list of element
struct CRemoveGroupPred
{
bool operator()(const CGroupParagraph::CElementInfo &info) const { return dynamic_cast(info.Element) != NULL; }
};
// ----------------------------------------------------------------------------
void CGroupParagraph::clearViews()
{
_IdCounter = 0;
// remove views from the list of elements
_Elements.erase(std::remove_if(_Elements.begin(), _Elements.end(), CRemoveViewPred()), _Elements.end());
CInterfaceGroup::clearViews();
updateCoords();
}
// ----------------------------------------------------------------------------
void CGroupParagraph::clearControls()
{
_IdCounter = 0;
// remove views from the list of elements
_Elements.erase(std::remove_if(_Elements.begin(), _Elements.end(), CRemoveCtrlPred()), _Elements.end());
CInterfaceGroup::clearControls();
updateCoords();
}
// ----------------------------------------------------------------------------
void CGroupParagraph::clearGroups()
{
_IdCounter = 0;
// remove views from the list of elements
_Elements.erase(std::remove_if(_Elements.begin(), _Elements.end(), CRemoveGroupPred()), _Elements.end());
CInterfaceGroup::clearGroups();
updateCoords();
}
// ----------------------------------------------------------------------------
void CGroupParagraph::forceSizeW (sint32 newSizeW)
{
_W = newSizeW;
for (uint32 i = 0; i < _Elements.size(); ++i)
{
_Elements[i].Element->setW (_W);
_Elements[i].Element->CInterfaceElement::updateCoords();
}
}
// ----------------------------------------------------------------------------
void CGroupParagraph::forceSizeH (sint32 newSizeH)
{
_H = newSizeH;
for (uint32 i = 0; i < _Elements.size(); ++i)
{
_Elements[i].Element->setH (_H);
_Elements[i].Element->CInterfaceElement::updateCoords();
}
}
// ----------------------------------------------------------------------------
void CGroupParagraph::setMinW(sint32 minW)
{
_MinW= minW;
invalidateCoords();
}
// ----------------------------------------------------------------------------
void CGroupParagraph::setMinH(sint32 minH)
{
_MinH= minH;
invalidateCoords();
}
// ----------------------------------------------------------------------------
bool CGroupParagraph::addChildAtIndex(CViewBase *child, uint index, bool deleteOnRemove /*=true*/)
{
if (!child)
{
nlwarning(" : tried to add a NULL view");
return false;
}
if (index > _Elements.size())
{
return false;
}
child->_Parent = this;
child->_ParentPos = NULL;
child->_Active = true;
child->_X = 0;
child->_Y = 0;
child->_RenderLayer = this->_RenderLayer;
// Can't have sizeref on the coordinate corresponding to alignement
switch(_AddElt)
{
case Top:
case Bottom:
child->_SizeRef &= 1; // sizeref on w is permitted
break;
case Left:
case Right:
child->_SizeRef &= 2; // sizeref on h is permitted
break;
default:
nlwarning(" bad align");
child->_SizeRef = 0;
break;
}
child->_SizeDivW = 10;
child->_SizeDivH = 10;
// Position the element according to the list alignement
// setHSGroup (child, _AddElt, _Align);
// update coords of the element (it may use child_resize_h or w)
//child->updateCoords();
child->invalidateCoords();
// Update size
if ((_AddElt == Top) || (_AddElt == Bottom))
{
// update the list size
sint32 newH = _H + child->getH();
if (_Elements.size() > 0)
newH += _Space;
_H = newH;
if ((_SizeRef&1) == 0) // No parent size reference in W
{
sint32 newW = max (_W, child->getW());
_W = newW;
}
}
else
{
// Update the list coords
sint32 newW = _W + child->getW();
if (_Elements.size() > 0)
newW += _Space;
_W = newW;
if ((_SizeRef&2) == 0) // No parent size reference in H
{
sint32 newH = max (_H, child->getH());
_H = newH;
}
}
CElementInfo ei;
ei.Element = child;
ei.EltDeleteOnRemove = deleteOnRemove;
ei.Order = 0;
if (index != 0)
{
// update alignement
// setHSParent(child, _AddElt, _Align, _Space);
// child->_ParentPos = _Elements[index - 1].Element;
}
_Elements.insert(_Elements.begin() + index, ei);
// link next element to this one
if (index < _Elements.size() - 1)
{
// _Elements[index + 1].Element->_ParentPos = child;
// setHSParent(_Elements[index + 1].Element, _AddElt, _Align, _Space);
}
// Add this element for drawing
{
CInterfaceGroup *pIG = dynamic_cast(child);
if (pIG != NULL)
{
addGroup (pIG, (sint) index);
return true;
}
CCtrlBase *pCB = dynamic_cast(child);
if (pCB != NULL)
{
addCtrl (pCB, (sint) index);
return true;
}
CViewBase *pVB = dynamic_cast(child);
if (pVB != NULL)
{
addView (pVB, (sint) index);
return true;
}
nlstop;
return false;
}
return false;
}
// ----------------------------------------------------------------------------
sint32 CGroupParagraph::getElementIndex(CViewBase* child) const
{
for(uint k = 0; k < _Elements.size(); ++k)
{
if (_Elements[k].Element == child) return k;
}
return -1;
}
// ----------------------------------------------------------------------------
/*void CGroupParagraph::swapChildren(uint index1, uint index2)
{
if (index1 >= _Elements.size()
|| index2 >= _Elements.size())
{
nlwarning(" bad indexes");
return;
}
// prevent elements from being deleted
bool oldMustDelete1 = _Elements[index1].EltDeleteOnRemove;
bool oldMustDelete2 = _Elements[index2].EltDeleteOnRemove;
uint order1 = _Elements[index1].Order;
uint order2 = _Elements[index2].Order;
_Elements[index1].EltDeleteOnRemove = false;
_Elements[index2].EltDeleteOnRemove = false;
CViewBase *v1 = _Elements[index1].Element;
CViewBase *v2 = _Elements[index2].Element;
if (index1 < index2)
{
delChild(index2);
delChild(index1);
addChildAtIndex(v2, index1, oldMustDelete2);
setOrder(index1, order2);
addChildAtIndex(v1, index2, oldMustDelete1);
setOrder(index2, order1);
}
else
{
delChild(index1);
delChild(index2);
addChildAtIndex(v1, index2, oldMustDelete1);
setOrder(index2, order1);
addChildAtIndex(v2, index1, oldMustDelete2);
setOrder(index1, order2);
}
}*/
// ----------------------------------------------------------------------------
void CGroupParagraph::deleteAllChildren()
{
uint numChildren = getNbElement();
for(uint k = 0; k < numChildren; ++k)
{
delChild(numChildren - 1 - k); // delete in reverse order to avoid unnecessary vector copies
}
}
// ----------------------------------------------------------------------------
uint CGroupParagraph::getNumActiveChildren() const
{
uint numChildren = 0;
for(uint k = 0; k < _Elements.size(); ++k)
{
if (_Elements[k].Element->getActive()) ++numChildren;
}
return numChildren;
}
// ----------------------------------------------------------------------------
void CGroupParagraph::setDelOnRemove(uint index, bool delOnRemove)
{
if (index >= _Elements.size())
{
nlwarning("bad index");
return;
}
_Elements[index].EltDeleteOnRemove = delOnRemove;
}
// ----------------------------------------------------------------------------
bool CGroupParagraph::getDelOnRemove(uint index) const
{
if (index >= _Elements.size())
{
nlwarning("bad index");
return false;
}
return _Elements[index].EltDeleteOnRemove;
}
// ----------------------------------------------------------------------------
void CGroupParagraph::addChildLink (CViewLink* child, bool deleteOnRemove)
{
// Add the child
addChild (child, deleteOnRemove);
// Add the link
_Links.push_back (CLink(child));
}
// ----------------------------------------------------------------------------
CGroupParagraph::CLink::CLink (CViewLink *link)
{
Link = link;
CtrlLink[0] = NULL;
CtrlLink[1] = NULL;
CtrlLink[2] = NULL;
}
// ----------------------------------------------------------------------------
void CGroupParagraph::onInvalidateContent()
{
_ContentValidated = false;
invalidateCoords();
}
// ----------------------------------------------------------------------------
sint32 CGroupParagraph::getMaxUsedW() const
{
// The paragraph max is the sum of the components max
sint maxWidth = 0;
for (uint k = 0; k < _Elements.size(); ++k)
{
// Get the child width
maxWidth += _Elements[k].Element->getMaxUsedW();
}
return maxWidth;
}
// ----------------------------------------------------------------------------
sint32 CGroupParagraph::getMinUsedW() const
{
// The paragraph min is the max of the components min
sint32 minWidth = 0;
for (uint k = 0; k < _Elements.size(); ++k)
{
// Get the child width
sint32 width = _Elements[k].Element->getMinUsedW();
if (width > minWidth)
minWidth = width;
}
return minWidth;
}