Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / gui / widget_manager.cpp
blob01aab120fa70963caed828435336862b1857c978
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2020 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013-2014 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2013-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "stdpch.h"
23 #include "nel/gui/db_manager.h"
24 #include "nel/gui/view_renderer.h"
25 #include "nel/gui/widget_manager.h"
26 #include "nel/gui/view_pointer.h"
27 #include "nel/gui/ctrl_draggable.h"
28 #include "nel/gui/interface_group.h"
29 #include "nel/gui/group_container_base.h"
30 #include "nel/gui/group_modal.h"
31 #include "nel/gui/group_editbox_base.h"
32 #include "nel/gui/interface_options.h"
33 #include "nel/gui/view_text.h"
34 #include "nel/gui/view_bitmap.h"
35 #include "nel/gui/group_container.h"
36 #include "nel/gui/interface_anim.h"
37 #include "nel/gui/proc.h"
38 #include "nel/gui/interface_expr.h"
39 #include "nel/gui/reflect_register.h"
40 #include "nel/gui/editor_selection_watcher.h"
41 #include "nel/misc/events.h"
42 #include "nel/gui/root_group.h"
44 #ifdef DEBUG_NEW
45 #define new DEBUG_NEW
46 #endif
48 namespace NLGUI
50 void LinkHack();
53 namespace
55 const uint DOUBLE_CLICK_MIN = 50;
56 const uint DOUBLE_CLICK_MAX = 750;
57 const float ROLLOVER_MIN_DELTA_PER_MS = 0.28f;
58 const float ROLLOVER_MAX_DELTA_PER_MS = 0.12f;
60 void Hack()
62 LinkHack();
66 namespace NLGUI
68 CWidgetManager* CWidgetManager::instance = NULL;
69 std::string CWidgetManager::_CtrlLaunchingModalId= "ctrl_launch_modal";
70 // ----------------------------------------------------------------------------
71 // SMasterGroup
72 // ----------------------------------------------------------------------------
74 // ----------------------------------------------------------------------------
75 void CWidgetManager::SMasterGroup::addWindow(CInterfaceGroup *pIG, uint8 nPrio)
77 nlassert(nPrio<WIN_PRIORITY_MAX);
79 // Priority WIN_PRIORITY_WORLD_SPACE is only for CGroupInScene !
80 // Add this group in another priority list
81 nlassert ((nPrio!=WIN_PRIORITY_MAX) || pIG->isGroupInScene() );
83 for (uint8 i = 0; i < WIN_PRIORITY_MAX; ++i)
85 std::list<CInterfaceGroup*>::iterator it = PrioritizedWindows[i].begin();
86 while (it != PrioritizedWindows[i].end())
88 // If the element already exists in the list return !
89 if (*it == pIG)
90 return;
91 it++;
94 PrioritizedWindows[nPrio].push_back(pIG);
97 // ----------------------------------------------------------------------------
98 void CWidgetManager::SMasterGroup::delWindow(CInterfaceGroup *pIG)
100 for (uint8 i = 0; i < WIN_PRIORITY_MAX; ++i)
102 std::list<CInterfaceGroup*>::iterator it = PrioritizedWindows[i].begin();
103 while (it != PrioritizedWindows[i].end())
105 if ((*it) == pIG)
107 PrioritizedWindows[i].erase(it);
108 return;
110 it++;
115 // ----------------------------------------------------------------------------
116 CInterfaceGroup* CWidgetManager::SMasterGroup::getWindowFromId(const std::string &winID)
118 for (uint8 i = 0; i < WIN_PRIORITY_MAX; ++i)
120 std::list<CInterfaceGroup*>::iterator it = PrioritizedWindows[i].begin();
121 while (it != PrioritizedWindows[i].end())
123 if ((*it)->getId() == winID)
124 return *it;
125 it++;
128 return NULL;
131 // ----------------------------------------------------------------------------
132 bool CWidgetManager::SMasterGroup::isWindowPresent(CInterfaceGroup *pIG)
134 for (uint8 i = 0; i < WIN_PRIORITY_MAX; ++i)
136 std::list<CInterfaceGroup*>::iterator it = PrioritizedWindows[i].begin();
137 while (it != PrioritizedWindows[i].end())
139 if ((*it) == pIG)
140 return true;
141 it++;
144 return false;
147 // Set a window top in its priority queue
148 // ----------------------------------------------------------------------------
149 void CWidgetManager::SMasterGroup::setTopWindow(CInterfaceGroup *pIG)
151 for (uint8 i = 0; i < WIN_PRIORITY_MAX; ++i)
153 std::list<CInterfaceGroup*>::iterator it = PrioritizedWindows[i].begin();
154 while (it != PrioritizedWindows[i].end())
156 if (*it == pIG)
158 PrioritizedWindows[i].erase(it);
159 PrioritizedWindows[i].push_back(pIG);
160 LastTopWindowPriority= i;
161 return;
163 it++;
166 // todo hulud interface syntax error
167 nlwarning("window %s do not exist in a priority list", pIG->getId().c_str());
170 // ----------------------------------------------------------------------------
171 void CWidgetManager::SMasterGroup::setBackWindow(CInterfaceGroup *pIG)
173 for (uint8 i = 0; i < WIN_PRIORITY_MAX; ++i)
175 std::list<CInterfaceGroup*>::iterator it = PrioritizedWindows[i].begin();
176 while (it != PrioritizedWindows[i].end())
178 if (*it == pIG)
180 PrioritizedWindows[i].erase(it);
181 PrioritizedWindows[i].push_front(pIG);
182 return;
184 it++;
187 // todo hulud interface syntax error
188 nlwarning("window %s do not exist in a priority list", pIG->getId().c_str());
191 // ----------------------------------------------------------------------------
192 void CWidgetManager::SMasterGroup::deactiveAllContainers()
194 std::vector<CGroupContainerBase*> gcs;
196 // Make first a list of all window (Warning: all group container are not window!)
197 for (uint8 i = 0; i < WIN_PRIORITY_MAX; ++i)
199 std::list<CInterfaceGroup*>::iterator it = PrioritizedWindows[i].begin();
200 while (it != PrioritizedWindows[i].end())
202 CGroupContainerBase *pGC = dynamic_cast<CGroupContainerBase*>(*it);
203 if (pGC != NULL)
204 gcs.push_back(pGC);
205 it++;
209 // Then hide them. Must do this in 2 times, because setActive(false) change PrioritizedWindows,
210 // and hence invalidate its.
211 for (uint32 i = 0; i < gcs.size(); ++i)
213 gcs[i]->setActive(false);
217 // ----------------------------------------------------------------------------
218 void CWidgetManager::SMasterGroup::centerAllContainers()
220 for (uint8 i = 0; i < WIN_PRIORITY_MAX; ++i)
222 std::list<CInterfaceGroup*>::iterator it = PrioritizedWindows[i].begin();
223 while (it != PrioritizedWindows[i].end())
225 CGroupContainerBase *pGC = dynamic_cast<CGroupContainerBase*>(*it);
226 if ((pGC != NULL) && (pGC->getParent() != NULL))
228 sint32 wParent = pGC->getParent()->getW(false);
229 sint32 w = pGC->getW(false);
230 pGC->setXAndInvalidateCoords((wParent - w) / 2);
231 sint32 hParent = pGC->getParent()->getH(false);
232 sint32 h = pGC->getH(false);
233 pGC->setYAndInvalidateCoords(h+(hParent - h) / 2);
236 it++;
241 // ----------------------------------------------------------------------------
242 void CWidgetManager::SMasterGroup::unlockAllContainers()
244 for (uint8 i = 0; i < WIN_PRIORITY_MAX; ++i)
246 std::list<CInterfaceGroup*>::iterator it = PrioritizedWindows[i].begin();
247 while (it != PrioritizedWindows[i].end())
249 CGroupContainerBase *pGC = dynamic_cast<CGroupContainerBase*>(*it);
250 if (pGC != NULL)
251 pGC->setLocked(false);
253 it++;
258 class CElementToSort
260 public:
261 CInterfaceGroup *pIG;
262 float Distance;
263 bool operator< (const CElementToSort& other) const
265 // We want first farest views
266 return Distance > other.Distance;
270 void CWidgetManager::SMasterGroup::sortWorldSpaceGroup ()
272 static std::vector<CElementToSort> sortTable;
273 sortTable.clear ();
275 // Fill the sort table
276 std::list<CInterfaceGroup*>::iterator it = PrioritizedWindows[WIN_PRIORITY_WORLD_SPACE].begin();
277 while (it != PrioritizedWindows[WIN_PRIORITY_WORLD_SPACE].end())
279 sortTable.push_back (CElementToSort ());
280 CElementToSort &elm = sortTable.back();
281 elm.pIG = *it;
282 elm.Distance = (*it)->getDepthForZSort();
284 it++;
287 // Sort the table
288 std::sort (sortTable.begin(), sortTable.end());
290 // Fill the final table
291 uint i = 0;
292 it = PrioritizedWindows[WIN_PRIORITY_WORLD_SPACE].begin();
293 while (it != PrioritizedWindows[WIN_PRIORITY_WORLD_SPACE].end())
295 *it = sortTable[i].pIG;
297 it++;
298 i++;
303 CWidgetManager* CWidgetManager::getInstance()
305 if( instance == NULL )
306 instance = new CWidgetManager;
308 return instance;
311 void CWidgetManager::release()
313 delete instance;
314 instance = NULL;
317 // ----------------------------------------------------------------------------
318 CInterfaceGroup* CWidgetManager::getMasterGroupFromId (const std::string &MasterGroupName)
320 for (uint32 i = 0; i < _MasterGroups.size(); ++i)
322 if (_MasterGroups[i].Group->getId() == MasterGroupName)
323 return _MasterGroups[i].Group;
325 return NULL;
328 // ----------------------------------------------------------------------------
329 CInterfaceGroup* CWidgetManager::getWindowFromId (const std::string & groupId)
331 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
333 SMasterGroup &rMG = _MasterGroups[nMasterGroup];
334 CInterfaceGroup *pIG = rMG.getWindowFromId(groupId);
335 if (pIG != NULL)
336 return pIG;
338 return NULL;
341 // ----------------------------------------------------------------------------
342 void CWidgetManager::addWindowToMasterGroup (const std::string &sMasterGroupName, CInterfaceGroup *pIG)
344 // Warning this function is not smart : its a o(n) !
345 if (pIG == NULL) return;
346 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); ++nMasterGroup)
348 SMasterGroup &rMG = _MasterGroups[nMasterGroup];
349 if (rMG.Group->getId() == sMasterGroupName)
351 rMG.addWindow(pIG, pIG->getPriority());
356 // ----------------------------------------------------------------------------
357 void CWidgetManager::removeWindowFromMasterGroup(const std::string &sMasterGroupName,CInterfaceGroup *pIG)
359 // Warning this function is not smart : its a o(n) !
360 if (pIG == NULL) return;
361 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); ++nMasterGroup)
363 SMasterGroup &rMG = _MasterGroups[nMasterGroup];
364 if (rMG.Group->getId() == sMasterGroupName)
366 rMG.delWindow(pIG);
371 void unlinkAllContainers (CInterfaceGroup *pIG)
373 const std::vector<CInterfaceGroup*> &rG = pIG->getGroups();
374 for(uint i = 0; i < rG.size(); ++i)
375 unlinkAllContainers (rG[i]);
377 CGroupContainerBase *pGC = dynamic_cast<CGroupContainerBase*>(pIG);
378 if (pGC != NULL)
379 pGC->removeAllContainers();
382 // ***************************************************************************
383 void CWidgetManager::removeAllMasterGroups()
385 uint i;
387 for (i = 0; i < _MasterGroups.size(); ++i)
388 unlinkAllContainers (_MasterGroups[i].Group);
390 // Yoyo: important to not Leave NULL in the array, because of CGroupHTML and LibWWW callback
391 // that may call CInterfaceManager::getElementFromId() (and this method hates having NULL in the arrays ^^)
392 while(!_MasterGroups.empty())
394 delete _MasterGroups.back().Group;
395 _MasterGroups.pop_back();
400 // ------------------------------------------------------------------------------------------------
401 void CWidgetManager::activateMasterGroup (const std::string &sMasterGroupName, bool bActive)
403 CInterfaceGroup *pIG = getMasterGroupFromId (sMasterGroupName);
404 if (pIG != NULL)
406 pIG->setActive(bActive);
407 pIG->invalidateCoords();
411 // ------------------------------------------------------------------------------------------------
412 CInterfaceGroup* CWidgetManager::getWindow(CInterfaceElement *pIE)
414 CInterfaceGroup *pIG = pIE->getParent();
415 if (pIG == NULL) return NULL;
416 if (pIG->getParent() == NULL) return NULL;
417 while (pIG->getParent()->getParent() != NULL)
419 pIG = pIG->getParent();
421 return pIG;
425 // ------------------------------------------------------------------------------------------------
426 CInterfaceElement* CWidgetManager::getElementFromId (const std::string &sEltId)
428 // System special
429 if(sEltId == _CtrlLaunchingModalId)
430 return getCtrlLaunchingModal();
432 // Search for all elements
433 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
435 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
436 CInterfaceElement *pIEL = rMG.Group->getElement (sEltId);
437 if (pIEL != NULL)
438 return pIEL;
440 return NULL;
443 // ------------------------------------------------------------------------------------------------
444 CInterfaceElement* CWidgetManager::getElementFromId (const std::string &sStart, const std::string &sEltId)
446 CInterfaceElement *pIEL = getElementFromId (sEltId);
447 if (pIEL == NULL)
449 std::string sZeStart = sStart, sTmp;
450 if (sZeStart[sZeStart.size()-1] == ':')
451 sZeStart = sZeStart.substr(0, sZeStart.size()-1);
453 while (!sZeStart.empty())
455 if (sEltId[0] == ':')
456 sTmp = sZeStart + sEltId;
457 else
458 sTmp = sZeStart + ":" + sEltId;
459 pIEL = getElementFromId (sTmp);
460 if (pIEL != NULL)
461 return pIEL;
462 std::string::size_type nextPos = sZeStart.rfind(':');
463 if (nextPos == std::string::npos) break;
464 sZeStart = sZeStart.substr(0, nextPos);
467 return pIEL;
470 // ------------------------------------------------------------------------------------------------
471 CInterfaceElement* CWidgetManager::getElementFromDefine( const std::string &defineId )
473 return getElementFromId( _Parser->getDefine( defineId ) );
476 // ------------------------------------------------------------------------------------------------
477 void CWidgetManager::setTopWindow (CInterfaceGroup* win)
479 //find the window in the window list
480 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
482 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
483 if (rMG.Group->getActive())
484 rMG.setTopWindow(win);
488 // ------------------------------------------------------------------------------------------------
489 void CWidgetManager::setBackWindow(CInterfaceGroup* win)
491 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
493 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
494 if (rMG.Group->getActive())
495 rMG.setBackWindow(win);
499 // ------------------------------------------------------------------------------------------------
500 CInterfaceGroup* CWidgetManager::getTopWindow (uint8 nPriority) const
502 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
504 const CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
505 if (rMG.Group->getActive())
507 // return the first.
508 if(rMG.PrioritizedWindows[nPriority].empty())
509 return NULL;
510 else
511 return rMG.PrioritizedWindows[nPriority].back();
514 return NULL;
518 // ------------------------------------------------------------------------------------------------
519 CInterfaceGroup* CWidgetManager::getBackWindow (uint8 nPriority) const
521 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
523 const CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
524 if (rMG.Group->getActive())
526 // return the first.
527 if(rMG.PrioritizedWindows[nPriority].empty())
528 return NULL;
529 else
530 return rMG.PrioritizedWindows[nPriority].front();
533 return NULL;
536 // ***************************************************************************
537 CInterfaceGroup* CWidgetManager::getLastEscapableTopWindow() const
539 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
541 const CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
542 if (rMG.Group->getActive())
544 for (uint8 nPriority = WIN_PRIORITY_MAX; nPriority > 0; nPriority--)
546 const std::list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority-1];
547 std::list<CInterfaceGroup*>::const_reverse_iterator it;
548 it= rList.rbegin();
549 for(;it!=rList.rend();it++)
551 if((*it)->getActive() && (*it)->getEscapable())
552 return *it;
557 return NULL;
560 // ***************************************************************************
561 void CWidgetManager::setWindowPriority (CInterfaceGroup *pWin, uint8 nNewPriority)
563 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
565 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
566 if (rMG.Group->getActive())
568 if (rMG.isWindowPresent(pWin))
570 rMG.delWindow(pWin);
571 rMG.addWindow(pWin, nNewPriority);
577 // ***************************************************************************
578 uint8 CWidgetManager::getLastTopWindowPriority() const
580 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
582 const CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
583 if (rMG.Group->getActive())
585 return rMG.LastTopWindowPriority;
588 return 0;
591 bool CWidgetManager::hasModal() const
593 if( !_ModalStack.empty() )
594 return true;
595 else
596 return false;
599 CWidgetManager::SModalWndInfo& CWidgetManager::getModal()
601 return _ModalStack.back();
604 bool CWidgetManager::isPreviousModal( CInterfaceGroup *wnd ) const
606 std::vector< SModalWndInfo >::size_type s = _ModalStack.size();
607 for( std::vector< SModalWndInfo >::size_type i = 0; i < s; i++ )
608 if( _ModalStack[ i ].ModalWindow == wnd )
609 return true;
611 return false;
614 // ------------------------------------------------------------------------------------------------
615 void CWidgetManager::enableModalWindow (CCtrlBase *ctrlLaunchingModal, CInterfaceGroup *pIG)
617 // disable any modal before. release keyboard
618 disableModalWindow();
619 pushModalWindow(ctrlLaunchingModal, pIG);
622 // ------------------------------------------------------------------------------------------------
623 void CWidgetManager::enableModalWindow (CCtrlBase *CtrlLaunchingModal, const std::string &groupName)
625 CInterfaceGroup *group= dynamic_cast<CGroupModal*>( getElementFromId(groupName) );
626 if(group)
628 // enable the modal
629 enableModalWindow(CtrlLaunchingModal, group);
633 // ------------------------------------------------------------------------------------------------
634 void CWidgetManager::disableModalWindow ()
636 while (!_ModalStack.empty())
638 SModalWndInfo winInfo = _ModalStack.back();
639 _ModalStack.pop_back(); // must pop back as early as possible because 'setActive' may trigger another 'popModalWindow', leading to a crash
640 // disable old modal window
641 if(winInfo.ModalWindow)
643 setBackWindow(winInfo.ModalWindow);
644 winInfo.ModalWindow->setActive(false);
648 // disable any context help
649 setCurContextHelp( NULL );
650 _DeltaTimeStopingContextHelp = 0;
653 // ------------------------------------------------------------------------------------------------
654 void CWidgetManager::pushModalWindow(CCtrlBase *ctrlLaunchingModal, CInterfaceGroup *pIG)
656 // enable the wanted modal
657 if(pIG)
659 SModalWndInfo mwi;
660 mwi.ModalWindow = pIG;
661 mwi.CtrlLaunchingModal = ctrlLaunchingModal;
662 // setup special group
663 CGroupModal *groupModal= dynamic_cast<CGroupModal*>(pIG);
664 if(groupModal)
666 mwi.ModalExitClickOut = groupModal->ExitClickOut;
667 mwi.ModalExitClickL = groupModal->ExitClickL;
668 mwi.ModalExitClickR = groupModal->ExitClickR;
669 mwi.ModalHandlerClickOut = groupModal->OnClickOut;
670 mwi.ModalClickOutParams = groupModal->OnClickOutParams;
671 mwi.ModalExitKeyPushed = groupModal->ExitKeyPushed;
672 // update coords of the modal
673 if(groupModal->SpawnOnMousePos)
675 groupModal->SpawnMouseX = _Pointer->getX();
676 groupModal->SpawnMouseY = _Pointer->getY();
679 else
681 // default for group not modal. Backward compatibility
682 mwi.ModalExitClickOut = false;
683 mwi.ModalExitClickL = false;
684 mwi.ModalExitClickR = false;
685 mwi.ModalExitKeyPushed = false;
688 _ModalStack.push_back(mwi);
690 // update coords and activate the modal
691 mwi.ModalWindow->invalidateCoords();
692 mwi.ModalWindow->setActive(true);
693 setTopWindow(mwi.ModalWindow);
697 // ------------------------------------------------------------------------------------------------
698 void CWidgetManager::pushModalWindow(CCtrlBase *ctrlLaunchingModal, const std::string &groupName)
700 CInterfaceGroup *group= dynamic_cast<CGroupModal*>( getElementFromId(groupName) );
701 if(group)
703 // enable the modal
704 enableModalWindow(ctrlLaunchingModal, group);
708 // ------------------------------------------------------------------------------------------------
709 void CWidgetManager::popModalWindow()
711 if (!_ModalStack.empty())
713 SModalWndInfo winInfo = _ModalStack.back();
714 _ModalStack.pop_back(); // must pop back as early as possible because 'setActive' may trigger another 'popModalWindow', leading to a crash
715 if(winInfo.ModalWindow)
717 setBackWindow(winInfo.ModalWindow);
718 winInfo.ModalWindow->setActive(false);
720 if (!_ModalStack.empty())
722 if(_ModalStack.back().ModalWindow)
724 _ModalStack.back().ModalWindow->setActive(true);
725 setTopWindow(_ModalStack.back().ModalWindow);
731 // ------------------------------------------------------------------------------------------------
732 void CWidgetManager::popModalWindowCategory(const std::string &category)
734 for(;;)
736 if (_ModalStack.empty()) break;
737 if (!_ModalStack.back().ModalWindow) break;
738 CGroupModal *gm = dynamic_cast<CGroupModal *>((CInterfaceGroup*)(_ModalStack.back().ModalWindow));
739 if (gm && gm->Category == category)
741 _ModalStack.back().ModalWindow->setActive(false);
742 _ModalStack.pop_back();
744 else
746 break;
751 // ***************************************************************************
752 void CWidgetManager::hideAllWindows()
754 for (uint nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
756 SMasterGroup &rMG = _MasterGroups[nMasterGroup];
757 if (rMG.Group->getActive())
759 for (uint8 nPriority = 0; nPriority < WIN_PRIORITY_MAX; nPriority++)
761 std::list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
762 std::list<CInterfaceGroup*>::const_iterator itw;
763 for (itw = rList.begin(); itw!= rList.end();)
765 CInterfaceGroup *pIG = *itw;
766 itw++; // since setActive invalidate the iterator, be sure we move to the next one before
767 pIG->setActive(false);
774 // ***************************************************************************
775 void CWidgetManager::hideAllNonSavableWindows()
777 for (uint nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
779 SMasterGroup &rMG = _MasterGroups[nMasterGroup];
780 if (rMG.Group->getActive())
782 for (uint8 nPriority = 0; nPriority < WIN_PRIORITY_MAX; nPriority++)
784 std::list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
785 std::list<CInterfaceGroup*>::const_iterator itw;
786 for (itw = rList.begin(); itw!= rList.end();)
788 CInterfaceGroup *pIG = *itw;
789 CGroupContainer *cont = dynamic_cast<CGroupContainer *>(pIG);
790 itw++; // since setActive invalidate the iterator, be sure we move to the next one before
791 if (!cont || !cont->isSavable())
793 pIG->setActive(false);
801 // ------------------------------------------------------------------------------------------------
802 CInterfaceGroup* CWidgetManager::getWindowUnder (sint32 x, sint32 y)
804 H_AUTO (RZ_Interface_Window_Under )
806 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
808 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
809 if (rMG.Group->getActive())
811 for (uint8 nPriority = WIN_PRIORITY_MAX; nPriority > 0; nPriority--)
813 const std::list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority-1];
814 std::list<CInterfaceGroup*>::const_reverse_iterator itw;
815 for (itw = rList.rbegin(); itw != rList.rend(); itw++)
817 CInterfaceGroup *pIG = *itw;
818 if (pIG->getActive() && pIG->getUseCursor())
820 if (pIG->isWindowUnder (x, y))
821 return pIG;
827 return NULL;
830 // ------------------------------------------------------------------------------------------------
831 CInterfaceGroup* CWidgetManager::getGroupUnder (sint32 x, sint32 y)
833 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
835 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
836 if (rMG.Group->getActive())
838 for (uint8 nPriority = WIN_PRIORITY_MAX; nPriority > 0; nPriority--)
840 const std::list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority-1];
841 std::list<CInterfaceGroup*>::const_reverse_iterator itw;
842 for (itw = rList.rbegin(); itw != rList.rend(); itw++)
844 CInterfaceGroup *pIG = *itw;
845 if (pIG->getActive() && pIG->getUseCursor())
847 CInterfaceGroup *pIGunder = pIG->getGroupUnder (x ,y);
848 if (pIGunder != NULL)
849 return pIGunder;
855 return NULL;
858 // ------------------------------------------------------------------------------------------------
859 void CWidgetManager::getViewsUnder (sint32 x, sint32 y, std::vector<CViewBase*> &vVB)
861 vVB.clear ();
863 // No Op if screen minimized
864 if(CViewRenderer::getInstance()->isMinimized())
865 return;
867 uint32 sw, sh;
868 CViewRenderer::getInstance()->getScreenSize(sw, sh);
869 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
871 SMasterGroup &rMG = _MasterGroups[nMasterGroup];
872 if (rMG.Group->getActive())
874 for (uint8 nPriority = WIN_PRIORITY_MAX; nPriority > 0; nPriority--)
876 const std::list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority-1];
877 std::list<CInterfaceGroup*>::const_reverse_iterator itw;
878 for (itw = rList.rbegin(); itw != rList.rend(); itw++)
880 CInterfaceGroup *pIG = *itw;
882 // Accecpt if not modal clip
883 if (pIG->getActive() && pIG->getUseCursor())
885 if (pIG->getViewsUnder (x, y, 0, 0, (sint32) sw, (sint32) sh, vVB))
886 return ;
894 // ------------------------------------------------------------------------------------------------
895 void CWidgetManager::getCtrlsUnder (sint32 x, sint32 y, std::vector<CCtrlBase*> &vICL)
897 vICL.clear ();
899 // No Op if screen minimized
900 if(CViewRenderer::getInstance()->isMinimized())
901 return;
903 uint32 sw, sh;
904 CViewRenderer::getInstance()->getScreenSize(sw, sh);
905 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
907 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
908 if (rMG.Group->getActive())
910 for (uint8 nPriority = WIN_PRIORITY_MAX; nPriority > 0 ; nPriority--)
912 const std::list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority-1];
913 std::list<CInterfaceGroup*>::const_reverse_iterator itw;
914 for (itw = rList.rbegin(); itw != rList.rend(); itw++)
916 CInterfaceGroup *pIG = *itw;
918 // Accecpt if not modal clip
919 if (!hasModal() || getModal().ModalWindow == pIG || getModal().ModalExitClickOut)
920 if (pIG->getActive() && pIG->getUseCursor())
922 if (pIG->getCtrlsUnder (x, y, 0, 0, (sint32) sw, (sint32) sh, vICL))
923 return;
932 // ------------------------------------------------------------------------------------------------
933 void CWidgetManager::getGroupsUnder (sint32 x, sint32 y, std::vector<CInterfaceGroup *> &vIGL)
935 vIGL.clear ();
937 // No Op if screen minimized
938 if(CViewRenderer::getInstance()->isMinimized())
939 return;
941 uint32 sw, sh;
942 CViewRenderer::getInstance()->getScreenSize(sw, sh);
943 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
945 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
946 if (rMG.Group->getActive())
948 for (uint8 nPriority = WIN_PRIORITY_MAX; nPriority > 0 ; nPriority--)
950 const std::list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority-1];
951 std::list<CInterfaceGroup*>::const_reverse_iterator itw;
952 for (itw = rList.rbegin(); itw != rList.rend(); itw++)
954 CInterfaceGroup *pIG = *itw;
956 // Accecpt if not modal clip
957 if (!hasModal() || getModal().ModalWindow == pIG ||
958 getModal().ModalExitClickOut)
959 if (pIG->getActive() && pIG->getUseCursor())
961 if (pIG->isIn(x, y))
963 vIGL.push_back(pIG);
964 pIG->getGroupsUnder (x, y, 0, 0, (sint32) sw, (sint32) sh, vIGL);
965 return;
975 // ***************************************************************************
976 void CWidgetManager::removeRefOnView( CViewBase *viewBase )
978 uint i;
979 for (i=0; i<_ViewsUnderPointer.size(); i++)
981 if (_ViewsUnderPointer[i] == viewBase)
983 _ViewsUnderPointer.erase (_ViewsUnderPointer.begin()+i);
984 i--;
989 // ***************************************************************************
990 void CWidgetManager::removeRefOnCtrl(CCtrlBase *ctrlBase)
992 if ( getCurContextHelp() == ctrlBase)
993 setCurContextHelp( NULL );
994 if (getCapturePointerLeft() == ctrlBase)
995 setCapturePointerLeft(NULL);
996 if (getCapturePointerRight() == ctrlBase)
997 setCapturePointerRight (NULL);
998 if (getCaptureKeyboard() == ctrlBase)
999 setCaptureKeyboard(NULL);
1000 if (getOldCaptureKeyboard() == ctrlBase)
1001 setOldCaptureKeyboard(NULL);
1002 if (getDefaultCaptureKeyboard() == ctrlBase)
1003 setDefaultCaptureKeyboard(NULL);
1004 uint i;
1005 for (i=0; i<_CtrlsUnderPointer.size(); i++)
1007 if (_CtrlsUnderPointer[i] == ctrlBase)
1009 _CtrlsUnderPointer.erase (_CtrlsUnderPointer.begin()+i);
1010 i--;
1014 // Unregister from ClockMsgTargets
1015 unregisterClockMsgTarget(ctrlBase);
1019 // ***************************************************************************
1020 void CWidgetManager::removeRefOnGroup (CInterfaceGroup *group)
1022 uint i;
1023 for (i=0; i<_GroupsUnderPointer.size(); i++)
1025 if (_GroupsUnderPointer[i] == group)
1027 _GroupsUnderPointer.erase (_GroupsUnderPointer.begin()+i);
1028 i--;
1034 void CWidgetManager::reset()
1036 setCurContextHelp( NULL );
1038 _ViewsUnderPointer.clear();
1039 _CtrlsUnderPointer.clear();
1040 _GroupsUnderPointer.clear();
1042 _CaptureKeyboard = NULL;
1043 _OldCaptureKeyboard = NULL;
1044 setCapturePointerLeft(NULL);
1045 setCapturePointerRight(NULL);
1046 _CapturedView = NULL;
1048 resetColorProps();
1049 resetAlphaRolloverSpeedProps();
1050 resetGlobalAlphasProps();
1052 _ContextHelpContentAlphaDB = NULL;
1053 _ContextHelpContainerColorDB = NULL;
1054 _ContextHelpContainerAlphaDB = NULL;
1056 activeAnims.clear();
1058 editorSelection.clear();
1062 // ------------------------------------------------------------------------------------------------
1063 void CWidgetManager::checkCoords()
1065 H_AUTO ( RZ_Interface_validateCoords )
1067 uint32 nMasterGroup;
1070 H_AUTO ( RZ_Interface_checkCoords )
1072 // checkCoords all the windows
1073 for (nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
1075 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
1076 if (rMG.Group->getActive())
1078 for (uint8 nPriority = 0; nPriority < WIN_PRIORITY_MAX; nPriority++)
1080 std::list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
1081 std::list<CInterfaceGroup*>::const_iterator itw;
1082 for (itw = rList.begin(); itw!= rList.end();)
1084 CInterfaceGroup *pIG = *itw;
1085 itw++; // since checkCoords invalidate the iterator, be sure we move to the next one before
1086 if (pIG->getActive())
1087 pIG->checkCoords ();
1094 bool bRecomputeCtrlUnderPtr = false;
1096 H_AUTO ( RZ_Interface_updateCoords )
1098 // updateCoords all the needed windows
1099 for (nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
1101 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
1102 if (rMG.Group->getActive())
1104 for (uint8 nPriority = 0; nPriority < WIN_PRIORITY_MAX; nPriority++)
1106 std::list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
1107 std::list<CInterfaceGroup*>::const_iterator itw;
1108 for (itw = rList.begin(); itw!= rList.end(); itw++)
1110 CInterfaceGroup *pIG = *itw;
1111 bool updateCoordCalled= false;
1112 // updateCoords the window only if the master group is his parent and if need it
1113 // do it until updateCoords() no more invalidate coordinates!!
1115 // add deadlock counter to prevent endless loop (Issue #73: web browser long scroll lockup)
1116 int deadlock = 10;
1117 while (--deadlock > 0 && pIG->getParent()==rMG.Group && (pIG->getInvalidCoords()>0))
1119 bRecomputeCtrlUnderPtr = true;
1120 // Update as many pass wanted (3 time for complex resizing, 1 for scroll for example)
1121 uint numPass= pIG->getInvalidCoords();
1122 // reset before updateCoords
1123 pIG->resetInvalidCoords();
1124 for(uint i=0;i<numPass;i++)
1126 pIG->updateCoords ();
1128 updateCoordCalled= true;
1130 // If the group need to update pos each frame (eg: CGroupInScene),
1131 // and updateCoords not called
1132 if(pIG->getParent()==rMG.Group && !updateCoordCalled && pIG->isNeedFrameUpdatePos())
1134 // This Group will compute the delta to apply.
1135 pIG->onFrameUpdateWindowPos(0,0);
1142 if ( getPointer() != NULL)
1143 getPointer()->updateCoords();
1148 if (bRecomputeCtrlUnderPtr)
1150 H_AUTO ( RZ_Interface_RecomputeCtrlUnderPtr )
1151 if ( getPointer() != NULL )
1153 sint32 mx = _Pointer->getX();
1154 sint32 my = _Pointer->getY();
1155 getViewsUnder (mx, my, _ViewsUnderPointer);
1156 getCtrlsUnder (mx, my, _CtrlsUnderPointer);
1157 getGroupsUnder (mx, my, _GroupsUnderPointer);
1158 CInterfaceGroup *ptr = getWindowUnder (mx, my);
1159 _WindowUnder = ptr;
1165 // ----------------------------------------------------------------------------
1166 CInterfaceGroup* CWidgetManager::getWindowForActiveMasterGroup( const std::string &window )
1168 // Search for all elements
1169 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
1171 const SMasterGroup &rMG = _MasterGroups[nMasterGroup];
1172 if (rMG.Group->getActive())
1174 CInterfaceElement *pEL= getElementFromId( rMG.Group->getId() + ":" + window);
1175 if(pEL && pEL->isGroup())
1176 return (CInterfaceGroup*)pEL;
1180 return NULL;
1184 // ***************************************************************************
1185 void CWidgetManager::drawOverExtendViewText()
1187 if( getOverExtendViewText() )
1189 CViewText *vtSrc= dynamic_cast<CViewText*>( getOverExtendViewText() );
1191 CInterfaceGroup *groupOver = getWindowForActiveMasterGroup("over_extend_view_text");
1192 if(groupOver)
1194 CViewText *vtDst = dynamic_cast<CViewText*>(groupOver->getView("text"));
1195 if (vtDst != NULL)
1197 groupOver->setParentPos(vtSrc);
1199 sint32 backupX = groupOver->getX();
1201 // Copy all aspects to the view
1202 vtDst->setLocalized (vtSrc->isLocalized());
1203 vtDst->setText (vtSrc->getText());
1204 vtDst->setFontSize (vtSrc->getFontSize());
1205 vtDst->setColor (vtSrc->getColor());
1206 vtDst->setModulateGlobalColor(vtSrc->getModulateGlobalColor());
1207 vtDst->setShadow(vtSrc->getShadow());
1208 vtDst->setShadowOutline(vtSrc->getShadowOutline());
1209 vtDst->setShadowColor(vtSrc->getShadowColor());
1210 vtDst->setCaseMode(vtSrc->getCaseMode());
1211 vtDst->setUnderlined(vtSrc->getUnderlined());
1213 // setup background
1214 CViewBitmap *pBack= dynamic_cast<CViewBitmap*>(groupOver->getView("midback"));
1215 CViewBitmap *pOutline= dynamic_cast<CViewBitmap*>(groupOver->getView("midoutline"));
1216 if(pBack)
1217 pBack->setColor( getOverExtendViewTextBackColor() );
1218 if(pOutline)
1220 pOutline->setColor(vtSrc->getColor());
1221 pOutline->setModulateGlobalColor(vtSrc->getModulateGlobalColor());
1224 // update one time only to get correct W/H
1225 groupOver->updateCoords ();
1227 // align and clamp to screen coords
1228 sint32 x = -backupX;
1229 if (vtSrc->isClampRight())
1231 x += std::max(0, (groupOver->getXReal() + groupOver->getWReal()) - (groupOver->getParent()->getXReal() + groupOver->getParent()->getWReal()));
1233 else
1235 x += vtDst->getWReal() - vtSrc->getWReal();
1236 if ( x > (groupOver->getXReal() - groupOver->getParent()->getXReal()) )
1238 x -= x - (groupOver->getXReal() - groupOver->getParent()->getXReal());
1241 if (x != 0) groupOver->setX(-x);
1243 // TODO: there should be no overflow on y, unless barely visible and next to screen border
1245 groupOver->updateCoords();
1247 // draw
1248 groupOver->draw ();
1249 // flush layers
1250 CViewRenderer::getInstance()->flush();
1252 // restore backup values
1253 if (x != 0) groupOver->setX(backupX);
1257 // Reset the ptr so at next frame, won't be rendered (but if reset)
1258 setOverExtendViewText( NULL, getOverExtendViewTextBackColor() );
1262 // ----------------------------------------------------------------------------
1263 void CWidgetManager::snapIfClose(CInterfaceGroup *group)
1265 if (!group || _WindowSnapDistance == 0 || _WindowSnapInvert != lastKeyEvent.isShiftDown())
1266 return;
1268 uint hsnap = _WindowSnapDistance;
1269 uint vsnap = _WindowSnapDistance;
1271 sint32 newX = group->getX();
1272 sint32 newY = group->getY();
1274 // new coords for window without snap
1275 // used to calculate distance from target
1276 sint gLeft = newX;
1277 sint gRight = newX + group->getWReal();
1278 sint gTop = newY;
1279 sint gBottom = newY - group->getHReal();
1281 // current window coords as if already snaped
1282 // used to calculate target for snap
1283 sint gLeftR = group->getXReal();
1284 sint gRightR = gLeftR + group->getWReal();
1285 sint gBottomR = group->getYReal();
1286 sint gTopR = gBottomR + group->getHReal();
1288 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
1290 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
1291 if (!rMG.Group->getActive()) continue;
1293 for (uint8 nPriority = WIN_PRIORITY_MAX; nPriority > 0 ; nPriority--)
1295 const std::list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority-1];
1296 std::list<CInterfaceGroup*>::const_reverse_iterator itw;
1297 for (itw = rList.rbegin(); itw != rList.rend(); itw++)
1299 CInterfaceGroup *pIG = *itw;
1300 // do not snap to self, inactive, or not using mouse interaction
1301 if (group == pIG || !(pIG->getActive() && pIG->getUseCursor()))
1302 continue;
1304 // target
1305 sint wLeft = pIG->getXReal();
1306 sint wRight = pIG->getXReal() + pIG->getWReal();
1307 sint wTop = pIG->getYReal() + pIG->getHReal();
1308 sint wBottom = pIG->getYReal();
1309 sint delta;
1311 if (gTopR >= wBottom && gBottomR <= wTop)
1313 delta = abs(gRight - wLeft);
1314 if (delta <= hsnap)
1316 hsnap = delta;
1317 newX = wLeft - group->getWReal();
1320 delta = abs(gLeft - wRight);
1321 if (delta <= hsnap)
1323 hsnap = delta;
1324 newX = wRight;
1327 delta = abs(gLeft - wLeft);
1328 if (delta <= hsnap)
1330 hsnap = delta;
1331 newX = wLeft;
1334 delta = abs(gRight - wRight);
1335 if (delta <= hsnap)
1337 hsnap = delta;
1338 newX = wRight - group->getWReal();
1342 if (gLeftR <= wRight && gRightR >= wLeft)
1344 delta = abs(gTop - wBottom);
1345 if (delta <= vsnap)
1347 vsnap = delta;
1348 newY = wBottom;
1351 delta = abs(gBottom - wTop);
1352 if (delta <= vsnap)
1354 vsnap = delta;
1355 newY = wTop + group->getHReal();
1358 delta = abs(gTop - wTop);
1359 if (delta <= vsnap)
1361 vsnap = delta;
1362 newY = wTop;
1365 delta = abs(gBottom - wBottom);
1366 if (delta <= vsnap)
1368 vsnap = delta;
1369 newY = wBottom + group->getHReal();
1372 }//windows
1373 }//priority
1374 }//master group
1376 group->setX(newX);
1377 group->setY(newY);
1380 // ----------------------------------------------------------------------------
1381 uint CWidgetManager::adjustTooltipPosition( CCtrlBase *newCtrl, CInterfaceGroup *win, THotSpot ttParentRef,
1382 THotSpot ttPosRef, sint32 xParent, sint32 yParent,
1383 sint32 wParent, sint32 hParent )
1385 CCtrlBase::TToolTipParentType parentType= newCtrl->getToolTipParent();
1386 CInterfaceGroup *groupContextHelp =
1387 getWindowForActiveMasterGroup(newCtrl->getContextHelpWindowName());
1389 uint32 _ScreenH, _ScreenW;
1390 CViewRenderer::getInstance()->getScreenSize( _ScreenW, _ScreenH );
1392 if(ttPosRef==Hotspot_TTAuto || ttParentRef==Hotspot_TTAuto)
1394 // NB: keep the special window if type is specialwindow (defined above)
1395 if(!win)
1396 win= newCtrl->getRootWindow();
1397 sint32 xWin= 0;
1398 sint32 yWin= 0;
1399 sint32 wWin= 0;
1400 sint32 hWin= 0;
1401 if(win)
1403 xWin = win->getXReal();
1404 yWin = win->getYReal();
1405 wWin = win->getWReal();
1406 hWin = win->getHReal();
1408 // for Window, display top or bottom according to window pos/size
1409 if(parentType==CCtrlBase::TTWindow || parentType==CCtrlBase::TTSpecialWindow)
1411 sint32 top= (sint32)_ScreenH - (yWin+hWin);
1412 sint32 bottom= yWin;
1413 if(top>bottom)
1415 ttParentRef= Hotspot_TL;
1416 ttPosRef= Hotspot_BL;
1418 else
1420 ttParentRef= Hotspot_BL;
1421 ttPosRef= Hotspot_TL;
1424 // for Ctrl, display top, left or right according to window pos/size
1425 else if(parentType==CCtrlBase::TTCtrl)
1427 sint32 right= (sint32)_ScreenW - (xWin+wWin);
1428 sint32 left= xWin;
1429 if(right>left)
1431 ttParentRef= Hotspot_TR;
1432 ttPosRef= Hotspot_BL;
1434 else
1436 ttParentRef= Hotspot_TL;
1437 ttPosRef= Hotspot_BR;
1440 else
1442 // default (mouse)
1443 ttParentRef= Hotspot_BL;
1444 ttPosRef= Hotspot_BL;
1448 // **** compute coordinates of the tooltip
1449 sint32 x= xParent;
1450 sint32 y= yParent;
1451 if (ttParentRef & Hotspot_Mx)
1452 y += hParent/2;
1453 if (ttParentRef & Hotspot_Tx)
1454 y += hParent;
1455 if (ttParentRef & Hotspot_xM)
1456 x += wParent/2;
1457 if (ttParentRef & Hotspot_xR)
1458 x += wParent;
1460 // adjust according to self posref
1461 if (ttPosRef & Hotspot_Mx)
1462 y -= groupContextHelp->getHReal()/2;
1463 if (ttPosRef & Hotspot_Tx)
1464 y -= groupContextHelp->getHReal();
1465 if (ttPosRef & Hotspot_xM)
1466 x -= groupContextHelp->getWReal()/2;
1467 if (ttPosRef & Hotspot_xR)
1468 x -= groupContextHelp->getWReal();
1471 // **** clamp to screen coords, and set
1472 uint clampCount = 0;
1474 if ((x+groupContextHelp->getW()) > groupContextHelp->getParent()->getWReal())
1476 ++ clampCount;
1477 x = groupContextHelp->getParent()->getWReal() - groupContextHelp->getW();
1479 if (x < 0)
1481 x = 0;
1482 ++ clampCount;
1484 if ((y+groupContextHelp->getH()) > groupContextHelp->getParent()->getHReal())
1486 y = groupContextHelp->getParent()->getHReal() - groupContextHelp->getH();
1487 ++ clampCount;
1489 if (y < 0)
1491 y = 0;
1492 ++ clampCount;
1495 // update coords 3 times is required
1496 groupContextHelp->setX (x);
1497 groupContextHelp->setY (y);
1498 groupContextHelp->updateCoords ();
1499 groupContextHelp->updateCoords ();
1500 groupContextHelp->updateCoords ();
1502 return clampCount;
1505 // ----------------------------------------------------------------------------
1506 void CWidgetManager::updateTooltipCoords()
1508 updateTooltipCoords( getCurContextHelp() );
1511 void CWidgetManager::updateTooltipCoords( CCtrlBase *newCtrl )
1513 if (!newCtrl) return;
1514 if (!newCtrl->getInvalidCoords()) return;
1516 CInterfaceGroup *groupContextHelp =
1517 getWindowForActiveMasterGroup(newCtrl->getContextHelpWindowName());
1519 if(groupContextHelp)
1521 CViewText *pTxt = (CViewText*)groupContextHelp->getView("text");
1522 if (pTxt != NULL)
1524 pTxt->setTextFormatTaged(_ContextHelpText);
1525 // update only to get correct W/H
1526 groupContextHelp->updateCoords ();
1529 // **** Compute parent coordinates
1530 CCtrlBase::TToolTipParentType parentType= newCtrl->getToolTipParent();
1531 CInterfaceGroup *win= NULL;
1532 // adjust to the mouse by default
1533 sint32 xParent= getPointer()->getX();
1534 sint32 yParent= getPointer()->getY();
1535 sint32 wParent= 0;
1536 sint32 hParent= 0;
1537 // adjust to the window
1538 if(parentType==CCtrlBase::TTWindow || parentType==CCtrlBase::TTSpecialWindow)
1540 if(parentType==CCtrlBase::TTWindow)
1541 win= newCtrl->getRootWindow();
1542 else
1543 win =
1544 dynamic_cast<CInterfaceGroup*>( getElementFromId(newCtrl->getToolTipSpecialParent()));
1546 if(win)
1548 xParent = win->getXReal();
1549 yParent = win->getYReal();
1550 wParent = win->getWReal();
1551 hParent = win->getHReal();
1553 // Bug...: leave default to pointer
1555 // adjust to the ctrl
1556 else if (parentType==CCtrlBase::TTCtrl)
1558 xParent = newCtrl->getXReal();
1559 yParent = newCtrl->getYReal();
1560 wParent = newCtrl->getWReal();
1561 hParent = newCtrl->getHReal();
1562 // Additionaly, must clip this ctrl with its parent
1563 // (else animals are buggy for instance)
1564 CInterfaceGroup *parent= newCtrl->getParent();
1565 if(parent)
1567 sint32 xClip,yClip,wClip,hClip;
1568 parent->getClip(xClip,yClip,wClip,hClip);
1569 // clip bottom left
1570 xParent= std::max(xParent, xClip);
1571 yParent= std::max(yParent, yClip);
1572 // clip top right
1573 sint32 xrParent= std::min(xParent+ wParent, xClip+wClip);
1574 sint32 ytParent= std::min(yParent+ hParent, yClip+hClip);
1575 wParent= std::max((sint32)0, xrParent-xParent);
1576 hParent= std::max((sint32)0, ytParent-yParent);
1581 // **** resolve auto posref
1582 uint clampCount =
1583 adjustTooltipPosition( newCtrl, win, newCtrl->getToolTipParentPosRef(),
1584 newCtrl->getToolTipPosRef(), xParent, yParent,
1585 wParent, hParent);
1587 if (clampCount != 0)
1589 // try to fallback on alternate tooltip posref
1590 uint altClampCount =
1591 adjustTooltipPosition( newCtrl, win, newCtrl->getToolTipParentPosRefAlt(),
1592 newCtrl->getToolTipPosRefAlt(), xParent, yParent,
1593 wParent, hParent);
1595 if (altClampCount > clampCount)
1597 // worst ? resume to first posref
1598 adjustTooltipPosition( newCtrl, win, newCtrl->getToolTipParentPosRef(),
1599 newCtrl->getToolTipPosRef(), xParent, yParent,
1600 wParent, hParent);
1607 // ------------------------------------------------------------------------------------------------
1608 void CWidgetManager::updateContextHelpColors()
1610 // TODO: should only update when dbProp changes and not on every frame
1611 if (!_ContextHelpContentAlphaDB)
1613 _ContextHelpContentAlphaDB = CDBManager::getInstance()->getDbProp("UI:SAVE:CONTEXT_HELP_CONTENT_ALPHA");
1614 _ContextHelpContainerColorDB = CDBManager::getInstance()->getDbProp("UI:SAVE:CONTEXT_HELP_CONTAINER_COLOR");
1615 _ContextHelpContainerAlphaDB = CDBManager::getInstance()->getDbProp("UI:SAVE:CONTEXT_HELP_CONTAINER_ALPHA");
1618 // tooltip content alpha
1619 _ContextHelpContentAlpha = (uint8) _ContextHelpContentAlphaDB->getValue32();
1621 // tooltip container (background) color
1622 CInterfaceProperty ip;
1623 ip.setNodePtr(_ContextHelpContainerColorDB);
1624 _ContextHelpContainerColor = ip.getRGBA();
1625 _ContextHelpContainerColor.A = (uint8) _ContextHelpContainerAlphaDB->getValue32();
1628 // ------------------------------------------------------------------------------------------------
1629 void CWidgetManager::disableContextHelp()
1631 setCurContextHelp( NULL );
1632 _DeltaTimeStopingContextHelp = 0;
1635 // ------------------------------------------------------------------------------------------------
1636 void CWidgetManager::disableContextHelpForControl( CCtrlBase *pCtrl )
1638 if( pCtrl == NULL )
1639 return;
1641 if( getCurContextHelp() == pCtrl )
1642 disableContextHelp();
1645 // ----------------------------------------------------------------------------
1646 CCtrlBase* CWidgetManager::getNewContextHelpCtrl()
1648 // get the top most ctrl under us
1649 CCtrlBase *best = NULL;
1650 sint8 bestRenderLayer = -128;
1652 for (sint i = (sint32)_CtrlsUnderPointer.size()-1; i>=0; i--)
1654 CCtrlBase *pICL = _CtrlsUnderPointer[i];
1655 if (pICL->getRenderLayer() > bestRenderLayer)
1657 if ((pICL->getActive()) && (!pICL->emptyContextHelp()))
1659 if (!getPointer()) return pICL;
1660 sint32 mx, my;
1661 getPointer()->getPointerPos(mx, my);
1662 if (pICL->preciseHitTest(mx, my))
1664 best = pICL;
1665 bestRenderLayer = pICL->getRenderLayer();
1670 if (!best)
1672 // if a control was not found, try with the groups
1673 sint8 bestRenderLayer = -128;
1675 for (sint i = (sint32)_GroupsUnderPointer.size()-1; i>=0; i--)
1677 CCtrlBase *pICL = _GroupsUnderPointer[i];
1678 if (pICL->getRenderLayer() > bestRenderLayer)
1680 if ((pICL->getActive()) && (!pICL->emptyContextHelp()))
1682 if (!getPointer()) return pICL;
1683 sint32 mx, my;
1684 getPointer()->getPointerPos(mx, my);
1685 if (pICL->preciseHitTest(mx, my))
1687 best = pICL;
1688 bestRenderLayer = pICL->getRenderLayer();
1694 return best;
1697 // ----------------------------------------------------------------------------
1698 void CWidgetManager::drawContextHelp ()
1700 if (!getPointer() || !_ContextHelpActive)
1701 return;
1704 sint32 x = getPointer()->getX();
1705 sint32 y = getPointer()->getY();
1708 // ***************
1709 // **** try to disable
1710 // ***************
1711 // test disable first, so can recheck asap if another present. see below
1712 CCtrlBase *_CurCtrlContextHelp = getCurContextHelp();
1713 if( _CurCtrlContextHelp)
1715 if(x!=_LastXContextHelp || y!=_LastYContextHelp)
1717 // May change of ctrl!! => disable context help
1718 CCtrlBase *newCtrl= getNewContextHelpCtrl();
1719 if(newCtrl!=_CurCtrlContextHelp)
1721 // disable
1722 disableContextHelp();
1726 // Check if _CurCtrlContextHelp is visible
1727 if (_CurCtrlContextHelp == NULL)
1729 disableContextHelp();
1731 else
1733 bool bVisible = true;
1734 if (_CurCtrlContextHelp->getActive() == false)
1735 bVisible = false;
1736 CInterfaceGroup *pParent = _CurCtrlContextHelp->getParent();
1737 while (pParent != NULL)
1739 if (pParent->getActive() == false)
1740 bVisible = false;
1741 pParent = pParent->getParent();
1743 if (!bVisible)
1744 disableContextHelp();
1749 // ***************
1750 // **** try to acquire
1751 // ***************
1752 if(!_CurCtrlContextHelp)
1754 // get the ctrl of interset
1755 CCtrlBase *newCtrl= getNewContextHelpCtrl();
1757 if(x==_LastXContextHelp && y==_LastYContextHelp)
1758 _DeltaTimeStopingContextHelp += ( interfaceTimes.frameDiffMs / 1000.0f );
1759 else
1760 _DeltaTimeStopingContextHelp = 0;
1762 // If reach the time limit
1763 if( ( _DeltaTimeStopingContextHelp > _MaxTimeStopingContextHelp )
1764 || (newCtrl && newCtrl->wantInstantContextHelp()))
1766 // if present, get the ctx help text.
1767 if(newCtrl)
1769 // get the text
1770 //newCtrl->getContextHelpToolTip(_ContextHelpText);
1771 newCtrl->getContextHelp( getContextHelpText() );
1772 // UserDefined context help
1773 if( !newCtrl->getContextHelpActionHandler().empty() )
1775 CAHManager::getInstance()->runActionHandler(newCtrl->getContextHelpActionHandler(), newCtrl, newCtrl->getContextHelpAHParams() );
1778 // If the text is finally empty (Special AH case), abort
1779 if( getContextHelpText().empty() )
1780 newCtrl= NULL;
1783 // not present? wait furthermore to move the mouse.
1784 if(!newCtrl)
1785 _DeltaTimeStopingContextHelp= 0;
1786 else
1788 // enable
1789 setCurContextHelp( newCtrl );
1790 newCtrl->invalidateCoords();
1795 updateTooltipCoords(_CurCtrlContextHelp);
1798 // ***************
1799 // **** display
1800 // ***************
1801 if(_CurCtrlContextHelp)
1803 CInterfaceGroup *groupContextHelp =
1804 getWindowForActiveMasterGroup(_CurCtrlContextHelp->getContextHelpWindowName());
1806 if(groupContextHelp)
1808 updateContextHelpColors();
1810 // setup new global color for tooltip
1811 NLMISC::CRGBA oldGlobalColorForContent = getGlobalColorForContent();
1812 NLMISC::CRGBA newGlobalColorForContent = oldGlobalColorForContent;
1813 newGlobalColorForContent.A = _ContextHelpContentAlpha;
1814 setGlobalColorForContent(newGlobalColorForContent);
1816 // container alpha
1817 CViewBase *pVB = groupContextHelp->getView("midcolor");
1818 if (pVB)
1820 CViewBitmap *bg = dynamic_cast<CViewBitmap*>(pVB);
1821 if (bg)
1823 bg->setColor(_ContextHelpContainerColor);
1827 /** If there's a modal box around, should be sure that the context help doesn't intersect it.
1828 * If this is the case, we just disable it, unless the tooltip was generated by the current modal window
1830 if ( hasModal() )
1832 CInterfaceGroup *mw = getModal().ModalWindow;
1833 if (mw && mw->isIn(*groupContextHelp))
1835 if (_CurCtrlContextHelp->isSonOf(mw))
1837 groupContextHelp->executeLuaScriptOnDraw();
1838 groupContextHelp->draw ();
1839 // flush layers
1840 CViewRenderer::getInstance()->flush();
1843 else
1845 groupContextHelp->executeLuaScriptOnDraw();
1846 groupContextHelp->draw ();
1847 // flush layers
1848 CViewRenderer::getInstance()->flush();
1851 else
1853 groupContextHelp->executeLuaScriptOnDraw();
1854 groupContextHelp->draw ();
1855 // flush layers
1856 CViewRenderer::getInstance()->flush();
1859 // restore global color
1860 setGlobalColorForContent(oldGlobalColorForContent);
1864 // Bkup movement
1865 _LastXContextHelp= x;
1866 _LastYContextHelp= y;
1869 void CWidgetManager::setContextHelpActive(bool active)
1871 if (!active)
1873 disableContextHelp();
1875 _ContextHelpActive = active;
1879 // ------------------------------------------------------------------------------------------------
1880 void CWidgetManager::getNewWindowCoordToNewScreenSize( sint32 &x, sint32 &y, sint32 w, sint32 h,
1881 sint32 newScreenW, sint32 newScreenH) const
1883 // NB: x is relative to Left of the window (and Left of screen)
1884 // NB: y is relative to Top of the window (but Bottom of screen)
1887 The goal here is to move the window so it fit the new resolution
1888 But we don't want to change its size (because somes windows just can't)
1889 We also cannot use specific code according to each window because user may completly modify his interface
1890 So the strategy is to dectect on which "side" (or center) the window is the best sticked,
1891 and then just move the window according to this position
1894 // *** First detect from which screen position the window is the more sticked (borders or center)
1895 // In X: best hotspot is left, middle or right?
1896 sint32 posXToLeft= x;
1897 sint32 posXToMiddle= x+w/2-_ScreenW/2;
1898 sint32 posXToRight= _ScreenW-(x+w);
1899 sint32 bestXHotSpot= Hotspot_xL;
1900 sint32 bestXPosVal= posXToLeft;
1901 if(abs(posXToMiddle) < bestXPosVal)
1903 bestXHotSpot= Hotspot_xM;
1904 bestXPosVal= abs(posXToMiddle);
1906 if(posXToRight < bestXPosVal)
1908 bestXHotSpot= Hotspot_xR;
1909 bestXPosVal= posXToRight;
1912 // Same In Y: best hotspot is bottom, middle or top?
1913 // remember here that y is the top of window (relative to bottom of screen)
1914 sint32 posYToBottom= y-h;
1915 sint32 posYToMiddle= y-h/2-_ScreenH/2;
1916 sint32 posYToTop= _ScreenH-y;
1917 sint32 bestYHotSpot= Hotspot_Bx;
1918 sint32 bestYPosVal= posYToBottom;
1919 const sint32 middleYWeight= 6; // Avoid default Mission/Team/Map/ContactList positions to be considered as "middle"
1920 if(abs(posYToMiddle)*middleYWeight < bestYPosVal)
1922 bestYHotSpot= Hotspot_Mx;
1923 bestYPosVal= abs(posYToMiddle)*middleYWeight;
1925 if(posYToTop < bestYPosVal)
1927 bestYHotSpot= Hotspot_Tx;
1928 bestYPosVal= posYToTop;
1931 // *** According to best matching hotspot, and new screen resolution, move the window
1932 // x
1933 if(bestXHotSpot==Hotspot_xM)
1934 x= newScreenW/2 + posXToMiddle - w/2;
1935 else if(bestXHotSpot==Hotspot_xR)
1936 x= newScreenW - posXToRight - w;
1937 // y
1938 if(bestYHotSpot==Hotspot_Mx)
1939 y= newScreenH/2 + posYToMiddle + h/2;
1940 else if(bestYHotSpot==Hotspot_Tx)
1941 y= newScreenH - posYToTop;
1944 // ------------------------------------------------------------------------------------------------
1945 void CWidgetManager::moveAllWindowsToNewScreenSize(uint32 newScreenW, uint32 newScreenH, bool fixCurrentUI)
1947 std::vector< CWidgetManager::SMasterGroup > &_MasterGroups = getAllMasterGroup();
1948 // If resolutions correctly setuped, and really different from new setup
1949 if( _ScreenW >0 && _ScreenH>0 &&
1950 newScreenW >0 && newScreenH>0 &&
1951 ( _ScreenW != newScreenW || _ScreenH != newScreenH)
1954 // *** Do it for the Active Desktop (if wanted)
1955 if(fixCurrentUI)
1957 // only for ui:interface (not login, nor outgame)
1958 for (uint nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
1960 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
1961 if (!rMG.Group || rMG.Group->getId() != "ui:interface")
1962 continue;
1964 // For all priorities, but the worldspace one
1965 for (uint8 nPriority = 0; nPriority < WIN_PRIORITY_MAX; nPriority++)
1967 if (nPriority==WIN_PRIORITY_WORLD_SPACE)
1968 continue;
1970 // For All windows (only layer 0 group container)
1971 std::list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
1972 std::list<CInterfaceGroup*>::const_iterator itw;
1973 for (itw = rList.begin(); itw != rList.end(); itw++)
1975 CInterfaceGroup *pIG = *itw;
1976 if(!pIG->isGroupContainer())
1977 continue;
1978 CGroupContainer *gc= dynamic_cast<CGroupContainer*>(pIG);
1979 if(gc->getLayerSetup()!=0)
1980 continue;
1981 // should all be BL / TL
1982 if(gc->getParentPosRef()!=Hotspot_BL || gc->getPosRef()!=Hotspot_TL)
1983 continue;
1985 // Get current window coordinates
1986 sint32 x= pIG->getX(); // x is relative to Left of the window
1987 sint32 y= pIG->getY(); // y is relative to Top of the window
1988 sint32 w= pIG->getW(false); // the window may be hid, still get the correct(or estimated) W
1989 sint32 h= pIG->getH(false); // the window may be hid, still get the correct(or estimated) H
1991 // Compute the new coordinate
1992 getNewWindowCoordToNewScreenSize(x, y, w, h, newScreenW, newScreenH);
1994 // Change
1995 pIG->setX(x);
1996 pIG->setY(y);
2002 std::vector< INewScreenSizeHandler* >::iterator itr;
2003 for( itr = newScreenSizeHandlers.begin(); itr != newScreenSizeHandlers.end(); ++itr )
2005 INewScreenSizeHandler *handler = *itr;
2006 handler->process( newScreenW, newScreenH );
2010 // Now those are the last screen coordinates used for window position correction
2011 if(newScreenW >0 && newScreenH>0)
2013 _ScreenW = newScreenW;
2014 _ScreenH = newScreenH;
2018 class InvalidateTextVisitor : public CInterfaceElementVisitor
2020 public:
2021 InvalidateTextVisitor( bool reset)
2023 this->reset = reset;
2026 void visitGroup( CInterfaceGroup *group )
2028 const std::vector< CViewBase* > &vs = group->getViews();
2029 for( std::vector< CViewBase* >::const_iterator itr = vs.begin(); itr != vs.end(); ++itr )
2031 CViewText *vt = dynamic_cast< CViewText* >( *itr );
2032 if( vt != NULL )
2034 if( reset )
2035 vt->resetTextIndex();
2036 vt->updateTextContext();
2041 private:
2042 bool reset;
2045 // ------------------------------------------------------------------------------------------------
2046 void CWidgetManager::updateAllLocalisedElements()
2049 uint32 nMasterGroup;
2051 uint32 w, h;
2052 CViewRenderer::getInstance()->checkNewScreenSize ();
2053 CViewRenderer::getInstance()->getScreenSize (w, h);
2055 // Update ui:* (limit the master containers to the height of the screen)
2056 for (nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
2058 SMasterGroup &rMG = _MasterGroups[nMasterGroup];
2059 rMG.Group->setW (w);
2060 rMG.Group->setH (h);
2062 CViewRenderer::getInstance()->setClipWindow(0, 0, w, h);
2064 bool scaleChanged = _InterfaceScale != CViewRenderer::getInstance()->getInterfaceScale();
2065 if (scaleChanged)
2067 _InterfaceScale = CViewRenderer::getInstance()->getInterfaceScale();
2068 notifyInterfaceScaleWatchers();
2071 // If all conditions are OK, move windows so they fit correctly with new screen size
2072 // Do this work only InGame when Config is loaded
2073 moveAllWindowsToNewScreenSize(w,h,true);
2075 // Invalidate coordinates of all Windows of each MasterGroup
2076 for (nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
2078 SMasterGroup &rMG = _MasterGroups[nMasterGroup];
2080 InvalidateTextVisitor inv( false);
2082 rMG.Group->visitGroupAndChildren( &inv );
2083 rMG.Group->invalidateCoords ();
2084 for (uint8 nPriority = 0; nPriority < WIN_PRIORITY_MAX; nPriority++)
2086 std::list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
2087 std::list<CInterfaceGroup*>::const_iterator itw;
2088 for (itw = rList.begin(); itw != rList.end(); itw++)
2090 CInterfaceGroup *pIG = *itw;
2091 pIG->visitGroupAndChildren( &inv );
2092 pIG->invalidateCoords ();
2097 // setup for all
2098 for (nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
2100 SMasterGroup &rMG = _MasterGroups[nMasterGroup];
2101 bool bActive = rMG.Group->getActive ();
2102 rMG.Group->setActive (true);
2103 rMG.Group->updateCoords ();
2104 rMG.Group->setActive (bActive);
2107 // update coords one
2108 checkCoords();
2110 // Action by default (container opening
2111 for (nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
2113 SMasterGroup &rMG = _MasterGroups[nMasterGroup];
2114 rMG.Group->launch ();
2119 void CWidgetManager::drawViews( NL3D::UCamera camera )
2121 CViewRenderer::getInstance()->activateWorldSpaceMatrix (false);
2122 NL3D::UDriver *driver = CViewRenderer::getInstance()->getDriver();
2124 // If an element has captured the keyboard, make sure it is alway visible (all parent windows active)
2125 if( getCaptureKeyboard() != NULL)
2127 CCtrlBase *cb = getCaptureKeyboard();
2130 if (!cb->getActive())
2132 setCaptureKeyboard(NULL);
2133 break;
2135 cb = cb->getParent();
2137 while (cb);
2140 // Check if screen size changed
2141 uint32 w, h;
2142 CViewRenderer::getInstance()->checkNewScreenSize ();
2143 CViewRenderer::getInstance()->getScreenSize (w, h);
2144 if ((w != _ScreenW) || (h != _ScreenH))
2146 // No Op if screen minimized
2147 if(w!=0 && h!=0 && !CViewRenderer::getInstance()->isMinimized())
2149 updateAllLocalisedElements ();
2150 setScreenWH(w, h);
2154 // Update global color from database
2155 if (!_RProp)
2157 _RProp = CDBManager::getInstance()->getDbProp("UI:SAVE:COLOR:R");
2158 _GProp = CDBManager::getInstance()->getDbProp("UI:SAVE:COLOR:G");
2159 _BProp = CDBManager::getInstance()->getDbProp("UI:SAVE:COLOR:B");
2160 _AProp = CDBManager::getInstance()->getDbProp("UI:SAVE:COLOR:A");
2163 setGlobalColor(NLMISC::CRGBA(
2164 (uint8)_RProp->getValue32(),
2165 (uint8)_GProp->getValue32(),
2166 (uint8)_BProp->getValue32(),
2167 (uint8)_AProp->getValue32()));
2169 NLMISC::CRGBA c = getGlobalColorForContent();
2170 NLMISC::CRGBA gc = getGlobalColor();
2171 c.R = gc.R;
2172 c.G = gc.G;
2173 c.B = gc.B;
2174 c.A = (uint8) (( (uint16) c.A * (uint16) getContentAlpha() ) >> 8);
2175 setGlobalColorForContent( c );
2177 // Update global alphaS from database
2178 updateGlobalAlphas();
2180 /* Draw all the windows
2181 To minimize texture swapping, we first sort per Window, then we sort per layer, then we render per Global Texture.
2182 Computed String are rendered in on big drawQuads at last part of each layer
2184 CDBManager::getInstance()->flushObserverCalls();
2186 for (uint32 nMasterGroup = 0; nMasterGroup < _MasterGroups.size(); nMasterGroup++)
2188 CWidgetManager::SMasterGroup &rMG = _MasterGroups[nMasterGroup];
2189 if (rMG.Group->getActive())
2191 // Sort world space windows
2192 rMG.sortWorldSpaceGroup ();
2194 for (uint8 nPriority = 0; nPriority < WIN_PRIORITY_MAX; ++nPriority)
2196 if ( (nPriority == WIN_PRIORITY_WORLD_SPACE) && !camera.empty())
2198 driver->setViewMatrix( NL3D::CMatrix::Identity);
2199 driver->setModelMatrix( NL3D::CMatrix::Identity);
2200 driver->setFrustum(camera.getFrustum());
2201 CViewRenderer::getInstance()->activateWorldSpaceMatrix (true);
2204 std::list<CInterfaceGroup*> &rList = rMG.PrioritizedWindows[nPriority];
2205 std::list<CInterfaceGroup*>::const_iterator itw;
2207 for (itw = rList.begin(); itw != rList.end(); itw++)
2209 CInterfaceGroup *pIG = *itw;
2210 if( pIG ) // TODO: debug null pointer in PrioritizedWindows list
2212 if (pIG->getActive())
2214 // Draw all the elements of this window in the layers in ViewRendered
2215 pIG->draw ();
2216 // flush the layers
2217 CViewRenderer::getInstance()->flush ();
2222 if( draggedElement != NULL )
2224 CInterfaceElement *e = draggedElement;
2225 static_cast< CViewBase* >( e )->draw();
2228 if ( (nPriority == WIN_PRIORITY_WORLD_SPACE) && !camera.empty())
2230 driver->setMatrixMode2D11();
2231 CViewRenderer::getInstance()->activateWorldSpaceMatrix (false);
2237 CDBManager::getInstance()->flushObserverCalls();
2239 // draw the special over extend text
2240 drawOverExtendViewText();
2242 // draw the context help
2243 drawContextHelp ();
2245 std::vector< IOnWidgetsDrawnHandler* >::iterator itr;
2246 for( itr = onWidgetsDrawnHandlers.begin(); itr != onWidgetsDrawnHandlers.end(); ++itr )
2248 IOnWidgetsDrawnHandler *handler = *itr;
2249 handler->process();
2252 // Draw the pointer and DND Item
2253 if (getPointer() != NULL)
2255 if (getPointer()->getActive())
2256 getPointer()->draw ();
2259 if (CInterfaceElement::getEditorMode())
2261 for(uint i = 0; i < editorSelection.size(); ++i)
2263 CInterfaceElement *e = getElementFromId(editorSelection[i]);
2264 if (e != NULL)
2265 e->drawHighlight();
2269 // flush layers
2270 CViewRenderer::getInstance()->flush();
2272 // todo hulud remove Return in 2d world
2273 driver->setMatrixMode2D11();
2275 CDBManager::getInstance()->flushObserverCalls();
2278 bool CWidgetManager::handleEvent( const CEventDescriptor &evnt )
2280 // Check if we can receive events (no anims!)
2281 for( uint32 i = 0; i < activeAnims.size(); ++i )
2282 if( activeAnims[i]->isDisableButtons() )
2283 return false;
2285 bool handled = false;
2287 if( evnt.getType() == CEventDescriptor::system )
2289 handleSystemEvent( evnt );
2291 else
2292 if (evnt.getType() == CEventDescriptor::key)
2294 handled = handleKeyboardEvent( evnt );
2296 else if (evnt.getType() == CEventDescriptor::mouse )
2298 handled = handleMouseEvent( evnt );
2301 CDBManager::getInstance()->flushObserverCalls();
2303 return handled;
2306 bool CWidgetManager::handleSystemEvent( const CEventDescriptor &evnt )
2308 const CEventDescriptorSystem &systemEvent = reinterpret_cast< const CEventDescriptorSystem& >( evnt );
2309 if( systemEvent.getEventTypeExtended() == CEventDescriptorSystem::setfocus )
2311 if( getCapturePointerLeft() != NULL )
2313 getCapturePointerLeft()->handleEvent( evnt );
2314 setCapturePointerLeft( NULL );
2317 if( getCapturePointerRight() != NULL )
2319 getCapturePointerRight()->handleEvent( evnt );
2320 setCapturePointerRight( NULL );
2323 if( _CapturedView != NULL )
2325 _CapturedView->handleEvent( evnt );
2326 _CapturedView = NULL;
2330 return true;
2333 bool CWidgetManager::handleKeyboardEvent( const CEventDescriptor &evnt )
2335 bool handled = false;
2337 CEventDescriptorKey &eventDesc = (CEventDescriptorKey&)evnt;
2339 //_LastEventKeyDesc = eventDesc;
2341 // Any Key event disable the ContextHelp
2342 disableContextHelp();
2344 // Hide menu if the key is pushed
2345 // if ((eventDesc.getKeyEventType() == CEventDescriptorKey::keydown) && !_ModalStack.empty() && !eventDesc.getKeyAlt() && !eventDesc.getKeyCtrl() && !eventDesc.getKeyShift())
2346 // Hide menu (or popup menu) is ESCAPE pressed
2347 if( eventDesc.getKeyEventType() == CEventDescriptorKey::keydown && eventDesc.getKey() == NLMISC::KeyESCAPE )
2349 if( hasModal() )
2351 SModalWndInfo mwi = getModal();
2352 if (mwi.ModalExitKeyPushed)
2353 disableModalWindow();
2355 handled= true;
2358 CInterfaceGroup *win= getLastEscapableTopWindow();
2359 if ( win )
2361 // Manage "quit window" If the Key is ESCAPE, no captureKeyboard
2362 // Get the last escapable active top window. NB: this is ergonomically better.
2364 // If the window is a modal, must pop it.
2365 if( dynamic_cast<CGroupModal*>(win) )
2367 if(!win->getAHOnEscape().empty())
2368 CAHManager::getInstance()->runActionHandler(win->getAHOnEscape(), win, win->getAHOnEscapeParams());
2369 popModalWindow();
2370 handled= true;
2372 // else just disable it.
2373 // Special case: leave the escape Key to the CaptureKeyboard .
2374 else if( !getCaptureKeyboard() )
2376 if(!win->getAHOnEscape().empty())
2377 CAHManager::getInstance()->runActionHandler(win->getAHOnEscape(), win, win->getAHOnEscapeParams());
2378 win->setActive(false);
2379 handled= true;
2384 // Manage complex "Enter"
2385 if( eventDesc.getKeyEventType() == CEventDescriptorKey::keychar && eventDesc.getChar() == NLMISC::KeyRETURN && !eventDesc.getKeyCtrl() )
2387 // If the top window has Enter AH
2388 CInterfaceGroup *tw= getTopWindow();
2389 if(tw && !tw->getAHOnEnter().empty())
2391 // if the captured keyboard is in this Modal window, then must handle him in priority
2392 if( getCaptureKeyboard() && getCaptureKeyboard()->getRootWindow()==tw)
2394 bool result = getCaptureKeyboard()->handleEvent(evnt);
2395 CDBManager::getInstance()->flushObserverCalls();
2396 return result;
2398 else
2400 // The window or modal control the OnEnter. Execute, and don't go to the chat.
2401 CAHManager::getInstance()->runActionHandler(tw->getAHOnEnter(), tw, tw->getAHOnEnterParams());
2402 handled= true;
2406 // else the 'return' key bring back to the last edit box (if possible)
2407 CCtrlBase *oldCapture = getOldCaptureKeyboard() ? getOldCaptureKeyboard() : getDefaultCaptureKeyboard();
2408 if ( getCaptureKeyboard() == NULL && oldCapture && !handled)
2410 /* If the editbox does not want to recover focus, then abort. This possibility is normaly avoided
2411 through setCaptureKeyboard() which already test getRecoverFocusOnEnter(), but it is still possible
2412 for the default capture (main chat) or the old captured window to not want to recover
2413 (temporary Read Only chat for instance)
2415 if(!dynamic_cast<CGroupEditBoxBase*>(oldCapture) ||
2416 dynamic_cast<CGroupEditBoxBase*>(oldCapture)->getRecoverFocusOnEnter())
2418 setCaptureKeyboard( oldCapture );
2419 notifyElementCaptured(getCaptureKeyboard() );
2420 // make sure all parent windows are active
2421 CCtrlBase *cb = getCaptureKeyboard();
2422 CGroupContainer *lastContainer = NULL;
2423 nlassert(cb);
2424 for(;;)
2426 CGroupContainer *gc = dynamic_cast<CGroupContainer *>(cb);
2427 if (gc) lastContainer = gc;
2428 cb->forceOpen();
2429 if (cb->getParent())
2431 cb = cb->getParent();
2433 else
2435 cb->invalidateCoords();
2436 break;
2439 if (lastContainer)
2441 setTopWindow(lastContainer);
2442 lastContainer->enableBlink(1);
2444 handled= true;
2449 // General case: handle it in the Captured keyboard
2450 if (!handled && getCaptureKeyboard() != NULL)
2452 bool result = getCaptureKeyboard()->handleEvent(evnt);
2453 CDBManager::getInstance()->flushObserverCalls();
2454 return result;
2457 if (!handled && eventDesc.getKeyEventType() == CEventDescriptorKey::keydown && eventDesc.getKey() == NLMISC::KeyESCAPE)
2459 CAHManager::getInstance()->runActionHandler("enter_modal", NULL, "group=ui:interface:quit_dialog");
2460 handled = true;
2463 lastKeyEvent = eventDesc;
2465 return handled;
2468 bool CWidgetManager::handleMouseEvent( const CEventDescriptor &evnt )
2470 bool handled = false;
2472 CEventDescriptorMouse &eventDesc = (CEventDescriptorMouse&)evnt;
2474 if( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown )
2475 _Pointer->setButtonState( static_cast< NLMISC::TMouseButton >( _Pointer->getButtonState() | NLMISC::leftButton ) );
2476 else
2477 if( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown )
2478 _Pointer->setButtonState( static_cast< NLMISC::TMouseButton >( _Pointer->getButtonState() | NLMISC::rightButton ) );
2479 else
2480 if( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftup )
2481 _Pointer->setButtonState( static_cast< NLMISC::TMouseButton >( _Pointer->getButtonState() & ~NLMISC::leftButton ) );
2482 if( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightup )
2483 _Pointer->setButtonState( static_cast< NLMISC::TMouseButton >( _Pointer->getButtonState() & ~NLMISC::rightButton ) );
2485 if( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mousemove )
2486 handleMouseMoveEvent( eventDesc );
2488 eventDesc.setX( _Pointer->getX() );
2489 eventDesc.setY( _Pointer->getY() );
2491 if( CInterfaceElement::getEditorMode() )
2493 // Let's pretend we've handled the event... or actually we have!
2494 if( ( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown ) ||
2495 ( eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightup ) )
2496 return true;
2499 if( isMouseHandlingEnabled() )
2501 // First thing to do : Capture handling
2502 if ( getCapturePointerLeft() != NULL)
2503 handled|= getCapturePointerLeft()->handleEvent(evnt);
2505 if ( getCapturePointerRight() != NULL &&
2506 getCapturePointerLeft() != getCapturePointerRight() )
2507 handled|= getCapturePointerRight()->handleEvent(evnt);
2509 if( _CapturedView != NULL &&
2510 _CapturedView != getCapturePointerLeft() &&
2511 _CapturedView != getCapturePointerRight() )
2512 _CapturedView->handleEvent( evnt );
2514 CInterfaceGroup *ptr = getWindowUnder (eventDesc.getX(), eventDesc.getY());
2515 setCurrentWindowUnder( ptr );
2517 // Any Mouse event but move disable the ContextHelp
2518 if(eventDesc.getEventTypeExtended() != CEventDescriptorMouse::mousemove)
2520 disableContextHelp();
2523 // get the group under the mouse
2524 CInterfaceGroup *pNewCurrentWnd = getCurrentWindowUnder();
2525 setMouseOverWindow( pNewCurrentWnd != NULL );
2528 NLMISC::CRefPtr<CGroupModal> clickedOutModalWindow;
2530 // modal special features
2531 if ( hasModal() )
2533 CWidgetManager::SModalWndInfo mwi = getModal();
2534 if(mwi.ModalWindow)
2536 // If we are not in "click out" mode so we dont handle controls other than those of the modal
2537 if (pNewCurrentWnd != mwi.ModalWindow && !mwi.ModalExitClickOut)
2539 pNewCurrentWnd = NULL;
2541 else
2543 // If there is a handler on click out launch it
2544 if (pNewCurrentWnd != mwi.ModalWindow)
2545 if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown ||
2546 (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown))
2547 if (!mwi.ModalHandlerClickOut.empty())
2548 CAHManager::getInstance()->runActionHandler(mwi.ModalHandlerClickOut,NULL,mwi.ModalClickOutParams);
2550 // If the current window is not the modal and if must quit on click out
2551 if(pNewCurrentWnd != mwi.ModalWindow && mwi.ModalExitClickOut)
2553 // NB: don't force handle==true because to quit a modal does not avoid other actions
2555 // quit if click outside
2556 if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown ||
2557 (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown))
2559 clickedOutModalWindow = dynamic_cast<CGroupModal *>((CInterfaceGroup*)mwi.ModalWindow);
2560 // disable the modal
2561 popModalWindow();
2562 if ( hasModal() )
2564 // don't handle event unless it is a previous modal window
2565 if( !isPreviousModal( pNewCurrentWnd ) )
2566 pNewCurrentWnd = NULL; // can't handle event before we have left all modal windows
2568 movePointer (0,0); // Reget controls under pointer
2575 // Manage LeftClick.
2576 if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown)
2578 if ((pNewCurrentWnd != NULL) && (!hasModal()) && (pNewCurrentWnd->getOverlappable()))
2580 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(pNewCurrentWnd);
2581 if (pGC != NULL)
2583 if (!pGC->isGrayed()) setTopWindow(pNewCurrentWnd);
2585 else
2587 setTopWindow(pNewCurrentWnd);
2591 bool captured = false;
2593 // must not capture a new element if a sheet is currentlty being dragged.
2594 // This may happen when alt-tab has been used => the sheet is dragged but the left button is up
2595 if (!CCtrlDraggable::getDraggedSheet())
2597 if( CInterfaceElement::getEditorMode() && _GroupSelection )
2599 for( sint32 i = _GroupsUnderPointer.size() - 1; i >= 0; i-- )
2601 CInterfaceGroup *g = _GroupsUnderPointer[ i ];
2602 if( ( g != NULL ) && ( g->isInGroup( pNewCurrentWnd ) ) )
2604 _CapturedView = g;
2605 captured = true;
2606 break;
2611 if( !captured )
2613 // Take the top most control.
2614 uint nMaxDepth = 0;
2615 const std::vector< CCtrlBase* >& _CtrlsUnderPointer = getCtrlsUnderPointer();
2616 for (sint32 i = (sint32)_CtrlsUnderPointer.size()-1; i >= 0; i--)
2618 CCtrlBase *ctrl= _CtrlsUnderPointer[i];
2619 if (ctrl && ctrl->isCapturable() && ctrl->isInGroup( pNewCurrentWnd ) )
2621 if( CInterfaceElement::getEditorMode() && !ctrl->isEditorSelectable() )
2622 continue;
2624 uint d = ctrl->getDepth( pNewCurrentWnd );
2625 if (d > nMaxDepth)
2627 nMaxDepth = d;
2628 setCapturePointerLeft( ctrl );
2629 captured = true;
2635 if( CInterfaceElement::getEditorMode() && !captured )
2637 for( sint32 i = _ViewsUnderPointer.size()-1; i >= 0; i-- )
2639 CViewBase *v = _ViewsUnderPointer[i];
2640 if( ( v != NULL ) && v->isInGroup( pNewCurrentWnd ) )
2642 if( CInterfaceElement::getEditorMode() && !v->isEditorSelectable() )
2643 continue;
2645 _CapturedView = v;
2646 captured = true;
2647 break;
2652 notifyElementCaptured( getCapturePointerLeft() );
2653 if (clickedOutModalWindow && !clickedOutModalWindow->OnPostClickOut.empty())
2655 CAHManager::getInstance()->runActionHandler(clickedOutModalWindow->OnPostClickOut, getCapturePointerLeft(), clickedOutModalWindow->OnPostClickOutParams);
2658 //if found
2659 if ( captured )
2661 // consider clicking on a control implies handling of the event.
2662 handled= true;
2664 if( getCapturePointerLeft() != NULL )
2665 _CapturedView = getCapturePointerLeft();
2667 // handle the capture
2668 _CapturedView->handleEvent( evnt );
2670 else
2672 if( CInterfaceElement::getEditorMode() )
2673 clearEditorSelection();
2677 // Manage RightClick
2678 if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown)
2680 if ((pNewCurrentWnd != NULL) && (!hasModal()) && (pNewCurrentWnd->getOverlappable()))
2682 CGroupContainer *pGC = dynamic_cast<CGroupContainer*>(pNewCurrentWnd);
2683 if (pGC != NULL)
2685 if (!pGC->isGrayed()) setTopWindow(pNewCurrentWnd);
2687 else
2689 setTopWindow(pNewCurrentWnd);
2693 // Take the top most control.
2695 uint nMaxDepth = 0;
2696 const std::vector< CCtrlBase* >& _CtrlsUnderPointer = getCtrlsUnderPointer();
2697 for (sint32 i = (sint32)_CtrlsUnderPointer.size()-1; i >= 0; i--)
2699 CCtrlBase *ctrl= _CtrlsUnderPointer[i];
2700 if (ctrl && ctrl->isCapturable() && ctrl->isInGroup( pNewCurrentWnd ) )
2702 uint d = ctrl->getDepth( pNewCurrentWnd );
2703 if (d > nMaxDepth)
2705 nMaxDepth = d;
2706 setCapturePointerRight( ctrl );
2710 notifyElementCaptured( getCapturePointerRight() );
2711 if (clickedOutModalWindow && !clickedOutModalWindow->OnPostClickOut.empty())
2713 CAHManager::getInstance()->runActionHandler(clickedOutModalWindow->OnPostClickOut, getCapturePointerRight(), clickedOutModalWindow->OnPostClickOutParams);
2716 //if found
2717 if ( getCapturePointerRight() != NULL)
2719 // handle the capture
2720 handled |= getCapturePointerRight()->handleEvent(evnt);
2725 if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightup)
2727 if (!handled)
2728 if (pNewCurrentWnd != NULL)
2729 pNewCurrentWnd->handleEvent(evnt);
2730 if ( getCapturePointerRight() != NULL)
2732 setCapturePointerRight(NULL);
2733 handled= true;
2737 // window handling. if not handled by a control
2738 if (!handled)
2740 if (((pNewCurrentWnd != NULL) && !hasModal()) ||
2741 ((hasModal() && getModal().ModalWindow == pNewCurrentWnd)))
2743 CEventDescriptorMouse ev2 = eventDesc;
2744 sint32 x= eventDesc.getX(), y = eventDesc.getY();
2745 if (pNewCurrentWnd)
2747 pNewCurrentWnd->absoluteToRelative (x, y);
2748 ev2.setX (x); ev2.setY (y);
2749 handled|= pNewCurrentWnd->handleEvent (ev2);
2752 // After handle event of a left click, may set window Top if movable (infos etc...)
2753 //if( (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown) && pNewCurrentWnd->isMovable() )
2754 // setTopWindow(pNewCurrentWnd);
2758 // Put here to let a chance to the window to handle if the capture dont
2759 if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftup)
2761 if ( getCapturePointerLeft() != NULL)
2763 if( !handled )
2765 CCtrlBase *c = getCapturePointerLeft();
2766 c->handleEvent( evnt );
2769 setCapturePointerLeft(NULL);
2770 handled = true;
2773 _CapturedView = NULL;
2775 if( CInterfaceElement::getEditorMode() )
2776 stopDragging();
2780 // If the current window is the modal, may Modal quit. Do it after standard event handle
2781 if(hasModal() && pNewCurrentWnd == getModal().ModalWindow)
2783 // NB: don't force handle==true because to quit a modal does not avoid other actions
2784 CWidgetManager::SModalWndInfo mwi = getModal();
2785 // and if must quit on click right
2786 if(mwi.ModalExitClickR)
2788 // quit if click right
2789 if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightup)
2790 // disable the modal
2791 disableModalWindow();
2794 // and if must quit on click left
2795 if(mwi.ModalExitClickL)
2797 // quit if click right
2798 if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftup)
2799 // disable the modal
2800 disableModalWindow();
2804 // If the mouse is over a window, always consider the event is taken (avoid click behind)
2805 handled|= isMouseOverWindow();
2807 // If mouse click was not on interface and we have keyboard captured, then release keyboard
2808 if (!handled && getCaptureKeyboard() != NULL && eventDesc.getEventTypeExtended() != CEventDescriptorMouse::mousemove)
2809 CWidgetManager::getInstance()->setCaptureKeyboard(NULL);
2812 return handled;
2815 bool CWidgetManager::handleMouseMoveEvent( const CEventDescriptor &eventDesc )
2817 if( getPointer() == NULL )
2818 return false;
2820 if( eventDesc.getType() != CEventDescriptor::mouse )
2821 return false;
2823 const CEventDescriptorMouse &e = static_cast< const CEventDescriptorMouse& >( eventDesc );
2825 if( e.getEventTypeExtended() != CEventDescriptorMouse::mousemove )
2826 return false;
2828 uint32 screenW, screenH;
2829 CViewRenderer::getInstance()->getScreenSize( screenW, screenH );
2830 sint32 oldX = getPointer()->getX();
2831 sint32 oldY = getPointer()->getY();
2833 sint32 x = e.getX();
2834 sint32 y = e.getY();
2836 // These are floats packed in the sint32 from the NEL events that provide them as float
2837 // see comment in CInputHandler::handleMouseMoveEvent
2838 sint32 newX = static_cast< sint32 >( std::floor( *reinterpret_cast< float* >( &x ) * screenW + 0.5f ) );
2839 sint32 newY = static_cast< sint32 >( std::floor( *reinterpret_cast< float* >( &y ) * screenH + 0.5f ) );
2841 if( ( oldX != newX ) || ( oldY != newY ) )
2843 movePointerAbs( newX, newY );
2844 CEventDescriptorMouse &ve = const_cast< CEventDescriptorMouse& >( e );
2845 ve.setX( getPointer()->getX() );
2846 ve.setY( getPointer()->getY() );
2849 if( CInterfaceElement::getEditorMode() )
2851 if( ( _CapturedView != NULL ) && ( draggedElement == NULL ) )
2853 startDragging();
2855 else
2856 if( draggedElement != NULL )
2858 sint32 dx = newX - oldX;
2859 sint32 dy = newY - oldY;
2861 draggedElement->moveBy( dx, dy );
2865 return true;
2868 // ------------------------------------------------------------------------------------------------
2869 bool CWidgetManager::startDragging()
2871 CInterfaceElement *e = NULL;
2873 CInterfaceGroup *g = _CapturedView->getParent();
2874 if( g != NULL )
2876 e = g->takeElement( _CapturedView );
2877 if( e == NULL )
2879 nlinfo( "Something went horribly wrong :(" );
2880 return false;
2883 else
2884 e = _CapturedView;
2886 e->setParent( NULL );
2887 draggedElement = e;
2889 return true;
2892 void CWidgetManager::stopDragging()
2894 if( draggedElement != NULL )
2896 CInterfaceGroup *g = getGroupUnder( draggedElement->getXReal(), draggedElement->getYReal() );
2897 CInterfaceElement *e = draggedElement;
2898 CInterfaceGroup *tw = getTopWindow();
2900 if( g == NULL )
2901 g = tw;
2903 std::string oldid = e->getId();
2905 e->setParent( g );
2906 e->setIdRecurse( e->getShortId() );
2907 e->setParentPos( g );
2908 e->setParentSize( g );
2909 g->addElement( e );
2911 e->alignTo( g );
2912 //e->setName( "==MARKED==" );
2914 draggedElement = NULL;
2916 onWidgetMoved( oldid, e->getId() );
2920 // ------------------------------------------------------------------------------------------------
2921 void CWidgetManager::movePointer (sint32 dx, sint32 dy)
2923 if (!_Pointer)
2924 return;
2926 uint32 nScrW, nScrH;
2927 sint32 oldpx, oldpy, newpx, newpy, disppx, disppy, olddisppx, olddisppy;
2929 CViewRenderer::getInstance()->getScreenSize (nScrW, nScrH);
2930 _Pointer->getPointerPos (oldpx, oldpy);
2932 olddisppx = oldpx;
2933 olddisppy = oldpy;
2935 newpx = oldpx + dx;
2936 newpy = oldpy + dy;
2938 if (newpx < 0) newpx = 0;
2939 if (newpy < 0) newpy = 0;
2940 if (newpx > (sint32)nScrW) newpx = nScrW;
2941 if (newpy > (sint32)nScrH) newpy = nScrH;
2942 dx = newpx - oldpx;
2943 dy = newpy - oldpy;
2945 disppx = newpx;
2946 disppy = newpy;
2948 _Pointer->setPointerPos (newpx, newpy);
2949 _Pointer->setPointerDispPos (disppx, disppy);
2951 // must get back coordinates because of snapping
2952 sint32 mx = _Pointer->getX();
2953 sint32 my = _Pointer->getY();
2954 getViewsUnder (mx, my, _ViewsUnderPointer);
2955 getCtrlsUnder (mx, my, _CtrlsUnderPointer);
2956 getGroupsUnder (mx, my, _GroupsUnderPointer);
2959 // ------------------------------------------------------------------------------------------------
2960 void CWidgetManager::movePointerAbs(sint32 px, sint32 py)
2962 if(!getPointer())
2963 return;
2965 uint32 nScrW, nScrH;
2966 CViewRenderer::getInstance()->getScreenSize (nScrW, nScrH);
2967 NLMISC::clamp(px, 0, (sint32) nScrW);
2968 NLMISC::clamp(py, 0, (sint32) nScrH);
2970 _Pointer->setPointerPos (px, py);
2971 _Pointer->setPointerDispPos (px, py);
2973 getViewsUnder (px, py, _ViewsUnderPointer);
2974 getCtrlsUnder (px, py, _CtrlsUnderPointer);
2975 getGroupsUnder (px, py, _GroupsUnderPointer);
2978 // ***************************************************************************
2979 void CWidgetManager::setCapturePointerLeft(CCtrlBase *c)
2981 _CapturedView = NULL;
2983 // additionally, abort any dragging
2984 if( CCtrlDraggable::getDraggedSheet() != NULL )
2985 CCtrlDraggable::getDraggedSheet()->abortDragging();
2987 _CapturePointerLeft = c;
2988 notifyElementCaptured(c);
2991 // ***************************************************************************
2992 void CWidgetManager::setCapturePointerRight(CCtrlBase *c)
2994 _CapturePointerRight = c;
2995 notifyElementCaptured(c);
2998 // ------------------------------------------------------------------------------------------------
2999 void CWidgetManager::setCaptureKeyboard(CCtrlBase *c)
3001 CGroupEditBoxBase *oldEb= dynamic_cast<CGroupEditBoxBase*>((CCtrlBase*)_CaptureKeyboard);
3002 CGroupEditBoxBase *newEb= dynamic_cast<CGroupEditBoxBase*>(c);
3004 if (_CaptureKeyboard && _CaptureKeyboard != c)
3006 _CaptureKeyboard->onKeyboardCaptureLost();
3008 // If the old capturedKeyboard is an editBox and allow recoverFocusOnEnter
3009 if ( oldEb && oldEb->getRecoverFocusOnEnter() )
3011 _OldCaptureKeyboard = _CaptureKeyboard;
3013 if ( newEb )
3015 CGroupEditBoxBase::disableSelection();
3017 if (!newEb->getAHOnFocus().empty())
3019 CAHManager::getInstance()->runActionHandler(newEb->getAHOnFocus(), newEb, newEb->getAHOnFocusParams());
3023 _CaptureKeyboard = c;
3024 notifyElementCaptured(c);
3027 // ------------------------------------------------------------------------------------------------
3028 void CWidgetManager::resetCaptureKeyboard()
3030 CCtrlBase *captureKeyboard = _CaptureKeyboard;
3031 _OldCaptureKeyboard = NULL;
3032 _CaptureKeyboard = NULL;
3033 if (captureKeyboard)
3035 captureKeyboard->onKeyboardCaptureLost();
3039 // ***************************************************************************
3040 void CWidgetManager::registerClockMsgTarget(CCtrlBase *vb)
3042 if (!vb) return;
3043 if (isClockMsgTarget(vb))
3045 nlwarning("<CInterfaceManager::registerClockMsgTarget> Element %s is already registered", vb->getId().c_str());
3046 return;
3048 _ClockMsgTargets.push_back(vb);
3051 // ***************************************************************************
3052 void CWidgetManager::unregisterClockMsgTarget(CCtrlBase *vb)
3054 if (!vb) return;
3055 std::list<CCtrlBase*>::iterator it = std::find(_ClockMsgTargets.begin(), _ClockMsgTargets.end(), vb);
3056 if (it != _ClockMsgTargets.end())
3058 // instead of deleting, just mark as deleted incase we are inside iterating loop,
3059 // it will be removed in sendClockTickEvent
3060 (*it) = NULL;
3064 // ***************************************************************************
3065 bool CWidgetManager::isClockMsgTarget(CCtrlBase *vb) const
3067 std::list<CCtrlBase*>::const_iterator it = std::find(_ClockMsgTargets.begin(), _ClockMsgTargets.end(), vb);
3068 return it != _ClockMsgTargets.end();
3071 void CWidgetManager::sendClockTickEvent()
3073 CEventDescriptorSystem clockTick;
3074 clockTick.setEventTypeExtended(CEventDescriptorSystem::clocktick);
3076 if (_CapturePointerLeft)
3078 _CapturePointerLeft->handleEvent(clockTick);
3080 if (_CapturePointerRight)
3082 _CapturePointerRight->handleEvent(clockTick);
3085 // and send clock tick msg to ctrl that are registered
3086 for(std::list<CCtrlBase*>::iterator it = _ClockMsgTargets.begin(); it != _ClockMsgTargets.end();)
3088 CCtrlBase* ctrl = *it;
3089 if (ctrl)
3091 ctrl->handleEvent(clockTick);
3092 ++it;
3094 else
3095 it = _ClockMsgTargets.erase(it);
3099 // ------------------------------------------------------------------------------------------------
3100 void CWidgetManager::notifyElementCaptured(CCtrlBase *c)
3102 std::set<CCtrlBase *> seen;
3103 CCtrlBase *curr = c;
3104 while (curr)
3106 seen.insert(curr);
3107 curr->elementCaptured(c);
3108 curr = curr->getParent();
3110 // also warn the ctrl under the pointer
3111 for (uint i = 0; i < (uint) _CtrlsUnderPointer.size(); ++i)
3113 if (!seen.count(_CtrlsUnderPointer[i]))
3115 _CtrlsUnderPointer[i]->elementCaptured(c);
3120 // ------------------------------------------------------------------------------------------------
3121 void CWidgetManager::makeWindow(CInterfaceGroup *group)
3123 if(!group)
3124 return;
3126 uint32 i = 0;
3127 for (i = 0; i < _MasterGroups.size(); ++i)
3129 if (_MasterGroups[i].Group == group->getParent())
3130 break;
3133 if (i == _MasterGroups.size())
3135 std::string stmp = std::string("not found master group for window: ")+group->getId();
3136 nlwarning (stmp.c_str());
3137 return;
3139 else
3141 // check if group hasn't been inserted twice.
3142 if (_MasterGroups[i].isWindowPresent(group))
3144 nlwarning("Window inserted twice");
3146 else
3148 _MasterGroups[i].addWindow(group,group->getPriority());
3153 // ------------------------------------------------------------------------------------------------
3154 void CWidgetManager::unMakeWindow(CInterfaceGroup *group, bool noWarning)
3156 if (!group)
3157 return;
3159 uint32 i = 0;
3160 for (i = 0; i < _MasterGroups.size(); ++i)
3162 if (_MasterGroups[i].Group == group->getParent())
3163 break;
3166 if (i == _MasterGroups.size())
3168 if (!noWarning)
3170 std::string stmp = std::string("not found master group for window: ")+group->getId();
3171 nlwarning (stmp.c_str());
3173 return;
3175 else
3177 // check if group hasn't been inserted twice.
3178 if (!_MasterGroups[i].isWindowPresent(group))
3180 if (!noWarning)
3181 nlwarning("Window not inserted in master group");
3183 else
3185 _MasterGroups[i].delWindow(group);
3190 // ------------------------------------------------------------------------------------------------
3191 void CWidgetManager::setGlobalColor (NLMISC::CRGBA col)
3193 if (!_RProp)
3195 _RProp = CDBManager::getInstance()->getDbProp("UI:SAVE:COLOR:R");
3196 _GProp = CDBManager::getInstance()->getDbProp("UI:SAVE:COLOR:G");
3197 _BProp = CDBManager::getInstance()->getDbProp("UI:SAVE:COLOR:B");
3198 _AProp = CDBManager::getInstance()->getDbProp("UI:SAVE:COLOR:A");
3200 _RProp ->setValue32 (col.R);
3201 _GProp ->setValue32 (col.G);
3202 _BProp ->setValue32 (col.B);
3203 _AProp ->setValue32 (col.A);
3205 _GlobalColor = col;
3207 // set the global color for content (the same with modulated alpha)
3208 _GlobalColorForContent = _GlobalColor;
3209 _GlobalColorForContent.A = (uint8) (( (uint16) _GlobalColorForContent.A * (uint16) _ContentAlpha) >> 8);
3212 // ***************************************************************************
3213 void CWidgetManager::setContentAlpha(uint8 alpha)
3215 _ContentAlpha = alpha;
3216 // update alpha of global color
3217 _GlobalColorForContent.A = alpha;/*(uint8) (( (uint16) _GlobalColor.A * (uint16) _ContentAlpha) >> 8);*/
3220 void CWidgetManager::resetColorProps()
3222 _RProp = NULL;
3223 _GProp = NULL;
3224 _BProp = NULL;
3225 _AProp = NULL;
3228 // ------------------------------------------------------------------------------------------------
3229 CInterfaceOptions* CWidgetManager::getOptions( const std::string &name )
3231 std::map< std::string, NLMISC::CSmartPtr< CInterfaceOptions > >::iterator it = _OptionsMap.find( name );
3232 if( it == _OptionsMap.end() )
3233 return NULL;
3234 else
3235 return it->second;
3238 void CWidgetManager::addOptions( std::string name, CInterfaceOptions *options )
3240 _OptionsMap.insert( std::map< std::string, CInterfaceOptions* >::value_type( name, options ) );
3243 void CWidgetManager::removeOptions( std::string name )
3245 _OptionsMap.erase( name );
3248 void CWidgetManager::removeAllOptions()
3250 _OptionsMap.clear();
3254 bool CWidgetManager::serializeOptions( xmlNodePtr parentNode ) const
3256 if( parentNode == NULL )
3257 return false;
3259 std::map< std::string, NLMISC::CSmartPtr< CInterfaceOptions > >::const_iterator itr;
3260 for( itr = _OptionsMap.begin(); itr != _OptionsMap.end(); ++itr )
3262 if( itr->second->serialize( parentNode, itr->first ) == NULL )
3263 return false;
3266 return true;
3270 bool CWidgetManager::serializeTreeData( xmlNodePtr parentNode ) const
3272 if( parentNode == NULL )
3273 return false;
3275 std::vector< SMasterGroup >::size_type i;
3276 for( i = 0; i < _MasterGroups.size(); i++ )
3278 const SMasterGroup &mg = _MasterGroups[ i ];
3280 std::vector< CInterfaceGroup* >::size_type j;
3281 for( j = 0; j < mg.Group->getNumGroup(); j++ )
3283 CInterfaceGroup *g = mg.Group->getGroup( j );
3284 nlassert(g);
3286 if( dynamic_cast< CGroupModal* >( g ) != NULL )
3287 continue;
3289 if( g->serializeTreeData( parentNode ) == NULL )
3290 return false;
3294 return true;
3298 // ***************************************************************************
3299 void CWidgetManager::enableMouseHandling( bool handle )
3301 _MouseHandlingEnabled = handle;
3302 if(!handle)
3304 if(!getPointer())
3305 return;
3307 // If Left captured, reset
3308 if( getCapturePointerLeft() )
3309 setCapturePointerLeft( NULL );
3311 // Same for Right
3312 if( getCapturePointerRight() )
3313 setCapturePointerRight( NULL );
3315 // Avoid any problem with modals
3316 disableModalWindow();
3320 // ***************************************************************************
3321 uint CWidgetManager::getUserDblClickDelay()
3323 uint nVal = 50;
3324 NLMISC::CCDBNodeLeaf *pNL = CDBManager::getInstance()->getDbProp("UI:SAVE:DOUBLE_CLICK_SPEED");
3325 if( pNL != NULL )
3326 nVal = pNL->getValue32();
3328 uint dbclickDelay = (uint)(DOUBLE_CLICK_MIN + (DOUBLE_CLICK_MAX-DOUBLE_CLICK_MIN) * (float)nVal / 100.0f);
3329 return dbclickDelay;
3332 // ------------------------------------------------------------------------------------------------
3333 void CWidgetManager::setupOptions()
3335 // After parsing options and templates node -> init system options.
3336 CInterfaceOptions *opt = getOptions( "system" );
3337 if( opt != NULL )
3339 // List here all Special options
3340 _SystemOptions[OptionCtrlSheetGrayColor]= opt->getValue("ctrl_sheet_gray_color");
3341 _SystemOptions[OptionCtrlTextGrayColor]= opt->getValue("ctrl_text_gray_color");
3342 _SystemOptions[OptionCtrlSheetRedifyColor]= opt->getValue("ctrl_sheet_redify_color");
3343 _SystemOptions[OptionCtrlTextRedifyColor]= opt->getValue("ctrl_text_redify_color");
3344 _SystemOptions[OptionCtrlSheetGreenifyColor]= opt->getValue("ctrl_sheet_greenify_color");
3345 _SystemOptions[OptionCtrlTextGreenifyColor]= opt->getValue("ctrl_text_greenify_color");
3346 _SystemOptions[OptionViewTextOverBackColor]= opt->getValue("text_over_back_color");
3347 _SystemOptions[OptionFont]= opt->getValue("font");
3348 _SystemOptions[OptionAddCoefFont]= opt->getValue("add_coef_font");
3349 _SystemOptions[OptionMulCoefAnim]= opt->getValue("mul_coef_anim");
3350 _SystemOptions[OptionTimeoutBubbles]= opt->getValue("bubbles_timeout");
3351 _SystemOptions[OptionTimeoutMessages]= opt->getValue("messages_timeout");
3352 _SystemOptions[OptionTimeoutContext]= opt->getValue("context_timeout");
3353 _SystemOptions[OptionTimeoutContextHtml]= opt->getValue("context_html_timeout");
3354 _SystemOptions[OptionMonospaceFont]= opt->getValue("monospace_font");
3359 // Get the alpha roll over speed
3360 float CWidgetManager::getAlphaRolloverSpeed()
3362 if( _AlphaRolloverSpeedDB == NULL )
3363 _AlphaRolloverSpeedDB = CDBManager::getInstance()->getDbProp("UI:SAVE:ALPHA_ROLLOVER_SPEED");
3364 float fTmp = ROLLOVER_MIN_DELTA_PER_MS + (ROLLOVER_MAX_DELTA_PER_MS - ROLLOVER_MIN_DELTA_PER_MS) * 0.01f * (100 - _AlphaRolloverSpeedDB->getValue32());
3365 return fTmp*fTmp*fTmp;
3368 void CWidgetManager::resetAlphaRolloverSpeedProps()
3370 _AlphaRolloverSpeedDB = NULL;
3373 void CWidgetManager::setContainerAlpha(uint8 alpha)
3375 _ContainerAlpha = alpha;
3376 // update alpha of global color
3377 NLMISC::CRGBA c = getGlobalColor();
3378 c.A = alpha;/*(uint8) (( (uint16) _GlobalColor.A * (uint16) _ContainerAlpha) >> 8); */
3379 setGlobalColor( c );
3382 void CWidgetManager::updateGlobalAlphas()
3384 if (!_GlobalContentAlphaDB)
3386 _GlobalContentAlphaDB = CDBManager::getInstance()->getDbProp("UI:SAVE:CONTENT_ALPHA");
3387 nlassert(_GlobalContentAlphaDB);
3388 _GlobalContainerAlphaDB = CDBManager::getInstance()->getDbProp("UI:SAVE:CONTAINER_ALPHA");
3389 nlassert(_GlobalContainerAlphaDB);
3390 _GlobalContentRolloverFactorDB = CDBManager::getInstance()->getDbProp("UI:SAVE:CONTENT_ROLLOVER_FACTOR");
3391 nlassert(_GlobalContentRolloverFactorDB);
3392 _GlobalContainerRolloverFactorDB = CDBManager::getInstance()->getDbProp("UI:SAVE:CONTAINER_ROLLOVER_FACTOR");
3393 nlassert(_GlobalContainerRolloverFactorDB);
3395 _GlobalContentAlpha = (uint8)_GlobalContentAlphaDB->getValue32();
3396 _GlobalContainerAlpha = (uint8)_GlobalContainerAlphaDB->getValue32();
3397 _GlobalRolloverFactorContent = (uint8)_GlobalContentRolloverFactorDB->getValue32();
3398 _GlobalRolloverFactorContainer = (uint8)_GlobalContainerRolloverFactorDB->getValue32();
3401 void CWidgetManager::resetGlobalAlphasProps()
3403 _GlobalContentAlphaDB = NULL;
3404 _GlobalContainerAlphaDB = NULL;
3405 _GlobalContentRolloverFactorDB = NULL;
3406 _GlobalContainerRolloverFactorDB = NULL;
3409 void CWidgetManager::registerNewScreenSizeHandler( INewScreenSizeHandler *handler )
3411 std::vector< INewScreenSizeHandler* >::iterator itr =
3412 std::find( newScreenSizeHandlers.begin(), newScreenSizeHandlers.end(), handler );
3414 if( itr != newScreenSizeHandlers.end() )
3415 return;
3417 newScreenSizeHandlers.push_back( handler );
3420 void CWidgetManager::removeNewScreenSizeHandler( INewScreenSizeHandler *handler )
3422 std::vector< INewScreenSizeHandler* >::iterator itr =
3423 std::find( newScreenSizeHandlers.begin(), newScreenSizeHandlers.end(), handler );
3425 if( itr == newScreenSizeHandlers.end() )
3426 return;
3428 newScreenSizeHandlers.erase( itr );
3431 void CWidgetManager::registerOnWidgetsDrawnHandler( IOnWidgetsDrawnHandler* handler )
3433 std::vector< IOnWidgetsDrawnHandler* >::iterator itr =
3434 std::find( onWidgetsDrawnHandlers.begin(), onWidgetsDrawnHandlers.end(), handler );
3436 if( itr != onWidgetsDrawnHandlers.end() )
3437 return;
3439 onWidgetsDrawnHandlers.push_back( handler );
3442 void CWidgetManager::removeOnWidgetsDrawnHandler( IOnWidgetsDrawnHandler* handler )
3444 std::vector< IOnWidgetsDrawnHandler* >::iterator itr =
3445 std::find( onWidgetsDrawnHandlers.begin(), onWidgetsDrawnHandlers.end(), handler );
3447 if( itr == onWidgetsDrawnHandlers.end() )
3448 return;
3450 onWidgetsDrawnHandlers.erase( itr );
3453 // ------------------------------------------------------------------------------------------------
3454 void CWidgetManager::startAnim( const std::string &animId )
3456 CInterfaceAnim *pIT = _Parser->getAnim( animId );
3457 if( pIT == NULL )
3458 return;
3460 stopAnim( animId );
3461 pIT->start();
3462 activeAnims.push_back( pIT );
3465 void CWidgetManager::removeFinishedAnims()
3467 sint32 i = 0;
3468 for( i = 0; i < (sint32)activeAnims.size(); ++i )
3470 CInterfaceAnim *pIA = activeAnims[i];
3471 if (pIA->isFinished())
3473 activeAnims.erase( activeAnims.begin() + i );
3474 --i;
3479 // ------------------------------------------------------------------------------------------------
3480 void CWidgetManager::stopAnim( const std::string &animId )
3482 CInterfaceAnim *pIT = _Parser->getAnim( animId );
3484 for( uint i = 0; i < activeAnims.size(); ++i )
3485 if( activeAnims[ i ] == pIT )
3487 activeAnims.erase( activeAnims.begin() + i );
3488 if( !pIT->isFinished() )
3489 pIT->stop();
3490 return;
3494 void CWidgetManager::updateAnims()
3496 for( std::vector< CInterfaceAnim* >::size_type i = 0; i < activeAnims.size(); i++ )
3497 activeAnims[ i ]->update();
3501 // ------------------------------------------------------------------------------------------------
3502 void CWidgetManager::runProcedure( const std::string &procName, CCtrlBase *pCaller,
3503 const std::vector< std::string> &paramList )
3505 CProcedure *procp = _Parser->getProc( procName );
3506 if( procp == NULL )
3507 return;
3509 CProcedure &proc = *procp;
3511 // Run all actions
3512 for( uint i = 0; i < proc.Actions.size(); i++ )
3514 const CProcAction &action = proc.Actions[i];
3515 // test if the condition for the action is valid
3516 if (!action.CondBlocks.empty())
3518 CInterfaceExprValue result;
3519 result.setBool( false );
3520 std::string cond;
3521 action.buildCond( paramList, cond );
3522 CInterfaceExpr::eval( cond, result, NULL );
3524 if( result.toBool() )
3525 if( !result.getBool() )
3526 continue;
3528 // build the params sting
3529 std::string params;
3530 action.buildParams( paramList, params );
3531 // run
3532 //nlwarning("step %d : %s, %s", (int) i, action.Action.c_str(), params.c_str());
3533 CAHManager::getInstance()->runActionHandler( action.Action, pCaller, params );
3537 // ------------------------------------------------------------------------------------------------
3538 void CWidgetManager::setProcedureAction( const std::string &procName, uint actionIndex,
3539 const std::string &ah, const std::string &params )
3541 CProcedure *procp = _Parser->getProc( procName );
3542 if( procp == NULL )
3543 return;
3545 CProcedure &proc = *procp;
3547 // set wanted action
3548 if( actionIndex<proc.Actions.size() )
3550 CProcAction &action = proc.Actions[ actionIndex ];
3551 action.Action = ah;
3552 action.ParamBlocks.clear();
3553 action.ParamBlocks.resize( 1 );
3554 action.ParamBlocks[ 0 ].String = params;
3558 void CWidgetManager::getEditorSelection( std::vector< std::string > &selection )
3560 selection.clear();
3561 for(uint i = 0; i < editorSelection.size(); ++i)
3562 selection.push_back(editorSelection[i]);
3565 void CWidgetManager::selectWidget( const std::string &name )
3567 std::vector< std::string >::iterator itr
3568 = std::find( editorSelection.begin(), editorSelection.end(), name );
3570 CInterfaceElement *e = getElementFromId( name );
3572 if( itr != editorSelection.end() )
3574 // If multiselection is on unselect if already selected
3575 if( multiSelection )
3577 editorSelection.erase( itr );
3578 if( e != NULL )
3579 e->setEditorSelected( false );
3582 else
3584 // Select if not yet selected
3585 if( e != NULL )
3587 // If multiselection is off, we can only have 1 widget selected
3588 if( !multiSelection )
3590 editorSelection.clear();
3593 e->setEditorSelected( true );
3594 editorSelection.push_back( name );
3599 notifySelectionWatchers();
3602 void CWidgetManager::clearEditorSelection()
3604 editorSelection.clear();
3605 notifySelectionWatchers();
3608 void CWidgetManager::notifySelectionWatchers()
3610 std::vector< IEditorSelectionWatcher* >::iterator itr = selectionWatchers.begin();
3611 while( itr != selectionWatchers.end() )
3613 (*itr)->selectionChanged();
3614 ++itr;
3618 void CWidgetManager::registerSelectionWatcher( IEditorSelectionWatcher *watcher )
3620 std::vector< IEditorSelectionWatcher* >::iterator itr =
3621 std::find( selectionWatchers.begin(), selectionWatchers.end(), watcher );
3623 // We already have this watcher
3624 if( itr != selectionWatchers.end() )
3625 return;
3627 selectionWatchers.push_back( watcher );
3630 void CWidgetManager::unregisterSelectionWatcher( IEditorSelectionWatcher *watcher )
3632 std::vector< IEditorSelectionWatcher* >::iterator itr =
3633 std::find( selectionWatchers.begin(), selectionWatchers.end(), watcher );
3635 // We don't have this watcher
3636 if( itr == selectionWatchers.end() )
3637 return;
3639 selectionWatchers.erase( itr );
3642 void CWidgetManager::onWidgetAdded( const std::string &id )
3644 std::vector< IWidgetWatcher* >::const_iterator itr = widgetWatchers.begin();
3645 while( itr != widgetWatchers.end() )
3647 (*itr)->onWidgetAdded( id );
3648 ++itr;
3652 void CWidgetManager::onWidgetMoved( const std::string &oldid, const std::string &newid )
3654 std::vector< IWidgetWatcher* >::const_iterator itr = widgetWatchers.begin();
3655 while( itr != widgetWatchers.end() )
3657 (*itr)->onWidgetMoved( oldid, newid );
3658 ++itr;
3662 void CWidgetManager::registerWidgetWatcher( IWidgetWatcher *watcher )
3664 std::vector< IWidgetWatcher* >::const_iterator itr
3665 = std::find( widgetWatchers.begin(), widgetWatchers.end(), watcher );
3666 // already exists
3667 if( itr != widgetWatchers.end() )
3668 return;
3670 widgetWatchers.push_back( watcher );
3673 void CWidgetManager::unregisterWidgetWatcher( IWidgetWatcher *watcher )
3675 std::vector< IWidgetWatcher* >::iterator itr
3676 = std::find( widgetWatchers.begin(), widgetWatchers.end(), watcher );
3677 // doesn't exist
3678 if( itr == widgetWatchers.end() )
3679 return;
3681 widgetWatchers.erase( itr );
3684 CInterfaceElement* CWidgetManager::addWidgetToGroup( std::string &group, std::string &widgetClass, std::string &widgetName )
3686 // Check if this group exists
3687 CInterfaceElement *e = getElementFromId( group );
3688 if( e == NULL )
3689 return NULL;
3690 CInterfaceGroup *g = dynamic_cast< CInterfaceGroup* >( e );
3691 if( g == NULL )
3692 return NULL;
3694 // Check if an element already exists with that name
3695 if( g->getElement( widgetName ) != NULL )
3696 return NULL;
3698 // Create and add the new widget
3699 CViewBase *v = getParser()->createClass( widgetClass );
3700 if( v == NULL )
3701 return NULL;
3703 v->setId( std::string( g->getId() + ":" + widgetName ) );
3704 v->setParent( g );
3706 if( v->isGroup() )
3707 g->addGroup( dynamic_cast< CInterfaceGroup* >( v ) );
3708 else
3709 if( v->isCtrl() )
3710 g->addCtrl( dynamic_cast< CCtrlBase* >( v ) );
3711 else
3712 g->addView( v );
3714 onWidgetAdded( v->getId() );
3716 return v;
3719 bool CWidgetManager::groupSelection()
3721 std::vector< CInterfaceElement* > elms;
3723 // Resolve the widget names
3724 for(uint i = 0; i < editorSelection.size(); ++i)
3726 CInterfaceElement *e = getElementFromId(editorSelection[i]);
3727 if (e != NULL)
3728 elms.push_back(e);
3731 editorSelection.clear();
3733 if( elms.empty() )
3734 return false;
3736 // Create the group as the subgroup of the top window
3737 CInterfaceGroup *g = static_cast< CInterfaceGroup* >( getParser()->createClass( "interface_group" ) );
3738 getTopWindow()->addGroup( g );
3739 g->setParent( getTopWindow() );
3740 g->setIdRecurse( std::string( "group" ) + NLMISC::toString( _WidgetCount ) );
3741 _WidgetCount++;
3742 onWidgetAdded( g->getId() );
3744 std::string oldId;
3746 // Reparent the widgets to the new group
3747 for(uint i = 0; i < elms.size(); ++i)
3749 CInterfaceElement *e = elms[i];
3750 oldId = e->getId();
3751 CInterfaceGroup *p = e->getParent();
3752 if (p != NULL)
3753 p->takeElement(e);
3755 g->addElement(e);
3756 e->setParent(g);
3757 e->setParentPos(g);
3758 e->setParentSize(g);
3759 e->setIdRecurse(e->getShortId());
3761 onWidgetMoved(oldId, e->getId());
3763 elms.clear();
3765 // Make sure widgets aren't clipped because the group isn't big enough
3766 g->spanElements();
3767 // Make sure widgets are aligned
3768 g->alignElements();
3769 // Align the new group to the top window
3770 g->alignTo( getTopWindow() );
3772 g->setActive( true );
3774 return true;
3777 bool CWidgetManager::unGroupSelection()
3779 if( editorSelection.size() != 1 )
3780 return false;
3782 // Does the element exist?
3783 CInterfaceElement *e = getElementFromId( editorSelection[ 0 ] );
3784 if( e == NULL )
3785 return false;
3787 // Is the element a group?
3788 CInterfaceGroup *g = dynamic_cast< CInterfaceGroup* >( e );
3789 if( g == NULL )
3790 return false;
3792 // Can't blow up a root group :(
3793 CInterfaceGroup *p = g->getParent();
3794 if( p == NULL )
3795 return false;
3797 // KABOOM!
3798 bool ok = g->explode();
3799 if( !ok )
3800 return false;
3802 p->delElement( g );
3804 clearEditorSelection();
3806 p->updateCoords();
3808 return true;
3812 bool CWidgetManager::createNewGUI( const std::string &project, const std::string &window )
3814 reset();
3816 for(uint i = 0; i < _MasterGroups.size(); ++i)
3817 delete _MasterGroups[i].Group;
3818 _MasterGroups.clear();
3820 // First create the master group
3821 CRootGroup *root = new CRootGroup( CViewBase::TCtorParam() );
3823 SMasterGroup mg;
3824 mg.Group = root;
3826 root->setIdRecurse( project );
3827 root->setW( 1024 );
3828 root->setH( 768 );
3829 root->setActive( true );
3831 // Create the first / main window
3832 CInterfaceGroup *wnd = new CInterfaceGroup( CViewBase::TCtorParam() );
3833 wnd->setW( 1024 );
3834 wnd->setH( 768 );
3835 wnd->setParent( root );
3836 wnd->setParentPos( root );
3837 wnd->setParentSize( root );
3838 wnd->setPosRef( Hotspot_MM );
3839 wnd->setParentPosRef( Hotspot_MM );
3840 wnd->setIdRecurse( window );
3841 wnd->setActive( true );
3843 // Add the window
3844 root->addElement( wnd );
3845 mg.addWindow( wnd, wnd->getPriority() );
3846 _MasterGroups.push_back( mg );
3848 _Pointer = new CViewPointer( CViewBase::TCtorParam() );
3850 IParser *parser = getParser();
3853 // Set base color to white
3854 VariableData v;
3855 v.type = "sint32";
3856 v.value = "255";
3858 v.entry = "UI:SAVE:COLOR:R";
3859 parser->setVariable( v );
3861 v.entry = "UI:SAVE:COLOR:G";
3862 parser->setVariable( v );
3864 v.entry = "UI:SAVE:COLOR:B";
3865 parser->setVariable( v );
3867 v.entry = "UI:SAVE:COLOR:A";
3868 parser->setVariable( v );
3870 return true;
3874 // ------------------------------------------------------------------------------------------------
3875 void CWidgetManager::notifyInterfaceScaleWatchers()
3877 std::vector< IInterfaceScaleWatcher* >::iterator itr = scaleWatchers.begin();
3878 while( itr != scaleWatchers.end() )
3880 (*itr)->onInterfaceScaleChanged();
3881 ++itr;
3885 // ------------------------------------------------------------------------------------------------
3886 void CWidgetManager::registerInterfaceScaleWatcher( IInterfaceScaleWatcher *watcher )
3888 std::vector< IInterfaceScaleWatcher* >::const_iterator itr
3889 = std::find( scaleWatchers.begin(), scaleWatchers.end(), watcher );
3891 if( itr != scaleWatchers.end() )
3892 return;
3894 scaleWatchers.push_back( watcher );
3897 // ------------------------------------------------------------------------------------------------
3898 void CWidgetManager::unregisterInterfaceScaleWatcher( IInterfaceScaleWatcher *watcher )
3900 std::vector< IInterfaceScaleWatcher* >::iterator itr
3901 = std::find( scaleWatchers.begin(), scaleWatchers.end(), watcher );
3903 if( itr == scaleWatchers.end() )
3904 return;
3906 scaleWatchers.erase( itr );
3909 // ------------------------------------------------------------------------------------------------
3910 CWidgetManager::CWidgetManager()
3912 LinkHack();
3913 CStringShared::createStringMapper();
3915 CReflectableRegister::registerClasses();
3917 _Parser = IParser::createParser();
3919 _Pointer = NULL;
3920 curContextHelp = NULL;
3921 _ContextHelpActive = true;
3922 _DeltaTimeStopingContextHelp = 0;
3923 _MaxTimeStopingContextHelp= 0.2f;
3924 _LastXContextHelp= -10000;
3925 _LastYContextHelp= -10000;
3927 resetColorProps();
3928 resetAlphaRolloverSpeedProps();
3929 resetGlobalAlphasProps();
3931 _GlobalColor = NLMISC::CRGBA(255,255,255,255);
3932 _GlobalColorForContent = _GlobalColor;
3933 _ContentAlpha = 255;
3934 _ContainerAlpha = 255;
3935 _GlobalContentAlpha = 255;
3936 _GlobalContainerAlpha = 255;
3937 _GlobalRolloverFactorContent = 255;
3938 _GlobalRolloverFactorContainer = 255;
3939 _AlphaRolloverSpeedDB = NULL;
3941 _MouseHandlingEnabled = true;
3942 _MouseOverWindow = false;
3943 inGame = false;
3945 setScreenWH(0, 0);
3946 _InterfaceScale = 1.0f;
3948 _WindowSnapDistance = 10;
3949 _WindowSnapInvert = false;
3951 _GroupSelection = false;
3952 multiSelection = false;
3953 _WidgetCount = 0;
3955 _ContextHelpContainerColor = NLMISC::CRGBA(255,255,159,255);
3956 _ContextHelpContentAlpha = 255;
3957 _ContextHelpContentAlphaDB = NULL;
3958 _ContextHelpContainerColorDB = NULL;
3959 _ContextHelpContainerAlphaDB = NULL;
3962 CWidgetManager::~CWidgetManager()
3964 for (uint32 i = 0; i < _MasterGroups.size(); ++i)
3966 delete _MasterGroups[i].Group;
3969 delete _Parser;
3970 _Parser = NULL;
3972 _Pointer = NULL;
3973 curContextHelp = NULL;
3975 CStringShared::deleteStringMapper();
3977 editorSelection.clear();