1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
26 #include "events_listener.h"
27 #include "interface_v3/interface_manager.h"
34 using namespace NLMISC
;
36 extern CEventsListener EventsListener
;
43 H_AUTO_DECL ( RZ_Client_Actions_Context_Mngr_Update
)
45 static bool getParam (CBaseAction::CParameter::TType type
, string
¶mName
, string
¶mValue
, const std::string
&argu
, uint paramId
);
47 /////////////////////////////////////////////////////
48 /////////////////////////////////////////////////////
49 // CAction //////////////////////////////////////////
50 /////////////////////////////////////////////////////
51 /////////////////////////////////////////////////////
52 //---------------------------------------------------
55 //---------------------------------------------------
65 void CAction::runAction ()
67 CInterfaceManager
*IM
= CInterfaceManager::getInstance ();
70 CAHManager::getInstance()->runActionHandler (Name
.Name
, NULL
, Name
.Argu
);
74 /////////////////////////////////////////////////////
75 /////////////////////////////////////////////////////
76 // CActionsManager //////////////////////////////////
77 /////////////////////////////////////////////////////
78 /////////////////////////////////////////////////////
79 //---------------------------------------------------
82 //---------------------------------------------------
83 CActionsManager::CActionsManager()
87 }// CActionsManager //
90 //---------------------------------------------------
92 // Add a new Action in the context.
93 //---------------------------------------------------
94 bool CActionsManager::addAction(const CAction::CName
&name
)
96 // Try to allocate memory for action
100 // Find the base action
101 const CBaseAction
*baseAction
= getBaseAction(name
);
104 // Copy the repeat flag
105 action
.Repeat
= baseAction
->Repeat
;
106 action
.KeyUp
= baseAction
->KeyUp
;
107 action
.KeyDown
= baseAction
->KeyDown
;
110 // Try to insert the new action.
111 pair
<TActionsMap::iterator
, bool> p
= _Actions
.insert(TActionsMap::value_type(name
, action
));
115 nlwarning ("Action (%s %s) already exist in the action manager.", name
.Name
.c_str (), name
.Argu
.c_str ());
121 // ***************************************************************************
123 CAction
* CActionsManager::getAction(const CAction::CName
&name
)
125 TActionsMap::iterator it
= _Actions
.find(name
);
126 if (it
== _Actions
.end()) return NULL
;
127 return &(it
->second
);
130 // ***************************************************************************
132 void CActionsManager::clear ()
135 _ActionForceDisplay
.clear ();
136 _ActionCombo
.clear ();
137 _ComboAction
.clear ();
139 _WatchedActions
.clear ();
140 _ActionCategory
.clear ();
141 _Categories
.clear ();
144 // ***************************************************************************
146 void CActionsManager::removeCombo (const CCombo
&combo
)
148 // Get the old action of the combo
149 TComboActionMap::iterator itePreviousCombo
= _ComboAction
.find (combo
);
150 if (itePreviousCombo
!= _ComboAction
.end ())
152 const CAction::CName oldName
= itePreviousCombo
->second
;
154 // Remove all affected keys
155 TKeyActionMap::iterator ite
= _KeyAction
.find (combo
.Key
);
156 while ((ite
!= _KeyAction
.end ()) && (ite
->first
== combo
.Key
))
158 TKeyActionMap::iterator copyToDelete
= ite
;
159 #ifdef NL_ISO_CPP0X_AVAILABLE
160 if (copyToDelete
->second
== oldName
)
161 ite
= _KeyAction
.erase (copyToDelete
);
166 if (copyToDelete
->second
== oldName
)
167 _KeyAction
.erase (copyToDelete
);
172 _ActionCombo
.erase (oldName
);
175 _ComboAction
.erase (itePreviousCombo
);
179 // ***************************************************************************
180 void CActionsManager::removeAllCombos()
183 _ActionCombo
.clear ();
184 _ComboAction
.clear ();
186 _WatchedActions
.clear ();
187 _ActionForceDisplay
.clear();
190 // ***************************************************************************
192 bool CActionsManager::addCombo(const CAction::CName
&name
, const CCombo
&combo
, bool createAction
)
194 // If createAction == "true" -> Create the Action before to add te combo.
198 // Erase previous values
199 TActionComboMap::iterator itePreviousCombo
= _ActionCombo
.find (name
);
200 if (itePreviousCombo
!= _ActionCombo
.end ())
202 // Remove the old action affected to the combo
203 removeCombo (itePreviousCombo
->second
);
206 // Remove the new combo
209 _ComboAction
.insert (TComboActionMap::value_type (combo
, name
));
210 _ActionCombo
.insert (TActionComboMap::value_type (name
, combo
));
211 _KeyAction
.insert (TKeyActionMap::value_type (combo
.Key
, name
));
216 // ***************************************************************************
217 bool CActionsManager::valide(const CAction::CName
&name
) const
219 // Recover the pointer on "actionName" if it exists.
220 TActionsMap::const_iterator it
= _Actions
.find(name
);
221 if(it
!= _Actions
.end())
223 return it
->second
.Valide
;
225 // No action of this name found.
230 // ***************************************************************************
231 bool CActionsManager::isActionPresentInContext(const CAction::CName
&name
) const
233 CInterfaceManager
*im
= CInterfaceManager::getInstance();
234 if (!im
->isInGame()) return true; // no filtering done when outgame, because actions.xml not loaded yet (no base actions where added)
236 const CBaseAction
*baseAction
= getBaseAction(name
);
237 if (!baseAction
) return false;
238 // see if action valid in current context
239 if (!ActionsContext
.matchContext(baseAction
->Contexts
)) return false;
240 // all parameters must be valid in current context
241 for (uint i
=0; i
<baseAction
->Parameters
.size (); i
++)
243 const CBaseAction::CParameter
¶meter
= baseAction
->Parameters
[i
];
244 if (parameter
.Type
== CBaseAction::CParameter::Constant
)
247 string paramValue
= parameter
.DefaultValue
;
249 // Get the param from the argu
250 getParam (parameter
.Type
, paramName
, paramValue
, name
.Argu
, i
);
253 for (uint k
= 0; k
< parameter
.Values
.size(); ++k
)
255 if (parameter
.Values
[k
].Value
== paramValue
)
257 if (!ActionsContext
.matchContext(parameter
.Values
[k
].Contexts
)) return false;
262 if (!found
) return false;
270 // ***************************************************************************
272 bool CActionsManager::keyPushed (const CEventKeyDown
&keyDown
)
274 bool actionExist
= false;
278 combo
.Key
= keyDown
.Key
;
279 combo
.KeyButtons
= keyDown
.Button
;
281 // Scan action binded to this key
282 TKeyActionMap::iterator iteKeyAction
= _KeyAction
.find (keyDown
.Key
);
283 while ((iteKeyAction
!= _KeyAction
.end ()) && (iteKeyAction
->first
== keyDown
.Key
))
285 if (isActionPresentInContext(iteKeyAction
->second
))
287 // Add it to the set of actions to watch
288 _WatchedActions
.insert (*iteKeyAction
);
293 // Update special valide actions
294 updateKeyButton (keyDown
.Button
);
297 TComboActionMap::iterator ite
= _ComboAction
.find (combo
);
298 if (ite
!= _ComboAction
.end ())
301 TActionsMap::iterator iteAction
= _Actions
.find (ite
->second
);
302 nlassert (iteAction
!= _Actions
.end ());
304 if (isActionPresentInContext(iteAction
->first
))
307 if (iteAction
->second
.KeyDown
&& (iteAction
->second
.Repeat
|| keyDown
.FirstTime
))
309 iteAction
->second
.runAction ();
325 // ***************************************************************************
327 void CActionsManager::keyReleased (const CEventKeyUp
&keyUp
)
331 // Update special keys state
332 updateKeyButton (keyUp
.Button
);
334 // For each watched actions
335 TKeyActionMap::iterator iteWatchedAction
= _WatchedActions
.begin ();
336 while (iteWatchedAction
!= _WatchedActions
.end ())
338 TKeyActionMap::iterator iteToDelete
= iteWatchedAction
;
340 // Get the combo for this action
341 TActionComboMap::iterator iteCombo
= _ActionCombo
.find (iteToDelete
->second
);
342 nlassert (iteCombo
!= _ActionCombo
.end());
344 // This combo released ?
345 if (iteCombo
->second
.Key
== keyUp
.Key
)
348 TActionsMap::iterator iteAction
= _Actions
.find (iteToDelete
->second
);
349 nlassert (iteAction
!= _Actions
.end());
351 // Remove this action from watching
352 #ifdef NL_ISO_CPP0X_AVAILABLE
353 // C++11 return the next item
354 iteWatchedAction
= _WatchedActions
.erase (iteToDelete
);
356 // remember the next iterator only if not using C++11
359 _WatchedActions
.erase (iteToDelete
);
362 // Invalidate the action
363 bool LastValid
= iteAction
->second
.Valide
;
364 iteAction
->second
.Valide
= false;
366 if ((LastValid
== true) && (iteAction
->second
.Valide
== false))
369 if (iteAction
->second
.KeyUp
)
371 iteAction
->second
.runAction ();
383 // ***************************************************************************
384 void CActionsManager::releaseAllKeyNoRunning()
386 // For each watched actions
387 TKeyActionMap::iterator iteWatchedAction
= _WatchedActions
.begin ();
388 while (iteWatchedAction
!= _WatchedActions
.end ())
390 TKeyActionMap::iterator iteToDelete
= iteWatchedAction
++;
392 // Invalidate the action
393 TActionsMap::iterator iteAction
= _Actions
.find (iteToDelete
->second
);
394 nlassert (iteAction
!= _Actions
.end());
395 iteAction
->second
.Valide
= false;
397 // Remove this action from watching
398 _WatchedActions
.erase (iteToDelete
);
403 // ***************************************************************************
405 sint
getMatchingNote (sint keyButton
, sint newButton
)
407 // At least all the needed key
408 if ((keyButton
& newButton
) != keyButton
)
411 // If exactly the same, we want it
412 if (keyButton
== newButton
)
415 // Else count the number of bits used
416 const uint flags
[3] = { ctrlKeyButton
, shiftKeyButton
, altKeyButton
};
418 for (uint i
=0; i
<3; i
++)
420 if (keyButton
& flags
[i
])
426 // ***************************************************************************
428 void CActionsManager::updateKeyButton (NLMISC::TKeyButton newButtons
)
430 // For each watched actions
431 TKeyActionMap::iterator iteWatchedAction
= _WatchedActions
.begin ();
432 while (iteWatchedAction
!= _WatchedActions
.end ())
434 // First action for this key
435 TKeyActionMap::iterator iteWatchedActionBegin
= iteWatchedAction
;
438 NLMISC::TKey key
= iteWatchedAction
->first
;
440 // Best matching action
441 CAction
*bestMatching
= NULL
;
442 sint bestMatchingNote
= -1;
444 // For each action with the same key, search the best combo
445 while ((iteWatchedAction
!= _WatchedActions
.end ()) && (key
== iteWatchedAction
->first
))
447 // Get the action combo
448 TActionComboMap::iterator iteCombo
= _ActionCombo
.find (iteWatchedAction
->second
);
449 if (iteCombo
== _ActionCombo
.end())
450 nlwarning("try to find Name:%s , Argu:%s",iteWatchedAction
->second
.Name
.c_str(), iteWatchedAction
->second
.Argu
.c_str());
451 nlassert (iteCombo
!= _ActionCombo
.end());
453 // Get the matching note
454 sint matchingNote
= getMatchingNote (iteCombo
->second
.KeyButtons
, newButtons
);
455 if (matchingNote
> bestMatchingNote
)
458 TActionsMap::iterator iteAction
= _Actions
.find (iteWatchedAction
->second
);
459 nlassert (iteAction
!= _Actions
.end());
461 // Memorise the best action
462 bestMatching
= &(iteAction
->second
);
463 bestMatchingNote
= matchingNote
;
469 // Invalide or valide actions
470 while (iteWatchedActionBegin
!= iteWatchedAction
)
473 TActionsMap::iterator iteAction
= _Actions
.find (iteWatchedActionBegin
->second
);
474 nlassert (iteAction
!= _Actions
.end());
476 // Valide or invalide it
477 bool LastValid
= iteAction
->second
.Valide
;
478 iteAction
->second
.Valide
= (&(iteAction
->second
) == bestMatching
);
479 if ((LastValid
== true) && (iteAction
->second
.Valide
== false))
481 // Run the action on keyup
482 if (iteAction
->second
.KeyUp
)
484 iteAction
->second
.runAction ();
489 iteWatchedActionBegin
++;
494 // ***************************************************************************
496 void CCombo::init (NLMISC::TKey key
, NLMISC::TKeyButton keyButtons
)
499 KeyButtons
= keyButtons
;
502 // ***************************************************************************
503 string
CCombo::toString() const
506 if ((KeyButtons
& shiftKeyButton
) && (Key
!= 0x10))
507 ret
+= CI18N::get("uiKeySHIFT") + "+";
508 if ((KeyButtons
& ctrlKeyButton
) && (Key
!= 0x11))
509 ret
+= CI18N::get("uiKeyCONTROL") + "+";
510 if ((KeyButtons
& altKeyButton
) && (Key
!= 0x12))
511 ret
+= CI18N::get("uiKeyMENU") + "+";
512 if (CI18N::hasTranslation("ui"+CEventKey::getStringFromKey(Key
)))
513 ret
+= CI18N::get("ui"+CEventKey::getStringFromKey(Key
));
515 ret
+= CEventKey::getStringFromKey(Key
);
519 // ***************************************************************************
521 const std::vector
<CCategory
> &CActionsManager::getCategories () const
526 // ***************************************************************************
528 void CActionsManager::reserveCategories (uint space
)
530 _Categories
.reserve (space
);
533 // ***************************************************************************
535 void CActionsManager::addCategory (const CCategory
&category
)
537 _Categories
.push_back (category
);
539 // Add an entry in the map to get the base action by the action name
541 for (i
=0; i
<category
.BaseActions
.size (); i
++)
543 CCategoryLocator locator
;
544 locator
.CategoryId
= (uint
)_Categories
.size ()-1;
545 locator
.BaseActionId
= i
;
546 _ActionCategory
.insert (TActionBaseActionMap::value_type (category
.BaseActions
[i
].Name
, locator
));
550 // ***************************************************************************
552 void CActionsManager::removeCategory (const string
&catName
)
554 // Search the category
556 for (catNb
=0; catNb
< _Categories
.size(); ++catNb
)
557 if (_Categories
[catNb
].Name
== catName
)
560 if (catNb
== _Categories
.size()) return;
562 // Remove all entries in the map to get the base action by the action name
563 for (i
=0; i
<_Categories
[catNb
].BaseActions
.size (); i
++)
565 CCategoryLocator locator
;
566 locator
.CategoryId
= catNb
;
567 locator
.BaseActionId
= i
;
568 _ActionCategory
.erase (_Categories
[catNb
].BaseActions
[i
].Name
);
570 _Categories
.erase (_Categories
.begin()+catNb
);
573 // ***************************************************************************
575 void CActionsManager::enable (bool enable
)
580 // ***************************************************************************
582 // ***************************************************************************
584 CBaseAction::CBaseAction ()
589 WaitForServer
= false;
593 // ***************************************************************************
594 bool CBaseAction::isUsableInCurrentContext() const
596 if (ActionsContext
.matchContext(Contexts
))
598 bool cteParamFound
= false;
599 bool matchingParamFound
= false;
600 // now, see if for all the constant parameter for this action,
601 // at least one is valid in current context
602 for (uint l
= 0; l
< Parameters
.size(); ++l
)
604 const CParameter
¶m
= Parameters
[l
];
605 if (param
.Type
== CParameter::Constant
)
607 cteParamFound
= true;
608 for (uint m
= 0; m
< param
.Values
.size(); ++m
)
610 if (ActionsContext
.matchContext(param
.Values
[m
].Contexts
))
612 matchingParamFound
= true;
617 if (matchingParamFound
) break;
619 if (!cteParamFound
|| matchingParamFound
) return true;
624 // ***************************************************************************
626 CBaseAction::CParameter::CParameter ()
632 // ***************************************************************************
634 static bool getParam (CBaseAction::CParameter::TType type
, string
¶mName
, string
¶mValue
, const std::string
&argu
, uint paramId
)
636 const string separator
= "|";
637 const string equal_separator
= "=";
641 string::size_type pos
= 0;
642 while (index
!= paramId
)
645 pos
= argu
.find_first_of(separator
, pos
);
646 if (pos
== string::npos
)
654 if (pos
< argu
.size ())
657 string::size_type end
= argu
.find_first_of(separator
, pos
);
658 if (end
== string::npos
)
662 string::size_type equal
= argu
.find_first_of(equal_separator
, pos
);
663 if ((equal
!= string::npos
) && (equal
>= end
))
664 equal
= string::npos
;
666 // Equal is present ?
667 if (equal
!= string::npos
)
669 // Extract parameter name
670 paramName
= argu
.substr(pos
, equal
-pos
);
675 paramValue
= argu
.substr(pos
, end
-pos
);
683 string
CBaseAction::getActionLocalizedText(const CAction::CName
&name
) const
686 string temp
= CI18N::get(LocalizedName
);
690 for (i
=0; i
<Parameters
.size (); i
++)
692 bool parameterOk
= false;
693 const CParameter
¶meter
= Parameters
[i
];
697 // Get the param from the argu
698 if (getParam (parameter
.Type
, paramName
, paramValue
, name
.Argu
, i
))
700 switch (parameter
.Type
)
702 case CParameter::Hidden
:
703 if ((parameter
.DefaultValue
== paramValue
) && (parameter
.Name
== paramName
))
706 case CParameter::Constant
:
709 for (j
=0; j
<parameter
.Values
.size (); j
++)
712 const CParameter::CValue
&value
= parameter
.Values
[j
];
713 if (value
.Value
== paramValue
)
717 if ((value
.LocalizedValue
.size() >= 2) &&
718 (value
.LocalizedValue
[0]=='u') && (value
.LocalizedValue
[1]=='i'))
719 temp
+= CI18N::get(value
.LocalizedValue
);
721 temp
+= value
.LocalizedValue
;
728 case CParameter::User
:
729 case CParameter::UserName
:
736 // Parameter not found ? Next base action..
743 if (i
==Parameters
.size ())
749 // ***************************************************************************
751 // ***************************************************************************
753 const CActionsManager::TComboActionMap
&CActionsManager::getComboActionMap () const
758 // ***************************************************************************
760 const CActionsManager::TActionComboMap
&CActionsManager::getActionComboMap () const
765 // ***************************************************************************
767 const CActionsManager::CCategoryLocator
*CActionsManager::getActionLocator (const CAction::CName
&name
) const
769 // Look for the base action
770 TActionBaseActionMap::const_iterator ite
= _ActionCategory
.find (name
.Name
);
771 while ((ite
!= _ActionCategory
.end ()) && (ite
->first
== name
.Name
))
773 // Ref on the base action
774 const CCategory
&cat
= _Categories
[ite
->second
.CategoryId
];
775 uint baseActionId
= ite
->second
.BaseActionId
;
776 uint baseActionSize
= cat
.BaseActions
.size();
778 if( ite
->second
.BaseActionId
>= cat
.BaseActions
.size() )
781 const CBaseAction
&baseAction
= cat
.BaseActions
[ite
->second
.BaseActionId
];
785 uint s
= baseAction
.Parameters
.size();
789 bool parameterOk
= false;
790 const CBaseAction::CParameter
¶meter
= baseAction
.Parameters
[i
];
794 // Get the param from the argu
795 if (getParam (parameter
.Type
, paramName
, paramValue
, name
.Argu
, i
))
797 switch (parameter
.Type
)
799 case CBaseAction::CParameter::Hidden
:
800 if ((parameter
.DefaultValue
== paramValue
) && (parameter
.Name
== paramName
))
803 case CBaseAction::CParameter::Constant
:
805 // If the value of the action param match with one of the values of the base action param so its ok
807 for (j
=0; j
<parameter
.Values
.size (); j
++)
809 const CBaseAction::CParameter::CValue
&value
= parameter
.Values
[j
];
810 if (value
.Value
== paramValue
)
818 case CBaseAction::CParameter::User
:
819 case CBaseAction::CParameter::UserName
:
825 // Parameter not found ? Next base action..
831 if (i
==baseAction
.Parameters
.size ())
840 // ***************************************************************************
841 const CBaseAction
*CActionsManager::getBaseAction (const CAction::CName
&name
) const
843 const CCategoryLocator
*pCL
= getActionLocator(name
);
844 if (pCL
== NULL
) return NULL
;
845 return &_Categories
[pCL
->CategoryId
].BaseActions
[pCL
->BaseActionId
];
848 // ***************************************************************************
849 void CActionsManager::removeBaseAction(const CAction::CName
&name
)
851 const CCategoryLocator
*pCL
= getActionLocator(name
);
854 nlwarning("Action %s %s not found.", name
.Name
.c_str(), name
.Argu
.c_str());
857 std::vector
<CBaseAction
> &baseActions
= _Categories
[pCL
->CategoryId
].BaseActions
;
858 baseActions
.erase(baseActions
.begin() + pCL
->BaseActionId
);
861 // ***************************************************************************
862 const CCategory
*CActionsManager::getCategory (const CAction::CName
&name
) const
864 const CCategoryLocator
*pCL
= getActionLocator(name
);
865 if (pCL
== NULL
) return NULL
;
866 return &_Categories
[pCL
->CategoryId
];
870 // ***************************************************************************
871 void CActionsManager::forceDisplayForAction(const CAction::CName
&name
, bool state
)
874 _ActionForceDisplay
.insert(name
);
876 _ActionForceDisplay
.erase(name
);
879 // ***************************************************************************
880 bool CActionsManager::isActionDisplayForced(const CAction::CName
&name
) const
882 return _ActionForceDisplay
.find(name
)!=_ActionForceDisplay
.end();
885 // ***************************************************************************
886 string
CActionsManager::getActionLocalizedText (const CAction::CName
&name
) const
888 const CBaseAction
*baseAction
= getBaseAction(name
);
891 return baseAction
->getActionLocalizedText(name
);
895 // ***************************************************************************
897 // ***************************************************************************
900 CActionsContext::CActionsContext()
905 bool CActionsContext::addActionsManager (CActionsManager
*actionManager
, const std::string
&category
)
907 return _ActionsManagers
.insert (TActionsManagerMap::value_type(category
, actionManager
)).second
;
910 // ***************************************************************************
911 CActionsManager
*CActionsContext::getActionsManager (const std::string
&category
) const
913 TActionsManagerMap::const_iterator ite
= _ActionsManagers
.find (category
);
914 if (ite
!= _ActionsManagers
.end())
918 ite
= _ActionsManagers
.find ("");
919 if (ite
!= _ActionsManagers
.end())
925 // ***************************************************************************
926 bool CActionsContext::matchContext(const std::string
&contexts
) const
928 std::vector
<std::string
> contextList
;
929 splitString(contexts
, ",", contextList
);
930 for (uint k
= 0; k
< contextList
.size(); ++k
)
932 std::string currContext
= contextList
[k
];
933 while(strFindReplace(currContext
, " ", ""));
934 while(strFindReplace(currContext
, "\t", ""));
935 if (nlstricmp(currContext
, _Context
) == 0) return true;
940 // ***************************************************************************
941 void CActionsContext::removeAllCombos()
943 for (TActionsManagerMap::iterator it
= _ActionsManagers
.begin(); it
!= _ActionsManagers
.end(); ++it
)
945 it
->second
->removeAllCombos();
949 // ***************************************************************************