1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "interface_config.h"
25 #include "interface_manager.h"
26 #include "nel/gui/group_container.h"
27 #include "nel/gui/ctrl_scroll.h"
29 using namespace NLMISC
;
33 // ***************************************************************************
36 - save of interface element specific infos
38 - save of the top window between modes.
40 - first version (well version not added but see loadconfig() hack).
42 #define INTERFACE_CONFIG_STREAM_VERSION 2
45 // ***************************************************************************
46 // SCont Data from container to be saved
47 // ***************************************************************************
49 // ***************************************************************************
50 void CInterfaceConfig::SCont::serial(NLMISC::IStream
&f
)
52 // version 10 : added minW & maxW
53 // version 9 : Backuped position & touchFlag
54 // version 8 : ContainerMode
55 // version 7 : RolloverAlphaContainer and RolloverAlphaContent separated
56 // version 6 : added 'pop_max_h' value
57 // version 5 : added 'active_savable' flag
58 // version 4 : added 'movable' flag
59 // version 3 : added 'locked' flag
60 // version 2 : added 'useGlobalAlpha' flag
61 // version 1 : added alpha's & popup coords & size
62 // version 0 : base version
63 sint ver
= f
.serialVersion(10);
74 Id
= "ui:interface:"+Id
;
79 std::string startString
;
82 startString
= Id
.substr(0, 13);
84 if (startString
== "ui:interface:")
86 shortId
= Id
.substr(13,Id
.size());
94 f
.serial(ContainerMode
);
95 if (ContainerMode
== 0)
106 f
.serial(ContentAlpha
);
107 f
.serial(RolloverAlphaContent
);
112 f
.serial(UseGlobalAlpha
);
115 f
.serial(ActiveSavable
);
117 f
.serial(RolloverAlphaContainer
);
120 f
.serial(BackupedPositionValid
);
121 if (BackupedPositionValid
)
129 else if (ContainerMode
== 1)
133 f
.serial(ActiveSavable
);
151 f
.serial(ContentAlpha
);
152 f
.serial(RolloverAlphaContent
);
162 RolloverAlphaContent
= RolloverAlphaContainer
= 255;
169 f
.serial(UseGlobalAlpha
);
171 UseGlobalAlpha
= true;
184 f
.serial(ActiveSavable
);
186 ActiveSavable
= true;
194 f
.serial(RolloverAlphaContainer
);
196 RolloverAlphaContainer
= RolloverAlphaContent
;
202 // ***************************************************************************
203 void CInterfaceConfig::SCont::setFrom (CGroupContainer
*pGC
)
208 MinW
= pGC
->getMinW();
209 MaxW
= pGC
->getMaxW();
211 // Check container mode
212 if ((pGC
->getLayerSetup()>0) && (!pGC
->isPopable()))
214 // The container is contained by another one and cannot be transformed in root container
216 Opened
= pGC
->isOpen();
217 ActiveSavable
= pGC
->isActiveSavable();
218 Active
= pGC
->getActive();
222 // Other type of container save all
223 Popuped
= pGC
->isPopuped();
224 Opened
= pGC
->isOpen();
226 ActiveSavable
= pGC
->isActiveSavable();
227 Active
= pGC
->getActive();
231 W
= pGC
->getW(false);
232 H
= pGC
->getH(false);
234 BgAlpha
= pGC
->getContainerAlpha();
235 ContentAlpha
= pGC
->getContentAlpha();
236 RolloverAlphaContent
= pGC
->getRolloverAlphaContent();
237 RolloverAlphaContainer
= pGC
->getRolloverAlphaContainer();
238 UseGlobalAlpha
= pGC
->isUsingGlobalAlpha();
242 PopupX
= pGC
->getX();
243 PopupY
= pGC
->getY();
244 PopupW
= pGC
->getW();
245 PopupH
= pGC
->getH();
249 PopupX
= pGC
->getPopupX();
250 PopupY
= pGC
->getPopupY();
251 PopupW
= pGC
->getPopupW();
252 PopupH
= pGC
->getPopupH();
254 PopupMaxH
= pGC
->getPopupMaxH();
256 Locked
= pGC
->isLocked();
257 Movable
= pGC
->isMovable();
260 CCtrlScroll
*pSB
= dynamic_cast<CCtrlScroll
*>(pGC
->getCtrl("sb"));
261 if (pSB
!= NULL
) ScrollPos
= pSB
->getTrackPos();
263 if (pGC
->isPositionBackuped())
265 BackupedPositionValid
= true;
266 BackupX
= pGC
->getBackupX();
267 BackupY
= pGC
->getBackupY();
271 BackupedPositionValid
= false;
273 TouchFlag
= pGC
->getTouchFlag(false);
276 // ***************************************************************************
277 void CInterfaceConfig::SCont::setTo (CGroupContainer
*pGC
)
279 if (ContainerMode
== 0)
284 if ( pGC
->isPopable() && Popuped
!= pGC
->isPopuped() )
287 pGC
->popupCurrentPos();
293 pGC
->forceRolloverAlpha();
294 pGC
->setOpen(Opened
);
296 pGC
->setXAndInvalidateCoords(X
);
297 pGC
->setYAndInvalidateCoords(Y
);
298 // Set the W and H only if resizer is enabled (else always take from scripts)
299 if(pGC
->getEnabledResizer())
303 // use the Popup min and max, it it is not popable.... (yoyo: what a mess....)
304 if(!pGC
->isPopable())
305 clamp(w
, pGC
->getPopupMinW(), pGC
->getPopupMaxW());
307 clamp(w
, pGC
->getMinW(), pGC
->getMaxW());
308 pGC
->setWAndInvalidateCoords(w
);
309 pGC
->setHAndInvalidateCoords(h
);
312 clamp(w
, pGC
->getPopupMinW(), pGC
->getPopupMaxW());
313 clamp(h
, pGC
->getPopupMinH(), pGC
->getPopupMaxH());
316 pGC
->setPopupMaxH(PopupMaxH
);
319 pGC
->setPopupX(PopupX
);
320 pGC
->setPopupY(PopupY
);
324 pGC
->setH(pGC
->getPopupH());
325 pGC
->setWAndInvalidateCoords(pGC
->getPopupW());
328 pGC
->setContainerAlpha(BgAlpha
);
329 pGC
->setContentAlpha(ContentAlpha
);
330 pGC
->setRolloverAlphaContent(RolloverAlphaContent
);
331 pGC
->setRolloverAlphaContainer(RolloverAlphaContainer
);
332 pGC
->setUseGlobalAlpha(UseGlobalAlpha
);
336 pGC
->setActive (false);
337 pGC
->setActive (Active
);
340 if (pGC
->isLockable()) pGC
->setLocked(Locked
);
341 pGC
->setMovable(Movable
);
343 CCtrlScroll
*pSB
= dynamic_cast<CCtrlScroll
*>(pGC
->getCtrl("sb"));
344 if (pSB
!= NULL
) pSB
->setTrackPos(ScrollPos
);
346 pGC
->touch(TouchFlag
);
348 if (BackupedPositionValid
)
350 pGC
->setBackupPosition(BackupX
, BackupY
);
358 else if (ContainerMode
== 1)
360 // Container that just need Opened, Active and ActiveSavable state to be retrieved
361 pGC
->setOpen(Opened
);
364 pGC
->setActive (false);
365 pGC
->setActive (Active
);
370 // ***************************************************************************
371 // SDBLeaf Data from database to be saved
372 // ***************************************************************************
374 // ***************************************************************************
375 void CInterfaceConfig::SDBLeaf::serial(NLMISC::IStream
&f
)
377 // version 1 : added old value ( else some observers are not launched )
378 // version 0 : base version
379 sint ver
= f
.serialVersion(1);
388 // ***************************************************************************
389 void CInterfaceConfig::SDBLeaf::setFrom (CCDBNodeLeaf
*pNL
)
391 Name
= pNL
->getFullName();
392 Value
= pNL
->getValue64();
393 OldValue
= pNL
->getOldValue64();
396 // ***************************************************************************
397 void CInterfaceConfig::SDBLeaf::setTo (CCDBNodeLeaf
*pNL
)
399 pNL
->setValue64(OldValue
);
400 pNL
->setValue64(Value
);
403 // ***************************************************************************
404 /** Visitor of the ui tree that save the config
405 * \author Nicolas Vizerie
406 * \author Nevrax France
409 class CSaveUIConfigVisitor
: public CInterfaceElementVisitor
412 // build the visitor to fill the given stream
413 CSaveUIConfigVisitor(NLMISC::IStream
&stream
) : Stream(stream
) {}
415 // The stream where datas are written
416 NLMISC::IStream
&Stream
;
417 // From CInterfaceElementVisitor
418 void visit(CInterfaceElement
*elem
)
421 nlassert(!Stream
.isReading());
422 if (!elem
->wantSerialConfig()) return; // has something to save ?
423 // if yes, save the name for further retrieval
424 std::string id
= elem
->getId();
426 // measure size of object
427 // NB : here we write in a separate stream to accomplish this because
428 // the object may do some 'serialPtr', this would cause the second serial to have a different size
429 // because the object would already have been recorded in the ptr table of the stream
430 CMemStream measureStream
;
431 nlassert(!measureStream
.isReading());
432 elem
->serialConfig(measureStream
);
433 uint32 chunkSize
= measureStream
.getPos();
434 Stream
.serial(chunkSize
);
435 elem
->serialConfig(Stream
);
439 // ***************************************************************************
440 /** Visitor to count the number of element that need config saving
441 * \author Nicolas Vizerie
442 * \author Nevrax France
445 class CCountUIElemWithConfigVisitor
: public CInterfaceElementVisitor
448 CCountUIElemWithConfigVisitor() : Count(0) {}
450 // From CInterfaceElementVisitor
451 void visit(CInterfaceElement
*elem
)
453 if (elem
->wantSerialConfig()) ++ Count
;
457 // ***************************************************************************
458 // visitor to send the 'onLoadConfig' msg
459 class COnLoadConfigVisitor
: public CInterfaceElementVisitor
461 void visit(CInterfaceElement
*elem
) { elem
->onLoadConfig(); }
464 // ***************************************************************************
465 CInterfaceConfig::CDesktopImage::CDesktopImage()
467 Version
= INTERFACE_CONFIG_STREAM_VERSION
;
470 // ***************************************************************************
471 void CInterfaceConfig::CDesktopImage::serial(NLMISC::IStream
&s
)
473 if (s
.isReading()) read(s
);
477 // ***************************************************************************
478 void CInterfaceConfig::CDesktopImage::read(NLMISC::IStream
&f
)
480 nlassert(f
.isReading());
481 f
.serialVersion(Version
);
482 f
.serialCont(GCImages
);
483 // extra datas go until the end of stream
484 sint32 begPos
= f
.getPos();
485 f
.seek (0, NLMISC::IStream::end
);
486 sint32 endPos
= f
.getPos();
487 f
.seek (begPos
, NLMISC::IStream::begin
);
488 NLMISC::contReset(ExtraDatas
);
489 if (ExtraDatas
.isReading())
493 sint32 length
= endPos
- begPos
;
496 uint8
*pBuffer
= new uint8
[length
];
497 f
.serialBuffer(pBuffer
, length
); // read buffer from file
498 ExtraDatas
.serialBuffer(pBuffer
, length
); // copy buffer to memstream
503 // ***************************************************************************
504 void CInterfaceConfig::CDesktopImage::write(NLMISC::IStream
&f
)
506 nlassert(!f
.isReading());
507 // Version is important when the stream will be saved on Disk.
508 f
.serialVersion(Version
);
509 f
.serialCont(GCImages
);
510 // serial extra datas
511 uint32 length
= ExtraDatas
.length();
514 uint8
*pBuffer
= new uint8
[length
];
515 memcpy(pBuffer
, ExtraDatas
.buffer(), length
);
516 f
.serialBuffer(pBuffer
, length
);
521 // ***************************************************************************
522 void CInterfaceConfig::CDesktopImage::fromCurrentDesktop()
524 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
525 // Count number of container to save
526 uint32 nCount
= 0, nMasterGroup
, i
, nCount2
;
528 const vector
<CWidgetManager::SMasterGroup
> &rVMG
= CWidgetManager::getInstance()->getAllMasterGroup();
529 for (nMasterGroup
= 0; nMasterGroup
< rVMG
.size(); nMasterGroup
++)
531 const CWidgetManager::SMasterGroup
&rMG
= rVMG
[nMasterGroup
];
532 const vector
<CInterfaceGroup
*> &rV
= rMG
.Group
->getGroups();
533 for (i
= 0; i
< rV
.size(); ++i
)
535 CGroupContainer
*pGC
= dynamic_cast<CGroupContainer
*>(rV
[i
]);
536 if ( pGC
!= NULL
&& pGC
->isSavable() )
541 GCImages
.resize(nCount
);
544 // retrieve all containers
545 for (nMasterGroup
= 0; nMasterGroup
< rVMG
.size(); nMasterGroup
++)
547 const CWidgetManager::SMasterGroup
&rMG
= rVMG
[nMasterGroup
];
548 const vector
<CInterfaceGroup
*> &rV
= rMG
.Group
->getGroups();
549 for (i
= 0; i
< rV
.size(); ++i
)
551 CGroupContainer
*pGC
= dynamic_cast<CGroupContainer
*>(rV
[i
]);
552 if ( pGC
!= NULL
&& pGC
->isSavable() )
554 GCImages
[nCount2
].setFrom(pGC
);
559 nlassert(nCount2
== nCount
);
560 // set extra data stream version (in memory)
561 Version
= INTERFACE_CONFIG_STREAM_VERSION
;
562 // serial extra data in the stream
563 NLMISC::CMemStream
&f
= ExtraDatas
;
569 f
.seek(0, NLMISC::IStream::begin
);
570 // Save the Top Window for this config.
571 CInterfaceGroup
*topWindow
= CWidgetManager::getInstance()->getTopWindow(CWidgetManager::getInstance()->getLastTopWindowPriority());
572 string topWindowName
;
575 CGroupContainer
*pGC
= dynamic_cast<CGroupContainer
*>(topWindow
);
576 if (pGC
!= NULL
&& pGC
->isSavable())
577 topWindowName
= pGC
->getId();
579 f
.serial(topWindowName
);
582 // retrieve number of elements that want their config saved
583 CCountUIElemWithConfigVisitor counter
;
584 pIM
->visit(&counter
);
585 f
.serial(counter
.Count
);
586 // Serial specific infos for each widget that reclaims it
587 CSaveUIConfigVisitor
saver(f
);
591 // ***************************************************************************
592 void CInterfaceConfig::CDesktopImage::toCurrentDesktop()
594 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
595 COnLoadConfigVisitor onLoadVisitor
;
596 pIM
->visit(&onLoadVisitor
); // send 'onLoad' msg to every element
597 // uint32 nCount = 0;
599 for(uint k
= 0; k
< GCImages
.size(); ++k
)
601 CGroupContainer
*pGC
= dynamic_cast<CGroupContainer
*>(CWidgetManager::getInstance()->getElementFromId(GCImages
[k
].Id
));
603 GCImages
[k
].setTo(pGC
);
605 // serial extra data from the stream
606 NLMISC::CMemStream
&f
= ExtraDatas
;
612 f
.seek(0, NLMISC::IStream::begin
);
613 f
.seek(0, NLMISC::IStream::end
);
614 if (f
.getPos() == 0) return;
615 f
.seek(0, NLMISC::IStream::begin
);
616 // Load TopWindow config
619 string topWindowName
;
620 f
.serial(topWindowName
);
621 if(!topWindowName
.empty())
623 CInterfaceGroup
*window
= dynamic_cast<CInterfaceGroup
*>(CWidgetManager::getInstance()->getElementFromId(topWindowName
));
624 if(window
&& window
->getActive())
625 CWidgetManager::getInstance()->setTopWindow(window
);
628 uint32 numElemWithConfig
;
629 f
.serial(numElemWithConfig
);
630 for(uint k
= 0; k
< numElemWithConfig
; ++k
)
634 uint32 chunkSize
= 0;
636 uint startPos
= f
.getPos();
637 CInterfaceManager
*im
= CInterfaceManager::getInstance();
638 CInterfaceElement
*elem
= CWidgetManager::getInstance()->getElementFromId(elemID
);
641 nlwarning("Element %s not found while loading config, skipping datas", elemID
.c_str());
642 f
.seek(chunkSize
, NLMISC::IStream::current
);
648 elem
->serialConfig(f
);
650 catch (const NLMISC::ENewerStream
&)
652 nlwarning("Element %s config in stream are too recent to be read by the application, config ignored", elemID
.c_str());
653 f
.seek(startPos
+ chunkSize
, NLMISC::IStream::begin
);
659 // ***************************************************************************
660 void CInterfaceConfig::CDesktopImage::updateGroupContainerImage(CGroupContainer
&gc
)
662 bool updated
= false;
663 for(uint k
= 0; k
< GCImages
.size(); ++k
)
665 if (GCImages
[k
].Id
== gc
.getId())
667 GCImages
[k
].setFrom(&gc
);
675 GCImages
.push_back(image
);
679 // predicate to see if a group container image match the given id
680 class CGroupContainerImageMatch
683 const std::string
&Id
;
684 CGroupContainerImageMatch(const std::string
&id
) : Id(id
) {}
685 bool operator()(const CInterfaceConfig::SCont
&image
) const
687 return image
.Id
== Id
;
691 // ***************************************************************************
692 void CInterfaceConfig::CDesktopImage::removeGroupContainerImage(const std::string
&groupName
)
694 GCImages
.erase(std::remove_if(GCImages
.begin(), GCImages
.end(), CGroupContainerImageMatch(groupName
)), GCImages
.end());
699 // ***************************************************************************
700 void CInterfaceConfig::dataBaseToStream (NLMISC::IStream
&f
)
704 nlwarning("stream is not in writing mode");
708 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
710 // Save branch of the database
712 CCDBNodeBranch
*pDB
= NLGUI::CDBManager::getInstance()->getDbBranch ("UI:SAVE");
715 // Number of leaf to save
716 uint32 nbLeaves
= pDB
->countLeaves();
719 for (uint32 i
= 0; i
< nbLeaves
; ++i
)
722 CCDBNodeLeaf
*pNL
= pDB
->findLeafAtCount(count
);
723 leafTmp
.setFrom(pNL
);
729 // ***************************************************************************
730 void CInterfaceConfig::streamToDataBase (NLMISC::IStream
&f
, uint32 uiDbSaveVersion
)
734 nlwarning("stream is not in reading mode");
738 sint32 begPos
= f
.getPos();
739 f
.seek (0, NLMISC::IStream::end
);
740 sint32 endPos
= f
.getPos();
741 if ((begPos
- endPos
) == 0) return;
742 f
.seek (begPos
, NLMISC::IStream::begin
);
744 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
746 // Load branch of the database
748 CCDBNodeBranch
*pDB
= NLGUI::CDBManager::getInstance()->getDbBranch ("UI:SAVE");
751 // Number of leaf to save
755 for (uint32 i
= 0; i
< nbLeaves
; ++i
)
759 // If there is a define RESET_VER_dbName that exist for this DB, check if version is OK
761 // Format dbName for version check
762 string defVerId
= "RESET_VER_";
763 defVerId
+= leafTmp
.Name
;
764 for(uint i
=0;i
<defVerId
.size();i
++)
770 if( CWidgetManager::getInstance()->getParser()->isDefineExist(defVerId
))
773 fromString(CWidgetManager::getInstance()->getParser()->getDefine(defVerId
), dbVer
);
774 // if the version in the file is older than the version this db want, abort read
775 if(uiDbSaveVersion
<dbVer
)
779 // if want read the value from file, read it, else keep the default one
782 CCDBNodeLeaf
*pNL
= NLGUI::CDBManager::getInstance()->getDbProp(leafTmp
.Name
,false);