1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2021 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) 2013-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/>.
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"
33 using namespace NLMISC
;
41 NLMISC_REGISTER_OBJECT(CViewBase
, CDBGroupComboBox
, std::string
, "combo_box");
43 void force_link_dbgroup_combo_box_cpp() { }
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
¶m
)
58 : CInterfaceGroup(param
)
64 _NotLinkedToDBSelection
= 0;
65 _CallingOnChangeActionHandler
= false;
66 _IsExternViewText
= false;
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
));
85 groupMenu
->setActive(true);
86 groupMenu
->updateCoords();
87 sint32 width
= groupMenu
->getWReal();
88 groupMenu
->setActive(false);
90 // add width for the selection arrow
94 std::string
CDBGroupComboBox::getProperty( const std::string
&name
) const
96 if( name
== "linked_to_db" )
98 return toString( _LinkedToDB
);
101 if( name
== "value" )
103 if( _Selection
.getNodePtr() != NULL
)
104 return _Selection
.getNodePtr()->getFullName();
109 return CInterfaceGroup::getProperty( name
);
112 void CDBGroupComboBox::setProperty( const std::string
&name
, const std::string
&value
)
114 if( name
== "linked_to_db" )
117 if( fromString( value
, b
) )
122 if( name
== "value" )
124 _Selection
.link( value
.c_str() );
128 CInterfaceGroup::setProperty( name
, value
);
131 xmlNodePtr
CDBGroupComboBox::serialize( xmlNodePtr parentNode
, const char *type
) const
133 xmlNodePtr node
= CInterfaceGroup::serialize( parentNode
, type
);
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() );
143 xmlSetProp( node
, BAD_CAST
"value", BAD_CAST
"" );
149 // ***************************************************************************
150 bool CDBGroupComboBox::parse (xmlNodePtr cur
, CInterfaceGroup
*parentGroup
)
152 if( !CInterfaceGroup::parse(cur
, parentGroup
) )
155 CXMLAutoPtr
prop((const char*)xmlGetProp(cur
, (xmlChar
*)"linked_to_db"));
158 _LinkedToDB
= convertBool(prop
);
163 // read the selection value
164 CXMLAutoPtr
prop((const char*)xmlGetProp(cur
, (xmlChar
*)"value"));
167 nlwarning("'value' not found in %s", _Id
.c_str());
172 _Selection
.link((const char*)prop
);
176 // read the sons text
178 child
= cur
->children
;
181 if (stricmp((char*)child
->name
,"combo_text") == 0)
183 CXMLAutoPtr
name((const char*) xmlGetProp (child
, (xmlChar
*)"name"));
186 const char *propPtr
= name
;
187 if (NLMISC::startsWith(propPtr
, "ui"))
188 addText(CI18N::get(propPtr
));
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
;
211 // ***************************************************************************
212 void CDBGroupComboBox::checkCoords ()
216 bool mustUpdate
= false;
219 // if some change in texts/selection
220 if(_DirtySelection
|| _CacheSelection
!=_Selection
.getSInt32())
222 _CacheSelection
= _Selection
.getSInt32();
228 // if some change in texts/selection
229 if(_DirtySelection
|| _CacheSelection
!= _NotLinkedToDBSelection
)
231 _CacheSelection
= _NotLinkedToDBSelection
;
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
);
248 _ViewText
->setText(_Texts
[_CacheSelection
].second
);
253 // ***************************************************************************
254 void CDBGroupComboBox::updateCoords ()
258 CInterfaceGroup::updateCoords();
262 // ***************************************************************************
263 void CDBGroupComboBox::dirt()
265 _DirtySelection
= true;
268 // ***************************************************************************
269 void CDBGroupComboBox::resetTexts()
277 // ***************************************************************************
278 void CDBGroupComboBox::addText(const std::string
&text
)
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
)
291 _Texts
[i
].second
= text
;
294 // ***************************************************************************
295 void CDBGroupComboBox::insertText(uint i
, const std::string
&text
)
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();
312 else if(i
==_Texts
.size())
316 // ***************************************************************************
317 void CDBGroupComboBox::setTexture(uint i
, const std::string
&texture
)
320 if(i
<_Textures
.size())
321 _Textures
[i
]= texture
;
324 // ***************************************************************************
325 void CDBGroupComboBox::setGrayed(uint i
, bool g
)
332 // ***************************************************************************
333 bool CDBGroupComboBox::getGrayed(uint i
) const
342 // ***************************************************************************
343 void CDBGroupComboBox::removeText(uint nPos
)
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
;
364 #ifdef RYZOM_LUA_UCSTRING
365 // ***************************************************************************
366 ucstring
CDBGroupComboBox::getTextAsUtf16(uint i
) const
368 return ucstring::makeFromUtf8(getText(i
));
372 // ***************************************************************************
373 uint
CDBGroupComboBox::getTextId(uint i
) const
375 static uint null
= 0;
377 return _Texts
[i
].first
;
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
;}
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())
408 #ifdef RYZOM_LUA_UCSTRING
409 // ***************************************************************************
410 ucstring
CDBGroupComboBox::getTextureAsUtf16(uint i
) const
412 return ucstring::makeFromUtf8(getTexture(i
));
416 // ***************************************************************************
417 void CDBGroupComboBox::setSelection(sint32 val
)
419 _IsExternViewText
= false;
423 _Selection
.setSInt32(val
);
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
)
445 _Selection
.setSInt32(val
);
449 _NotLinkedToDBSelection
= val
;
453 // ***************************************************************************
454 sint32
CDBGroupComboBox::getSelection() const
458 return _Selection
.getSInt32();
462 return _NotLinkedToDBSelection
;
466 // ***************************************************************************
467 void CDBGroupComboBox::setSelectionText(const std::string
& val
)
470 for(uint i
=0; i
<getNumTexts(); i
++)
472 std::string sText
= getText(i
);
482 // ***************************************************************************
483 void CDBGroupComboBox::setViewText(const std::string
&text
)
485 _IsExternViewText
= true;
486 _ExternViewText
= text
;
487 _ViewText
->setText(_ExternViewText
);
490 // ***************************************************************************
491 std::string
CDBGroupComboBox::getViewText() const
493 return _ViewText
->getText();
496 #ifdef RYZOM_LUA_UCSTRING
497 // ***************************************************************************
498 ucstring
CDBGroupComboBox::getViewTextAsUtf16() const
500 return CUtfStringView(_ViewText
->getText()).toUtf16();
504 // ***************************************************************************
505 CViewText
*CDBGroupComboBox::getViewText()
510 // ***************************************************************************
511 std::string
CDBGroupComboBox::getSelectionText() const
515 return getText(_Selection
.getSInt32());
519 return getText(_NotLinkedToDBSelection
);
523 // ***************************************************************************
524 void CDBGroupComboBox::setup()
529 _ViewText
= dynamic_cast<CViewText
*>(CInterfaceGroup::getView("text"));
531 _SelectButton
= dynamic_cast<CCtrlBaseButton
*>(CInterfaceGroup::getCtrl("select"));
533 // force the action handler
535 _SelectButton
->setActionOnLeftClick("combo_box_select_start");
540 // ***************************************************************************
541 int CDBGroupComboBox::luaRemoveSelection(CLuaState
&ls
)
543 CLuaIHM::checkArgCount(ls
, "removeSelection", 1);
545 if(CLuaIHM::popSINT32(ls
, value
))
552 // ***************************************************************************
553 int CDBGroupComboBox::luaRemoveText(CLuaState
&ls
)
555 CLuaIHM::checkArgCount(ls
, "removeText", 1);
556 CLuaIHM::checkArgType(ls
, "removeText", 1, LUA_TSTRING
);
557 std::string text
= ls
.toString(1);
559 for(uint i
=0; i
<getNumTexts(); i
++)
561 std::string sText
= getText(i
);
572 // ***************************************************************************
573 int CDBGroupComboBox::luaResetTexts(CLuaState
&ls
)
575 CLuaIHM::checkArgCount(ls
, "resetTexts", 0);
580 // ***************************************************************************
581 int CDBGroupComboBox::luaAddText(CLuaState
&ls
)
583 const char *funcName
= "addText";
584 CLuaIHM::checkArgCount(ls
, funcName
, 1);
585 #ifdef RYZOM_LUA_UCSTRING
586 CLuaIHM::checkArgTypeUCString(ls
, funcName
, 1);
587 ucstring text
; // Compatibility
588 nlverify(CLuaIHM::pop(ls
, text
));
589 addText(text
.toUtf8());
591 CLuaIHM::checkArgType(ls
, funcName
, 1, LUA_TSTRING
);
592 string text
= ls
.toString(1);
598 // ***************************************************************************
599 int CDBGroupComboBox::luaSetText(CLuaState
&ls
)
601 const char *funcName
= "setText";
602 CLuaIHM::checkArgCount(ls
, funcName
, 2);
603 CLuaIHM::checkArgType(ls
, funcName
, 1, LUA_TNUMBER
);
604 #ifdef RYZOM_LUA_UCSTRING
605 CLuaIHM::checkArgTypeUCString(ls
, funcName
, 2);
606 ucstring text
; // Compatibility
607 nlverify(CLuaIHM::pop(ls
, text
));
608 setText((uint
) ls
.toInteger(1), text
.toUtf8());
610 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TSTRING
);
611 string text
= ls
.toString(2);
612 setText((uint
)ls
.toInteger(1), text
);
617 // ***************************************************************************
618 int CDBGroupComboBox::luaInsertText(CLuaState
&ls
)
620 const char *funcName
= "insertText";
621 CLuaIHM::checkArgCount(ls
, funcName
, 2);
622 CLuaIHM::checkArgType(ls
, funcName
, 1, LUA_TNUMBER
);
623 #ifdef RYZOM_LUA_UCSTRING
624 CLuaIHM::checkArgTypeUCString(ls
, funcName
, 2);
626 nlverify(CLuaIHM::pop(ls
, text
));
627 insertText((uint
) ls
.toInteger(1), text
.toUtf8()); // FIXME: Lua should just do UTF-8!
629 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TSTRING
);
630 string text
= ls
.toString(2);
631 insertText((uint
)ls
.toInteger(1), text
);
636 // ***************************************************************************
637 int CDBGroupComboBox::luaSetTexture(CLuaState
&ls
)
639 const char *funcName
= "setTexture";
640 CLuaIHM::checkArgCount(ls
, funcName
, 2);
641 CLuaIHM::checkArgType(ls
, funcName
, 1, LUA_TNUMBER
);
642 #ifdef RYZOM_LUA_UCSTRING
643 CLuaIHM::checkArgTypeUCString(ls
, funcName
, 2);
645 nlverify(CLuaIHM::pop(ls
, texture
));
646 setTexture((uint
) ls
.toInteger(1), texture
.toUtf8()); // FIXME: Lua should just do UTF-8!
648 CLuaIHM::checkArgType(ls
, funcName
, 2, LUA_TSTRING
);
649 string texture
= ls
.toString(2);
650 setTexture((uint
)ls
.toInteger(1), texture
);
655 // ***************************************************************************
656 int CDBGroupComboBox::luaGetText(CLuaState
&ls
)
658 const char *funcName
= "getText";
659 CLuaIHM::checkArgCount(ls
, funcName
, 1);
660 CLuaIHM::checkArgType(ls
, funcName
, 1, LUA_TNUMBER
);
661 #ifdef RYZOM_LUA_UCSTRING
662 CLuaIHM::push(ls
, getTextAsUtf16((uint
) ls
.toInteger(1)));
664 ls
.push(getText((uint
)ls
.toInteger(1)));
669 // ***************************************************************************
670 int CDBGroupComboBox::luaRemoveTextByIndex(CLuaState
&ls
)
672 const char *funcName
= "removeText";
673 CLuaIHM::checkArgCount(ls
, funcName
, 1);
674 CLuaIHM::checkArgType(ls
, funcName
, 1, LUA_TNUMBER
);
675 removeText((uint
)ls
.toInteger(1));
679 // ***************************************************************************
680 int CDBGroupComboBox::luaGetNumTexts(CLuaState
&ls
)
682 const char *funcName
= "getNumTexts";
683 CLuaIHM::checkArgCount(ls
, funcName
, 0);
684 ls
.push(getNumTexts());
688 // ***************************************************************************
689 void CDBGroupComboBox::fillMenu(CGroupMenu
*groupMenu
) const
694 groupMenu
->setFontSize(_ViewText
->getFontSize());
696 // Setup the menu with combo action.
698 for(uint i
=0; i
<getNumTexts(); i
++)
700 // set the id as the parameter
701 bool checkable
= false;
702 if (getTexture(i
) != std::string())
706 groupMenu
->addLine(getText(i
), "combo_box_select_end", toString(i
),
707 "", std::string(), getTexture(i
), checkable
);
708 groupMenu
->setGrayedLine(i
, getGrayed(i
));
716 // ***************************************************************************
717 class CHandlerComboBoxSelectStart
: public IActionHandler
720 virtual void execute (CCtrlBase
*pCaller
, const std::string
&/* Params */)
722 CDBGroupComboBox
*pCB
= dynamic_cast<CDBGroupComboBox
*>(pCaller
->getParent());
723 if (pCB
== NULL
) return;
724 // if no choice, return.
725 if( pCB
->getNumTexts()==0 )
728 // get the menu to open.
729 CGroupMenu
*groupMenu
= dynamic_cast<CGroupMenu
*>(CWidgetManager::getInstance()->getElementFromId( CDBGroupComboBox::selectMenu
));
732 groupMenu
= dynamic_cast<CGroupMenu
*>(CWidgetManager::getInstance()->getElementFromId( CDBGroupComboBox::selectMenuOut
));
737 pCB
->fillMenu(groupMenu
);
739 groupMenu
->setMaxVisibleLine(8);
741 // pos and size wisely the menu.
742 groupMenu
->setMinW(pCB
->getWReal());
743 groupMenu
->setX(pCB
->getXReal());
744 groupMenu
->setBaseX(pCB
->getXReal());
745 groupMenu
->setY(pCB
->getYReal());
746 groupMenu
->setBaseY(pCB
->getYReal());
748 // Must ensure the combo menu has same windows priority than the combo box window
749 CInterfaceGroup
*rootWin
= pCB
->getRootWindow();
751 groupMenu
->setPriority(rootWin
->getPriority());
753 // After menu init, Call user activation method
754 if( !pCB
->_AHOnSelectStart
.empty() )
756 CAHManager::getInstance()->runActionHandler(pCB
->_AHOnSelectStart
, pCB
);
760 // if the combo box is in a modal, must do a push, else just replace
761 if(dynamic_cast<CGroupModal
*>(pCB
->getRootWindow()))
763 groupMenu
->setCloseSubMenuUsingPopModal(true);
764 CWidgetManager::getInstance()->pushModalWindow(pCB
, groupMenu
);
768 groupMenu
->setCloseSubMenuUsingPopModal(false);
769 CWidgetManager::getInstance()->enableModalWindow (pCB
, groupMenu
);
773 REGISTER_ACTION_HANDLER (CHandlerComboBoxSelectStart
, "combo_box_select_start");
778 // ***************************************************************************
779 class CHandlerComboBoxSelectEnd
: public IActionHandler
782 virtual void execute (CCtrlBase
* /* pCaller */, const std::string
&Params
)
784 CDBGroupComboBox
*pCB
= dynamic_cast<CDBGroupComboBox
*>(CWidgetManager::getInstance()->getCtrlLaunchingModal());
785 if (pCB
== NULL
) return;
789 fromString(Params
, selection
);
790 pCB
->setSelection(selection
);
793 REGISTER_ACTION_HANDLER (CHandlerComboBoxSelectEnd
, "combo_box_select_end");