CHANGED: CGroupHeader is now part of the NELGUI library and is under the NLGUI namespace.
--HG-- branch : gui-refactoringhg/feature/sse2
parent
5893f791d4
commit
14247e9659
@ -0,0 +1,86 @@
|
||||
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef CL_GROUP_HEADER_H
|
||||
#define CL_GROUP_HEADER_H
|
||||
|
||||
#include "nel/gui/group_list.h"
|
||||
|
||||
namespace NLGUI
|
||||
{
|
||||
|
||||
class CGroupHeaderEntry;
|
||||
|
||||
// *****************************************************************************************************************
|
||||
/** Display a header with movable entries.
|
||||
* Usually used with a table to change the size of each column (much like the windows file explorer in 'details' mode)
|
||||
*
|
||||
* \author Nicolas Vizerie
|
||||
* \author Nevrax France
|
||||
* \date 2006
|
||||
*/
|
||||
class CGroupHeader : public CGroupList
|
||||
{
|
||||
public:
|
||||
REFLECT_EXPORT_START(CGroupHeader, CGroupList)
|
||||
REFLECT_LUA_METHOD("enlargeColumns", luaEnlargeColumns);
|
||||
REFLECT_LUA_METHOD("resizeColumnsAndContainer", luaResizeColumnsAndContainer);
|
||||
REFLECT_EXPORT_END
|
||||
|
||||
CGroupHeader(const TCtorParam ¶m);
|
||||
// from CInterfaceGroup
|
||||
virtual bool parse(xmlNodePtr cur, CInterfaceGroup * parentGroup);
|
||||
sint32 getHeaderMaxSize() const { return _HeaderMaxSize; }
|
||||
// get the entries in this header
|
||||
void getEntries(std::vector<CGroupHeaderEntry *> &dest);
|
||||
// ensure that max. content of columns is visible (without the total width becoming more than 'getHeaderMaxSize()'
|
||||
void enlargeColumns(sint32 margin);
|
||||
// ensure that content of each column is visible
|
||||
void resizeColumnsAndContainer(sint32 margin);
|
||||
private:
|
||||
sint32 _HeaderMaxSize;
|
||||
int luaEnlargeColumns(CLuaState &ls);
|
||||
int luaResizeColumnsAndContainer(CLuaState &ls);
|
||||
};
|
||||
|
||||
// *****************************************************************************************************************
|
||||
// an entry in a header, includes a "mover control" to move it inside its parent header
|
||||
// NOTE : when not used inside a CGroupHeader, will work, but there will be no 'max_size'
|
||||
class CGroupHeaderEntry : public CInterfaceGroup
|
||||
{
|
||||
public:
|
||||
CGroupHeaderEntry(const TCtorParam ¶m);
|
||||
// from CInterfaceGroup
|
||||
virtual bool parse(xmlNodePtr cur, CInterfaceGroup * parentGroup);
|
||||
sint32 getMinSize() const { return _MinSize; }
|
||||
virtual void updateCoords();
|
||||
CInterfaceGroup *getTargetColumn() const;
|
||||
|
||||
const std::string &getAHOnResize() const { return _AHOnResize; }
|
||||
const std::string &getAHOnResizeParams() const { return _AHOnResizeParams; }
|
||||
|
||||
private:
|
||||
sint32 _MinSize;
|
||||
std::string _TargetColumnId;
|
||||
std::string _AHOnResize;
|
||||
std::string _AHOnResizeParams;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,441 @@
|
||||
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#include "nel/gui/group_container.h"
|
||||
#include "nel/gui/group_header.h"
|
||||
#include "nel/gui/lua_ihm.h"
|
||||
#include "nel/gui/widget_manager.h"
|
||||
|
||||
|
||||
using namespace NLMISC;
|
||||
|
||||
namespace NLGUI
|
||||
{
|
||||
|
||||
//////////////////
|
||||
// CGroupHeader //
|
||||
//////////////////
|
||||
|
||||
// *****************************************************************************************************************
|
||||
CGroupHeader::CGroupHeader(const TCtorParam ¶m) : CGroupList(param), _HeaderMaxSize(32767)
|
||||
{
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************
|
||||
void CGroupHeader::enlargeColumns(sint32 margin)
|
||||
{
|
||||
std::vector<CGroupHeaderEntry *> entries;
|
||||
getEntries(entries);
|
||||
sint32 totalWidth = 0;
|
||||
for (uint k = 0; k < entries.size(); ++k)
|
||||
{
|
||||
CInterfaceGroup *colEnclosing = entries[k]->getTargetColumn();
|
||||
if (colEnclosing && !colEnclosing->getGroups().empty())
|
||||
{
|
||||
CInterfaceGroup *col = colEnclosing->getGroups()[0];
|
||||
if (col)
|
||||
{
|
||||
// enlarge to the max to be able to measure the sub text (they may clamp themselves based
|
||||
// on their first non-"child resizing" parent (see CViewText::updateCoords)
|
||||
colEnclosing->setW(16384);
|
||||
colEnclosing->invalidateCoords();
|
||||
colEnclosing->updateCoords();
|
||||
|
||||
// assume that first child is resizing from its children width (either 'child_resize_w=true' or a CGroupList)
|
||||
entries[k]->setW(std::max(entries[k]->getMinSize(), col->getW() + margin));
|
||||
entries[k]->invalidateCoords();
|
||||
totalWidth += entries[k]->getW();
|
||||
}
|
||||
}
|
||||
}
|
||||
// if total width bigger than allowed, reduce proportionnally
|
||||
if (totalWidth > _HeaderMaxSize)
|
||||
{
|
||||
while (totalWidth > _HeaderMaxSize)
|
||||
{
|
||||
bool adjusted = false;
|
||||
// stupid algo here, but ponctual ...
|
||||
for (uint k = 0; k < entries.size() && totalWidth > _HeaderMaxSize; ++k)
|
||||
{
|
||||
if (entries[k]->getW() > entries[k]->getMinSize())
|
||||
{
|
||||
entries[k]->setW(entries[k]->getW() - 1);
|
||||
entries[k]->invalidateCoords();
|
||||
--totalWidth;
|
||||
adjusted = true;
|
||||
}
|
||||
}
|
||||
// if all at min size, just exit ...
|
||||
if (!adjusted) break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// search first parent that limit size, if it is larger then enlarge to fit size
|
||||
CInterfaceGroup *limitingParent = getParent();
|
||||
while (limitingParent && (limitingParent->getResizeFromChildW() || dynamic_cast<CGroupList *>(limitingParent)))
|
||||
{
|
||||
// NB nico : the dynamic_cast for CGroupList is bad!!
|
||||
// can't avoid it for now, because, CGroupList implicitly does a "resize from child" in its update coords
|
||||
// ...
|
||||
limitingParent = limitingParent->getParent();
|
||||
}
|
||||
if (limitingParent && limitingParent->getWReal() > totalWidth)
|
||||
{
|
||||
while (limitingParent->getWReal() > totalWidth && totalWidth < _HeaderMaxSize)
|
||||
{
|
||||
// enlarge to matche parent size
|
||||
// stupid algo here, but ponctual ...
|
||||
for (uint k = 0; k < entries.size(); ++k)
|
||||
{
|
||||
entries[k]->setW(entries[k]->getW() + 1);
|
||||
entries[k]->invalidateCoords();
|
||||
++totalWidth;
|
||||
if (limitingParent->getWReal() <= totalWidth || totalWidth >= _HeaderMaxSize) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
invalidateCoords();
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************
|
||||
void CGroupHeader::resizeColumnsAndContainer(sint32 margin)
|
||||
{
|
||||
std::vector<CGroupHeaderEntry *> entries;
|
||||
getEntries(entries);
|
||||
sint32 totalWidth = 0;
|
||||
for (uint k = 0; k < entries.size(); ++k)
|
||||
{
|
||||
CInterfaceGroup *colEnclosing = entries[k]->getTargetColumn();
|
||||
if (colEnclosing && !colEnclosing->getGroups().empty())
|
||||
{
|
||||
CInterfaceGroup *col = colEnclosing->getGroups()[0];
|
||||
if (col)
|
||||
{
|
||||
// enlarge to the max to be able to measure the sub text (they may clamp themselves based
|
||||
// on their first non-"child resizing" parent (see CViewText::updateCoords)
|
||||
colEnclosing->setW(16384);
|
||||
colEnclosing->invalidateCoords();
|
||||
colEnclosing->updateCoords();
|
||||
|
||||
// assume that first child is resizing from its children width (either 'child_resize_w=true' or a CGroupList)
|
||||
entries[k]->setW(std::max(entries[k]->getMinSize(), col->getW() + margin));
|
||||
entries[k]->invalidateCoords();
|
||||
totalWidth += entries[k]->getW();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// resize W
|
||||
if (totalWidth <= _HeaderMaxSize)
|
||||
{
|
||||
// search first parent that limit size, if it is larger then enlarge to fit size
|
||||
CInterfaceGroup *limitingParent = getParent();
|
||||
while (limitingParent && (limitingParent->getResizeFromChildW() || dynamic_cast<CGroupList *>(limitingParent)))
|
||||
{
|
||||
// NB nico : the dynamic_cast for CGroupList is bad!!
|
||||
// can't avoid it for now, because, CGroupList implicitly does a "resize from child" in its update coords
|
||||
// ...
|
||||
limitingParent = limitingParent->getParent();
|
||||
}
|
||||
|
||||
getParentContainer()->setW(totalWidth + getParentContainer()->getWReal() - limitingParent->getWReal());
|
||||
}
|
||||
|
||||
// resize H
|
||||
if(entries.size()>0)
|
||||
{
|
||||
CInterfaceGroup *colEnclosing = entries[0]->getTargetColumn();
|
||||
if (colEnclosing && !colEnclosing->getGroups().empty())
|
||||
{
|
||||
CInterfaceGroup *col = colEnclosing->getGroups()[0];
|
||||
if (col)
|
||||
{
|
||||
// search first parent that limit size, if it is larger then enlarge to fit size
|
||||
CInterfaceGroup *limitingParent = colEnclosing->getParent();
|
||||
while (limitingParent && (limitingParent->getResizeFromChildH() || dynamic_cast<CGroupList *>(limitingParent)))
|
||||
limitingParent = limitingParent->getParent();
|
||||
|
||||
getParentContainer()->setH(col->getH() + getParentContainer()->getHReal() - limitingParent->getHReal());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
invalidateCoords();
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************
|
||||
void CGroupHeader::getEntries(std::vector<CGroupHeaderEntry *> &dest)
|
||||
{
|
||||
dest.clear();
|
||||
const std::vector<CInterfaceGroup*> &groups = getGroups();
|
||||
for (uint k = 0; k < groups.size(); ++k)
|
||||
{
|
||||
CGroupHeaderEntry *entry = dynamic_cast<CGroupHeaderEntry *>(groups[k]);
|
||||
if (entry)
|
||||
{
|
||||
dest.push_back(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************
|
||||
int CGroupHeader::luaEnlargeColumns(CLuaState &ls)
|
||||
{
|
||||
const char *funcName = "enlargeColumns";
|
||||
CLuaIHM::checkArgCount(ls, funcName, 1);
|
||||
CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER);
|
||||
enlargeColumns((sint32) ls.toNumber(1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************
|
||||
int CGroupHeader::luaResizeColumnsAndContainer(CLuaState &ls)
|
||||
{
|
||||
const char *funcName = "resizeColumnsAndContainer";
|
||||
CLuaIHM::checkArgCount(ls, funcName, 1);
|
||||
CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER);
|
||||
resizeColumnsAndContainer((sint32) ls.toNumber(1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************
|
||||
bool CGroupHeader::parse(xmlNodePtr cur, CInterfaceGroup * parentGroup)
|
||||
{
|
||||
if(!CGroupList::parse(cur, parentGroup)) return false;
|
||||
CXMLAutoPtr prop((const char*) xmlGetProp( cur, (xmlChar*)"header_max_size" ));
|
||||
if (prop) fromString((const char*)prop, _HeaderMaxSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
// CHeaderEntryResizer //
|
||||
/////////////////////////
|
||||
|
||||
class CHeaderEntryResizer : public CCtrlBase
|
||||
{
|
||||
public:
|
||||
CHeaderEntryResizer(bool rightSide, sint32 wMin) : CCtrlBase(TCtorParam()),
|
||||
_RightSide(rightSide),
|
||||
_Moving(false),
|
||||
_StartX(0),
|
||||
_OffsetX(0),
|
||||
_WMin(wMin)
|
||||
{}
|
||||
void release()
|
||||
{
|
||||
if (CWidgetManager::getInstance()->getCapturePointerLeft() == this)
|
||||
{
|
||||
_Moving = false;
|
||||
CWidgetManager::getInstance()->setCapturePointerLeft(NULL);
|
||||
}
|
||||
}
|
||||
virtual uint getDeltaDepth() const { return 100; }
|
||||
CInterfaceGroup *getTargetGroup()
|
||||
{
|
||||
if (_RightSide) return _Parent;
|
||||
|
||||
if (getParent()->getParent() == _Parent->getParentPos()) return NULL; // leftmost header
|
||||
return dynamic_cast<CInterfaceGroup *>(getParent()->getParentPos());
|
||||
}
|
||||
bool handleEvent (const NLGUI::CEventDescriptor &event)
|
||||
{
|
||||
if (_Parent)
|
||||
{
|
||||
if (event.getType() == NLGUI::CEventDescriptor::system)
|
||||
{
|
||||
const NLGUI::CEventDescriptorSystem &eds = (const NLGUI::CEventDescriptorSystem &) event;
|
||||
if (eds.getEventTypeExtended() == NLGUI::CEventDescriptorSystem::setfocus)
|
||||
{
|
||||
const NLGUI::CEventDescriptorSetFocus &edsf = (const NLGUI::CEventDescriptorSetFocus &) eds;
|
||||
if (edsf.hasFocus() == false)
|
||||
{
|
||||
release();
|
||||
return CCtrlBase::handleEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (event.getType() == NLGUI::CEventDescriptor::mouse)
|
||||
{
|
||||
const NLGUI::CEventDescriptorMouse &eventDesc = (const NLGUI::CEventDescriptorMouse &)event;
|
||||
if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftdown)
|
||||
{
|
||||
if (!this->isIn(eventDesc.getX(), eventDesc.getY())) return false;
|
||||
_TargetGroup = getTargetGroup();
|
||||
if (!_TargetGroup) return false;
|
||||
CWidgetManager::getInstance()->setCapturePointerLeft(this);
|
||||
_Moving = true;
|
||||
_OffsetX = _TargetGroup->getW() - eventDesc.getX();
|
||||
return true;
|
||||
}
|
||||
if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftup)
|
||||
{
|
||||
release();
|
||||
}
|
||||
if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mousemove)
|
||||
{
|
||||
if (_Moving && CWidgetManager::getInstance()->getCapturePointerLeft() == this)
|
||||
{
|
||||
if (!_TargetGroup)
|
||||
{
|
||||
release();
|
||||
return false;
|
||||
}
|
||||
sint32 newW = eventDesc.getX() + _OffsetX;
|
||||
// compute width of all header entries but this one
|
||||
CGroupHeader *header = dynamic_cast<CGroupHeader *>(getParent()->getParent());
|
||||
if (header)
|
||||
{
|
||||
sint32 w = 0;
|
||||
for (uint k = 0; k < header->getNumChildren(); ++k)
|
||||
{
|
||||
if (header->getChild(k) != _TargetGroup)
|
||||
{
|
||||
w += header->getChild(k)->getW();
|
||||
}
|
||||
}
|
||||
sint32 excess = w + newW - header->getHeaderMaxSize();
|
||||
if (excess)
|
||||
{
|
||||
// try to diminish the size of all headers starting from the last
|
||||
for (sint k = header->getNumChildren() - 1; k >= 0 && excess > 0; --k)
|
||||
{
|
||||
if (header->getChild(k) == _TargetGroup) break;
|
||||
CGroupHeaderEntry *ghe = dynamic_cast<CGroupHeaderEntry *>(header->getChild(k));
|
||||
sint32 wGain = std::min(excess, std::max((sint32) 0, ghe->getW() - ghe->getMinSize()));
|
||||
if (wGain > 0)
|
||||
{
|
||||
ghe->setW(ghe->getW() - wGain);
|
||||
ghe->invalidateCoords();
|
||||
excess -= wGain;
|
||||
}
|
||||
}
|
||||
}
|
||||
newW -= std::max((sint32) 0, excess);
|
||||
}
|
||||
_TargetGroup->setW(std::max(_WMin, newW));
|
||||
_TargetGroup->invalidateCoords();
|
||||
CGroupHeaderEntry *ghe = dynamic_cast<CGroupHeaderEntry *>((CInterfaceGroup *) _TargetGroup);
|
||||
if (ghe)
|
||||
{
|
||||
ghe->setW(_TargetGroup->getW());
|
||||
ghe->invalidateCoords();
|
||||
CAHManager::getInstance()->runActionHandler(ghe->getAHOnResize(), ghe, ghe->getAHOnResizeParams());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
_Moving = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return CCtrlBase::handleEvent(event);
|
||||
}
|
||||
virtual void draw ()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
virtual bool getMouseOverShape(std::string &texName, uint8 &rot, NLMISC::CRGBA &col)
|
||||
{
|
||||
|
||||
if (!getTargetGroup()) return false;
|
||||
texName = "curs_resize_LR.tga";
|
||||
rot = 0;
|
||||
col = CRGBA::White;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
NLMISC::CRefPtr<CInterfaceGroup> _TargetGroup; // group for which w is modified
|
||||
bool _RightSide; // right or left side mover ?
|
||||
bool _Moving;
|
||||
sint32 _StartX; // value to add to mouse to get local x pos of target group
|
||||
sint32 _OffsetX;
|
||||
sint32 _WMin;
|
||||
};
|
||||
|
||||
// *****************************************************************************************************************
|
||||
CGroupHeaderEntry::CGroupHeaderEntry(const TCtorParam ¶m) : CInterfaceGroup(param)
|
||||
{
|
||||
_MinSize = 4;
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************
|
||||
bool CGroupHeaderEntry::parse(xmlNodePtr cur, CInterfaceGroup * parentGroup)
|
||||
{
|
||||
if (!CInterfaceGroup::parse(cur, parentGroup)) return false;
|
||||
// left mover
|
||||
CXMLAutoPtr prop((const char*) xmlGetProp( cur, (xmlChar*)"wmin" ));
|
||||
if (prop) fromString((const char*)prop, _MinSize);
|
||||
sint32 resizerSize = 4;
|
||||
prop = (char*) xmlGetProp( cur, (xmlChar*)"resizer_size" );
|
||||
if (prop) fromString((const char*)prop, resizerSize);
|
||||
prop = (char*) xmlGetProp(cur, (xmlChar*) "target");
|
||||
if (prop) _TargetColumnId = (const char *) prop;
|
||||
|
||||
prop = (char*) xmlGetProp(cur, (xmlChar*) "on_resize");
|
||||
if (prop) _AHOnResize = (const char *) prop;
|
||||
prop = (char*) xmlGetProp(cur, (xmlChar*) "on_resize_params");
|
||||
if (prop) _AHOnResizeParams = (const char *) prop;
|
||||
|
||||
CHeaderEntryResizer *hm = new CHeaderEntryResizer(false, _MinSize);
|
||||
addCtrl(hm);
|
||||
hm->setW(resizerSize);
|
||||
hm->setSizeRef(2);
|
||||
hm->setParent(this);
|
||||
hm->setParentPosRef(Hotspot_TL);
|
||||
hm->setPosRef(Hotspot_TL);
|
||||
// right mover
|
||||
hm = new CHeaderEntryResizer(true, _MinSize);
|
||||
addCtrl(hm);
|
||||
hm->setW(resizerSize);
|
||||
hm->setSizeRef(2);
|
||||
hm->setParent(this);
|
||||
hm->setParentPosRef(Hotspot_TR);
|
||||
hm->setPosRef(Hotspot_TR);
|
||||
//
|
||||
return true;
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************
|
||||
CInterfaceGroup *CGroupHeaderEntry::getTargetColumn() const
|
||||
{
|
||||
return dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(_TargetColumnId));
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************
|
||||
void CGroupHeaderEntry::updateCoords()
|
||||
{
|
||||
CInterfaceGroup::updateCoords();
|
||||
CInterfaceGroup *targetColumn = getTargetColumn();
|
||||
if (targetColumn)
|
||||
{
|
||||
if (targetColumn->getW() != getW())
|
||||
{
|
||||
targetColumn->setW(getW());
|
||||
targetColumn->invalidateCoords();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NLMISC_REGISTER_OBJECT(CViewBase, CGroupHeader, std::string, "header");
|
||||
NLMISC_REGISTER_OBJECT(CViewBase, CGroupHeaderEntry, std::string, "header_entry");
|
||||
|
||||
}
|
||||
|
@ -1,435 +0,0 @@
|
||||
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#include "nel/gui/group_container.h"
|
||||
#include "group_header.h"
|
||||
#include "nel/gui/lua_ihm.h"
|
||||
#include "nel/gui/widget_manager.h"
|
||||
|
||||
|
||||
using namespace NLMISC;
|
||||
|
||||
//////////////////
|
||||
// CGroupHeader //
|
||||
//////////////////
|
||||
|
||||
// *****************************************************************************************************************
|
||||
CGroupHeader::CGroupHeader(const TCtorParam ¶m) : CGroupList(param), _HeaderMaxSize(32767)
|
||||
{
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************
|
||||
void CGroupHeader::enlargeColumns(sint32 margin)
|
||||
{
|
||||
std::vector<CGroupHeaderEntry *> entries;
|
||||
getEntries(entries);
|
||||
sint32 totalWidth = 0;
|
||||
for (uint k = 0; k < entries.size(); ++k)
|
||||
{
|
||||
CInterfaceGroup *colEnclosing = entries[k]->getTargetColumn();
|
||||
if (colEnclosing && !colEnclosing->getGroups().empty())
|
||||
{
|
||||
CInterfaceGroup *col = colEnclosing->getGroups()[0];
|
||||
if (col)
|
||||
{
|
||||
// enlarge to the max to be able to measure the sub text (they may clamp themselves based
|
||||
// on their first non-"child resizing" parent (see CViewText::updateCoords)
|
||||
colEnclosing->setW(16384);
|
||||
colEnclosing->invalidateCoords();
|
||||
colEnclosing->updateCoords();
|
||||
|
||||
// assume that first child is resizing from its children width (either 'child_resize_w=true' or a CGroupList)
|
||||
entries[k]->setW(std::max(entries[k]->getMinSize(), col->getW() + margin));
|
||||
entries[k]->invalidateCoords();
|
||||
totalWidth += entries[k]->getW();
|
||||
}
|
||||
}
|
||||
}
|
||||
// if total width bigger than allowed, reduce proportionnally
|
||||
if (totalWidth > _HeaderMaxSize)
|
||||
{
|
||||
while (totalWidth > _HeaderMaxSize)
|
||||
{
|
||||
bool adjusted = false;
|
||||
// stupid algo here, but ponctual ...
|
||||
for (uint k = 0; k < entries.size() && totalWidth > _HeaderMaxSize; ++k)
|
||||
{
|
||||
if (entries[k]->getW() > entries[k]->getMinSize())
|
||||
{
|
||||
entries[k]->setW(entries[k]->getW() - 1);
|
||||
entries[k]->invalidateCoords();
|
||||
--totalWidth;
|
||||
adjusted = true;
|
||||
}
|
||||
}
|
||||
// if all at min size, just exit ...
|
||||
if (!adjusted) break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// search first parent that limit size, if it is larger then enlarge to fit size
|
||||
CInterfaceGroup *limitingParent = getParent();
|
||||
while (limitingParent && (limitingParent->getResizeFromChildW() || dynamic_cast<CGroupList *>(limitingParent)))
|
||||
{
|
||||
// NB nico : the dynamic_cast for CGroupList is bad!!
|
||||
// can't avoid it for now, because, CGroupList implicitly does a "resize from child" in its update coords
|
||||
// ...
|
||||
limitingParent = limitingParent->getParent();
|
||||
}
|
||||
if (limitingParent && limitingParent->getWReal() > totalWidth)
|
||||
{
|
||||
while (limitingParent->getWReal() > totalWidth && totalWidth < _HeaderMaxSize)
|
||||
{
|
||||
// enlarge to matche parent size
|
||||
// stupid algo here, but ponctual ...
|
||||
for (uint k = 0; k < entries.size(); ++k)
|
||||
{
|
||||
entries[k]->setW(entries[k]->getW() + 1);
|
||||
entries[k]->invalidateCoords();
|
||||
++totalWidth;
|
||||
if (limitingParent->getWReal() <= totalWidth || totalWidth >= _HeaderMaxSize) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
invalidateCoords();
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************
|
||||
void CGroupHeader::resizeColumnsAndContainer(sint32 margin)
|
||||
{
|
||||
std::vector<CGroupHeaderEntry *> entries;
|
||||
getEntries(entries);
|
||||
sint32 totalWidth = 0;
|
||||
for (uint k = 0; k < entries.size(); ++k)
|
||||
{
|
||||
CInterfaceGroup *colEnclosing = entries[k]->getTargetColumn();
|
||||
if (colEnclosing && !colEnclosing->getGroups().empty())
|
||||
{
|
||||
CInterfaceGroup *col = colEnclosing->getGroups()[0];
|
||||
if (col)
|
||||
{
|
||||
// enlarge to the max to be able to measure the sub text (they may clamp themselves based
|
||||
// on their first non-"child resizing" parent (see CViewText::updateCoords)
|
||||
colEnclosing->setW(16384);
|
||||
colEnclosing->invalidateCoords();
|
||||
colEnclosing->updateCoords();
|
||||
|
||||
// assume that first child is resizing from its children width (either 'child_resize_w=true' or a CGroupList)
|
||||
entries[k]->setW(std::max(entries[k]->getMinSize(), col->getW() + margin));
|
||||
entries[k]->invalidateCoords();
|
||||
totalWidth += entries[k]->getW();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// resize W
|
||||
if (totalWidth <= _HeaderMaxSize)
|
||||
{
|
||||
// search first parent that limit size, if it is larger then enlarge to fit size
|
||||
CInterfaceGroup *limitingParent = getParent();
|
||||
while (limitingParent && (limitingParent->getResizeFromChildW() || dynamic_cast<CGroupList *>(limitingParent)))
|
||||
{
|
||||
// NB nico : the dynamic_cast for CGroupList is bad!!
|
||||
// can't avoid it for now, because, CGroupList implicitly does a "resize from child" in its update coords
|
||||
// ...
|
||||
limitingParent = limitingParent->getParent();
|
||||
}
|
||||
|
||||
getParentContainer()->setW(totalWidth + getParentContainer()->getWReal() - limitingParent->getWReal());
|
||||
}
|
||||
|
||||
// resize H
|
||||
if(entries.size()>0)
|
||||
{
|
||||
CInterfaceGroup *colEnclosing = entries[0]->getTargetColumn();
|
||||
if (colEnclosing && !colEnclosing->getGroups().empty())
|
||||
{
|
||||
CInterfaceGroup *col = colEnclosing->getGroups()[0];
|
||||
if (col)
|
||||
{
|
||||
// search first parent that limit size, if it is larger then enlarge to fit size
|
||||
CInterfaceGroup *limitingParent = colEnclosing->getParent();
|
||||
while (limitingParent && (limitingParent->getResizeFromChildH() || dynamic_cast<CGroupList *>(limitingParent)))
|
||||
limitingParent = limitingParent->getParent();
|
||||
|
||||
getParentContainer()->setH(col->getH() + getParentContainer()->getHReal() - limitingParent->getHReal());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
invalidateCoords();
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************
|
||||
void CGroupHeader::getEntries(std::vector<CGroupHeaderEntry *> &dest)
|
||||
{
|
||||
dest.clear();
|
||||
const std::vector<CInterfaceGroup*> &groups = getGroups();
|
||||
for (uint k = 0; k < groups.size(); ++k)
|
||||
{
|
||||
CGroupHeaderEntry *entry = dynamic_cast<CGroupHeaderEntry *>(groups[k]);
|
||||
if (entry)
|
||||
{
|
||||
dest.push_back(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************
|
||||
int CGroupHeader::luaEnlargeColumns(CLuaState &ls)
|
||||
{
|
||||
const char *funcName = "enlargeColumns";
|
||||
CLuaIHM::checkArgCount(ls, funcName, 1);
|
||||
CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER);
|
||||
enlargeColumns((sint32) ls.toNumber(1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************
|
||||
int CGroupHeader::luaResizeColumnsAndContainer(CLuaState &ls)
|
||||
{
|
||||
const char *funcName = "resizeColumnsAndContainer";
|
||||
CLuaIHM::checkArgCount(ls, funcName, 1);
|
||||
CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER);
|
||||
resizeColumnsAndContainer((sint32) ls.toNumber(1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************
|
||||
bool CGroupHeader::parse(xmlNodePtr cur, CInterfaceGroup * parentGroup)
|
||||
{
|
||||
if(!CGroupList::parse(cur, parentGroup)) return false;
|
||||
CXMLAutoPtr prop((const char*) xmlGetProp( cur, (xmlChar*)"header_max_size" ));
|
||||
if (prop) fromString((const char*)prop, _HeaderMaxSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
// CHeaderEntryResizer //
|
||||
/////////////////////////
|
||||
|
||||
class CHeaderEntryResizer : public CCtrlBase
|
||||
{
|
||||
public:
|
||||
CHeaderEntryResizer(bool rightSide, sint32 wMin) : CCtrlBase(TCtorParam()),
|
||||
_RightSide(rightSide),
|
||||
_Moving(false),
|
||||
_StartX(0),
|
||||
_OffsetX(0),
|
||||
_WMin(wMin)
|
||||
{}
|
||||
void release()
|
||||
{
|
||||
if (CWidgetManager::getInstance()->getCapturePointerLeft() == this)
|
||||
{
|
||||
_Moving = false;
|
||||
CWidgetManager::getInstance()->setCapturePointerLeft(NULL);
|
||||
}
|
||||
}
|
||||
virtual uint getDeltaDepth() const { return 100; }
|
||||
CInterfaceGroup *getTargetGroup()
|
||||
{
|
||||
if (_RightSide) return _Parent;
|
||||
|
||||
if (getParent()->getParent() == _Parent->getParentPos()) return NULL; // leftmost header
|
||||
return dynamic_cast<CInterfaceGroup *>(getParent()->getParentPos());
|
||||
}
|
||||
bool handleEvent (const NLGUI::CEventDescriptor &event)
|
||||
{
|
||||
if (_Parent)
|
||||
{
|
||||
if (event.getType() == NLGUI::CEventDescriptor::system)
|
||||
{
|
||||
const NLGUI::CEventDescriptorSystem &eds = (const NLGUI::CEventDescriptorSystem &) event;
|
||||
if (eds.getEventTypeExtended() == NLGUI::CEventDescriptorSystem::setfocus)
|
||||
{
|
||||
const NLGUI::CEventDescriptorSetFocus &edsf = (const NLGUI::CEventDescriptorSetFocus &) eds;
|
||||
if (edsf.hasFocus() == false)
|
||||
{
|
||||
release();
|
||||
return CCtrlBase::handleEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (event.getType() == NLGUI::CEventDescriptor::mouse)
|
||||
{
|
||||
const NLGUI::CEventDescriptorMouse &eventDesc = (const NLGUI::CEventDescriptorMouse &)event;
|
||||
if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftdown)
|
||||
{
|
||||
if (!this->isIn(eventDesc.getX(), eventDesc.getY())) return false;
|
||||
_TargetGroup = getTargetGroup();
|
||||
if (!_TargetGroup) return false;
|
||||
CWidgetManager::getInstance()->setCapturePointerLeft(this);
|
||||
_Moving = true;
|
||||
_OffsetX = _TargetGroup->getW() - eventDesc.getX();
|
||||
return true;
|
||||
}
|
||||
if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftup)
|
||||
{
|
||||
release();
|
||||
}
|
||||
if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mousemove)
|
||||
{
|
||||
if (_Moving && CWidgetManager::getInstance()->getCapturePointerLeft() == this)
|
||||
{
|
||||
if (!_TargetGroup)
|
||||
{
|
||||
release();
|
||||
return false;
|
||||
}
|
||||
sint32 newW = eventDesc.getX() + _OffsetX;
|
||||
// compute width of all header entries but this one
|
||||
CGroupHeader *header = dynamic_cast<CGroupHeader *>(getParent()->getParent());
|
||||
if (header)
|
||||
{
|
||||
sint32 w = 0;
|
||||
for (uint k = 0; k < header->getNumChildren(); ++k)
|
||||
{
|
||||
if (header->getChild(k) != _TargetGroup)
|
||||
{
|
||||
w += header->getChild(k)->getW();
|
||||
}
|
||||
}
|
||||
sint32 excess = w + newW - header->getHeaderMaxSize();
|
||||
if (excess)
|
||||
{
|
||||
// try to diminish the size of all headers starting from the last
|
||||
for (sint k = header->getNumChildren() - 1; k >= 0 && excess > 0; --k)
|
||||
{
|
||||
if (header->getChild(k) == _TargetGroup) break;
|
||||
CGroupHeaderEntry *ghe = dynamic_cast<CGroupHeaderEntry *>(header->getChild(k));
|
||||
sint32 wGain = std::min(excess, std::max((sint32) 0, ghe->getW() - ghe->getMinSize()));
|
||||
if (wGain > 0)
|
||||
{
|
||||
ghe->setW(ghe->getW() - wGain);
|
||||
ghe->invalidateCoords();
|
||||
excess -= wGain;
|
||||
}
|
||||
}
|
||||
}
|
||||
newW -= std::max((sint32) 0, excess);
|
||||
}
|
||||
_TargetGroup->setW(std::max(_WMin, newW));
|
||||
_TargetGroup->invalidateCoords();
|
||||
CGroupHeaderEntry *ghe = dynamic_cast<CGroupHeaderEntry *>((CInterfaceGroup *) _TargetGroup);
|
||||
if (ghe)
|
||||
{
|
||||
ghe->setW(_TargetGroup->getW());
|
||||
ghe->invalidateCoords();
|
||||
CAHManager::getInstance()->runActionHandler(ghe->getAHOnResize(), ghe, ghe->getAHOnResizeParams());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
_Moving = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return CCtrlBase::handleEvent(event);
|
||||
}
|
||||
virtual void draw ()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
virtual bool getMouseOverShape(std::string &texName, uint8 &rot, NLMISC::CRGBA &col)
|
||||
{
|
||||
|
||||
if (!getTargetGroup()) return false;
|
||||
texName = "curs_resize_LR.tga";
|
||||
rot = 0;
|
||||
col = CRGBA::White;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
NLMISC::CRefPtr<CInterfaceGroup> _TargetGroup; // group for which w is modified
|
||||
bool _RightSide; // right or left side mover ?
|
||||
bool _Moving;
|
||||
sint32 _StartX; // value to add to mouse to get local x pos of target group
|
||||
sint32 _OffsetX;
|
||||
sint32 _WMin;
|
||||
};
|
||||
|
||||
// *****************************************************************************************************************
|
||||
CGroupHeaderEntry::CGroupHeaderEntry(const TCtorParam ¶m) : CInterfaceGroup(param)
|
||||
{
|
||||
_MinSize = 4;
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************
|
||||
bool CGroupHeaderEntry::parse(xmlNodePtr cur, CInterfaceGroup * parentGroup)
|
||||
{
|
||||
if (!CInterfaceGroup::parse(cur, parentGroup)) return false;
|
||||
// left mover
|
||||
CXMLAutoPtr prop((const char*) xmlGetProp( cur, (xmlChar*)"wmin" ));
|
||||
if (prop) fromString((const char*)prop, _MinSize);
|
||||
sint32 resizerSize = 4;
|
||||
prop = (char*) xmlGetProp( cur, (xmlChar*)"resizer_size" );
|
||||
if (prop) fromString((const char*)prop, resizerSize);
|
||||
prop = (char*) xmlGetProp(cur, (xmlChar*) "target");
|
||||
if (prop) _TargetColumnId = (const char *) prop;
|
||||
|
||||
prop = (char*) xmlGetProp(cur, (xmlChar*) "on_resize");
|
||||
if (prop) _AHOnResize = (const char *) prop;
|
||||
prop = (char*) xmlGetProp(cur, (xmlChar*) "on_resize_params");
|
||||
if (prop) _AHOnResizeParams = (const char *) prop;
|
||||
|
||||
CHeaderEntryResizer *hm = new CHeaderEntryResizer(false, _MinSize);
|
||||
addCtrl(hm);
|
||||
hm->setW(resizerSize);
|
||||
hm->setSizeRef(2);
|
||||
hm->setParent(this);
|
||||
hm->setParentPosRef(Hotspot_TL);
|
||||
hm->setPosRef(Hotspot_TL);
|
||||
// right mover
|
||||
hm = new CHeaderEntryResizer(true, _MinSize);
|
||||
addCtrl(hm);
|
||||
hm->setW(resizerSize);
|
||||
hm->setSizeRef(2);
|
||||
hm->setParent(this);
|
||||
hm->setParentPosRef(Hotspot_TR);
|
||||
hm->setPosRef(Hotspot_TR);
|
||||
//
|
||||
return true;
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************
|
||||
CInterfaceGroup *CGroupHeaderEntry::getTargetColumn() const
|
||||
{
|
||||
return dynamic_cast<CInterfaceGroup*>(CWidgetManager::getInstance()->getElementFromId(_TargetColumnId));
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************
|
||||
void CGroupHeaderEntry::updateCoords()
|
||||
{
|
||||
CInterfaceGroup::updateCoords();
|
||||
CInterfaceGroup *targetColumn = getTargetColumn();
|
||||
if (targetColumn)
|
||||
{
|
||||
if (targetColumn->getW() != getW())
|
||||
{
|
||||
targetColumn->setW(getW());
|
||||
targetColumn->invalidateCoords();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NLMISC_REGISTER_OBJECT(CViewBase, CGroupHeader, std::string, "header");
|
||||
NLMISC_REGISTER_OBJECT(CViewBase, CGroupHeaderEntry, std::string, "header_entry");
|
@ -1,85 +0,0 @@
|
||||
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef CL_GROUP_HEADER_H
|
||||
#define CL_GROUP_HEADER_H
|
||||
|
||||
|
||||
#include "nel/gui/group_list.h"
|
||||
|
||||
|
||||
class CGroupHeaderEntry;
|
||||
|
||||
// *****************************************************************************************************************
|
||||
/** Display a header with movable entries.
|
||||
* Usually used with a table to change the size of each column (much like the windows file explorer in 'details' mode)
|
||||
*
|
||||
* \author Nicolas Vizerie
|
||||
* \author Nevrax France
|
||||
* \date 2006
|
||||
*/
|
||||
class CGroupHeader : public CGroupList
|
||||
{
|
||||
public:
|
||||
REFLECT_EXPORT_START(CGroupHeader, CGroupList)
|
||||
REFLECT_LUA_METHOD("enlargeColumns", luaEnlargeColumns);
|
||||
REFLECT_LUA_METHOD("resizeColumnsAndContainer", luaResizeColumnsAndContainer);
|
||||
REFLECT_EXPORT_END
|
||||
CGroupHeader(const TCtorParam ¶m);
|
||||
// from CInterfaceGroup
|
||||
virtual bool parse(xmlNodePtr cur, CInterfaceGroup * parentGroup);
|
||||
sint32 getHeaderMaxSize() const { return _HeaderMaxSize; }
|
||||
// get the entries in this header
|
||||
void getEntries(std::vector<CGroupHeaderEntry *> &dest);
|
||||
// ensure that max. content of columns is visible (without the total width becoming more than 'getHeaderMaxSize()'
|
||||
void enlargeColumns(sint32 margin);
|
||||
// ensure that content of each column is visible
|
||||
void resizeColumnsAndContainer(sint32 margin);
|
||||
private:
|
||||
sint32 _HeaderMaxSize;
|
||||
int luaEnlargeColumns(CLuaState &ls);
|
||||
int luaResizeColumnsAndContainer(CLuaState &ls);
|
||||
};
|
||||
|
||||
// *****************************************************************************************************************
|
||||
// an entry in a header, includes a "mover control" to move it inside its parent header
|
||||
// NOTE : when not used inside a CGroupHeader, will work, but there will be no 'max_size'
|
||||
class CGroupHeaderEntry : public CInterfaceGroup
|
||||
{
|
||||
public:
|
||||
CGroupHeaderEntry(const TCtorParam ¶m);
|
||||
// from CInterfaceGroup
|
||||
virtual bool parse(xmlNodePtr cur, CInterfaceGroup * parentGroup);
|
||||
sint32 getMinSize() const { return _MinSize; }
|
||||
virtual void updateCoords();
|
||||
CInterfaceGroup *getTargetColumn() const;
|
||||
|
||||
const std::string &getAHOnResize() const { return _AHOnResize; }
|
||||
const std::string &getAHOnResizeParams() const { return _AHOnResizeParams; }
|
||||
|
||||
private:
|
||||
sint32 _MinSize;
|
||||
std::string _TargetColumnId;
|
||||
|
||||
std::string _AHOnResize;
|
||||
std::string _AHOnResizeParams;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue