1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2018 Winch Gate Property Limited
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) 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/group_editbox.h"
24 #include "nel/misc/command.h"
25 #include "nel/misc/utf_string_view.h"
26 #include "nel/gui/view_text.h"
27 #include "nel/misc/xml_auto_ptr.h"
28 #include "nel/gui/interface_options.h"
29 #include "nel/gui/ctrl_draggable.h"
30 #include "nel/gui/group_container_base.h"
31 #include "nel/gui/lua_ihm.h"
32 #include "nel/gui/widget_manager.h"
33 #include "nel/gui/view_renderer.h"
34 #include "nel/gui/db_manager.h"
35 #include "nel/gui/interface_factory.h"
38 using namespace NLMISC
;
53 sint32
CGroupEditBox::_SelectCursorPos
= 0;
54 CGroupEditBox
*CGroupEditBox::_MenuFather
= NULL
;
55 CGroupEditBox::IComboKeyHandler
* CGroupEditBox::comboKeyHandler
= NULL
;
57 // For now, just trim unsupported codepoints to make emoji fallback to text form
58 static u32char
supportedCodepoint(u32char c
)
60 if (c
>= 0xFE00 && c
< 0xFE10)
61 return 0; // Variation Selectors, unsupported
62 else if (c
>= 0xE0100 && c
< 0xE01F0)
63 return 0; // Variation Selectors Supplement, unsupported
64 else if (c
>= 0x200B && c
< 0x2010)
65 return 0; // ZERO WIDTH JOINER, etcetera, unsupported
66 else if (c
>= 0x2028 && c
< 0x202F)
67 return 0; // PARAGRAPH SEPARATOR, etcetera, unsupported
68 else if (c
>= 0x2060 && c
< 0x2070)
69 return 0; // WORD JOINER, etcetera, unsupported
71 return 0; // BOM, unsupported
72 else if ((c
& 0xFC00) == 0xD800)
73 return 0xFFFD; // UTF-16 surrogate, unmatched pair, invalid, set to replacement character
74 else if ((c
& 0xFC00) == 0xDC00)
75 return 0xFFFD; // UTF-16 surrogate, unmatched pair, invalid, set to replacement character
79 // For now, just trim unsupported codepoints to make emoji fallback to text form
80 static ::u32string
trimUnsupported(const ::u32string str
)
83 res
.reserve(str
.size());
84 for (::u32string::const_iterator
it(str
.begin()), end(str
.end()); it
!= end
; ++it
)
86 u32char c
= supportedCodepoint(*it
);
87 if (c
) // This also trims NUL
93 // ----------------------------------------------------------------------------
94 NLMISC_REGISTER_OBJECT(CViewBase
, CGroupEditBox
, std::string
, "edit_box");
96 CGroupEditBox::CGroupEditBox(const TCtorParam
¶m
) :
97 CGroupEditBoxBase(param
),
100 _MaxNumChar(std::numeric_limits
<uint32
>::max()),
102 _MaxNumReturn(std::numeric_limits
<uint32
>::max()),
104 _MaxCharsSize(32768),
105 _FirstVisibleChar(0),
107 _SelectingText(false),
110 _CurrentHistoricIndex(-1),
114 _BypassNextKey(false),
116 _CursorAtPreviousLineEnd(false),
117 _LooseFocusOnEnter(true),
118 _ResetFocusOnHide(false),
119 _BackupFatherContainerPos(false),
121 _ClearOnEscape(false),
123 _DefaultInputString(false),
129 _IntegerMinValue(INT_MIN
),
130 _IntegerMaxValue(INT_MAX
),
131 _PositiveIntegerMinValue(0),
132 _PositiveIntegerMaxValue(UINT_MAX
),
136 _Prompt
= ::u32string(1, (u32char
)'>');
137 _BackSelectColor
= CRGBA::White
;
138 _TextSelectColor
= CRGBA::Black
;
141 // ----------------------------------------------------------------------------
142 CGroupEditBox::~CGroupEditBox()
144 if (this == _CurrSelection
) _CurrSelection
= NULL
;
145 if (CWidgetManager::getInstance()->getCaptureKeyboard() == this || CWidgetManager::getInstance()->getOldCaptureKeyboard() == this)
147 CWidgetManager::getInstance()->resetCaptureKeyboard();
151 std::string
CGroupEditBox::getProperty( const std::string
&name
) const
153 if( name
== "onchange" )
158 if( name
== "onchange_params" )
160 return _ParamsOnChange
;
163 if( name
== "on_focus_lost" )
165 return _AHOnFocusLost
;
168 if( name
== "on_focus_lost_params" )
170 return _AHOnFocusLostParams
;
173 if( name
== "on_focus" )
178 if( name
== "on_focus_params" )
180 return _AHOnFocusParams
;
183 if( name
== "max_num_chars" )
185 return toString( _MaxNumChar
);
188 if( name
== "max_num_bytes" )
190 return toString( _MaxNumBytes
);
193 if( name
== "max_num_return" )
195 return toString( _MaxNumReturn
);
198 if( name
== "max_chars_size" )
200 return toString( _MaxCharsSize
);
203 if( name
== "enter_loose_focus" )
205 return toString( _LooseFocusOnEnter
);
208 if( name
== "enter_recover_focus" )
210 return toString( _RecoverFocusOnEnter
);
213 if( name
== "prompt" )
215 return CUtfStringView(_Prompt
).toUtf8();
218 if( name
== "enter_type" )
226 case PositiveInteger
:
227 return "positive_integer";
235 return "positive_float";
247 return "alpha_num_space";
269 if( name
== "menu_r" )
271 return _ListMenuRight
;
274 if( name
== "max_historic" )
276 return toString( _MaxHistoric
);
279 if( name
== "backup_father_container_pos" )
281 return toString( _BackupFatherContainerPos
);
284 if( name
== "want_return" )
286 return toString( _WantReturn
);
289 if( name
== "clear_on_escape" )
291 return toString( _ClearOnEscape
);
294 if( name
== "savable" )
296 return toString( _Savable
);
299 if( name
== "max_float_prec" )
301 return toString( _MaxFloatPrec
);
304 if( name
== "negative_filter" )
307 s
.reserve( _NegativeFilter
.size() );
309 std::vector
< u32char
>::const_iterator itr
;
310 for (itr
= _NegativeFilter
.begin(); itr
!= _NegativeFilter
.end(); ++itr
)
311 CUtfStringView::append(s
, *itr
);
316 return CInterfaceGroup::getProperty( name
);
319 void CGroupEditBox::setProperty( const std::string
&name
, const std::string
&value
)
321 if( name
== "onchange" )
327 if( name
== "onchange_params" )
329 _ParamsOnChange
= value
;
333 if( name
== "on_focus_lost" )
335 _AHOnFocusLost
= value
;
339 if( name
== "on_focus_lost_params" )
341 _AHOnFocusLostParams
= value
;
345 if( name
== "on_focus" )
351 if( name
== "on_focus_params" )
353 _AHOnFocusParams
= value
;
357 if( name
== "max_num_chars" )
360 if( fromString( value
, i
) )
365 if( name
== "max_num_bytes" )
368 if( fromString( value
, i
) )
373 if( name
== "max_num_return" )
376 if( fromString( value
, i
) )
381 if( name
== "max_chars_size" )
384 if( fromString( value
, i
) )
389 if( name
== "enter_loose_focus" )
392 if( fromString( value
, b
) )
393 _LooseFocusOnEnter
= b
;
397 if( name
== "enter_recover_focus" )
400 if( fromString( value
, b
) )
401 _RecoverFocusOnEnter
= b
;
405 if( name
== "prompt" )
407 _Prompt
= CUtfStringView(value
).toUtf32();
411 if( name
== "enter_type" )
413 if( value
== "integer" )
414 _EntryType
= Integer
;
416 if( value
== "positive_integer" )
417 _EntryType
= PositiveInteger
;
419 if( value
== "float" )
422 if( value
== "positive_float" )
423 _EntryType
= PositiveFloat
;
425 if( value
== "alpha" )
428 if( value
== "alpha_num" )
429 _EntryType
= AlphaNum
;
431 if( value
== "alpha_num_space" )
432 _EntryType
= AlphaNumSpace
;
434 if( value
== "password" )
435 _EntryType
= Password
;
437 if( value
== "filename" )
438 _EntryType
= Filename
;
440 if( value
== "playername" )
441 _EntryType
= PlayerName
;
446 if( name
== "menu_r" )
448 _ListMenuRight
= value
;
452 if( name
== "max_historic" )
455 if( fromString( value
, i
) )
460 if( name
== "backup_father_container_pos" )
463 if( fromString( value
, b
) )
464 _BackupFatherContainerPos
= b
;
468 if( name
== "want_return" )
471 if( fromString( value
, b
) )
476 if( name
== "clear_on_escape" )
479 if( fromString( value
, b
) )
484 if( name
== "savable" )
487 if( fromString( value
, b
) )
492 if( name
== "max_float_prec" )
495 if( fromString( value
, i
) )
500 if( name
== "negative_filter" )
502 _NegativeFilter
.clear();
503 ::u32string::size_type i
;
504 ::u32string ustr
= CUtfStringView(value
).toUtf32();
505 for( i
= 0; i
< ustr
.size(); i
++ )
506 _NegativeFilter
.push_back(ustr
[i
]);
509 CInterfaceGroup::setProperty( name
, value
);
512 xmlNodePtr
CGroupEditBox::serialize( xmlNodePtr parentNode
, const char *type
) const
514 xmlNodePtr node
= CInterfaceGroup::serialize( parentNode
, type
);
518 xmlSetProp( node
, BAD_CAST
"type", BAD_CAST
"edit_box" );
519 xmlSetProp( node
, BAD_CAST
"onchange", BAD_CAST _AHOnChange
.c_str() );
520 xmlSetProp( node
, BAD_CAST
"onchange_params", BAD_CAST _ParamsOnChange
.c_str() );
521 xmlSetProp( node
, BAD_CAST
"on_focus_lost", BAD_CAST _AHOnFocusLost
.c_str() );
522 xmlSetProp( node
, BAD_CAST
"on_focus_lost_params", BAD_CAST _AHOnFocusLostParams
.c_str() );
523 xmlSetProp( node
, BAD_CAST
"on_focus", BAD_CAST _AHOnFocus
.c_str() );
524 xmlSetProp( node
, BAD_CAST
"on_focus_params", BAD_CAST _AHOnFocusParams
.c_str() );
525 xmlSetProp( node
, BAD_CAST
"max_num_chars", BAD_CAST
toString( _MaxNumChar
).c_str() );
526 xmlSetProp( node
, BAD_CAST
"max_num_bytes", BAD_CAST
toString( _MaxNumBytes
).c_str() );
527 xmlSetProp( node
, BAD_CAST
"max_num_return", BAD_CAST
toString( _MaxNumReturn
).c_str() );
528 xmlSetProp( node
, BAD_CAST
"max_chars_size", BAD_CAST
toString( _MaxCharsSize
).c_str() );
529 xmlSetProp( node
, BAD_CAST
"enter_loose_focus", BAD_CAST
toString( _LooseFocusOnEnter
).c_str() );
530 xmlSetProp( node
, BAD_CAST
"enter_recover_focus", BAD_CAST
toString( _RecoverFocusOnEnter
).c_str() );
531 xmlSetProp( node
, BAD_CAST
"prompt", BAD_CAST
CUtfStringView(_Prompt
).toUtf8().c_str() );
540 case PositiveInteger
:
541 e
= "positive_integer";
549 e
= "positive_float";
561 e
= "alpha_num_space";
580 xmlSetProp( node
, BAD_CAST
"enter_type", BAD_CAST e
.c_str() );
581 xmlSetProp( node
, BAD_CAST
"menu_r", BAD_CAST _ListMenuRight
.c_str() );
582 xmlSetProp( node
, BAD_CAST
"max_historic", BAD_CAST
toString( _MaxHistoric
).c_str() );
583 xmlSetProp( node
, BAD_CAST
"backup_father_container_pos",
584 BAD_CAST
toString( _BackupFatherContainerPos
).c_str() );
585 xmlSetProp( node
, BAD_CAST
"want_return", BAD_CAST
toString( _WantReturn
).c_str() );
586 xmlSetProp( node
, BAD_CAST
"clear_on_escape", BAD_CAST
toString( _ClearOnEscape
).c_str() );
587 xmlSetProp( node
, BAD_CAST
"savable", BAD_CAST
toString( _Savable
).c_str() );
588 xmlSetProp( node
, BAD_CAST
"max_float_prec", BAD_CAST
toString( _MaxFloatPrec
).c_str() );
591 s
.reserve( _NegativeFilter
.size() );
593 std::vector
< u32char
>::const_iterator itr
;
594 for( itr
= _NegativeFilter
.begin(); itr
!= _NegativeFilter
.end(); ++itr
)
595 CUtfStringView::append(s
, *itr
);
597 xmlSetProp( node
, BAD_CAST
"negative_filter", BAD_CAST s
.c_str() );
602 // ----------------------------------------------------------------------------
603 bool CGroupEditBox::parse(xmlNodePtr cur
, CInterfaceGroup
* parentGroup
)
605 if(!CInterfaceGroup::parse(cur
, parentGroup
))
609 if (! CInterfaceGroup::parse(cur
,parentGroup
) )
611 string tmp
= "cannot parse view:"+getId()+", parent:"+parentGroup
->getId();
616 // NB: use InterfaceGroup "OnEnter" data. Different script params for an historic reason
617 CAHManager::getInstance()->parseAH(cur
, "onenter", "params", _AHOnEnter
, _AHOnEnterParams
);
621 prop
= (char*) xmlGetProp( cur
, BAD_CAST
"onenter" );
623 mapAHString( "onenter", std::string( (const char*)prop
) );
626 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"onchange" );
627 if (prop
) _AHOnChange
= (const char *) prop
;
628 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"onchange_params" );
629 if (prop
) _ParamsOnChange
= (const char *) prop
;
631 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"on_focus_lost" );
632 if (prop
) _AHOnFocusLost
= (const char *) prop
;
633 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"on_focus_lost_params" );
634 if (prop
) _AHOnFocusLostParams
= (const char *) prop
;
636 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"on_focus" );
637 if (prop
) _AHOnFocus
= (const char *) prop
;
638 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"on_focus_params" );
639 if (prop
) _AHOnFocusParams
= (const char *) prop
;
641 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"max_num_chars" );
642 if (prop
) fromString((const char*)prop
, _MaxNumChar
);
644 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"max_num_bytes" );
645 if (prop
) fromString((const char*)prop
, _MaxNumBytes
);
647 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"max_num_return" );
648 if (prop
) fromString((const char*)prop
, _MaxNumReturn
);
650 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"max_chars_size" );
651 if (prop
) fromString((const char*)prop
, _MaxCharsSize
);
653 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"enter_loose_focus" );
654 if (prop
) _LooseFocusOnEnter
= convertBool(prop
);
656 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"enter_recover_focus" );
657 if (prop
) _RecoverFocusOnEnter
= convertBool(prop
);
659 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"reset_focus_on_hide" );
660 if (prop
) _ResetFocusOnHide
= convertBool(prop
);
662 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"prompt" );
663 if (prop
) _Prompt
= CUtfStringView((const char*)prop
).toUtf32();
665 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"entry_type" );
669 if (stricmp(prop
, "text") == 0) _EntryType
= Text
;
670 else if (stricmp(prop
, "integer") == 0) _EntryType
= Integer
;
671 else if (stricmp(prop
, "positive_integer") == 0) _EntryType
= PositiveInteger
;
672 else if (stricmp(prop
, "float") == 0) _EntryType
= Float
;
673 else if (stricmp(prop
, "positive_float") == 0) _EntryType
= PositiveFloat
;
674 else if (stricmp(prop
, "alpha") == 0) _EntryType
= Alpha
;
675 else if (stricmp(prop
, "alpha_num") == 0) _EntryType
= AlphaNum
;
676 else if (stricmp(prop
, "alpha_num_space") == 0) _EntryType
= AlphaNumSpace
;
677 else if (stricmp(prop
, "password") == 0) _EntryType
= Password
;
678 else if (stricmp(prop
, "filename") == 0) _EntryType
= Filename
;
679 else if (stricmp(prop
, "playername") == 0) _EntryType
= PlayerName
;
681 nlwarning("<CGroupEditBox::parse> Unknown entry type %s", (const char *) prop
);
684 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"menu_r" );
685 if (prop
) _ListMenuRight
= toLowerAscii((const char *) prop
);
687 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"max_historic" );
688 if (prop
) fromString((const char*)prop
, _MaxHistoric
);
690 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"backup_father_container_pos" );
691 if (prop
) _BackupFatherContainerPos
= convertBool(prop
);
693 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"want_return" );
694 if (prop
) _WantReturn
= convertBool(prop
);
696 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"clear_on_escape" );
697 if (prop
) _ClearOnEscape
= convertBool(prop
);
699 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"savable" );
700 if (prop
) _Savable
= convertBool(prop
);
702 // For float conversion only
703 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"max_float_prec" );
706 fromString((const char*)prop
, _MaxFloatPrec
);
707 _MaxFloatPrec
= min((uint32
)20, _MaxFloatPrec
);
710 // negative characters filter
711 prop
= (char*) xmlGetProp( cur
, (xmlChar
*)"negative_filter" );
714 _NegativeFilter
.clear();
715 ::u32string::size_type i
;
716 ::u32string ustr
= CUtfStringView(prop
).toUtf32();
717 for( i
= 0; i
< ustr
.size(); i
++ )
718 _NegativeFilter
.push_back(ustr
[i
]);
724 // ----------------------------------------------------------------------------
725 void CGroupEditBox::draw ()
728 CViewRenderer
&rVR
= *CViewRenderer::getInstance();
731 col.modulateFromColor(CRGBA(64,64,64,255), pIM->getGlobalColorForContent());
732 rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), col );
735 // Frozen? display text in "grayed"
737 if(_Frozen
&& _ViewText
)
739 bkupTextColor
= _ViewText
->getColor();
740 CRGBA grayed
= bkupTextColor
;
742 _ViewText
->setColor(grayed
);
745 // draw the group and thus the text
746 CInterfaceGroup::draw();
748 // restore the text color if changed
749 if(_Frozen
&& _ViewText
)
750 _ViewText
->setColor(bkupTextColor
);
752 // no text setuped? abort
753 if (!_ViewText
) return;
755 // Display the selection if needed
756 if (_CurrSelection
== this && _SelectCursorPos
!=_CursorPos
)
758 sint32 blankTextId
= rVR
.getBlankTextureId();
759 CRGBA col
= _BackSelectColor
;
760 col
.A
= CWidgetManager::getInstance()->getGlobalColorForContent().A
;
761 sint32 minPos
= min(_CursorPos
, _SelectCursorPos
) + (sint32
)_Prompt
.length();
762 sint32 maxPos
= max(_CursorPos
, _SelectCursorPos
) + (sint32
)_Prompt
.length();
764 // get its position on screen
765 float cxMinPos
, cyMinPos
;
766 float cxMaxPos
, cyMaxPos
;
768 _ViewText
->getCharacterPositionFromIndex(minPos
, false, cxMinPos
, cyMinPos
, height
);
769 _ViewText
->getCharacterPositionFromIndex(maxPos
, false, cxMaxPos
, cyMaxPos
, height
);
771 // Multiline selection if cy different!
772 if(cyMinPos
!=cyMaxPos
)
774 nlassert(cyMaxPos
<cyMinPos
);
775 // draw the 1st quad from the first line from min pos to end of line
776 rVR
.drawRotFlipBitmap(_RenderLayer
, _ViewText
->getXReal() + cxMinPos
, _ViewText
->getYReal() + cyMinPos
, _ViewText
->getW()-cxMinPos
, height
, 0, 0, blankTextId
, col
);
778 // Draw One quad for all lines into the big selection (if any)
779 sint32 cyBigQuad
= cyMaxPos
+height
;
780 if(cyBigQuad
<cyMinPos
)
782 rVR
.drawRotFlipBitmap(_RenderLayer
, _ViewText
->getXReal(), _ViewText
->getYReal() + cyBigQuad
, _ViewText
->getW(), cyMinPos
-cyBigQuad
, 0, 0, blankTextId
, col
);
785 // draw the 3rd quad from the last line from start of line to max pos
786 rVR
.drawRotFlipBitmap(_RenderLayer
, _ViewText
->getXReal(), _ViewText
->getYReal() + cyMaxPos
, cxMaxPos
, height
, 0, 0, blankTextId
, col
);
790 rVR
.drawRotFlipBitmap(_RenderLayer
, _ViewText
->getXReal() + cxMinPos
, _ViewText
->getYReal() + cyMinPos
, cxMaxPos
-cxMinPos
, height
, 0, 0, blankTextId
, col
);
793 // Draw The Selection String in black
794 CRGBA bkup
= _ViewText
->getColor();
795 _ViewText
->setColor(_TextSelectColor
);
796 _ViewText
->enableStringSelection(minPos
, maxPos
);
797 // redraw just this string,clipped by the group
798 CInterfaceGroup::drawElement(_ViewText
);
800 _ViewText
->setColor(bkup
);
801 _ViewText
->disableStringSelection();
804 // Display the cursor if needed
805 if (CWidgetManager::getInstance()->getCaptureKeyboard () == this)
807 const CWidgetManager::SInterfaceTimes
×
= CWidgetManager::getInstance()->getInterfaceTimes();
809 _BlinkTime
+= ( static_cast< float >( times
.frameDiffMs
) / 1000.0f
);
810 if (_BlinkTime
> 0.25f
)
812 _BlinkTime
= fmodf(_BlinkTime
, 0.25f
);
813 _BlinkState
= !_BlinkState
;
815 if (_BlinkState
) // is the cursor shown ?
817 // get its position on screen
820 _ViewText
->getCharacterPositionFromIndex(_CursorPos
+ (sint
)_Prompt
.length(), _CursorAtPreviousLineEnd
, cx
, cy
, height
);
821 // display the cursor
822 // get the texture for the cursor
823 if (_CursorTexID
== -1)
825 _CursorTexID
= rVR
.getTextureIdFromName("text_cursor.tga");
826 sint32 dummyCursorHeight
;
827 rVR
.getTextureSizeFromId(_CursorTexID
, _CursorWidth
, dummyCursorHeight
);
829 // draw in a layer after to be on TOP of the text
830 sint32 cursorx
= std::max((sint
) 0, (sint
)(cx
- (_CursorWidth
>> 1)));
831 rVR
.drawRotFlipBitmap(_RenderLayer
+1, _ViewText
->getXReal() + cursorx
, _ViewText
->getYReal() + cy
, 3, height
, 0, 0, _CursorTexID
);
836 // ----------------------------------------------------------------------------
837 void CGroupEditBox::copy()
839 if (_CurrSelection
!= this)
841 nlwarning("Selection can only be on focus");
845 // get the selection and copy it
846 if (CViewRenderer::getInstance()->getDriver()->copyTextToClipboard(getSelection()))
847 nlinfo ("Chat input was copied in the clipboard");
850 // ----------------------------------------------------------------------------
851 void CGroupEditBox::paste()
853 if(_CurrSelection
!= NULL
)
855 if (_CurrSelection
!= this)
857 nlwarning("Selection can only be on focus");
864 if (CViewRenderer::getInstance()->getDriver()->pasteTextFromClipboard(sString
))
867 appendStringFromClipboard(sString
);
871 // ----------------------------------------------------------------------------
872 void CGroupEditBox::appendStringFromClipboard(const std::string
&str
)
877 writeString(str
, true, false);
878 nlinfo ("Chat input was pasted from the clipboard");
882 _CursorAtPreviousLineEnd
= false;
885 // ----------------------------------------------------------------------------
886 void CGroupEditBox::writeString(const std::string
&str16
, bool replace
, bool atEnd
)
888 // For now, just trim unsupported codepoints to make emoji fallback to text form
889 ::u32string str
= trimUnsupported(CUtfStringView(str16
).toUtf32());
890 sint length
= (sint
)str
.length();
892 ::u32string toAppend
;
893 // filter character depending on the entry type
899 if (_NegativeFilter
.empty())
905 for (sint k
= 0; k
< length
; ++k
)
907 if (!isFiltered(str
[k
]))
913 // remove '\r' characters
914 toAppend
.erase(std::remove(toAppend
.begin(), toAppend
.end(), (u32char
) '\r'), toAppend
.end());
918 case PositiveInteger
:
921 for (sint k
= 0; k
< length
; ++k
)
923 if (isdigit(str
[k
]) || str
[k
]== ' ' ||
924 (_EntryType
==PositiveFloat
&& str
[k
]=='.') )
926 if (!isFiltered(str
[k
]))
937 for (sint k
= 0; k
< length
; ++k
)
939 if (isdigit(str
[k
]) || str
[k
]== ' ' || str
[k
]== '-' ||
940 (_EntryType
==Float
&& str
[k
]=='.') )
942 if (!isFiltered(str
[k
]))
952 for (sint k
= 0; k
< length
; ++k
)
954 if (isValidAlphaNumSpace(str
[k
]))
956 if (!isFiltered(str
[k
]))
966 for (sint k
= 0; k
< length
; ++k
)
968 if (isValidAlphaNum(str
[k
]))
970 if (!isFiltered(str
[k
]))
980 for (sint k
= 0; k
< length
; ++k
)
982 if (isValidAlpha(str
[k
]))
984 if (!isFiltered(str
[k
]))
994 for (sint k
= 0; k
< length
; ++k
)
996 if (isValidFilenameChar(str
[k
]))
998 if (!isFiltered(str
[k
]))
1008 for (sint k
= 0; k
< length
; ++k
)
1010 if (isValidPlayerNameChar(str
[k
]))
1012 if (!isFiltered(str
[k
]))
1020 length
= (sint
)toAppend
.size();
1021 if ((uint
) (_InputString
.length() + length
) > _MaxNumChar
)
1023 length
= _MaxNumChar
- (sint
)_InputString
.length();
1025 ::u32string toAdd
= toAppend
.substr(0, length
);
1026 if (_MaxNumBytes
&& length
)
1028 sint baseBytes
= CUtfStringView(_InputString
).toUtf8().length();
1029 sint bytes
= baseBytes
+ CUtfStringView(toAdd
).toUtf8().length();
1030 while (bytes
> _MaxNumBytes
)
1032 length
-= std::max((int)(bytes
- _MaxNumBytes
) >> 2, 1);
1033 toAdd
= toAdd
.substr(0, length
);
1034 bytes
= baseBytes
+ CUtfStringView(toAdd
).toUtf8().length();
1039 if (_CurrSelection
== this)
1041 minPos
= min(_CursorPos
, _SelectCursorPos
);
1042 maxPos
= max(_CursorPos
, _SelectCursorPos
);
1046 minPos
= _CursorPos
;
1047 maxPos
= _CursorPos
;
1052 _InputString
= _InputString
.substr(0, minPos
) + toAdd
+ _InputString
.substr(maxPos
);
1053 _CursorPos
= minPos
+(sint32
)toAdd
.length();
1059 _InputString
= _InputString
.substr(0, maxPos
) + toAdd
+ _InputString
.substr(maxPos
);
1060 _CursorPos
= maxPos
;
1061 _SelectCursorPos
= _CursorPos
;
1066 _InputString
= _InputString
.substr(0, minPos
) + toAdd
+ _InputString
.substr(minPos
);
1067 _CursorPos
= minPos
+(sint32
)toAdd
.length();
1068 _SelectCursorPos
= maxPos
+(sint32
)toAdd
.length();
1073 // ----------------------------------------------------------------------------
1074 void CGroupEditBox::handleEventChar(const NLGUI::CEventDescriptorKey
&rEDK
)
1077 switch(rEDK
.getChar())
1080 _CurrentHistoricIndex
= -1;
1082 _CurrSelection
= NULL
;
1083 _CursorAtPreviousLineEnd
= false;
1086 setInputStringRef(::u32string());
1087 triggerOnChangeAH();
1089 CWidgetManager::getInstance()->setCaptureKeyboard(NULL
);
1096 bool isKeyRETURN
= !rEDK
.getKeyCtrl() && rEDK
.getChar() == KeyRETURN
;
1097 if (isKeyRETURN
&& !_WantReturn
)
1102 if( !_InputString
.empty() )
1104 _Historic
.push_front(_InputString
);
1105 if(_Historic
.size()>_MaxHistoric
)
1106 _Historic
.pop_back();
1108 _CurrentHistoricIndex
= -1;
1112 // loose the keyboard focus
1113 if (NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:CHAT:ENTER_DONT_QUIT_CB")->getValue32() == 0)
1115 if(_LooseFocusOnEnter
)
1116 CWidgetManager::getInstance()->setCaptureKeyboard(NULL
);
1119 _CurrSelection
= NULL
;
1120 _CursorAtPreviousLineEnd
= false;
1121 CAHManager::getInstance()->runActionHandler(_AHOnEnter
, this, _AHOnEnterParams
);
1125 // If the char is not alphanumeric -> return.
1126 // if(!isalnum(ec.Char))
1128 if( (rEDK
.getChar()>=32) || isKeyRETURN
)
1132 //u32string copyStr= _InputString;
1133 //if ((uint) std::count(copyStr.begin(), copyStr.end(), '\n') >= _MaxNumReturn)
1134 if ((uint
)std::count(_InputString
.begin(), _InputString
.end(), '\n') >= _MaxNumReturn
)
1138 // if selection is activated, then cut the selection
1139 if(_CurrSelection
!= NULL
)
1141 if (_CurrSelection
!= this)
1143 nlwarning("Selection can only be on focus");
1148 u32char c
= isKeyRETURN
? '\n' : rEDK
.getChar();
1149 if (isFiltered(c
)) return;
1150 c
= supportedCodepoint(c
);
1151 if (!c
) return; // For now, just trim unsupported codepoints to make emoji fallback to text form
1155 if (c
> 255 || !(c
=='-' || c
==' ' || isdigit((int) c
)))
1158 case PositiveInteger
:
1159 if (c
> 255 || !(c
== ' ' || isdigit((int) c
)))
1163 if (c
> 255 || !(c
=='-' || c
==' ' || c
=='.' || isdigit((int) c
)))
1167 if (c
> 255 || !(c
== ' ' || c
=='.' || isdigit((int) c
)))
1171 if (!isValidAlphaNumSpace(c
))
1175 if (!isValidAlphaNum(c
))
1179 if (!isValidAlpha(c
))
1183 if (!isValidFilenameChar(c
))
1187 if (!isValidPlayerNameChar(c
))
1193 // verify integer bounds
1194 if(_EntryType
==Integer
&& (_IntegerMinValue
!=INT_MIN
|| _IntegerMaxValue
!=INT_MAX
))
1196 // estimate new string
1197 ::u32string copyStr
= _InputString
;
1198 ::u32string::iterator it
= copyStr
.begin() + _CursorPos
;
1199 copyStr
.insert(it
, c
);
1201 fromString(CUtfStringView(copyStr
).toUtf8(), value
);
1202 // if out of bounds, abort char
1203 if(value
<_IntegerMinValue
|| value
>_IntegerMaxValue
)
1206 // verify integer bounds
1207 if(_EntryType
==PositiveInteger
&& (_PositiveIntegerMinValue
!=0 || _PositiveIntegerMaxValue
!=UINT_MAX
))
1209 // estimate new string
1210 ::u32string copyStr
= _InputString
;
1211 ::u32string::iterator it
= copyStr
.begin() + _CursorPos
;
1212 copyStr
.insert(it
, c
);
1213 // \todo yoyo: this doesn't really work i think....
1215 fromString(CUtfStringView(copyStr
).toUtf8(), value
);
1216 // if out of bounds, abort char
1217 if(value
<_PositiveIntegerMinValue
|| value
>_PositiveIntegerMaxValue
)
1220 // verify max num char
1221 if ((uint
) _InputString
.length() < _MaxNumChar
)
1223 if (!_MaxNumBytes
|| CUtfStringView(_InputString
+ c
).toUtf8().size() <= _MaxNumBytes
)
1226 ::u32string::iterator it
= _InputString
.begin() + _CursorPos
;
1227 _InputString
.insert(it
, c
);
1229 triggerOnChangeAH();
1234 CAHManager::getInstance()->runActionHandler(_AHOnEnter
, this, _AHOnEnterParams
);
1237 _CursorAtPreviousLineEnd
= false;
1243 // ----------------------------------------------------------------------------
1244 void CGroupEditBox::handleEventString(const NLGUI::CEventDescriptorKey
&rEDK
)
1246 appendStringFromClipboard(rEDK
.getString());
1249 // ----------------------------------------------------------------------------
1250 bool CGroupEditBox::undo()
1252 if (CWidgetManager::getInstance()->getCaptureKeyboard() != this) return false;
1253 if (!_CanUndo
) return false;
1254 _ModifiedInputString
= _InputString
;
1255 setInputStringRef(_StartInputString
);
1258 setCursorPos((sint32
)_InputString
.length());
1263 // ----------------------------------------------------------------------------
1264 bool CGroupEditBox::redo()
1266 if (CWidgetManager::getInstance()->getCaptureKeyboard() != this) return false;
1267 if (!_CanRedo
) return false;
1268 setInputStringRef(_ModifiedInputString
);
1271 setCursorPos((sint32
)_InputString
.length());
1276 // ----------------------------------------------------------------------------
1277 void CGroupEditBox::triggerOnChangeAH()
1282 if (!_AHOnChange
.empty())
1283 CAHManager::getInstance()->runActionHandler(_AHOnChange
, this, _ParamsOnChange
);
1287 // ----------------------------------------------------------------------------
1288 bool CGroupEditBox::expand()
1290 if ((_EntryType
== Integer
) ||
1291 (_EntryType
== PositiveInteger
) ||
1292 (_EntryType
== Float
) ||
1293 (_EntryType
== PositiveFloat
) ||
1294 (_EntryType
== AlphaNumSpace
) ||
1295 (_EntryType
== AlphaNum
) ||
1296 (_EntryType
== Alpha
) ||
1297 (_EntryType
== Filename
) ||
1298 (_EntryType
== PlayerName
)
1302 if(!_InputString
.empty())
1304 if (_InputString
[0] == '/')
1307 // for french, deutsch and russian, be aware of unicode
1308 std::string command
= CUtfStringView(_InputString
.substr(1)).toUtf8();
1309 ICommand::expand(command
);
1310 // then back to u32string
1311 _InputString
= CUtfStringView('/' + command
).toUtf32();
1312 _InputString
= _InputString
;
1313 _CursorPos
= (sint32
)_InputString
.length();
1314 _CursorAtPreviousLineEnd
= false;
1315 triggerOnChangeAH();
1322 // ----------------------------------------------------------------------------
1323 void CGroupEditBox::back()
1326 // if selection is activated and not same cursors pos, then cut the selection
1327 if(_CurrSelection
!= NULL
&& _CursorPos
!= _SelectCursorPos
)
1329 if (_CurrSelection
!= this)
1331 nlwarning("Selection can only be on focus");
1334 _CursorAtPreviousLineEnd
= false;
1336 // else delete last character
1337 else if(_InputString
.size () > 0 && _CursorPos
!= 0)
1339 ::u32string::iterator it
= _InputString
.begin() + (_CursorPos
- 1);
1340 _InputString
.erase(it
);
1342 _CursorAtPreviousLineEnd
= false;
1343 triggerOnChangeAH();
1345 // must stop selection in all case
1348 if (_CurrSelection
!= this)
1350 nlwarning("Selection can only be on focus");
1352 _CurrSelection
= NULL
;
1356 // ----------------------------------------------------------------------------
1357 bool CGroupEditBox::handleEvent (const NLGUI::CEventDescriptor
& event
)
1359 if (!_Active
|| !_ViewText
)
1361 if (event
.getType() == NLGUI::CEventDescriptor::key
)
1365 _BypassNextKey
= false;
1371 const NLGUI::CEventDescriptorKey
&rEDK
= (const NLGUI::CEventDescriptorKey
&)event
;
1372 switch(rEDK
.getKeyEventType())
1374 case NLGUI::CEventDescriptorKey::keychar
: handleEventChar(rEDK
); break;
1375 case NLGUI::CEventDescriptorKey::keystring
: handleEventString(rEDK
); break;
1379 setInputStringRef(_InputString
);
1381 // if event of type char or string, consider handle all of them
1382 if( rEDK
.getKeyEventType()==NLGUI::CEventDescriptorKey::keychar
|| rEDK
.getKeyEventType()==NLGUI::CEventDescriptorKey::keystring
)
1384 // Else filter the EventKeyDown AND EventKeyUp.
1387 // Look into the input handler Manager if the key combo has to be considered as handled
1388 if( ( CGroupEditBox::comboKeyHandler
!= NULL
) && comboKeyHandler
->isComboKeyChat(rEDK
) )
1395 if (event
.getType() == NLGUI::CEventDescriptor::mouse
)
1400 const NLGUI::CEventDescriptorMouse
&eventDesc
= (const NLGUI::CEventDescriptorMouse
&)event
;
1402 if (eventDesc
.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightup
)
1404 if (CWidgetManager::getInstance()->getCapturePointerRight() == this)
1406 CWidgetManager::getInstance()->setCapturePointerRight(NULL
);
1407 if (!_ListMenuRight
.empty())
1409 if (CCtrlDraggable::getDraggedSheet() == NULL
)
1412 CWidgetManager::getInstance()->enableModalWindow (this, _ListMenuRight
);
1424 // if click, and not frozen, then get the focus
1425 if (eventDesc
.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftup
&& !_Frozen
)
1427 _SelectingText
= false;
1428 if (_SelectCursorPos
== _CursorPos
)
1429 _CurrSelection
= NULL
;
1434 if (!isIn(eventDesc
.getX(), eventDesc
.getY()))
1437 // if click, and not frozen, then get the focus
1438 if (eventDesc
.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftdown
&& !_Frozen
)
1440 if( getEditorMode() )
1442 return CViewBase::handleEvent( event
);
1445 _SelectingText
= true;
1447 CWidgetManager::getInstance()->setCaptureKeyboard (this);
1448 CWidgetManager::getInstance()->setCapturePointerLeft (this);
1449 // set the right cursor position
1451 bool cursorAtPreviousLineEnd
;
1452 _ViewText
->getCharacterIndexFromPosition(eventDesc
.getX() - _ViewText
->getXReal(), eventDesc
.getY() - _ViewText
->getYReal(), newCurPos
, cursorAtPreviousLineEnd
);
1453 _CursorAtPreviousLineEnd
= cursorAtPreviousLineEnd
;
1454 _CursorPos
= newCurPos
;
1455 _CursorPos
-= (sint32
)_Prompt
.length();
1456 _CursorPos
= std::max(_CursorPos
, sint32(0));
1457 _SelectCursorPos
= _CursorPos
;
1458 _CurrSelection
= NULL
;
1462 // if click, and not frozen, then get the focus
1463 if (eventDesc
.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mousemove
&& !_Frozen
&& _SelectingText
)
1465 // set the right cursor position
1467 bool cursorAtPreviousLineEnd
;
1468 _CurrSelection
= this;
1469 _ViewText
->getCharacterIndexFromPosition(eventDesc
.getX() - _ViewText
->getXReal(), eventDesc
.getY() - _ViewText
->getYReal(), newCurPos
, cursorAtPreviousLineEnd
);
1470 _SelectCursorPos
= newCurPos
;
1471 _SelectCursorPos
-= (sint32
)_Prompt
.length();
1472 _SelectCursorPos
= std::max(_SelectCursorPos
, sint32(0));
1476 if (eventDesc
.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightdown
)
1478 CWidgetManager::getInstance()->setCapturePointerRight(this);
1487 const NLGUI::CEventDescriptorSystem
&eventDesc
= (const NLGUI::CEventDescriptorSystem
&)event
;
1488 if (eventDesc
.getEventTypeExtended() == NLGUI::CEventDescriptorSystem::activecalledonparent
)
1490 NLGUI::CEventDescriptorActiveCalledOnParent
&activeEvent
= (NLGUI::CEventDescriptorActiveCalledOnParent
&) eventDesc
;
1491 if (activeEvent
.getActive() == false && _ResetFocusOnHide
)
1493 CWidgetManager::getInstance()->resetCaptureKeyboard();
1494 // If a selection was shown, reset it
1495 if (_CurrSelection
== this) _CurrSelection
= NULL
;
1497 CInterfaceGroup::handleEvent(activeEvent
);
1504 // ----------------------------------------------------------------------------
1505 void CGroupEditBox::setupDisplayText()
1510 if (_EntryType
== Password
)
1512 usTmp
= CUtfStringView(_Prompt
+ ::u32string(_InputString
.size(), 0x2022)).toUtf8();
1516 usTmp
= CUtfStringView(_Prompt
+ _InputString
).toUtf8();
1518 _ViewText
->setText (usTmp
);
1522 // ----------------------------------------------------------------------------
1523 void CGroupEditBox::checkCoords()
1528 CInterfaceGroup::checkCoords();
1531 // ----------------------------------------------------------------------------
1532 void CGroupEditBox::updateCoords()
1539 CInterfaceGroup::updateCoords();
1543 bool bRecalc
= false;
1545 // if the length of the view text exceed the max w we allow, cut it
1546 while (_ViewText
->getWReal() > _MaxCharsSize
)
1549 _InputString
= _InputString
.substr(0, _InputString
.size()-1);
1553 _ViewText
->updateCoords();
1557 // if the length of the view text exceed our real size, ensure the Cursor position is at least visible
1558 sint32 viewTextNewX
= _ViewText
->getX();
1559 if (_ViewText
->getWReal() > _WReal
)
1561 // Check if cursor visible
1562 float xCursVT
, xCurs
, yTmp
, hTmp
;
1563 // Get the cursor pos from the BL of the viewtext
1564 _ViewText
->getCharacterPositionFromIndex(_CursorPos
+(sint
)_Prompt
.size(), false, xCursVT
, yTmp
, hTmp
);
1565 // Get the cursor pos from the BL of the edit box
1566 xCurs
= xCursVT
- (_XReal
- _ViewText
->getXReal());
1567 // If the cursor is outside the edit box move the view text to show the cursor
1570 viewTextNewX
= _ViewTextDeltaX
- (xCursVT
- _WReal
);
1574 if ((xCursVT
+ xCurs
) < 0)
1575 viewTextNewX
= _ViewTextDeltaX
;
1577 viewTextNewX
= _ViewTextDeltaX
- (xCursVT
+ xCurs
);
1579 if (_CursorPos
== 0)
1581 viewTextNewX
= _ViewTextDeltaX
;
1586 viewTextNewX
= _ViewTextDeltaX
;
1589 // if X position changed, must recompute
1590 if (viewTextNewX
!= _ViewText
->getX())
1592 _ViewText
->setX(viewTextNewX
);
1596 // recompute position
1598 CInterfaceGroup::updateCoords();
1601 if (_BackupFatherContainerPos
)
1603 CGroupContainerBase
*gc
= static_cast< CGroupContainerBase
* >( getEnclosingContainer() );
1605 if (gc
&& !gc
->getTouchFlag(true))
1608 if (_ViewText
&& _ViewText
->getNumLine() <= 1)
1610 if (_PrevNumLine
> 1)
1612 gc
->restorePosition();
1613 CInterfaceGroup::updateCoords();
1618 if (_PrevNumLine
<= 1)
1620 gc
->backupPosition();
1623 _PrevNumLine
= _ViewText
->getNumLine();
1627 gc
->backupPosition();
1632 // ----------------------------------------------------------------------------
1633 void CGroupEditBox::clearViews()
1635 CInterfaceGroup::clearViews();
1638 // ----------------------------------------------------------------------------
1640 void CGroupEditBox::createViewText()
1642 nlwarning("Interface: CGroupEditBox: text 'edit_text' missing or bad type");
1643 nlwarning( "Trying to create a new 'edit_text' for %s", getId().c_str() );
1644 _ViewText
= dynamic_cast< CViewText
* >( CInterfaceFactory::createClass( "text" ) );
1645 if( _ViewText
== NULL
)
1647 nlwarning( "Failed to create new 'edit_text' for %s", getId().c_str() );
1651 _ViewText
->setParent( this );
1652 _ViewText
->setIdRecurse( "edit_text" );
1653 _ViewText
->setTextLocalized( "", false );
1654 _ViewText
->setPosRef( Hotspot_ML
);
1655 _ViewText
->setParentPosRef( Hotspot_ML
);
1656 addView( _ViewText
);
1659 w
= std::max( sint32( _ViewText
->getFontWidth() * CUtfStringView(_ViewText
->getText()).count() ), getW() );
1660 h
= std::max( sint32( _ViewText
->getFontHeight() ), getH() );
1666 // ----------------------------------------------------------------------------
1667 void CGroupEditBox::setup()
1669 // bind to the controls
1670 if( _ViewText
== NULL
)
1671 _ViewText
= dynamic_cast<CViewText
*>(CInterfaceGroup::getView("edit_text"));
1673 if(_ViewText
== NULL
)
1676 _ViewText
->setEditorSelectable( false );
1678 // For MultiLine editbox, clip the end space, else weird when edit space at end of line (nothing happens)
1680 _ViewText
->setMultiLineClipEndSpace(true);
1682 // Bakcup the delta X of this view text
1684 _ViewTextDeltaX
= _ViewText
->getX();
1689 CInterfaceOptions
*pIO
= CWidgetManager::getInstance()->getOptions("text_selection");
1692 _BackSelectColor
= pIO
->getValColor("back_select_color");
1693 _TextSelectColor
= pIO
->getValColor("text_select_color");
1698 // ----------------------------------------------------------------------------
1699 void CGroupEditBox::setPrompt(const std::string
&s
)
1701 _Prompt
= CUtfStringView(s
).toUtf32();
1705 // ----------------------------------------------------------------------------
1706 void CGroupEditBox::setInputString(const std::string
&str
)
1708 setInputStringRef(CUtfStringView(str
).toUtf32());
1710 void CGroupEditBox::setInputStringRef(const ::u32string
&str
)
1713 if (_CursorPos
> (sint32
) str
.length())
1715 _CursorPos
= (sint32
)str
.length();
1716 _CursorAtPreviousLineEnd
= false;
1718 if (!_ViewText
) return;
1725 // ***************************************************************************
1726 void CGroupEditBox::setDefaultInputString(const std::string
&str
)
1728 _DefaultInputString
= true;
1729 setInputString(str
);
1732 // ***************************************************************************
1733 sint32
CGroupEditBox::getInputStringAsInt() const
1736 fromString(getInputString(), value
);
1740 // ***************************************************************************
1741 void CGroupEditBox::setInputStringAsInt(sint32 val
)
1743 setInputString(NLMISC::toString(val
));
1746 // ***************************************************************************
1747 sint64
CGroupEditBox::getInputStringAsInt64() const
1750 fromString(getInputString(), value
);
1754 // ***************************************************************************
1755 void CGroupEditBox::setInputStringAsInt64(sint64 val
)
1757 setInputString(NLMISC::toString(val
));
1760 // ***************************************************************************
1761 float CGroupEditBox::getInputStringAsFloat() const
1764 fromString(getInputString(), value
);
1768 // ***************************************************************************
1769 void CGroupEditBox::setInputStringAsFloat(float val
)
1771 string fmt
= "%." + NLMISC::toString(_MaxFloatPrec
) + "f";
1772 setInputString(NLMISC::toString(fmt
.c_str(), val
));
1775 // ***************************************************************************
1776 void CGroupEditBox::cutSelection()
1778 ptrdiff_t minPos
= min(_CursorPos
, _SelectCursorPos
);
1779 ptrdiff_t maxPos
= max(_CursorPos
, _SelectCursorPos
);
1780 // cut the selection
1781 if(!_InputString
.empty())
1783 _InputString
= _InputString
.substr(0, minPos
) + _InputString
.substr(maxPos
);
1785 _CurrSelection
= NULL
;
1787 triggerOnChangeAH();
1790 // ***************************************************************************
1791 std::string
CGroupEditBox::getSelection()
1793 ptrdiff_t minPos
= min(_CursorPos
, _SelectCursorPos
);
1794 ptrdiff_t maxPos
= max(_CursorPos
, _SelectCursorPos
);
1795 // get the selection
1796 return CUtfStringView(_InputString
.substr(minPos
, maxPos
-minPos
)).toUtf8();
1801 // ***************************************************************************
1802 void CGroupEditBox::setSelectionAll()
1804 if(!_InputString
.empty())
1806 _CurrSelection
= this;
1807 _SelectCursorPos
= 0;
1808 _CursorPos
= (sint32
)_InputString
.size();
1809 _CursorAtPreviousLineEnd
= false;
1813 // ***************************************************************************
1814 void CGroupEditBox::setActive(bool active
)
1816 if (!active
&& _ResetFocusOnHide
)
1817 CWidgetManager::getInstance()->resetCaptureKeyboard();
1819 CInterfaceGroup::setActive(active
);
1822 // ***************************************************************************
1823 std::string
CGroupEditBox::getPrompt() const
1825 return NLMISC::CUtfStringView(_Prompt
).toUtf8();
1828 // ***************************************************************************
1829 std::string
CGroupEditBox::getInputString() const
1831 return NLMISC::CUtfStringView(_InputString
).toUtf8();
1834 #ifdef RYZOM_LUA_UCSTRING
1835 // ***************************************************************************
1836 void CGroupEditBox::setInputStringAsUtf16(const ucstring
&str
)
1838 setInputStringAsUtf32(CUtfStringView(str
).toUtf32());
1841 // ***************************************************************************
1842 ucstring
CGroupEditBox::getInputStringAsUtf16() const
1844 return CUtfStringView(_InputString
).toUtf16();
1848 // ***************************************************************************
1849 void CGroupEditBox::setCommand(const std::string
&command
, bool execute
)
1851 // do nothing if frozen
1855 // set the string and maybe execute
1856 setInputString('/' + command
);
1860 _CurrSelection
= NULL
;
1861 _CursorAtPreviousLineEnd
= false;
1862 CAHManager::getInstance()->runActionHandler(_AHOnEnter
, this, _AHOnEnterParams
);
1866 CWidgetManager::getInstance()->setCaptureKeyboard (this);
1867 _CursorPos
= (sint32
)_InputString
.length();
1871 // ***************************************************************************
1872 void CGroupEditBox::makeTopWindow()
1874 CInterfaceGroup
*root
= getRootWindow();
1876 CWidgetManager::getInstance()->setTopWindow(root
);
1879 // ***************************************************************************
1880 void CGroupEditBox::clearAllEditBox()
1882 _InputString
.clear();
1884 _CursorAtPreviousLineEnd
= false;
1885 if (!_ViewText
) return;
1890 // ***************************************************************************
1891 sint32
CGroupEditBox::getMaxUsedW() const
1896 // ***************************************************************************
1897 sint32
CGroupEditBox::getMinUsedW() const
1902 // ***************************************************************************
1903 bool CGroupEditBox::wantSerialConfig() const
1905 return _Savable
&& !_InputString
.empty();
1908 // ***************************************************************************
1909 void CGroupEditBox::serialConfig(NLMISC::IStream
&f
)
1911 uint version
= f
.serialVersion(1);
1912 if(_DefaultInputString
) // Don't want to save the default input
1914 _DefaultInputString
= false;
1915 _InputString
.clear();
1919 ucstring str
; // Compatibility
1921 str
= CUtfStringView(_InputString
).toUtf16();
1924 _InputString
= CUtfStringView(str
).toUtf32();
1930 str
= CUtfStringView(_InputString
).toUtf8();
1933 _InputString
= CUtfStringView(str
).toUtf32();
1935 f
.serial(_CursorPos
);
1936 f
.serial(_PrevNumLine
);
1939 setInputStringRef(_InputString
);
1943 bool isSelected
= (_CurrSelection
== this);
1944 f
.serial(isSelected
);
1947 _CurrSelection
= this;
1948 f
.serial(_SelectCursorPos
);
1952 // ***************************************************************************
1953 void CGroupEditBox::onQuit()
1955 // clear the text and restore backup pos before final save
1956 setInputStringRef(::u32string());
1957 _CurrSelection
= NULL
;
1960 // ***************************************************************************
1961 void CGroupEditBox::onLoadConfig()
1963 // config is not saved when there's an empty string, so restore that default state.
1964 setInputStringRef(::u32string());
1965 _CurrSelection
= NULL
;
1970 // ***************************************************************************
1971 void CGroupEditBox::elementCaptured(CCtrlBase
*capturedElement
)
1973 // If the input string is the default one, then reset it
1974 if(capturedElement
== this)
1976 if (_DefaultInputString
)
1978 _DefaultInputString
= false;
1979 setInputStringRef(::u32string());
1983 _StartInputString
= _ModifiedInputString
= _InputString
;
1985 CInterfaceGroup::elementCaptured(capturedElement
);
1988 // ***************************************************************************
1989 void CGroupEditBox::onKeyboardCaptureLost()
1991 if (!_AHOnFocusLost
.empty())
1992 CAHManager::getInstance()->runActionHandler(_AHOnFocusLost
, this, _AHOnFocusLostParams
);
1996 // ***************************************************************************
1997 int CGroupEditBox::luaSetSelectionAll(CLuaState
&ls
)
1999 const char *funcName
= "setSelectionAll";
2000 CLuaIHM::checkArgCount(ls
, funcName
, 0);
2005 // ***************************************************************************
2006 void CGroupEditBox::setFocusOnText()
2008 // do nothing if frozen
2012 // else set the focus
2013 CWidgetManager::getInstance()->setCaptureKeyboard (this);
2015 _CurrSelection
= this;
2016 _SelectCursorPos
= (sint32
)_InputString
.size();
2017 _CursorPos
= (sint32
)_InputString
.size();
2018 _CursorAtPreviousLineEnd
= false;
2021 // ***************************************************************************
2022 int CGroupEditBox::luaSetFocusOnText(CLuaState
&ls
)
2024 const char *funcName
= "setFocusOnText";
2025 CLuaIHM::checkArgCount(ls
, funcName
, 0);
2032 // ***************************************************************************
2033 int CGroupEditBox::luaCancelFocusOnText(CLuaState
&ls
)
2035 const char *funcName
= "cancelFocusOnText";
2036 CLuaIHM::checkArgCount(ls
, funcName
, 0);
2038 if (CWidgetManager::getInstance()->getCaptureKeyboard()==this || CWidgetManager::getInstance()->getOldCaptureKeyboard()==this)
2039 CWidgetManager::getInstance()->resetCaptureKeyboard();
2041 _CurrSelection
= NULL
;
2042 _SelectCursorPos
= 0;
2044 _CursorAtPreviousLineEnd
= false;
2049 // ***************************************************************************
2050 int CGroupEditBox::luaSetupDisplayText(CLuaState
&ls
)
2052 const char *funcName
= "setupDisplayText";
2053 CLuaIHM::checkArgCount(ls
, funcName
, 0);
2058 // ***************************************************************************
2059 void CGroupEditBox::setColor(NLMISC::CRGBA col
)
2062 _ViewText
->setColor(col
);
2065 // ***************************************************************************
2066 void CGroupEditBox::setFrozen (bool state
)
2070 // if frozen, loose the focus
2073 // stop capture and selection
2074 CWidgetManager::getInstance()->setCaptureKeyboard (NULL
);
2075 if(_CurrSelection
==this) _CurrSelection
= NULL
;
2076 // do not allow to recover focus
2077 if (CWidgetManager::getInstance()->getOldCaptureKeyboard() == this)
2079 CWidgetManager::getInstance()->resetCaptureKeyboard();