Change Encyclo button name and macros icon
[ryzomcore.git] / nel / src / gui / dbgroup_combo_box.cpp
blob3a37c9b992a1c8c03bc746d86291cad12a8ea013
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2021 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // 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/dbgroup_combo_box.h"
24 #include "nel/gui/group_menu.h"
25 #include "nel/misc/xml_auto_ptr.h"
26 #include "nel/gui/ctrl_button.h"
27 #include "nel/gui/action_handler.h"
28 #include "nel/gui/lua_ihm.h"
29 #include "nel/gui/widget_manager.h"
30 #include "nel/misc/i18n.h"
32 using namespace std;
33 using namespace NLMISC;
35 #ifdef DEBUG_NEW
36 #define new DEBUG_NEW
37 #endif
39 namespace NLGUI
41 NLMISC_REGISTER_OBJECT(CViewBase, CDBGroupComboBox, std::string, "combo_box");
43 void force_link_dbgroup_combo_box_cpp() { }
45 // Compare strings
46 static inline bool lt_text(const std::pair<int,std::string> &s1, const std::pair<int,std::string> &s2)
48 // return toLower(s1.second) < toLower(s2.second);
49 return NLMISC::compareCaseInsensitive(s1.second, s2.second) < 0;
52 std::string CDBGroupComboBox::measureMenu;
53 std::string CDBGroupComboBox::selectMenu;
54 std::string CDBGroupComboBox::selectMenuOut;
56 // ***************************************************************************
57 CDBGroupComboBox::CDBGroupComboBox(const TCtorParam &param)
58 : CInterfaceGroup(param)
60 _Setuped= false;
61 _ViewText= NULL;
62 _SelectButton= NULL;
63 _LinkedToDB = true;
64 _NotLinkedToDBSelection = 0;
65 _CallingOnChangeActionHandler = false;
66 _IsExternViewText = false;
67 dirt();
70 // ***************************************************************************
71 CDBGroupComboBox::~CDBGroupComboBox()
75 // ***************************************************************************
76 sint32 CDBGroupComboBox::evalContentWidth() const
78 // get the menu to open.
79 CGroupMenu *groupMenu= dynamic_cast<CGroupMenu*>(CWidgetManager::getInstance()->getElementFromId( CDBGroupComboBox::measureMenu ));
80 if( !groupMenu )
82 return 0;
84 fillMenu(groupMenu);
85 groupMenu->setActive(true);
86 groupMenu->updateCoords();
87 sint32 width = groupMenu->getWReal();
88 groupMenu->setActive(false);
89 groupMenu->reset();
90 // add width for the selection arrow
91 return width;
94 std::string CDBGroupComboBox::getProperty( const std::string &name ) const
96 if( name == "linked_to_db" )
98 return toString( _LinkedToDB );
100 else
101 if( name == "value" )
103 if( _Selection.getNodePtr() != NULL )
104 return _Selection.getNodePtr()->getFullName();
105 else
106 return "";
108 else
109 return CInterfaceGroup::getProperty( name );
112 void CDBGroupComboBox::setProperty( const std::string &name, const std::string &value )
114 if( name == "linked_to_db" )
116 bool b;
117 if( fromString( value, b ) )
118 _LinkedToDB = b;
119 return;
121 else
122 if( name == "value" )
124 _Selection.link( value.c_str() );
125 return;
127 else
128 CInterfaceGroup::setProperty( name, value );
131 xmlNodePtr CDBGroupComboBox::serialize( xmlNodePtr parentNode, const char *type ) const
133 xmlNodePtr node = CInterfaceGroup::serialize( parentNode, type );
134 if( node == NULL )
135 return NULL;
137 xmlSetProp( node, BAD_CAST "type", BAD_CAST "combo_box" );
138 xmlSetProp( node, BAD_CAST "linked_to_db", BAD_CAST toString( _LinkedToDB ).c_str() );
140 if( _Selection.getNodePtr() != NULL )
141 xmlSetProp( node, BAD_CAST "value", BAD_CAST _Selection.getNodePtr()->getFullName().c_str() );
142 else
143 xmlSetProp( node, BAD_CAST "value", BAD_CAST "" );
146 return node;
149 // ***************************************************************************
150 bool CDBGroupComboBox::parse (xmlNodePtr cur, CInterfaceGroup *parentGroup)
152 if( !CInterfaceGroup::parse(cur, parentGroup) )
153 return false;
155 CXMLAutoPtr prop((const char*)xmlGetProp(cur, (xmlChar*)"linked_to_db"));
156 if (prop)
158 _LinkedToDB = convertBool(prop);
161 if (_LinkedToDB)
163 // read the selection value
164 CXMLAutoPtr prop((const char*)xmlGetProp(cur, (xmlChar*)"value"));
165 if(!prop)
167 nlwarning("'value' not found in %s", _Id.c_str());
168 return false;
170 else
172 _Selection.link((const char*)prop);
176 // read the sons text
177 xmlNodePtr child;
178 child = cur->children;
179 while (child)
181 if (stricmp((char*)child->name,"combo_text") == 0)
183 CXMLAutoPtr name((const char*) xmlGetProp (child, (xmlChar*)"name"));
184 if (name)
186 const char *propPtr = name;
187 if (NLMISC::startsWith(propPtr, "ui"))
188 addText(CI18N::get(propPtr));
189 else
190 addText(propPtr);
193 child = child->next;
196 // optional ActionHandler on click
197 prop= xmlGetProp(cur, (xmlChar*)"on_select_start");
198 if(prop) _AHOnSelectStart= (const char*)prop;
200 // optional ActionHandler on change
201 prop= xmlGetProp(cur, (xmlChar*)"on_change");
202 if(prop) _AHOnChange= (const char*)prop;
204 prop= xmlGetProp(cur, (xmlChar*)"on_change_params");
205 if(prop) _AHOnChangeParams= (const char*)prop;
208 return true;
211 // ***************************************************************************
212 void CDBGroupComboBox::checkCoords ()
214 if(!_ViewText)
215 return;
216 bool mustUpdate = false;
217 if (_LinkedToDB)
219 // if some change in texts/selection
220 if(_DirtySelection || _CacheSelection!=_Selection.getSInt32())
222 _CacheSelection= _Selection.getSInt32();
223 mustUpdate = true;
226 else
228 // if some change in texts/selection
229 if(_DirtySelection || _CacheSelection != _NotLinkedToDBSelection)
231 _CacheSelection= _NotLinkedToDBSelection;
232 mustUpdate = true;
235 if (mustUpdate)
237 // change selected text
238 if(_CacheSelection<0 || _CacheSelection>=(sint32)_Texts.size() )
240 _ViewText->setText(std::string());
242 else if(_IsExternViewText)
244 _ViewText->setText(_ExternViewText);
246 else
248 _ViewText->setText(_Texts[_CacheSelection].second);
253 // ***************************************************************************
254 void CDBGroupComboBox::updateCoords ()
256 if(!_Setuped)
257 setup();
258 CInterfaceGroup::updateCoords();
262 // ***************************************************************************
263 void CDBGroupComboBox::dirt()
265 _DirtySelection= true;
268 // ***************************************************************************
269 void CDBGroupComboBox::resetTexts()
271 dirt();
272 _Texts.clear();
273 _Textures.clear();
274 _Grayed.clear();
277 // ***************************************************************************
278 void CDBGroupComboBox::addText(const std::string &text)
280 dirt();
281 _Texts.push_back(make_pair((uint)_Texts.size(), text));
282 _Textures.push_back(std::string());
283 _Grayed.push_back(false);
286 // ***************************************************************************
287 void CDBGroupComboBox::setText(uint i, const std::string &text)
289 dirt();
290 if(i<_Texts.size())
291 _Texts[i].second= text;
294 // ***************************************************************************
295 void CDBGroupComboBox::insertText(uint i, const std::string &text)
297 dirt();
298 if(i<_Texts.size())
300 addText(_Texts[_Texts.size()-1].second);
302 for(uint t=i; t<_Texts.size()-1; t++)
304 _Texts[t+1] = _Texts[t];
305 _Textures[t+1] = _Textures[t];
306 _Grayed[t+1] = _Grayed[t];
308 _Texts[i] = make_pair(i, text);
309 _Textures[i] = std::string();
310 _Grayed[i] = false;
312 else if(i==_Texts.size())
313 addText(text);
316 // ***************************************************************************
317 void CDBGroupComboBox::setTexture(uint i, const std::string &texture)
319 dirt();
320 if(i<_Textures.size())
321 _Textures[i]= texture;
324 // ***************************************************************************
325 void CDBGroupComboBox::setGrayed(uint i, bool g)
327 dirt();
328 if(i<_Grayed.size())
329 _Grayed[i] = g;
332 // ***************************************************************************
333 bool CDBGroupComboBox::getGrayed(uint i) const
335 if(i<_Grayed.size())
336 return _Grayed[i];
337 else
338 return false;
342 // ***************************************************************************
343 void CDBGroupComboBox::removeText(uint nPos)
345 dirt();
346 if(nPos<_Texts.size())
348 _Texts.erase( _Texts.begin()+nPos );
349 _Textures.erase( _Textures.begin()+nPos );
350 _Grayed.erase ( _Grayed.begin()+nPos );
354 // ***************************************************************************
355 const std::string &CDBGroupComboBox::getText(uint i) const
357 static const std::string empty;
358 if (i < _Texts.size())
359 return _Texts[i].second;
360 else
361 return empty;
364 #ifdef RYZOM_LUA_UCSTRING
365 // ***************************************************************************
366 ucstring CDBGroupComboBox::getTextAsUtf16(uint i) const
368 return ucstring::makeFromUtf8(getText(i));
370 #endif
372 // ***************************************************************************
373 uint CDBGroupComboBox::getTextId(uint i) const
375 static uint null = 0;
376 if(i<_Texts.size())
377 return _Texts[i].first;
378 else
379 return null;
382 // ***************************************************************************
383 uint CDBGroupComboBox::getTextPos(uint nId) const
385 for(uint i=0; i<_Texts.size(); i++)
387 if(nId == _Texts[i].first) {return i;}
389 return 0;
392 // ***************************************************************************
393 void CDBGroupComboBox::sortText()
395 sort(_Texts.begin(), _Texts.end(), lt_text);
398 // ***************************************************************************
399 const std::string &CDBGroupComboBox::getTexture(uint i) const
401 static const std::string empty;
402 if (i < _Textures.size())
403 return _Textures[i];
404 else
405 return empty;
408 #ifdef RYZOM_LUA_UCSTRING
409 // ***************************************************************************
410 ucstring CDBGroupComboBox::getTextureAsUtf16(uint i) const
412 return ucstring::makeFromUtf8(getTexture(i));
414 #endif
416 // ***************************************************************************
417 void CDBGroupComboBox::setSelection(sint32 val)
419 _IsExternViewText = false;
421 if (_LinkedToDB)
423 _Selection.setSInt32(val);
425 else
427 _NotLinkedToDBSelection = val;
429 if (!_AHOnChange.empty())
431 if (!_CallingOnChangeActionHandler)
433 _CallingOnChangeActionHandler = true;
434 CAHManager::getInstance()->runActionHandler (_AHOnChange, this, _AHOnChangeParams);
435 _CallingOnChangeActionHandler = false;
440 // ***************************************************************************
441 void CDBGroupComboBox::setSelectionNoTrigger(sint32 val)
443 if (_LinkedToDB)
445 _Selection.setSInt32(val);
447 else
449 _NotLinkedToDBSelection = val;
453 // ***************************************************************************
454 sint32 CDBGroupComboBox::getSelection() const
456 if (_LinkedToDB)
458 return _Selection.getSInt32();
460 else
462 return _NotLinkedToDBSelection;
466 // ***************************************************************************
467 void CDBGroupComboBox::setSelectionText(const std::string & val)
469 sint32 value;
470 for(uint i=0; i<getNumTexts(); i++)
472 std::string sText = getText(i);
473 if(sText == val)
475 value = i;
476 setSelection(value);
477 break;
482 // ***************************************************************************
483 void CDBGroupComboBox::setOnChange(const std::string & val)
485 _AHOnChange = "lua";
486 _AHOnChangeParams = val;
489 // ***************************************************************************
490 void CDBGroupComboBox::setViewText(const std::string &text)
492 _IsExternViewText = true;
493 _ExternViewText = text;
494 _ViewText->setText(_ExternViewText);
497 // ***************************************************************************
498 std::string CDBGroupComboBox::getViewText() const
500 return _ViewText->getText();
503 #ifdef RYZOM_LUA_UCSTRING
504 // ***************************************************************************
505 ucstring CDBGroupComboBox::getViewTextAsUtf16() const
507 return CUtfStringView(_ViewText->getText()).toUtf16();
509 #endif
511 // ***************************************************************************
512 CViewText *CDBGroupComboBox::getViewText()
514 return _ViewText;
517 // ***************************************************************************
518 std::string CDBGroupComboBox::getSelectionText() const
520 if (_LinkedToDB)
522 return getText(_Selection.getSInt32());
524 else
526 return getText(_NotLinkedToDBSelection);
530 // ***************************************************************************
531 std::string CDBGroupComboBox::getOnChange() const
533 return _AHOnChangeParams;
537 // ***************************************************************************
538 void CDBGroupComboBox::setup()
540 _Setuped= true;
542 // get the viewText
543 _ViewText= dynamic_cast<CViewText*>(CInterfaceGroup::getView("text"));
544 // get the button
545 _SelectButton= dynamic_cast<CCtrlBaseButton*>(CInterfaceGroup::getCtrl("select"));
547 // force the action handler
548 if( _SelectButton )
549 _SelectButton->setActionOnLeftClick("combo_box_select_start");
554 // ***************************************************************************
555 int CDBGroupComboBox::luaRemoveSelection(CLuaState &ls)
557 CLuaIHM::checkArgCount(ls, "removeSelection", 1);
558 sint32 value;
559 if(CLuaIHM::popSINT32(ls, value))
561 removeText(value);
563 return 0;
566 // ***************************************************************************
567 int CDBGroupComboBox::luaRemoveText(CLuaState &ls)
569 CLuaIHM::checkArgCount(ls, "removeText", 1);
570 CLuaIHM::checkArgType(ls, "removeText", 1, LUA_TSTRING);
571 std::string text = ls.toString(1);
572 sint32 value;
573 for(uint i=0; i<getNumTexts(); i++)
575 std::string sText = getText(i);
576 if(sText == text)
578 value = i;
579 removeText(value);
580 break;
583 return 0;
586 // ***************************************************************************
587 int CDBGroupComboBox::luaResetTexts(CLuaState &ls)
589 CLuaIHM::checkArgCount(ls, "resetTexts", 0);
590 resetTexts();
591 return 0;
594 // ***************************************************************************
595 int CDBGroupComboBox::luaAddText(CLuaState &ls)
597 const char *funcName = "addText";
598 CLuaIHM::checkArgCount(ls, funcName, 1);
599 #ifdef RYZOM_LUA_UCSTRING
600 CLuaIHM::checkArgTypeUCString(ls, funcName, 1);
601 ucstring text; // Compatibility
602 nlverify(CLuaIHM::pop(ls, text));
603 addText(text.toUtf8());
604 #else
605 CLuaIHM::checkArgType(ls, funcName, 1, LUA_TSTRING);
606 string text = ls.toString(1);
607 addText(text);
608 #endif
609 return 0;
612 // ***************************************************************************
613 int CDBGroupComboBox::luaSetText(CLuaState &ls)
615 const char *funcName = "setText";
616 CLuaIHM::checkArgCount(ls, funcName, 2);
617 CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER);
618 #ifdef RYZOM_LUA_UCSTRING
619 CLuaIHM::checkArgTypeUCString(ls, funcName, 2);
620 ucstring text; // Compatibility
621 nlverify(CLuaIHM::pop(ls, text));
622 setText((uint) ls.toInteger(1), text.toUtf8());
623 #else
624 CLuaIHM::checkArgType(ls, funcName, 2, LUA_TSTRING);
625 string text = ls.toString(2);
626 setText((uint)ls.toInteger(1), text);
627 #endif
628 return 0;
631 // ***************************************************************************
632 int CDBGroupComboBox::luaInsertText(CLuaState &ls)
634 const char *funcName = "insertText";
635 CLuaIHM::checkArgCount(ls, funcName, 2);
636 CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER);
637 #ifdef RYZOM_LUA_UCSTRING
638 CLuaIHM::checkArgTypeUCString(ls, funcName, 2);
639 ucstring text;
640 nlverify(CLuaIHM::pop(ls, text));
641 insertText((uint) ls.toInteger(1), text.toUtf8()); // FIXME: Lua should just do UTF-8!
642 #else
643 CLuaIHM::checkArgType(ls, funcName, 2, LUA_TSTRING);
644 string text = ls.toString(2);
645 insertText((uint)ls.toInteger(1), text);
646 #endif
647 return 0;
650 // ***************************************************************************
651 int CDBGroupComboBox::luaSetTexture(CLuaState &ls)
653 const char *funcName = "setTexture";
654 CLuaIHM::checkArgCount(ls, funcName, 2);
655 CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER);
656 #ifdef RYZOM_LUA_UCSTRING
657 CLuaIHM::checkArgTypeUCString(ls, funcName, 2);
658 ucstring texture;
659 nlverify(CLuaIHM::pop(ls, texture));
660 setTexture((uint) ls.toInteger(1), texture.toUtf8()); // FIXME: Lua should just do UTF-8!
661 #else
662 CLuaIHM::checkArgType(ls, funcName, 2, LUA_TSTRING);
663 string texture = ls.toString(2);
664 setTexture((uint)ls.toInteger(1), texture);
665 #endif
666 return 0;
669 // ***************************************************************************
670 int CDBGroupComboBox::luaGetText(CLuaState &ls)
672 const char *funcName = "getText";
673 CLuaIHM::checkArgCount(ls, funcName, 1);
674 CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER);
675 #ifdef RYZOM_LUA_UCSTRING
676 CLuaIHM::push(ls, getTextAsUtf16((uint) ls.toInteger(1)));
677 #else
678 ls.push(getText((uint)ls.toInteger(1)));
679 #endif
680 return 1;
683 // ***************************************************************************
684 int CDBGroupComboBox::luaRemoveTextByIndex(CLuaState &ls)
686 const char *funcName = "removeText";
687 CLuaIHM::checkArgCount(ls, funcName, 1);
688 CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER);
689 removeText((uint)ls.toInteger(1));
690 return 0;
693 // ***************************************************************************
694 int CDBGroupComboBox::luaGetNumTexts(CLuaState &ls)
696 const char *funcName = "getNumTexts";
697 CLuaIHM::checkArgCount(ls, funcName, 0);
698 ls.push(getNumTexts());
699 return 1;
702 // ***************************************************************************
703 void CDBGroupComboBox::fillMenu(CGroupMenu *groupMenu) const
705 nlassert(groupMenu);
707 if (_ViewText)
708 groupMenu->setFontSize(_ViewText->getFontSize());
710 // Setup the menu with combo action.
711 groupMenu->reset();
712 for(uint i=0; i<getNumTexts(); i++)
714 // set the id as the parameter
715 bool checkable = false;
716 if (getTexture(i) != std::string())
718 checkable = true;
720 groupMenu->addLine(getText(i), "combo_box_select_end", toString(i),
721 "", std::string(), getTexture(i), checkable);
722 groupMenu->setGrayedLine(i, getGrayed(i));
730 // ***************************************************************************
731 class CHandlerComboBoxSelectStart : public IActionHandler
733 public:
734 virtual void execute (CCtrlBase *pCaller, const std::string &/* Params */)
736 CDBGroupComboBox *pCB = dynamic_cast<CDBGroupComboBox*>(pCaller->getParent());
737 if (pCB == NULL) return;
738 // if no choice, return.
739 if( pCB->getNumTexts()==0 )
740 return;
742 // get the menu to open.
743 CGroupMenu *groupMenu= dynamic_cast<CGroupMenu*>(CWidgetManager::getInstance()->getElementFromId( CDBGroupComboBox::selectMenu ));
744 if( !groupMenu )
746 groupMenu= dynamic_cast<CGroupMenu*>(CWidgetManager::getInstance()->getElementFromId( CDBGroupComboBox::selectMenuOut ));
748 if( !groupMenu )
749 return;
751 pCB->fillMenu(groupMenu);
753 groupMenu->setMaxVisibleLine(8);
755 // pos and size wisely the menu.
756 groupMenu->setMinW(pCB->getWReal());
757 groupMenu->setX(pCB->getXReal());
758 groupMenu->setBaseX(pCB->getXReal());
759 groupMenu->setY(pCB->getYReal());
760 groupMenu->setBaseY(pCB->getYReal());
762 // Must ensure the combo menu has same windows priority than the combo box window
763 CInterfaceGroup *rootWin= pCB->getRootWindow();
764 if(rootWin)
765 groupMenu->setPriority(rootWin->getPriority());
767 // After menu init, Call user activation method
768 if( !pCB->_AHOnSelectStart.empty() )
770 CAHManager::getInstance()->runActionHandler(pCB->_AHOnSelectStart, pCB);
773 // launch the menu
774 // if the combo box is in a modal, must do a push, else just replace
775 if(dynamic_cast<CGroupModal*>(pCB->getRootWindow()))
777 groupMenu->setCloseSubMenuUsingPopModal(true);
778 CWidgetManager::getInstance()->pushModalWindow(pCB, groupMenu);
780 else
782 groupMenu->setCloseSubMenuUsingPopModal(false);
783 CWidgetManager::getInstance()->enableModalWindow (pCB, groupMenu);
787 REGISTER_ACTION_HANDLER (CHandlerComboBoxSelectStart, "combo_box_select_start");
792 // ***************************************************************************
793 class CHandlerComboBoxSelectEnd : public IActionHandler
795 public:
796 virtual void execute (CCtrlBase * /* pCaller */, const std::string &Params)
798 CDBGroupComboBox *pCB = dynamic_cast<CDBGroupComboBox*>(CWidgetManager::getInstance()->getCtrlLaunchingModal());
799 if (pCB == NULL) return;
801 // set the selection
802 sint32 selection;
803 fromString(Params, selection);
804 pCB->setSelection(selection);
807 REGISTER_ACTION_HANDLER (CHandlerComboBoxSelectEnd, "combo_box_select_end");