Added spawnCrystalItem
[ryzomcore.git] / ryzom / client / src / interface_v3 / interface_config.cpp
blob13a592b44fb8cb1365d377bc4d125ca378027985
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 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/>.
22 #include "stdpch.h"
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;
30 using namespace std;
33 // ***************************************************************************
35 Version 2:
36 - save of interface element specific infos
37 Version 1:
38 - save of the top window between modes.
39 Version 0:
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);
64 if (ver >= 10)
66 f.serial(MinW);
67 f.serial(MaxW);
69 if (ver >= 8)
71 if (f.isReading())
73 f.serial(Id);
74 Id = "ui:interface:"+Id;
76 else
78 std::string shortId;
79 std::string startString;
80 if (Id.size() >= 13)
82 startString = Id.substr(0, 13);
84 if (startString == "ui:interface:")
86 shortId = Id.substr(13,Id.size());
88 else
90 shortId = Id;
92 f.serial(shortId);
94 f.serial(ContainerMode);
95 if (ContainerMode == 0)
97 f.serial(Popuped);
98 f.serial(Opened);
99 f.serial(X);
100 f.serial(Y);
101 f.serial(W);
102 f.serial(H);
103 f.serial(Active);
104 f.serial(ScrollPos);
105 f.serial(BgAlpha);
106 f.serial(ContentAlpha);
107 f.serial(RolloverAlphaContent);
108 f.serial(PopupX);
109 f.serial(PopupY);
110 f.serial(PopupW);
111 f.serial(PopupH);
112 f.serial(UseGlobalAlpha);
113 f.serial(Locked);
114 f.serial(Movable);
115 f.serial(ActiveSavable);
116 f.serial(PopupMaxH);
117 f.serial(RolloverAlphaContainer);
118 if (ver >= 9)
120 f.serial(BackupedPositionValid);
121 if (BackupedPositionValid)
123 f.serial(BackupX);
124 f.serial(BackupY);
126 f.serial(TouchFlag);
129 else if (ContainerMode == 1)
131 f.serial(Opened);
132 f.serial(Active);
133 f.serial(ActiveSavable);
136 else
138 ContainerMode = 0;
139 f.serial(Id);
140 f.serial(Popuped);
141 f.serial(Opened);
142 f.serial(X);
143 f.serial(Y);
144 f.serial(W);
145 f.serial(H);
146 f.serial(Active);
147 f.serial(ScrollPos);
148 if (ver >= 1)
150 f.serial(BgAlpha);
151 f.serial(ContentAlpha);
152 f.serial(RolloverAlphaContent);
153 f.serial(PopupX);
154 f.serial(PopupY);
155 f.serial(PopupW);
156 f.serial(PopupH);
158 else
160 BgAlpha = 255;
161 ContentAlpha = 255;
162 RolloverAlphaContent = RolloverAlphaContainer = 255;
163 PopupX = -1;
164 PopupY = -1;
165 PopupW = -1;
166 PopupH = -1;
168 if (ver >= 2)
169 f.serial(UseGlobalAlpha);
170 else
171 UseGlobalAlpha = true;
173 if (ver >= 3)
174 f.serial(Locked);
175 else
176 Locked = false;
178 if (ver >= 4)
179 f.serial(Movable);
180 else
181 Movable = true;
183 if (ver >= 5)
184 f.serial(ActiveSavable);
185 else
186 ActiveSavable = true;
188 if (ver >= 6)
189 f.serial(PopupMaxH);
190 else
191 PopupMaxH = 512;
193 if (ver >= 7)
194 f.serial(RolloverAlphaContainer);
195 else
196 RolloverAlphaContainer = RolloverAlphaContent;
202 // ***************************************************************************
203 void CInterfaceConfig::SCont::setFrom (CGroupContainer *pGC)
205 ContainerMode = 0;
206 Id = pGC->getId();
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
215 ContainerMode = 1;
216 Opened = pGC->isOpen();
217 ActiveSavable = pGC->isActiveSavable();
218 Active = pGC->getActive();
220 else
222 // Other type of container save all
223 Popuped = pGC->isPopuped();
224 Opened = pGC->isOpen();
226 ActiveSavable = pGC->isActiveSavable();
227 Active = pGC->getActive();
229 X = pGC->getX();
230 Y = pGC->getY();
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();
240 if (Popuped)
242 PopupX = pGC->getX();
243 PopupY = pGC->getY();
244 PopupW = pGC->getW();
245 PopupH = pGC->getH();
247 else
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();
259 ScrollPos = 0;
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();
269 else
271 BackupedPositionValid = false;
273 TouchFlag = pGC->getTouchFlag(false);
276 // ***************************************************************************
277 void CInterfaceConfig::SCont::setTo (CGroupContainer *pGC)
279 if (ContainerMode == 0)
281 pGC->setMinW(MinW);
282 pGC->setMaxW(MaxW);
283 // Normal container
284 if ( pGC->isPopable() && Popuped != pGC->isPopuped() )
286 if (Popuped)
287 pGC->popupCurrentPos();
288 else
289 pGC->popin();
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())
301 sint w= W;
302 sint h= H;
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());
306 else
307 clamp(w, pGC->getMinW(), pGC->getMaxW());
308 pGC->setWAndInvalidateCoords(w);
309 pGC->setHAndInvalidateCoords(h);
310 w= PopupW;
311 h= PopupH;
312 clamp(w, pGC->getPopupMinW(), pGC->getPopupMaxW());
313 clamp(h, pGC->getPopupMinH(), pGC->getPopupMaxH());
314 pGC->setPopupW(w);
315 pGC->setPopupH(h);
316 pGC->setPopupMaxH(PopupMaxH);
319 pGC->setPopupX(PopupX);
320 pGC->setPopupY(PopupY);
322 if (Popuped)
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);
334 if (ActiveSavable)
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);
352 else
354 pGC->clearBackup();
358 else if (ContainerMode == 1)
360 // Container that just need Opened, Active and ActiveSavable state to be retrieved
361 pGC->setOpen(Opened);
362 if (ActiveSavable)
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);
380 f.serial(Name);
381 f.serial(Value);
382 if (ver >= 1)
383 f.serial(OldValue);
384 else
385 OldValue = Value;
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
407 * \date 2003
409 class CSaveUIConfigVisitor : public CInterfaceElementVisitor
411 public:
412 // build the visitor to fill the given stream
413 CSaveUIConfigVisitor(NLMISC::IStream &stream) : Stream(stream) {}
414 private:
415 // The stream where datas are written
416 NLMISC::IStream &Stream;
417 // From CInterfaceElementVisitor
418 void visit(CInterfaceElement *elem)
420 if (!elem) return;
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();
425 Stream.serial(id);
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
443 * \date 2003
445 class CCountUIElemWithConfigVisitor : public CInterfaceElementVisitor
447 public:
448 CCountUIElemWithConfigVisitor() : Count(0) {}
449 uint32 Count;
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);
474 else write(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())
491 ExtraDatas.invert();
493 sint32 length = endPos - begPos;
494 if (length > 0)
496 uint8 *pBuffer = new uint8[length];
497 f.serialBuffer(pBuffer, length); // read buffer from file
498 ExtraDatas.serialBuffer(pBuffer, length); // copy buffer to memstream
499 delete [] pBuffer;
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();
512 if (length > 0)
514 uint8 *pBuffer = new uint8[length];
515 memcpy(pBuffer, ExtraDatas.buffer(), length);
516 f.serialBuffer(pBuffer, length);
517 delete [] pBuffer;
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() )
537 nCount++;
541 GCImages.resize(nCount);
542 SCont contTmp;
543 nCount2 = 0;
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);
555 nCount2++;
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;
564 if (f.isReading())
566 f.invert();
568 f.resetPtrTable();
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;
573 if (topWindow)
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);
588 pIM->visit(&saver);
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));
602 if (pGC != NULL)
603 GCImages[k].setTo(pGC);
605 // serial extra data from the stream
606 NLMISC::CMemStream &f = ExtraDatas;
607 if (!f.isReading())
609 f.invert();
611 f.resetPtrTable();
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
617 if(Version>=1)
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)
632 std::string elemID;
633 f.serial(elemID);
634 uint32 chunkSize = 0;
635 f.serial(chunkSize);
636 uint startPos = f.getPos();
637 CInterfaceManager *im = CInterfaceManager::getInstance();
638 CInterfaceElement *elem = CWidgetManager::getInstance()->getElementFromId(elemID);
639 if (!elem)
641 nlwarning("Element %s not found while loading config, skipping datas", elemID.c_str());
642 f.seek(chunkSize, NLMISC::IStream::current);
644 else
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);
668 updated = true;
671 if (!updated)
673 SCont image;
674 image.setFrom(&gc);
675 GCImages.push_back(image);
679 // predicate to see if a group container image match the given id
680 class CGroupContainerImageMatch
682 public:
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)
702 if (f.isReading())
704 nlwarning("stream is not in writing mode");
705 return;
708 CInterfaceManager *pIM = CInterfaceManager::getInstance();
710 // Save branch of the database
711 SDBLeaf leafTmp;
712 CCDBNodeBranch *pDB = NLGUI::CDBManager::getInstance()->getDbBranch ("UI:SAVE");
713 if (pDB != NULL)
715 // Number of leaf to save
716 uint32 nbLeaves = pDB->countLeaves();
717 f.serial(nbLeaves);
719 for (uint32 i = 0; i < nbLeaves; ++i)
721 uint count = i;
722 CCDBNodeLeaf *pNL = pDB->findLeafAtCount(count);
723 leafTmp.setFrom(pNL);
724 f.serial(leafTmp);
729 // ***************************************************************************
730 void CInterfaceConfig::streamToDataBase (NLMISC::IStream &f, uint32 uiDbSaveVersion)
732 if (!f.isReading())
734 nlwarning("stream is not in reading mode");
735 return;
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
747 SDBLeaf leafTmp;
748 CCDBNodeBranch *pDB = NLGUI::CDBManager::getInstance()->getDbBranch ("UI:SAVE");
749 if (pDB != NULL)
751 // Number of leaf to save
752 uint32 nbLeaves = 0;
753 f.serial(nbLeaves);
755 for (uint32 i = 0; i < nbLeaves; ++i)
757 f.serial(leafTmp);
759 // If there is a define RESET_VER_dbName that exist for this DB, check if version is OK
760 bool wantRead= true;
761 // Format dbName for version check
762 string defVerId= "RESET_VER_";
763 defVerId+= leafTmp.Name;
764 for(uint i=0;i<defVerId.size();i++)
766 if(defVerId[i]==':')
767 defVerId[i]='_';
769 // check if exist
770 if( CWidgetManager::getInstance()->getParser()->isDefineExist(defVerId))
772 uint32 dbVer;
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)
776 wantRead= false;
779 // if want read the value from file, read it, else keep the default one
780 if(wantRead)
782 CCDBNodeLeaf *pNL = NLGUI::CDBManager::getInstance()->getDbProp(leafTmp.Name,false);
783 if (pNL != NULL)
784 leafTmp.setTo(pNL);