Line data Source code
1 : // 11.11.2011 11:11 ValkaTR
2 : //
3 : // This is a copy of intlGUIEditBox from the irrlicht, but with a
4 : // fix in the OnEvent function, which doesn't allowed input of
5 : // other keyboard layouts than latin-1
6 : //
7 : // Characters like: ä ö ü õ ы й ю я ъ № € ° ...
8 : //
9 : // This fix is only needed for linux, because of a bug
10 : // in the CIrrDeviceLinux.cpp:1014-1015 of the irrlicht
11 : //
12 : // Also locale in the programm should not be changed to
13 : // a "C", "POSIX" or whatever, it should be set to "",
14 : // or XLookupString will return nothing for the international
15 : // characters.
16 : //
17 : // From the "man setlocale":
18 : //
19 : // On startup of the main program, the portable "C" locale
20 : // is selected as default. A program may be made
21 : // portable to all locales by calling:
22 : //
23 : // setlocale(LC_ALL, "");
24 : //
25 : // after program initialization....
26 : //
27 :
28 : // Copyright (C) 2002-2013 Nikolaus Gebhardt
29 : // This file is part of the "Irrlicht Engine".
30 : // For conditions of distribution and use, see copyright notice in irrlicht.h
31 :
32 : #include "intlGUIEditBox.h"
33 :
34 : #if defined(_IRR_COMPILE_WITH_GUI_) && IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 9
35 :
36 : #include "IGUISkin.h"
37 : #include "IGUIEnvironment.h"
38 : #include "IGUIFont.h"
39 : #include "IVideoDriver.h"
40 : //#include "rect.h"
41 : //#include "irrlicht/os.cpp"
42 : #include "porting.h"
43 : //#include "Keycodes.h"
44 : #include "log.h"
45 :
46 : /*
47 : todo:
48 : optional scrollbars
49 : ctrl+left/right to select word
50 : double click/ctrl click: word select + drag to select whole words, triple click to select line
51 : optional? dragging selected text
52 : numerical
53 : */
54 :
55 : namespace irr
56 : {
57 : namespace gui
58 : {
59 :
60 : //! constructor
61 6 : intlGUIEditBox::intlGUIEditBox(const wchar_t* text, bool border,
62 : IGUIEnvironment* environment, IGUIElement* parent, s32 id,
63 : const core::rect<s32>& rectangle)
64 : : IGUIEditBox(environment, parent, id, rectangle), MouseMarking(false),
65 : Border(border), OverrideColorEnabled(false), MarkBegin(0), MarkEnd(0),
66 : OverrideColor(video::SColor(101,255,255,255)), OverrideFont(0), LastBreakFont(0),
67 : Operator(0), BlinkStartTime(0), CursorPos(0), HScrollPos(0), VScrollPos(0), Max(0),
68 : WordWrap(false), MultiLine(false), AutoScroll(true), PasswordBox(false),
69 : PasswordChar(L'*'), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER),
70 6 : CurrentTextRect(0,0,1,1), FrameRect(rectangle)
71 : {
72 : #ifdef _DEBUG
73 : setDebugName("intlintlGUIEditBox");
74 : #endif
75 :
76 6 : Text = text;
77 :
78 6 : if (Environment)
79 6 : Operator = Environment->getOSOperator();
80 :
81 6 : if (Operator)
82 6 : Operator->grab();
83 :
84 : // this element can be tabbed to
85 6 : setTabStop(true);
86 6 : setTabOrder(-1);
87 :
88 6 : IGUISkin *skin = 0;
89 6 : if (Environment)
90 6 : skin = Environment->getSkin();
91 6 : if (Border && skin)
92 : {
93 6 : FrameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
94 6 : FrameRect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
95 6 : FrameRect.LowerRightCorner.X -= skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
96 6 : FrameRect.LowerRightCorner.Y -= skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
97 : }
98 :
99 6 : breakText();
100 :
101 6 : calculateScrollPos();
102 6 : }
103 :
104 :
105 : //! destructor
106 0 : intlGUIEditBox::~intlGUIEditBox()
107 : {
108 0 : if (OverrideFont)
109 0 : OverrideFont->drop();
110 :
111 0 : if (Operator)
112 0 : Operator->drop();
113 0 : }
114 :
115 :
116 : //! Sets another skin independent font.
117 0 : void intlGUIEditBox::setOverrideFont(IGUIFont* font)
118 : {
119 0 : if (OverrideFont == font)
120 0 : return;
121 :
122 0 : if (OverrideFont)
123 0 : OverrideFont->drop();
124 :
125 0 : OverrideFont = font;
126 :
127 0 : if (OverrideFont)
128 0 : OverrideFont->grab();
129 :
130 0 : breakText();
131 : }
132 :
133 0 : IGUIFont * intlGUIEditBox::getOverrideFont() const
134 : {
135 0 : return OverrideFont;
136 : }
137 :
138 : //! Get the font which is used right now for drawing
139 0 : IGUIFont* intlGUIEditBox::getActiveFont() const
140 : {
141 0 : if ( OverrideFont )
142 0 : return OverrideFont;
143 0 : IGUISkin* skin = Environment->getSkin();
144 0 : if (skin)
145 0 : return skin->getFont();
146 0 : return 0;
147 : }
148 :
149 : //! Sets another color for the text.
150 0 : void intlGUIEditBox::setOverrideColor(video::SColor color)
151 : {
152 0 : OverrideColor = color;
153 0 : OverrideColorEnabled = true;
154 0 : }
155 :
156 0 : video::SColor intlGUIEditBox::getOverrideColor() const
157 : {
158 0 : return OverrideColor;
159 : }
160 :
161 : //! Turns the border on or off
162 0 : void intlGUIEditBox::setDrawBorder(bool border)
163 : {
164 0 : Border = border;
165 0 : }
166 :
167 : //! Sets whether to draw the background
168 0 : void intlGUIEditBox::setDrawBackground(bool draw)
169 : {
170 0 : }
171 :
172 : //! Sets if the text should use the overide color or the color in the gui skin.
173 0 : void intlGUIEditBox::enableOverrideColor(bool enable)
174 : {
175 0 : OverrideColorEnabled = enable;
176 0 : }
177 :
178 0 : bool intlGUIEditBox::isOverrideColorEnabled() const
179 : {
180 : _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
181 0 : return OverrideColorEnabled;
182 : }
183 :
184 : //! Enables or disables word wrap
185 0 : void intlGUIEditBox::setWordWrap(bool enable)
186 : {
187 0 : WordWrap = enable;
188 0 : breakText();
189 0 : }
190 :
191 :
192 0 : void intlGUIEditBox::updateAbsolutePosition()
193 : {
194 0 : core::rect<s32> oldAbsoluteRect(AbsoluteRect);
195 0 : IGUIElement::updateAbsolutePosition();
196 0 : if ( oldAbsoluteRect != AbsoluteRect )
197 : {
198 0 : breakText();
199 : }
200 0 : }
201 :
202 :
203 : //! Checks if word wrap is enabled
204 0 : bool intlGUIEditBox::isWordWrapEnabled() const
205 : {
206 : _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
207 0 : return WordWrap;
208 : }
209 :
210 :
211 : //! Enables or disables newlines.
212 0 : void intlGUIEditBox::setMultiLine(bool enable)
213 : {
214 0 : MultiLine = enable;
215 0 : }
216 :
217 :
218 : //! Checks if multi line editing is enabled
219 0 : bool intlGUIEditBox::isMultiLineEnabled() const
220 : {
221 : _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
222 0 : return MultiLine;
223 : }
224 :
225 :
226 0 : void intlGUIEditBox::setPasswordBox(bool passwordBox, wchar_t passwordChar)
227 : {
228 0 : PasswordBox = passwordBox;
229 0 : if (PasswordBox)
230 : {
231 0 : PasswordChar = passwordChar;
232 0 : setMultiLine(false);
233 0 : setWordWrap(false);
234 0 : BrokenText.clear();
235 : }
236 0 : }
237 :
238 :
239 0 : bool intlGUIEditBox::isPasswordBox() const
240 : {
241 : _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
242 0 : return PasswordBox;
243 : }
244 :
245 :
246 : //! Sets text justification
247 0 : void intlGUIEditBox::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical)
248 : {
249 0 : HAlign = horizontal;
250 0 : VAlign = vertical;
251 0 : }
252 :
253 :
254 : //! called if an event happened.
255 6 : bool intlGUIEditBox::OnEvent(const SEvent& event)
256 : {
257 6 : if (IsEnabled)
258 : {
259 :
260 6 : switch(event.EventType)
261 : {
262 : case EET_GUI_EVENT:
263 0 : if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
264 : {
265 0 : if (event.GUIEvent.Caller == this)
266 : {
267 0 : MouseMarking = false;
268 0 : setTextMarkers(0,0);
269 : }
270 : }
271 0 : break;
272 : case EET_KEY_INPUT_EVENT:
273 : {
274 : #if (defined(linux) || defined(__linux) || defined(__FreeBSD__))
275 : // ################################################################
276 : // ValkaTR:
277 : // This part is the difference from the original intlGUIEditBox
278 : // It converts UTF-8 character into a UCS-2 (wchar_t)
279 6 : wchar_t wc = L'_';
280 6 : mbtowc( &wc, (char *) &event.KeyInput.Char, sizeof(event.KeyInput.Char) );
281 :
282 : //printf( "char: %lc (%u) \r\n", wc, wc );
283 :
284 6 : SEvent irrevent(event);
285 6 : irrevent.KeyInput.Char = wc;
286 : // ################################################################
287 :
288 6 : if (processKey(irrevent))
289 6 : return true;
290 : #else
291 : if (processKey(event))
292 : return true;
293 : #endif // defined(linux)
294 :
295 0 : break;
296 : }
297 : case EET_MOUSE_INPUT_EVENT:
298 0 : if (processMouse(event))
299 0 : return true;
300 0 : break;
301 : default:
302 0 : break;
303 : }
304 : }
305 :
306 0 : return IGUIElement::OnEvent(event);
307 : }
308 :
309 :
310 6 : bool intlGUIEditBox::processKey(const SEvent& event)
311 : {
312 6 : if (!event.KeyInput.PressedDown)
313 0 : return false;
314 :
315 6 : bool textChanged = false;
316 6 : s32 newMarkBegin = MarkBegin;
317 6 : s32 newMarkEnd = MarkEnd;
318 :
319 : // control shortcut handling
320 :
321 6 : if (event.KeyInput.Control)
322 : {
323 : // german backlash '\' entered with control + '?'
324 0 : if ( event.KeyInput.Char == '\\' )
325 : {
326 0 : inputChar(event.KeyInput.Char);
327 0 : return true;
328 : }
329 :
330 0 : switch(event.KeyInput.Key)
331 : {
332 : case KEY_KEY_A:
333 : // select all
334 0 : newMarkBegin = 0;
335 0 : newMarkEnd = Text.size();
336 0 : break;
337 : case KEY_KEY_C:
338 : // copy to clipboard
339 0 : if (!PasswordBox && Operator && MarkBegin != MarkEnd)
340 : {
341 0 : const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
342 0 : const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
343 :
344 0 : core::stringc s;
345 0 : s = Text.subString(realmbgn, realmend - realmbgn).c_str();
346 0 : Operator->copyToClipboard(s.c_str());
347 : }
348 0 : break;
349 : case KEY_KEY_X:
350 : // cut to the clipboard
351 0 : if (!PasswordBox && Operator && MarkBegin != MarkEnd)
352 : {
353 0 : const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
354 0 : const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
355 :
356 : // copy
357 0 : core::stringc sc;
358 0 : sc = Text.subString(realmbgn, realmend - realmbgn).c_str();
359 0 : Operator->copyToClipboard(sc.c_str());
360 :
361 0 : if (IsEnabled)
362 : {
363 : // delete
364 0 : core::stringw s;
365 0 : s = Text.subString(0, realmbgn);
366 0 : s.append( Text.subString(realmend, Text.size()-realmend) );
367 0 : Text = s;
368 :
369 0 : CursorPos = realmbgn;
370 0 : newMarkBegin = 0;
371 0 : newMarkEnd = 0;
372 0 : textChanged = true;
373 : }
374 : }
375 0 : break;
376 : case KEY_KEY_V:
377 0 : if ( !IsEnabled )
378 0 : break;
379 :
380 : // paste from the clipboard
381 0 : if (Operator)
382 : {
383 0 : const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
384 0 : const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
385 :
386 : // add new character
387 0 : const c8* p = Operator->getTextFromClipboard();
388 0 : if (p)
389 : {
390 0 : if (MarkBegin == MarkEnd)
391 : {
392 : // insert text
393 0 : core::stringw s = Text.subString(0, CursorPos);
394 0 : s.append(p);
395 0 : s.append( Text.subString(CursorPos, Text.size()-CursorPos) );
396 :
397 0 : if (!Max || s.size()<=Max) // thx to Fish FH for fix
398 : {
399 0 : Text = s;
400 0 : s = p;
401 0 : CursorPos += s.size();
402 : }
403 : }
404 : else
405 : {
406 : // replace text
407 :
408 0 : core::stringw s = Text.subString(0, realmbgn);
409 0 : s.append(p);
410 0 : s.append( Text.subString(realmend, Text.size()-realmend) );
411 :
412 0 : if (!Max || s.size()<=Max) // thx to Fish FH for fix
413 : {
414 0 : Text = s;
415 0 : s = p;
416 0 : CursorPos = realmbgn + s.size();
417 : }
418 : }
419 : }
420 :
421 0 : newMarkBegin = 0;
422 0 : newMarkEnd = 0;
423 0 : textChanged = true;
424 : }
425 0 : break;
426 : case KEY_HOME:
427 : // move/highlight to start of text
428 0 : if (event.KeyInput.Shift)
429 : {
430 0 : newMarkEnd = CursorPos;
431 0 : newMarkBegin = 0;
432 0 : CursorPos = 0;
433 : }
434 : else
435 : {
436 0 : CursorPos = 0;
437 0 : newMarkBegin = 0;
438 0 : newMarkEnd = 0;
439 : }
440 0 : break;
441 : case KEY_END:
442 : // move/highlight to end of text
443 0 : if (event.KeyInput.Shift)
444 : {
445 0 : newMarkBegin = CursorPos;
446 0 : newMarkEnd = Text.size();
447 0 : CursorPos = 0;
448 : }
449 : else
450 : {
451 0 : CursorPos = Text.size();
452 0 : newMarkBegin = 0;
453 0 : newMarkEnd = 0;
454 : }
455 0 : break;
456 : default:
457 0 : return false;
458 : }
459 : }
460 : // default keyboard handling
461 : else
462 6 : switch(event.KeyInput.Key)
463 : {
464 : case KEY_END:
465 : {
466 6 : s32 p = Text.size();
467 6 : if (WordWrap || MultiLine)
468 : {
469 0 : p = getLineFromPos(CursorPos);
470 0 : p = BrokenTextPositions[p] + (s32)BrokenText[p].size();
471 0 : if (p > 0 && (Text[p-1] == L'\r' || Text[p-1] == L'\n' ))
472 0 : p-=1;
473 : }
474 :
475 6 : if (event.KeyInput.Shift)
476 : {
477 0 : if (MarkBegin == MarkEnd)
478 0 : newMarkBegin = CursorPos;
479 :
480 0 : newMarkEnd = p;
481 : }
482 : else
483 : {
484 6 : newMarkBegin = 0;
485 6 : newMarkEnd = 0;
486 : }
487 6 : CursorPos = p;
488 6 : BlinkStartTime = porting::getTimeMs();
489 : }
490 6 : break;
491 : case KEY_HOME:
492 : {
493 :
494 0 : s32 p = 0;
495 0 : if (WordWrap || MultiLine)
496 : {
497 0 : p = getLineFromPos(CursorPos);
498 0 : p = BrokenTextPositions[p];
499 : }
500 :
501 0 : if (event.KeyInput.Shift)
502 : {
503 0 : if (MarkBegin == MarkEnd)
504 0 : newMarkBegin = CursorPos;
505 0 : newMarkEnd = p;
506 : }
507 : else
508 : {
509 0 : newMarkBegin = 0;
510 0 : newMarkEnd = 0;
511 : }
512 0 : CursorPos = p;
513 0 : BlinkStartTime = porting::getTimeMs();
514 : }
515 0 : break;
516 : case KEY_RETURN:
517 0 : if (MultiLine)
518 : {
519 0 : inputChar(L'\n');
520 0 : return true;
521 : }
522 : else
523 : {
524 0 : sendGuiEvent( EGET_EDITBOX_ENTER );
525 : }
526 0 : break;
527 : case KEY_LEFT:
528 :
529 0 : if (event.KeyInput.Shift)
530 : {
531 0 : if (CursorPos > 0)
532 : {
533 0 : if (MarkBegin == MarkEnd)
534 0 : newMarkBegin = CursorPos;
535 :
536 0 : newMarkEnd = CursorPos-1;
537 : }
538 : }
539 : else
540 : {
541 0 : newMarkBegin = 0;
542 0 : newMarkEnd = 0;
543 : }
544 :
545 0 : if (CursorPos > 0) CursorPos--;
546 0 : BlinkStartTime = porting::getTimeMs();
547 0 : break;
548 :
549 : case KEY_RIGHT:
550 0 : if (event.KeyInput.Shift)
551 : {
552 0 : if (Text.size() > (u32)CursorPos)
553 : {
554 0 : if (MarkBegin == MarkEnd)
555 0 : newMarkBegin = CursorPos;
556 :
557 0 : newMarkEnd = CursorPos+1;
558 : }
559 : }
560 : else
561 : {
562 0 : newMarkBegin = 0;
563 0 : newMarkEnd = 0;
564 : }
565 :
566 0 : if (Text.size() > (u32)CursorPos) CursorPos++;
567 0 : BlinkStartTime = porting::getTimeMs();
568 0 : break;
569 : case KEY_UP:
570 0 : if (MultiLine || (WordWrap && BrokenText.size() > 1) )
571 : {
572 0 : s32 lineNo = getLineFromPos(CursorPos);
573 0 : s32 mb = (MarkBegin == MarkEnd) ? CursorPos : (MarkBegin > MarkEnd ? MarkBegin : MarkEnd);
574 0 : if (lineNo > 0)
575 : {
576 0 : s32 cp = CursorPos - BrokenTextPositions[lineNo];
577 0 : if ((s32)BrokenText[lineNo-1].size() < cp)
578 0 : CursorPos = BrokenTextPositions[lineNo-1] + (s32)BrokenText[lineNo-1].size()-1;
579 : else
580 0 : CursorPos = BrokenTextPositions[lineNo-1] + cp;
581 : }
582 :
583 0 : if (event.KeyInput.Shift)
584 : {
585 0 : newMarkBegin = mb;
586 0 : newMarkEnd = CursorPos;
587 : }
588 : else
589 : {
590 0 : newMarkBegin = 0;
591 0 : newMarkEnd = 0;
592 : }
593 :
594 : }
595 : else
596 : {
597 0 : return false;
598 : }
599 0 : break;
600 : case KEY_DOWN:
601 0 : if (MultiLine || (WordWrap && BrokenText.size() > 1) )
602 : {
603 0 : s32 lineNo = getLineFromPos(CursorPos);
604 0 : s32 mb = (MarkBegin == MarkEnd) ? CursorPos : (MarkBegin < MarkEnd ? MarkBegin : MarkEnd);
605 0 : if (lineNo < (s32)BrokenText.size()-1)
606 : {
607 0 : s32 cp = CursorPos - BrokenTextPositions[lineNo];
608 0 : if ((s32)BrokenText[lineNo+1].size() < cp)
609 0 : CursorPos = BrokenTextPositions[lineNo+1] + BrokenText[lineNo+1].size()-1;
610 : else
611 0 : CursorPos = BrokenTextPositions[lineNo+1] + cp;
612 : }
613 :
614 0 : if (event.KeyInput.Shift)
615 : {
616 0 : newMarkBegin = mb;
617 0 : newMarkEnd = CursorPos;
618 : }
619 : else
620 : {
621 0 : newMarkBegin = 0;
622 0 : newMarkEnd = 0;
623 : }
624 :
625 : }
626 : else
627 : {
628 0 : return false;
629 : }
630 0 : break;
631 :
632 : case KEY_BACK:
633 0 : if ( !this->IsEnabled )
634 0 : break;
635 :
636 0 : if (Text.size())
637 : {
638 0 : core::stringw s;
639 :
640 0 : if (MarkBegin != MarkEnd)
641 : {
642 : // delete marked text
643 0 : const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
644 0 : const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
645 :
646 0 : s = Text.subString(0, realmbgn);
647 0 : s.append( Text.subString(realmend, Text.size()-realmend) );
648 0 : Text = s;
649 :
650 0 : CursorPos = realmbgn;
651 : }
652 : else
653 : {
654 : // delete text behind cursor
655 0 : if (CursorPos>0)
656 0 : s = Text.subString(0, CursorPos-1);
657 : else
658 0 : s = L"";
659 0 : s.append( Text.subString(CursorPos, Text.size()-CursorPos) );
660 0 : Text = s;
661 0 : --CursorPos;
662 : }
663 :
664 0 : if (CursorPos < 0)
665 0 : CursorPos = 0;
666 0 : BlinkStartTime = porting::getTimeMs();
667 0 : newMarkBegin = 0;
668 0 : newMarkEnd = 0;
669 0 : textChanged = true;
670 : }
671 0 : break;
672 : case KEY_DELETE:
673 0 : if ( !this->IsEnabled )
674 0 : break;
675 :
676 0 : if (Text.size() != 0)
677 : {
678 0 : core::stringw s;
679 :
680 0 : if (MarkBegin != MarkEnd)
681 : {
682 : // delete marked text
683 0 : const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
684 0 : const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
685 :
686 0 : s = Text.subString(0, realmbgn);
687 0 : s.append( Text.subString(realmend, Text.size()-realmend) );
688 0 : Text = s;
689 :
690 0 : CursorPos = realmbgn;
691 : }
692 : else
693 : {
694 : // delete text before cursor
695 0 : s = Text.subString(0, CursorPos);
696 0 : s.append( Text.subString(CursorPos+1, Text.size()-CursorPos-1) );
697 0 : Text = s;
698 : }
699 :
700 0 : if (CursorPos > (s32)Text.size())
701 0 : CursorPos = (s32)Text.size();
702 :
703 0 : BlinkStartTime = porting::getTimeMs();
704 0 : newMarkBegin = 0;
705 0 : newMarkEnd = 0;
706 0 : textChanged = true;
707 : }
708 0 : break;
709 :
710 : case KEY_ESCAPE:
711 : case KEY_TAB:
712 : case KEY_SHIFT:
713 : case KEY_F1:
714 : case KEY_F2:
715 : case KEY_F3:
716 : case KEY_F4:
717 : case KEY_F5:
718 : case KEY_F6:
719 : case KEY_F7:
720 : case KEY_F8:
721 : case KEY_F9:
722 : case KEY_F10:
723 : case KEY_F11:
724 : case KEY_F12:
725 : case KEY_F13:
726 : case KEY_F14:
727 : case KEY_F15:
728 : case KEY_F16:
729 : case KEY_F17:
730 : case KEY_F18:
731 : case KEY_F19:
732 : case KEY_F20:
733 : case KEY_F21:
734 : case KEY_F22:
735 : case KEY_F23:
736 : case KEY_F24:
737 : // ignore these keys
738 0 : return false;
739 :
740 : default:
741 0 : inputChar(event.KeyInput.Char);
742 0 : return true;
743 : }
744 :
745 : // Set new text markers
746 6 : setTextMarkers( newMarkBegin, newMarkEnd );
747 :
748 : // break the text if it has changed
749 6 : if (textChanged)
750 : {
751 0 : breakText();
752 0 : sendGuiEvent(EGET_EDITBOX_CHANGED);
753 : }
754 :
755 6 : calculateScrollPos();
756 :
757 6 : return true;
758 : }
759 :
760 :
761 : //! draws the element and its children
762 273 : void intlGUIEditBox::draw()
763 : {
764 273 : if (!IsVisible)
765 0 : return;
766 :
767 273 : const bool focus = Environment->hasFocus(this);
768 :
769 273 : IGUISkin* skin = Environment->getSkin();
770 273 : if (!skin)
771 0 : return;
772 :
773 273 : FrameRect = AbsoluteRect;
774 :
775 : // draw the border
776 :
777 273 : if (Border)
778 : {
779 273 : skin->draw3DSunkenPane(this, skin->getColor(EGDC_WINDOW),
780 546 : false, true, FrameRect, &AbsoluteClippingRect);
781 :
782 273 : FrameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
783 273 : FrameRect.UpperLeftCorner.Y += skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
784 273 : FrameRect.LowerRightCorner.X -= skin->getSize(EGDS_TEXT_DISTANCE_X)+1;
785 273 : FrameRect.LowerRightCorner.Y -= skin->getSize(EGDS_TEXT_DISTANCE_Y)+1;
786 : }
787 273 : core::rect<s32> localClipRect = FrameRect;
788 273 : localClipRect.clipAgainst(AbsoluteClippingRect);
789 :
790 : // draw the text
791 :
792 273 : IGUIFont* font = OverrideFont;
793 273 : if (!OverrideFont)
794 273 : font = skin->getFont();
795 :
796 273 : s32 cursorLine = 0;
797 273 : s32 charcursorpos = 0;
798 :
799 273 : if (font)
800 : {
801 273 : if (LastBreakFont != font)
802 : {
803 273 : breakText();
804 : }
805 :
806 : // calculate cursor pos
807 :
808 273 : core::stringw *txtLine = &Text;
809 273 : s32 startPos = 0;
810 :
811 546 : core::stringw s, s2;
812 :
813 : // get mark position
814 273 : const bool ml = (!PasswordBox && (WordWrap || MultiLine));
815 273 : const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
816 273 : const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
817 273 : const s32 hlineStart = ml ? getLineFromPos(realmbgn) : 0;
818 273 : const s32 hlineCount = ml ? getLineFromPos(realmend) - hlineStart + 1 : 1;
819 273 : const s32 lineCount = ml ? BrokenText.size() : 1;
820 :
821 : // Save the override color information.
822 : // Then, alter it if the edit box is disabled.
823 273 : const bool prevOver = OverrideColorEnabled;
824 273 : const video::SColor prevColor = OverrideColor;
825 :
826 273 : if (Text.size())
827 : {
828 273 : if (!IsEnabled && !OverrideColorEnabled)
829 : {
830 0 : OverrideColorEnabled = true;
831 0 : OverrideColor = skin->getColor(EGDC_GRAY_TEXT);
832 : }
833 :
834 546 : for (s32 i=0; i < lineCount; ++i)
835 : {
836 273 : setTextRect(i);
837 :
838 : // clipping test - don't draw anything outside the visible area
839 273 : core::rect<s32> c = localClipRect;
840 273 : c.clipAgainst(CurrentTextRect);
841 273 : if (!c.isValid())
842 0 : continue;
843 :
844 : // get current line
845 273 : if (PasswordBox)
846 : {
847 0 : if (BrokenText.size() != 1)
848 : {
849 0 : BrokenText.clear();
850 0 : BrokenText.push_back(core::stringw());
851 : }
852 0 : if (BrokenText[0].size() != Text.size())
853 : {
854 0 : BrokenText[0] = Text;
855 0 : for (u32 q = 0; q < Text.size(); ++q)
856 : {
857 0 : BrokenText[0] [q] = PasswordChar;
858 : }
859 : }
860 0 : txtLine = &BrokenText[0];
861 0 : startPos = 0;
862 : }
863 : else
864 : {
865 273 : txtLine = ml ? &BrokenText[i] : &Text;
866 273 : startPos = ml ? BrokenTextPositions[i] : 0;
867 : }
868 :
869 :
870 : // draw normal text
871 819 : font->draw(txtLine->c_str(), CurrentTextRect,
872 546 : OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT),
873 546 : false, true, &localClipRect);
874 :
875 : // draw mark and marked text
876 273 : if (focus && MarkBegin != MarkEnd && i >= hlineStart && i < hlineStart + hlineCount)
877 : {
878 :
879 0 : s32 mbegin = 0, mend = 0;
880 0 : s32 lineStartPos = 0, lineEndPos = txtLine->size();
881 :
882 0 : if (i == hlineStart)
883 : {
884 : // highlight start is on this line
885 0 : s = txtLine->subString(0, realmbgn - startPos);
886 0 : mbegin = font->getDimension(s.c_str()).Width;
887 :
888 : // deal with kerning
889 0 : mbegin += font->getKerningWidth(
890 0 : &((*txtLine)[realmbgn - startPos]),
891 0 : realmbgn - startPos > 0 ? &((*txtLine)[realmbgn - startPos - 1]) : 0);
892 :
893 0 : lineStartPos = realmbgn - startPos;
894 : }
895 0 : if (i == hlineStart + hlineCount - 1)
896 : {
897 : // highlight end is on this line
898 0 : s2 = txtLine->subString(0, realmend - startPos);
899 0 : mend = font->getDimension(s2.c_str()).Width;
900 0 : lineEndPos = (s32)s2.size();
901 : }
902 : else
903 0 : mend = font->getDimension(txtLine->c_str()).Width;
904 :
905 0 : CurrentTextRect.UpperLeftCorner.X += mbegin;
906 0 : CurrentTextRect.LowerRightCorner.X = CurrentTextRect.UpperLeftCorner.X + mend - mbegin;
907 :
908 : // draw mark
909 0 : skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), CurrentTextRect, &localClipRect);
910 :
911 : // draw marked text
912 0 : s = txtLine->subString(lineStartPos, lineEndPos - lineStartPos);
913 :
914 0 : if (s.size())
915 0 : font->draw(s.c_str(), CurrentTextRect,
916 0 : OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_HIGH_LIGHT_TEXT),
917 0 : false, true, &localClipRect);
918 :
919 : }
920 : }
921 :
922 : // Return the override color information to its previous settings.
923 273 : OverrideColorEnabled = prevOver;
924 273 : OverrideColor = prevColor;
925 : }
926 :
927 : // draw cursor
928 :
929 273 : if (WordWrap || MultiLine)
930 : {
931 0 : cursorLine = getLineFromPos(CursorPos);
932 0 : txtLine = &BrokenText[cursorLine];
933 0 : startPos = BrokenTextPositions[cursorLine];
934 : }
935 273 : s = txtLine->subString(0,CursorPos-startPos);
936 546 : charcursorpos = font->getDimension(s.c_str()).Width +
937 546 : font->getKerningWidth(L"_", CursorPos-startPos > 0 ? &((*txtLine)[CursorPos-startPos-1]) : 0);
938 :
939 273 : if (focus && (porting::getTimeMs() - BlinkStartTime) % 700 < 350)
940 : {
941 0 : setTextRect(cursorLine);
942 0 : CurrentTextRect.UpperLeftCorner.X += charcursorpos;
943 :
944 0 : font->draw(L"_", CurrentTextRect,
945 0 : OverrideColorEnabled ? OverrideColor : skin->getColor(EGDC_BUTTON_TEXT),
946 0 : false, true, &localClipRect);
947 : }
948 : }
949 :
950 : // draw children
951 273 : IGUIElement::draw();
952 : }
953 :
954 :
955 : //! Sets the new caption of this element.
956 0 : void intlGUIEditBox::setText(const wchar_t* text)
957 : {
958 0 : Text = text;
959 0 : if (u32(CursorPos) > Text.size())
960 0 : CursorPos = Text.size();
961 0 : HScrollPos = 0;
962 0 : breakText();
963 0 : }
964 :
965 :
966 : //! Enables or disables automatic scrolling with cursor position
967 : //! \param enable: If set to true, the text will move around with the cursor position
968 0 : void intlGUIEditBox::setAutoScroll(bool enable)
969 : {
970 0 : AutoScroll = enable;
971 0 : }
972 :
973 :
974 : //! Checks to see if automatic scrolling is enabled
975 : //! \return true if automatic scrolling is enabled, false if not
976 0 : bool intlGUIEditBox::isAutoScrollEnabled() const
977 : {
978 : _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
979 0 : return AutoScroll;
980 : }
981 :
982 :
983 : //! Gets the area of the text in the edit box
984 : //! \return Returns the size in pixels of the text
985 0 : core::dimension2du intlGUIEditBox::getTextDimension()
986 : {
987 0 : core::rect<s32> ret;
988 :
989 0 : setTextRect(0);
990 0 : ret = CurrentTextRect;
991 :
992 0 : for (u32 i=1; i < BrokenText.size(); ++i)
993 : {
994 0 : setTextRect(i);
995 0 : ret.addInternalPoint(CurrentTextRect.UpperLeftCorner);
996 0 : ret.addInternalPoint(CurrentTextRect.LowerRightCorner);
997 : }
998 :
999 0 : return core::dimension2du(ret.getSize());
1000 : }
1001 :
1002 :
1003 : //! Sets the maximum amount of characters which may be entered in the box.
1004 : //! \param max: Maximum amount of characters. If 0, the character amount is
1005 : //! infinity.
1006 0 : void intlGUIEditBox::setMax(u32 max)
1007 : {
1008 0 : Max = max;
1009 :
1010 0 : if (Text.size() > Max && Max != 0)
1011 0 : Text = Text.subString(0, Max);
1012 0 : }
1013 :
1014 :
1015 : //! Returns maximum amount of characters, previously set by setMax();
1016 0 : u32 intlGUIEditBox::getMax() const
1017 : {
1018 0 : return Max;
1019 : }
1020 :
1021 :
1022 0 : bool intlGUIEditBox::processMouse(const SEvent& event)
1023 : {
1024 0 : switch(event.MouseInput.Event)
1025 : {
1026 : case irr::EMIE_LMOUSE_LEFT_UP:
1027 0 : if (Environment->hasFocus(this))
1028 : {
1029 0 : CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
1030 0 : if (MouseMarking)
1031 : {
1032 0 : setTextMarkers( MarkBegin, CursorPos );
1033 : }
1034 0 : MouseMarking = false;
1035 0 : calculateScrollPos();
1036 0 : return true;
1037 : }
1038 0 : break;
1039 : case irr::EMIE_MOUSE_MOVED:
1040 : {
1041 0 : if (MouseMarking)
1042 : {
1043 0 : CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
1044 0 : setTextMarkers( MarkBegin, CursorPos );
1045 0 : calculateScrollPos();
1046 0 : return true;
1047 : }
1048 : }
1049 0 : break;
1050 : case EMIE_LMOUSE_PRESSED_DOWN:
1051 0 : if (!Environment->hasFocus(this))
1052 : {
1053 0 : BlinkStartTime = porting::getTimeMs();
1054 0 : MouseMarking = true;
1055 0 : CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
1056 0 : setTextMarkers(CursorPos, CursorPos );
1057 0 : calculateScrollPos();
1058 0 : return true;
1059 : }
1060 : else
1061 : {
1062 0 : if (!AbsoluteClippingRect.isPointInside(
1063 0 : core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y)))
1064 : {
1065 0 : return false;
1066 : }
1067 : else
1068 : {
1069 : // move cursor
1070 0 : CursorPos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
1071 :
1072 0 : s32 newMarkBegin = MarkBegin;
1073 0 : if (!MouseMarking)
1074 0 : newMarkBegin = CursorPos;
1075 :
1076 0 : MouseMarking = true;
1077 0 : setTextMarkers( newMarkBegin, CursorPos);
1078 0 : calculateScrollPos();
1079 0 : return true;
1080 : }
1081 : }
1082 : default:
1083 0 : break;
1084 : }
1085 :
1086 0 : return false;
1087 : }
1088 :
1089 :
1090 0 : s32 intlGUIEditBox::getCursorPos(s32 x, s32 y)
1091 : {
1092 0 : IGUIFont* font = OverrideFont;
1093 0 : IGUISkin* skin = Environment->getSkin();
1094 0 : if (!OverrideFont)
1095 0 : font = skin->getFont();
1096 :
1097 0 : const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1;
1098 :
1099 0 : core::stringw *txtLine=0;
1100 0 : s32 startPos=0;
1101 0 : x+=3;
1102 :
1103 0 : for (u32 i=0; i < lineCount; ++i)
1104 : {
1105 0 : setTextRect(i);
1106 0 : if (i == 0 && y < CurrentTextRect.UpperLeftCorner.Y)
1107 0 : y = CurrentTextRect.UpperLeftCorner.Y;
1108 0 : if (i == lineCount - 1 && y > CurrentTextRect.LowerRightCorner.Y )
1109 0 : y = CurrentTextRect.LowerRightCorner.Y;
1110 :
1111 : // is it inside this region?
1112 0 : if (y >= CurrentTextRect.UpperLeftCorner.Y && y <= CurrentTextRect.LowerRightCorner.Y)
1113 : {
1114 : // we've found the clicked line
1115 0 : txtLine = (WordWrap || MultiLine) ? &BrokenText[i] : &Text;
1116 0 : startPos = (WordWrap || MultiLine) ? BrokenTextPositions[i] : 0;
1117 0 : break;
1118 : }
1119 : }
1120 :
1121 0 : if (x < CurrentTextRect.UpperLeftCorner.X)
1122 0 : x = CurrentTextRect.UpperLeftCorner.X;
1123 :
1124 0 : s32 idx = font->getCharacterFromPos(Text.c_str(), x - CurrentTextRect.UpperLeftCorner.X);
1125 :
1126 : // click was on or left of the line
1127 0 : if (idx != -1)
1128 0 : return idx + startPos;
1129 :
1130 : // click was off the right edge of the line, go to end.
1131 0 : return txtLine->size() + startPos;
1132 : }
1133 :
1134 :
1135 : //! Breaks the single text line.
1136 279 : void intlGUIEditBox::breakText()
1137 : {
1138 279 : IGUISkin* skin = Environment->getSkin();
1139 :
1140 279 : if ((!WordWrap && !MultiLine) || !skin)
1141 558 : return;
1142 :
1143 0 : BrokenText.clear(); // need to reallocate :/
1144 0 : BrokenTextPositions.set_used(0);
1145 :
1146 0 : IGUIFont* font = OverrideFont;
1147 0 : if (!OverrideFont)
1148 0 : font = skin->getFont();
1149 :
1150 0 : if (!font)
1151 0 : return;
1152 :
1153 0 : LastBreakFont = font;
1154 :
1155 0 : core::stringw line;
1156 0 : core::stringw word;
1157 0 : core::stringw whitespace;
1158 0 : s32 lastLineStart = 0;
1159 0 : s32 size = Text.size();
1160 0 : s32 length = 0;
1161 0 : s32 elWidth = RelativeRect.getWidth() - 6;
1162 : wchar_t c;
1163 :
1164 0 : for (s32 i=0; i<size; ++i)
1165 : {
1166 0 : c = Text[i];
1167 0 : bool lineBreak = false;
1168 :
1169 0 : if (c == L'\r') // Mac or Windows breaks
1170 : {
1171 0 : lineBreak = true;
1172 0 : c = ' ';
1173 0 : if (Text[i+1] == L'\n') // Windows breaks
1174 : {
1175 0 : Text.erase(i+1);
1176 0 : --size;
1177 : }
1178 : }
1179 0 : else if (c == L'\n') // Unix breaks
1180 : {
1181 0 : lineBreak = true;
1182 0 : c = ' ';
1183 : }
1184 :
1185 : // don't break if we're not a multi-line edit box
1186 0 : if (!MultiLine)
1187 0 : lineBreak = false;
1188 :
1189 0 : if (c == L' ' || c == 0 || i == (size-1))
1190 : {
1191 0 : if (word.size())
1192 : {
1193 : // here comes the next whitespace, look if
1194 : // we can break the last word to the next line.
1195 0 : s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
1196 0 : s32 worldlgth = font->getDimension(word.c_str()).Width;
1197 :
1198 0 : if (WordWrap && length + worldlgth + whitelgth > elWidth)
1199 : {
1200 : // break to next line
1201 0 : length = worldlgth;
1202 0 : BrokenText.push_back(line);
1203 0 : BrokenTextPositions.push_back(lastLineStart);
1204 0 : lastLineStart = i - (s32)word.size();
1205 0 : line = word;
1206 : }
1207 : else
1208 : {
1209 : // add word to line
1210 0 : line += whitespace;
1211 0 : line += word;
1212 0 : length += whitelgth + worldlgth;
1213 : }
1214 :
1215 0 : word = L"";
1216 0 : whitespace = L"";
1217 : }
1218 :
1219 0 : whitespace += c;
1220 :
1221 : // compute line break
1222 0 : if (lineBreak)
1223 : {
1224 0 : line += whitespace;
1225 0 : line += word;
1226 0 : BrokenText.push_back(line);
1227 0 : BrokenTextPositions.push_back(lastLineStart);
1228 0 : lastLineStart = i+1;
1229 0 : line = L"";
1230 0 : word = L"";
1231 0 : whitespace = L"";
1232 0 : length = 0;
1233 0 : }
1234 : }
1235 : else
1236 : {
1237 : // yippee this is a word..
1238 0 : word += c;
1239 : }
1240 : }
1241 :
1242 0 : line += whitespace;
1243 0 : line += word;
1244 0 : BrokenText.push_back(line);
1245 0 : BrokenTextPositions.push_back(lastLineStart);
1246 : }
1247 :
1248 :
1249 285 : void intlGUIEditBox::setTextRect(s32 line)
1250 : {
1251 285 : core::dimension2du d;
1252 :
1253 285 : IGUISkin* skin = Environment->getSkin();
1254 285 : if (!skin)
1255 0 : return;
1256 :
1257 285 : IGUIFont* font = OverrideFont ? OverrideFont : skin->getFont();
1258 :
1259 285 : if (!font)
1260 0 : return;
1261 :
1262 : // get text dimension
1263 285 : const u32 lineCount = (WordWrap || MultiLine) ? BrokenText.size() : 1;
1264 285 : if (WordWrap || MultiLine)
1265 : {
1266 0 : d = font->getDimension(BrokenText[line].c_str());
1267 : }
1268 : else
1269 : {
1270 285 : d = font->getDimension(Text.c_str());
1271 285 : d.Height = AbsoluteRect.getHeight();
1272 : }
1273 285 : d.Height += font->getKerningHeight();
1274 :
1275 : // justification
1276 285 : switch (HAlign)
1277 : {
1278 : case EGUIA_CENTER:
1279 : // align to h centre
1280 0 : CurrentTextRect.UpperLeftCorner.X = (FrameRect.getWidth()/2) - (d.Width/2);
1281 0 : CurrentTextRect.LowerRightCorner.X = (FrameRect.getWidth()/2) + (d.Width/2);
1282 0 : break;
1283 : case EGUIA_LOWERRIGHT:
1284 : // align to right edge
1285 0 : CurrentTextRect.UpperLeftCorner.X = FrameRect.getWidth() - d.Width;
1286 0 : CurrentTextRect.LowerRightCorner.X = FrameRect.getWidth();
1287 0 : break;
1288 : default:
1289 : // align to left edge
1290 285 : CurrentTextRect.UpperLeftCorner.X = 0;
1291 285 : CurrentTextRect.LowerRightCorner.X = d.Width;
1292 :
1293 : }
1294 :
1295 285 : switch (VAlign)
1296 : {
1297 : case EGUIA_CENTER:
1298 : // align to v centre
1299 : CurrentTextRect.UpperLeftCorner.Y =
1300 285 : (FrameRect.getHeight()/2) - (lineCount*d.Height)/2 + d.Height*line;
1301 285 : break;
1302 : case EGUIA_LOWERRIGHT:
1303 : // align to bottom edge
1304 : CurrentTextRect.UpperLeftCorner.Y =
1305 0 : FrameRect.getHeight() - lineCount*d.Height + d.Height*line;
1306 0 : break;
1307 : default:
1308 : // align to top edge
1309 0 : CurrentTextRect.UpperLeftCorner.Y = d.Height*line;
1310 0 : break;
1311 : }
1312 :
1313 285 : CurrentTextRect.UpperLeftCorner.X -= HScrollPos;
1314 285 : CurrentTextRect.LowerRightCorner.X -= HScrollPos;
1315 285 : CurrentTextRect.UpperLeftCorner.Y -= VScrollPos;
1316 285 : CurrentTextRect.LowerRightCorner.Y = CurrentTextRect.UpperLeftCorner.Y + d.Height;
1317 :
1318 285 : CurrentTextRect += FrameRect.UpperLeftCorner;
1319 :
1320 : }
1321 :
1322 :
1323 12 : s32 intlGUIEditBox::getLineFromPos(s32 pos)
1324 : {
1325 12 : if (!WordWrap && !MultiLine)
1326 12 : return 0;
1327 :
1328 0 : s32 i=0;
1329 0 : while (i < (s32)BrokenTextPositions.size())
1330 : {
1331 0 : if (BrokenTextPositions[i] > pos)
1332 0 : return i-1;
1333 0 : ++i;
1334 : }
1335 0 : return (s32)BrokenTextPositions.size() - 1;
1336 : }
1337 :
1338 :
1339 0 : void intlGUIEditBox::inputChar(wchar_t c)
1340 : {
1341 0 : if (!IsEnabled)
1342 0 : return;
1343 :
1344 0 : if (c != 0)
1345 : {
1346 0 : if (Text.size() < Max || Max == 0)
1347 : {
1348 0 : core::stringw s;
1349 :
1350 0 : if (MarkBegin != MarkEnd)
1351 : {
1352 : // replace marked text
1353 0 : const s32 realmbgn = MarkBegin < MarkEnd ? MarkBegin : MarkEnd;
1354 0 : const s32 realmend = MarkBegin < MarkEnd ? MarkEnd : MarkBegin;
1355 :
1356 0 : s = Text.subString(0, realmbgn);
1357 0 : s.append(c);
1358 0 : s.append( Text.subString(realmend, Text.size()-realmend) );
1359 0 : Text = s;
1360 0 : CursorPos = realmbgn+1;
1361 : }
1362 : else
1363 : {
1364 : // add new character
1365 0 : s = Text.subString(0, CursorPos);
1366 0 : s.append(c);
1367 0 : s.append( Text.subString(CursorPos, Text.size()-CursorPos) );
1368 0 : Text = s;
1369 0 : ++CursorPos;
1370 : }
1371 :
1372 0 : BlinkStartTime = porting::getTimeMs();
1373 0 : setTextMarkers(0, 0);
1374 : }
1375 : }
1376 0 : breakText();
1377 0 : sendGuiEvent(EGET_EDITBOX_CHANGED);
1378 0 : calculateScrollPos();
1379 : }
1380 :
1381 :
1382 12 : void intlGUIEditBox::calculateScrollPos()
1383 : {
1384 12 : if (!AutoScroll)
1385 0 : return;
1386 :
1387 : // calculate horizontal scroll position
1388 12 : s32 cursLine = getLineFromPos(CursorPos);
1389 12 : setTextRect(cursLine);
1390 :
1391 : // don't do horizontal scrolling when wordwrap is enabled.
1392 12 : if (!WordWrap)
1393 : {
1394 : // get cursor position
1395 12 : IGUISkin* skin = Environment->getSkin();
1396 12 : if (!skin)
1397 0 : return;
1398 12 : IGUIFont* font = OverrideFont ? OverrideFont : skin->getFont();
1399 12 : if (!font)
1400 0 : return;
1401 :
1402 12 : core::stringw *txtLine = MultiLine ? &BrokenText[cursLine] : &Text;
1403 12 : s32 cPos = MultiLine ? CursorPos - BrokenTextPositions[cursLine] : CursorPos;
1404 :
1405 24 : s32 cStart = CurrentTextRect.UpperLeftCorner.X + HScrollPos +
1406 24 : font->getDimension(txtLine->subString(0, cPos).c_str()).Width;
1407 :
1408 12 : s32 cEnd = cStart + font->getDimension(L"_ ").Width;
1409 :
1410 12 : if (FrameRect.LowerRightCorner.X < cEnd)
1411 2 : HScrollPos = cEnd - FrameRect.LowerRightCorner.X;
1412 10 : else if (FrameRect.UpperLeftCorner.X > cStart)
1413 0 : HScrollPos = cStart - FrameRect.UpperLeftCorner.X;
1414 : else
1415 10 : HScrollPos = 0;
1416 :
1417 : // todo: adjust scrollbar
1418 : }
1419 :
1420 : // vertical scroll position
1421 12 : if (FrameRect.LowerRightCorner.Y < CurrentTextRect.LowerRightCorner.Y + VScrollPos)
1422 12 : VScrollPos = CurrentTextRect.LowerRightCorner.Y - FrameRect.LowerRightCorner.Y + VScrollPos;
1423 :
1424 0 : else if (FrameRect.UpperLeftCorner.Y > CurrentTextRect.UpperLeftCorner.Y + VScrollPos)
1425 0 : VScrollPos = CurrentTextRect.UpperLeftCorner.Y - FrameRect.UpperLeftCorner.Y + VScrollPos;
1426 : else
1427 0 : VScrollPos = 0;
1428 :
1429 : // todo: adjust scrollbar
1430 : }
1431 :
1432 : //! set text markers
1433 6 : void intlGUIEditBox::setTextMarkers(s32 begin, s32 end)
1434 : {
1435 6 : if ( begin != MarkBegin || end != MarkEnd )
1436 : {
1437 0 : MarkBegin = begin;
1438 0 : MarkEnd = end;
1439 0 : sendGuiEvent(EGET_EDITBOX_MARKING_CHANGED);
1440 : }
1441 6 : }
1442 :
1443 : //! send some gui event to parent
1444 0 : void intlGUIEditBox::sendGuiEvent(EGUI_EVENT_TYPE type)
1445 : {
1446 0 : if ( Parent )
1447 : {
1448 : SEvent e;
1449 0 : e.EventType = EET_GUI_EVENT;
1450 0 : e.GUIEvent.Caller = this;
1451 0 : e.GUIEvent.Element = 0;
1452 0 : e.GUIEvent.EventType = type;
1453 :
1454 0 : Parent->OnEvent(e);
1455 : }
1456 0 : }
1457 :
1458 : //! Writes attributes of the element.
1459 0 : void intlGUIEditBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
1460 : {
1461 : // IGUIEditBox::serializeAttributes(out,options);
1462 :
1463 0 : out->addBool ("OverrideColorEnabled",OverrideColorEnabled );
1464 0 : out->addColor ("OverrideColor", OverrideColor);
1465 : // out->addFont("OverrideFont",OverrideFont);
1466 0 : out->addInt ("MaxChars", Max);
1467 0 : out->addBool ("WordWrap", WordWrap);
1468 0 : out->addBool ("MultiLine", MultiLine);
1469 0 : out->addBool ("AutoScroll", AutoScroll);
1470 0 : out->addBool ("PasswordBox", PasswordBox);
1471 0 : core::stringw ch = L" ";
1472 0 : ch[0] = PasswordChar;
1473 0 : out->addString("PasswordChar", ch.c_str());
1474 0 : out->addEnum ("HTextAlign", HAlign, GUIAlignmentNames);
1475 0 : out->addEnum ("VTextAlign", VAlign, GUIAlignmentNames);
1476 :
1477 0 : IGUIEditBox::serializeAttributes(out,options);
1478 0 : }
1479 :
1480 :
1481 : //! Reads attributes of the element
1482 0 : void intlGUIEditBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
1483 : {
1484 0 : IGUIEditBox::deserializeAttributes(in,options);
1485 :
1486 0 : setOverrideColor(in->getAttributeAsColor("OverrideColor"));
1487 0 : enableOverrideColor(in->getAttributeAsBool("OverrideColorEnabled"));
1488 0 : setMax(in->getAttributeAsInt("MaxChars"));
1489 0 : setWordWrap(in->getAttributeAsBool("WordWrap"));
1490 0 : setMultiLine(in->getAttributeAsBool("MultiLine"));
1491 0 : setAutoScroll(in->getAttributeAsBool("AutoScroll"));
1492 0 : core::stringw ch = in->getAttributeAsStringW("PasswordChar");
1493 :
1494 0 : if (!ch.size())
1495 0 : setPasswordBox(in->getAttributeAsBool("PasswordBox"));
1496 : else
1497 0 : setPasswordBox(in->getAttributeAsBool("PasswordBox"), ch[0]);
1498 :
1499 0 : setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames),
1500 0 : (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames));
1501 :
1502 : // setOverrideFont(in->getAttributeAsFont("OverrideFont"));
1503 0 : }
1504 :
1505 :
1506 : } // end namespace gui
1507 3 : } // end namespace irr
1508 :
1509 : #endif // _IRR_COMPILE_WITH_GUI_
|