1 //------------------------------------------------------------------------------
2 // emTextField.cpp
3 //
4 // Copyright (C) 2005-2011,2014-2016,2018 Oliver Hamann.
5 //
6 // Homepage: http://eaglemode.sourceforge.net/
7 //
8 // This program is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU General Public License version 3 as published by the
10 // Free Software Foundation.
11 //
12 // This program is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
15 // more details.
16 //
17 // You should have received a copy of the GNU General Public License version 3
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //------------------------------------------------------------------------------
20
21 #include <emCore/emTextField.h>
22
23
emTextField(ParentArg parent,const emString & name,const emString & caption,const emString & description,const emImage & icon,const emString & text,bool editable)24 emTextField::emTextField(
25 ParentArg parent, const emString & name, const emString & caption,
26 const emString & description, const emImage & icon,
27 const emString & text, bool editable
28 )
29 : emBorder(parent,name,caption,description,icon)
30 {
31 Clipboard=emClipboard::LookupInherited(GetView());
32 if (!Clipboard) {
33 emFatalError("emTextField: No emClipboard available.");
34 }
35 Editable=editable;
36 MultiLineMode=false;
37 PasswordMode=false;
38 OverwriteMode=false;
39 Text=text;
40 TextLen=Text.GetLen();
41 CursorIndex=TextLen;
42 SelectionStartIndex=0;
43 SelectionEndIndex=0;
44 MagicCursorColumn=-1;
45 SelectionId=-1;
46 CursorBlinkTime=emGetClockMS();
47 CursorBlinkOn=true;
48 DragMode=DM_NONE;
49 DragPosC=0.0;
50 DragPosR=0.0;
51 SetBorderType(OBT_INSTRUMENT,Editable?IBT_INPUT_FIELD:IBT_OUTPUT_FIELD);
52 }
53
54
~emTextField()55 emTextField::~emTextField()
56 {
57 }
58
59
SetEditable(bool editable)60 void emTextField::SetEditable(bool editable)
61 {
62 if (Editable!=editable) {
63 Editable=editable;
64 if (editable) {
65 if (GetInnerBorderType()==IBT_OUTPUT_FIELD) {
66 SetInnerBorderType(IBT_INPUT_FIELD);
67 }
68 }
69 else {
70 if (GetInnerBorderType()==IBT_INPUT_FIELD) {
71 SetInnerBorderType(IBT_OUTPUT_FIELD);
72 }
73 }
74 InvalidatePainting();
75 }
76 }
77
78
SetMultiLineMode(bool multiLineMode)79 void emTextField::SetMultiLineMode(bool multiLineMode)
80 {
81 if (MultiLineMode!=multiLineMode) {
82 MultiLineMode=multiLineMode;
83 InvalidatePainting();
84 }
85 }
86
87
SetPasswordMode(bool passwordMode)88 void emTextField::SetPasswordMode(bool passwordMode)
89 {
90 if (PasswordMode!=passwordMode) {
91 PasswordMode=passwordMode;
92 InvalidatePainting();
93 }
94 }
95
96
SetOverwriteMode(bool overwriteMode)97 void emTextField::SetOverwriteMode(bool overwriteMode)
98 {
99 if (OverwriteMode!=overwriteMode) {
100 OverwriteMode=overwriteMode;
101 InvalidatePainting();
102 }
103 }
104
105
SetText(const emString & text)106 void emTextField::SetText(const emString & text)
107 {
108 if (Text==text) return;
109 EmptySelection();
110 Text=text;
111 TextLen=Text.GetLen();
112 CursorIndex=TextLen;
113 MagicCursorColumn=-1;
114 InvalidatePainting();
115 Signal(TextSignal);
116 TextChanged();
117 }
118
119
SetCursorIndex(int index)120 void emTextField::SetCursorIndex(int index)
121 {
122 if (index<0) index=0;
123 if (index>TextLen) index=TextLen;
124 if (CursorIndex!=index) {
125 index=GetNormalizedIndex(index);
126 if (CursorIndex!=index) {
127 CursorIndex=index;
128 InvalidatePainting();
129 }
130 }
131 }
132
133
Select(int startIndex,int endIndex,bool publish)134 void emTextField::Select(int startIndex, int endIndex, bool publish)
135 {
136 if (startIndex<0) startIndex=0;
137 if (endIndex>TextLen) endIndex=TextLen;
138 if (startIndex>=endIndex) {
139 startIndex=0;
140 endIndex=0;
141 }
142 if (SelectionStartIndex==startIndex && SelectionEndIndex==endIndex) return;
143 startIndex=GetNormalizedIndex(startIndex);
144 endIndex=GetNormalizedIndex(endIndex);
145 if (SelectionStartIndex==startIndex && SelectionEndIndex==endIndex) return;
146 if (SelectionId!=-1) {
147 Clipboard->Clear(true,SelectionId);
148 SelectionId=-1;
149 }
150 SelectionStartIndex=startIndex;
151 SelectionEndIndex=endIndex;
152 InvalidatePainting();
153 if (publish) PublishSelection();
154 Signal(SelectionSignal);
155 SelectionChanged();
156 }
157
158
EmptySelection()159 void emTextField::EmptySelection()
160 {
161 Select(0,0,false);
162 }
163
164
SelectAll(bool publish)165 void emTextField::SelectAll(bool publish)
166 {
167 Select(0,TextLen,publish);
168 }
169
170
PublishSelection()171 void emTextField::PublishSelection()
172 {
173 emString str;
174 int len;
175
176 len=SelectionEndIndex-SelectionStartIndex;
177 if (len>0 && SelectionId==-1) {
178 if (PasswordMode) str=emString('*',len);
179 else str=Text.GetSubString(SelectionStartIndex,len);
180 SelectionId=Clipboard->PutText(str,true);
181 }
182 }
183
184
CutSelectedTextToClipboard()185 void emTextField::CutSelectedTextToClipboard()
186 {
187 CopySelectedTextToClipboard();
188 DeleteSelectedText();
189 }
190
191
CopySelectedTextToClipboard()192 void emTextField::CopySelectedTextToClipboard()
193 {
194 emString str;
195 int len;
196
197 len=SelectionEndIndex-SelectionStartIndex;
198 if (len>0) {
199 if (PasswordMode) str=emString('*',len);
200 else str=Text.GetSubString(SelectionStartIndex,len);
201 Clipboard->PutText(str);
202 }
203 }
204
205
PasteSelectedTextFromClipboard()206 void emTextField::PasteSelectedTextFromClipboard()
207 {
208 PasteSelectedText(Clipboard->GetText());
209 }
210
211
PasteSelectedText(const emString & text)212 void emTextField::PasteSelectedText(const emString & text)
213 {
214 int i,l,d;
215
216 if (text.IsEmpty()) return;
217 if (SelectionStartIndex<SelectionEndIndex) {
218 i=SelectionStartIndex;
219 l=SelectionEndIndex-SelectionStartIndex;
220 d=TextLen-SelectionEndIndex;
221 EmptySelection();
222 }
223 else {
224 i=CursorIndex;
225 l=0;
226 d=TextLen-CursorIndex;
227 }
228 Text.Replace(i,l,text);
229 TextLen=Text.GetLen();
230 CursorIndex=TextLen-d;
231 MagicCursorColumn=-1;
232 InvalidatePainting();
233 Signal(TextSignal);
234 TextChanged();
235 }
236
237
DeleteSelectedText()238 void emTextField::DeleteSelectedText()
239 {
240 int i,l;
241
242 i=SelectionStartIndex;
243 l=SelectionEndIndex-SelectionStartIndex;
244 if (l<=0) return;
245 CursorIndex=i;
246 EmptySelection();
247 Text.Remove(i,l);
248 TextLen=Text.GetLen();
249 MagicCursorColumn=-1;
250 InvalidatePainting();
251 Signal(TextSignal);
252 TextChanged();
253 }
254
255
TextChanged()256 void emTextField::TextChanged()
257 {
258 }
259
260
SelectionChanged()261 void emTextField::SelectionChanged()
262 {
263 }
264
265
Cycle()266 bool emTextField::Cycle()
267 {
268 emUInt64 clk;
269 bool busy;
270
271 clk=emGetClockMS();
272 busy=false;
273
274 if (IsInFocusedPath()) {
275 if (clk>=CursorBlinkTime+1000) {
276 CursorBlinkTime=clk;
277 if (!CursorBlinkOn) {
278 CursorBlinkOn=true;
279 InvalidatePainting();
280 }
281 }
282 else if (clk>=CursorBlinkTime+500) {
283 if (CursorBlinkOn) {
284 CursorBlinkOn=false;
285 InvalidatePainting();
286 }
287 }
288 busy=true;
289 }
290 else {
291 CursorBlinkTime=clk;
292 if (!CursorBlinkOn) {
293 CursorBlinkOn=true;
294 InvalidatePainting();
295 }
296 }
297
298 if (emBorder::Cycle()) busy=true;
299 return busy;
300 }
301
302
Notice(NoticeFlags flags)303 void emTextField::Notice(NoticeFlags flags)
304 {
305 if ((flags&(NF_FOCUS_CHANGED))!=0 && IsInFocusedPath()) {
306 RestartCursorBlinking();
307 WakeUp();
308 }
309 emBorder::Notice(flags);
310 }
311
312
Input(emInputEvent & event,const emInputState & state,double mx,double my)313 void emTextField::Input(
314 emInputEvent & event, const emInputState & state, double mx, double my
315 )
316 {
317 static const double minExt=4.5;
318 double mc,mr;
319 int col,row,i,i1,i2,j1,j2;
320 bool inArea;
321 emString str;
322
323 inArea=CheckMouse(mx,my,&mc,&mr);
324
325 switch (DragMode) {
326 case DM_NONE:
327 if (
328 inArea && event.IsKey(EM_KEY_LEFT_BUTTON) &&
329 !state.GetAlt() && !state.GetMeta() &&
330 GetViewCondition(VCT_MIN_EXT)>=minExt
331 ) {
332 MagicCursorColumn=-1;
333 if (state.GetCtrl()) {
334 if (IsEditable() && IsEnabled()) {
335 i=ColRow2Index(mc,mr,false);
336 if (i<SelectionStartIndex || i>=SelectionEndIndex) {
337 SetCursorIndex(ColRow2Index(mc,mr,true));
338 SetDragMode(DM_INSERT);
339 }
340 else {
341 SetCursorIndex(SelectionEndIndex);
342 Index2ColRow(SelectionStartIndex,&col,&row);
343 DragPosC=mc-col;
344 DragPosR=mr-row;
345 SetDragMode(DM_MOVE);
346 }
347 }
348 }
349 else if (event.GetRepeat()==0) {
350 i=ColRow2Index(mc,mr,true);
351 if (state.GetShift()) ModifySelection(i,i,false);
352 else EmptySelection();
353 SetCursorIndex(i);
354 SetDragMode(DM_SELECT);
355 }
356 else if (event.GetRepeat()==1) {
357 i2=GetNextWordBoundaryIndex(ColRow2Index(mc,mr,false));
358 i1=GetPrevWordBoundaryIndex(i2);
359 if (!state.GetShift() || IsSelectionEmpty()) {
360 Select(i1,i2,false);
361 SetCursorIndex(i2);
362 }
363 else if (i2>SelectionEndIndex) {
364 ModifySelection(i2,i2,false);
365 SetCursorIndex(i2);
366 }
367 else {
368 ModifySelection(i1,i1,false);
369 SetCursorIndex(i1);
370 }
371 SetDragMode(DM_SELECT_BY_WORDS);
372 }
373 else if (event.GetRepeat()==2) {
374 i2=GetNextRowIndex(ColRow2Index(mc,mr,false));
375 i1=GetPrevRowIndex(i2);
376 if (!state.GetShift() || IsSelectionEmpty()) {
377 Select(i1,i2,false);
378 SetCursorIndex(i2);
379 }
380 else if (i2>SelectionEndIndex) {
381 ModifySelection(i2,i2,false);
382 SetCursorIndex(i2);
383 }
384 else {
385 ModifySelection(i1,i1,false);
386 SetCursorIndex(i1);
387 }
388 SetDragMode(DM_SELECT_BY_ROWS);
389 }
390 else {
391 SelectAll(true);
392 SetCursorIndex(TextLen);
393 }
394 RestartCursorBlinking();
395 Focus();
396 event.Eat();
397 }
398 break;
399 case DM_SELECT:
400 i=ColRow2Index(mc,mr,true);
401 if (i!=CursorIndex) {
402 MagicCursorColumn=-1;
403 ModifySelection(CursorIndex,i,false);
404 SetCursorIndex(i);
405 RestartCursorBlinking();
406 }
407 if (!state.Get(EM_KEY_LEFT_BUTTON)) {
408 PublishSelection();
409 SetDragMode(DM_NONE);
410 }
411 break;
412 case DM_SELECT_BY_WORDS:
413 i2=GetNextWordBoundaryIndex(ColRow2Index(mc,mr,false));
414 i1=GetPrevWordBoundaryIndex(i2);
415 if (IsSelectionEmpty()) {
416 Select(i1,i2,false);
417 SetCursorIndex(i2);
418 }
419 else {
420 j1=SelectionStartIndex;
421 j2=SelectionEndIndex;
422 if (CursorIndex<=j1) j1=GetPrevWordBoundaryIndex(j2);
423 else j2=GetNextWordBoundaryIndex(j1);
424 if (j1<=i1) {
425 Select(j1,i2,false);
426 SetCursorIndex(i2);
427 }
428 else {
429 Select(i1,j2,false);
430 SetCursorIndex(i1);
431 }
432 }
433 MagicCursorColumn=-1;
434 RestartCursorBlinking();
435 if (!state.Get(EM_KEY_LEFT_BUTTON)) {
436 PublishSelection();
437 SetDragMode(DM_NONE);
438 }
439 break;
440 case DM_SELECT_BY_ROWS:
441 i2=GetNextRowIndex(ColRow2Index(mc,mr,false));
442 i1=GetPrevRowIndex(i2);
443 if (IsSelectionEmpty()) {
444 Select(i1,i2,false);
445 SetCursorIndex(i2);
446 }
447 else {
448 j1=SelectionStartIndex;
449 j2=SelectionEndIndex;
450 if (CursorIndex<=j1) j1=GetPrevRowIndex(j2);
451 else j2=GetNextRowIndex(j1);
452 if (j1<=i1) {
453 Select(j1,i2,false);
454 SetCursorIndex(i2);
455 }
456 else {
457 Select(i1,j2,false);
458 SetCursorIndex(i1);
459 }
460 }
461 MagicCursorColumn=-1;
462 RestartCursorBlinking();
463 if (!state.Get(EM_KEY_LEFT_BUTTON)) {
464 PublishSelection();
465 SetDragMode(DM_NONE);
466 }
467 break;
468 case DM_INSERT:
469 i=ColRow2Index(mc,mr,true);
470 if (i!=CursorIndex) {
471 SetCursorIndex(i);
472 MagicCursorColumn=-1;
473 RestartCursorBlinking();
474 }
475 if (!state.Get(EM_KEY_LEFT_BUTTON)) {
476 if (inArea && IsEditable() && IsEnabled()) {
477 SelectionId=-1;
478 EmptySelection();
479 PasteSelectedText(Clipboard->GetText(true));
480 }
481 SetDragMode(DM_NONE);
482 }
483 break;
484 case DM_MOVE:
485 // When extending this for moving the text to somewhere else,
486 // don't forget to disable that in password mode.
487 i1=SelectionStartIndex;
488 i2=SelectionEndIndex;
489 if (i1<i2 && IsEditable() && IsEnabled()) {
490 str=Text.Extract(i1,i2-i1);
491 TextLen=Text.GetLen();
492 i=ColRow2Index(mc-DragPosC,mr-DragPosR+0.5,true);
493 Text.Insert(i,str);
494 TextLen=Text.GetLen();
495 if (i!=i1) {
496 SelectionStartIndex+=i-i1;
497 SelectionEndIndex+=i-i1;
498 CursorIndex=SelectionEndIndex;
499 MagicCursorColumn=-1;
500 RestartCursorBlinking();
501 InvalidatePainting();
502 Signal(TextSignal);
503 TextChanged();
504 Signal(SelectionSignal);
505 SelectionChanged();
506 }
507 }
508 if (!state.Get(EM_KEY_LEFT_BUTTON)) {
509 SetDragMode(DM_NONE);
510 }
511 break;
512 }
513
514 if (
515 !event.IsEmpty() && DragMode==DM_NONE &&
516 GetViewCondition(VCT_MIN_EXT)>=minExt
517 ) {
518 if (event.IsKey(EM_KEY_CURSOR_LEFT) && !state.GetAlt() && !state.GetMeta()) {
519 if (state.GetCtrl()) i=GetPrevWordIndex(CursorIndex);
520 else i=GetPrevIndex(CursorIndex);
521 if (state.GetShift()) ModifySelection(CursorIndex,i,true);
522 else EmptySelection();
523 SetCursorIndex(i);
524 MagicCursorColumn=-1;
525 RestartCursorBlinking();
526 ScrollToCursor();
527 event.Eat();
528 }
529 if (event.IsKey(EM_KEY_CURSOR_RIGHT) && !state.GetAlt() && !state.GetMeta()) {
530 if (state.GetCtrl()) i=GetNextWordIndex(CursorIndex);
531 else i=GetNextIndex(CursorIndex);
532 if (state.GetShift()) ModifySelection(CursorIndex,i,true);
533 else EmptySelection();
534 SetCursorIndex(i);
535 MagicCursorColumn=-1;
536 RestartCursorBlinking();
537 ScrollToCursor();
538 event.Eat();
539 }
540 if (MultiLineMode) {
541 if (event.IsKey(EM_KEY_CURSOR_UP) && !state.GetAlt() && !state.GetMeta()) {
542 if (state.GetCtrl()) {
543 i=GetPrevParagraphIndex(CursorIndex);
544 MagicCursorColumn=-1;
545 }
546 else {
547 Index2ColRow(CursorIndex,&col,&row);
548 if (MagicCursorColumn<0) MagicCursorColumn=col;
549 i=ColRow2Index(MagicCursorColumn,row-1,true);
550 }
551 if (state.GetShift()) ModifySelection(CursorIndex,i,true);
552 else EmptySelection();
553 SetCursorIndex(i);
554 RestartCursorBlinking();
555 ScrollToCursor();
556 event.Eat();
557 }
558 if (event.IsKey(EM_KEY_CURSOR_DOWN) && !state.GetAlt() && !state.GetMeta()) {
559 if (state.GetCtrl()) {
560 i=GetNextParagraphIndex(CursorIndex);
561 MagicCursorColumn=-1;
562 }
563 else {
564 Index2ColRow(CursorIndex,&col,&row);
565 if (MagicCursorColumn<0) MagicCursorColumn=col;
566 i=ColRow2Index(MagicCursorColumn,row+1,true);
567 }
568 if (state.GetShift()) ModifySelection(CursorIndex,i,true);
569 else EmptySelection();
570 SetCursorIndex(i);
571 RestartCursorBlinking();
572 ScrollToCursor();
573 event.Eat();
574 }
575 }
576 if (event.IsKey(EM_KEY_HOME) && !state.GetAlt() && !state.GetMeta()) {
577 if (state.GetCtrl()) i=0;
578 else i=GetRowStartIndex(CursorIndex);
579 if (state.GetShift()) ModifySelection(CursorIndex,i,true);
580 else EmptySelection();
581 SetCursorIndex(i);
582 MagicCursorColumn=-1;
583 RestartCursorBlinking();
584 ScrollToCursor();
585 event.Eat();
586 }
587 if (event.IsKey(EM_KEY_END) && !state.GetAlt() && !state.GetMeta()) {
588 if (state.GetCtrl()) i=TextLen;
589 else i=GetRowEndIndex(CursorIndex);
590 if (state.GetShift()) ModifySelection(CursorIndex,i,true);
591 else EmptySelection();
592 SetCursorIndex(i);
593 MagicCursorColumn=-1;
594 RestartCursorBlinking();
595 ScrollToCursor();
596 event.Eat();
597 }
598 if (event.IsKey(EM_KEY_A) && state.IsCtrlMod()) {
599 SelectAll(true);
600 SetCursorIndex(TextLen);
601 MagicCursorColumn=-1;
602 RestartCursorBlinking();
603 ScrollToCursor();
604 event.Eat();
605 }
606 if (event.IsKey(EM_KEY_INSERT) && state.IsNoMod()) {
607 SetOverwriteMode(!GetOverwriteMode());
608 RestartCursorBlinking();
609 event.Eat();
610 }
611 if ((event.IsKey(EM_KEY_INSERT) && state.IsCtrlMod()) ||
612 (event.IsKey(EM_KEY_C) && state.IsCtrlMod())) {
613 CopySelectedTextToClipboard();
614 RestartCursorBlinking();
615 event.Eat();
616 }
617 }
618
619 if (
620 !event.IsEmpty() && DragMode==DM_NONE &&
621 IsEditable() && IsEnabled() &&
622 GetViewCondition(VCT_MIN_EXT)>=minExt
623 ) {
624 if (event.IsKey(EM_KEY_BACKSPACE) && state.IsNoMod()) {
625 if (IsSelectionEmpty()) {
626 Select(GetPrevIndex(CursorIndex),CursorIndex,false);
627 }
628 DeleteSelectedText();
629 RestartCursorBlinking();
630 ScrollToCursor();
631 event.Eat();
632 }
633 if (event.IsKey(EM_KEY_DELETE) && state.IsNoMod()) {
634 if (IsSelectionEmpty()) {
635 Select(CursorIndex,GetNextIndex(CursorIndex),false);
636 }
637 DeleteSelectedText();
638 RestartCursorBlinking();
639 ScrollToCursor();
640 event.Eat();
641 }
642 if ((event.IsKey(EM_KEY_DELETE) && state.IsShiftMod()) ||
643 (event.IsKey(EM_KEY_X) && state.IsCtrlMod())) {
644 CutSelectedTextToClipboard();
645 RestartCursorBlinking();
646 ScrollToCursor();
647 event.Eat();
648 }
649 if ((event.IsKey(EM_KEY_INSERT) && state.IsShiftMod()) ||
650 (event.IsKey(EM_KEY_V) && state.IsCtrlMod())) {
651 PasteSelectedTextFromClipboard();
652 RestartCursorBlinking();
653 ScrollToCursor();
654 event.Eat();
655 }
656 if (event.IsKey(EM_KEY_BACKSPACE) && state.IsCtrlMod()) {
657 if (IsSelectionEmpty()) {
658 Select(GetPrevWordIndex(CursorIndex),CursorIndex,false);
659 }
660 DeleteSelectedText();
661 RestartCursorBlinking();
662 ScrollToCursor();
663 event.Eat();
664 }
665 if (event.IsKey(EM_KEY_DELETE) && state.IsCtrlMod()) {
666 if (IsSelectionEmpty()) {
667 Select(
668 CursorIndex,
669 GetNextWordIndex(CursorIndex),
670 false
671 );
672 }
673 DeleteSelectedText();
674 RestartCursorBlinking();
675 ScrollToCursor();
676 event.Eat();
677 }
678 if (event.IsKey(EM_KEY_BACKSPACE) && state.IsShiftCtrlMod()) {
679 if (IsSelectionEmpty()) {
680 Select(GetRowStartIndex(CursorIndex),CursorIndex,false);
681 }
682 DeleteSelectedText();
683 RestartCursorBlinking();
684 ScrollToCursor();
685 event.Eat();
686 }
687 if (event.IsKey(EM_KEY_DELETE) && state.IsShiftCtrlMod()) {
688 if (IsSelectionEmpty()) {
689 Select(CursorIndex,GetRowEndIndex(CursorIndex),false);
690 }
691 DeleteSelectedText();
692 RestartCursorBlinking();
693 ScrollToCursor();
694 event.Eat();
695 }
696 if (MultiLineMode && event.IsKey(EM_KEY_ENTER) && state.IsNoMod()) {
697 PasteSelectedText("\n");
698 RestartCursorBlinking();
699 ScrollToCursor();
700 event.Eat();
701 }
702 if (
703 !event.GetChars().IsEmpty() &&
704 (unsigned char)(event.GetChars()[0])>=32 &&
705 event.GetChars()[0]!=127
706 ) {
707 if (
708 OverwriteMode && IsSelectionEmpty() &&
709 CursorIndex<GetRowEndIndex(CursorIndex)
710 ) {
711 Select(CursorIndex,GetNextIndex(CursorIndex),false);
712 }
713 PasteSelectedText(event.GetChars());
714 RestartCursorBlinking();
715 ScrollToCursor();
716 event.Eat();
717 }
718 }
719
720 emBorder::Input(event,state,mx,my);
721 }
722
723
HasHowTo() const724 bool emTextField::HasHowTo() const
725 {
726 return true;
727 }
728
729
GetHowTo() const730 emString emTextField::GetHowTo() const
731 {
732 emString h;
733
734 h=emBorder::GetHowTo();
735 h+=HowToTextField;
736 if (MultiLineMode) h+=HowToMultiLineOn; else h+=HowToMultiLineOff;
737 if (!IsEditable()) h+=HowToReadOnly;
738 return h;
739 }
740
741
PaintContent(const emPainter & painter,double x,double y,double w,double h,emColor canvasColor) const742 void emTextField::PaintContent(
743 const emPainter & painter, double x, double y, double w, double h,
744 emColor canvasColor
745 ) const
746 {
747 DoTextField(TEXT_FIELD_FUNC_PAINT,&painter,canvasColor,0.0,0.0,NULL,NULL,NULL);
748 }
749
750
CheckMouse(double mx,double my,double * pCol,double * pRow) const751 bool emTextField::CheckMouse(
752 double mx, double my, double * pCol, double * pRow
753 ) const
754 {
755 bool b;
756
757 DoTextField(TEXT_FIELD_FUNC_XY2CR,NULL,0,mx,my,pCol,pRow,&b);
758 return b;
759 }
760
761
CheckMouse(double mx,double my,double * pCol,double * pRow)762 bool emTextField::CheckMouse(
763 double mx, double my, double * pCol, double * pRow
764 )
765 {
766 return ((const emTextField*)this)->CheckMouse(mx,my,pCol,pRow);
767 }
768
769
DoTextField(DoTextFieldFunc func,const emPainter * painter,emColor canvasColor,double xIn,double yIn,double * pXOut,double * pYOut,bool * pHit) const770 void emTextField::DoTextField(
771 DoTextFieldFunc func, const emPainter * painter, emColor canvasColor,
772 double xIn, double yIn, double * pXOut, double * pYOut, bool * pHit
773 ) const
774 {
775 emColor bgColor,fgColor,hlColor,selColor,curColor;
776 emString txt;
777 double xy[10*2];
778 double x,y,w,h,r,ws,d,d1,d2,cx,cy,cw,ch,dx,dy,tx,ty,tw,th;
779 int i,i0,j,n,c,rows,cols,col,row,col0,row0,selIdx,selEnd;
780 bool selected,selected0;
781
782 GetContentRoundRect(&x,&y,&w,&h,&r);
783
784 d=emMin(h,w)*0.1+r*0.5;
785 tx=x+d;
786 ty=y+d;
787 tw=w-2*d;
788 th=h-2*d;
789
790 CalcTotalColsRows(&cols,&rows);
791 if (OverwriteMode && IsInFocusedPath()) {
792 Index2ColRow(CursorIndex,&col,&row);
793 if (col==cols) cols++;
794 }
795 ch=th/rows;
796 cw=emPainter::GetTextSize("X",ch,false);
797
798 ws=1.0;
799 if (cw*cols>tw) {
800 ws=tw/(cw*cols);
801 cw=tw/cols;
802 d=0.66;
803 if (ws<d) {
804 ty+=(ch-ch*ws/d)*0.5;
805 ch-=ch-ch*ws/d;
806 ws=d;
807 }
808 }
809
810 if (func!=TEXT_FIELD_FUNC_PAINT) {
811 if (func==TEXT_FIELD_FUNC_XY2CR) {
812 *pXOut=(xIn-tx)/cw;
813 *pYOut=(yIn-ty)/ch;
814 }
815 else {
816 xIn=tx+xIn*cw;
817 yIn=ty+yIn*ch;
818 *pXOut=xIn;
819 *pYOut=yIn;
820 }
821 dx=emMax(emMax(x-xIn,xIn-x-w)+r,0.0);
822 dy=emMax(emMax(y-yIn,yIn-y-h)+r,0.0);
823 *pHit = dx*dx+dy*dy <= r*r;
824 return;
825 }
826
827 if (IsEditable()) {
828 bgColor=GetLook().GetInputBgColor();
829 fgColor=GetLook().GetInputFgColor();
830 hlColor=GetLook().GetInputHlColor();
831 }
832 else {
833 bgColor=GetLook().GetOutputBgColor();
834 fgColor=GetLook().GetOutputFgColor();
835 hlColor=GetLook().GetOutputHlColor();
836 }
837
838 if (!IsEnabled()) {
839 bgColor=bgColor.GetBlended(GetLook().GetBgColor(),80.0F);
840 fgColor=fgColor.GetBlended(GetLook().GetBgColor(),80.0F);
841 hlColor=hlColor.GetBlended(GetLook().GetBgColor(),80.0F);
842 }
843
844 selColor=hlColor;
845 selIdx=GetSelectionStartIndex();
846 selEnd=GetSelectionEndIndex();
847 if (selIdx<selEnd) {
848 if (!IsInFocusedPath()) {
849 selColor=bgColor.GetBlended(fgColor,40.0);
850 }
851 Index2ColRow(selIdx,&col0,&row0);
852 Index2ColRow(selEnd,&col,&row);
853 xy[ 0]=tx+col0*cw; xy[ 1]=ty+row0*ch;
854 xy[ 2]=tx+tw; xy[ 3]=ty+row0*ch;
855 xy[ 4]=tx+tw; xy[ 5]=ty+row*ch;
856 xy[ 6]=tx+col*cw; xy[ 7]=ty+row*ch;
857 xy[ 8]=tx+col*cw; xy[ 9]=ty+row*ch+ch;
858 xy[10]=tx; xy[11]=ty+row*ch+ch;
859 xy[12]=tx; xy[13]=ty+row0*ch+ch;
860 xy[14]=tx+col0*cw; xy[15]=ty+row0*ch+ch;
861 painter->PaintPolygon(xy,8,selColor,canvasColor);
862 }
863
864 row0=0;
865 col0=0;
866 i0=0;
867 selected0=(i0>=selIdx && i0<selEnd);
868 row=0;
869 col=0;
870 emMBState mbState;
871 for (i=0;;) {
872 n=emDecodeChar(&c,Text.Get()+i,INT_MAX,&mbState);
873 selected=(i>=selIdx && i<selEnd);
874 if (
875 (
876 c<=0x0d &&
877 (c==0 || (MultiLineMode && (c==0x09 || c==0x0d || c==0x0a)))
878 ) ||
879 selected0!=selected
880 ) {
881 if (i0<i) {
882 if (PasswordMode) {
883 for (j=0; j<col-col0; j++) {
884 painter->PaintText(
885 tx+(col0+j)*cw,ty+row0*ch,"*",ch,ws,
886 selected0 ? bgColor : fgColor,
887 selected0 ? selColor : canvasColor
888 );
889 }
890 }
891 else {
892 painter->PaintText(
893 tx+col0*cw,ty+row0*ch,Text.Get()+i0,ch,ws,
894 selected0 ? bgColor : fgColor,
895 selected0 ? selColor : canvasColor,
896 i-i0
897 );
898 }
899 }
900 if (c==0) break;
901 row0=row;
902 col0=col;
903 i0=i;
904 selected0=selected;
905 }
906 i+=n;
907 col++;
908 if (c<=0x0d && MultiLineMode) {
909 if (c==0x09) {
910 col=(col+7)&~7;
911 col0=col;
912 i0=i;
913 selected0=(i0>=selIdx && i0<selEnd);
914 }
915 else if (c==0x0a || c==0x0d) {
916 if (c==0x0d && Text[i]==0x0a) i++;
917 col=0;
918 row++;
919 row0=row;
920 col0=col;
921 i0=i;
922 selected0=(i0>=selIdx && i0<selEnd);
923 }
924 }
925 }
926
927 if (IsInFocusedPath()) {
928 curColor=fgColor;
929 if (!IsEditable()) curColor=curColor.GetTransparented(75.0F);
930 else if (!IsCursorBlinkOn()) curColor=curColor.GetTransparented(88.0F);
931 Index2ColRow(CursorIndex,&col,&row);
932 cx=tx+cw*col;
933 cy=ty+ch*row;
934 if (GetOverwriteMode()) {
935 d=ch*0.07;
936 xy[ 0]=cx-d; xy[ 1]=cy-d;
937 xy[ 2]=cx+cw+d; xy[ 3]=cy-d;
938 xy[ 4]=cx+cw+d; xy[ 5]=cy+ch+d;
939 xy[ 6]=cx-d; xy[ 7]=cy+ch+d;
940 xy[ 8]=cx-d; xy[ 9]=cy-d;
941 xy[10]=cx; xy[11]=cy;
942 xy[12]=cx; xy[13]=cy+ch;
943 xy[14]=cx+cw; xy[15]=cy+ch;
944 xy[16]=cx+cw; xy[17]=cy;
945 xy[18]=cx; xy[19]=cy;
946 painter->PaintPolygon(xy,10,curColor);
947 }
948 else {
949 d=ch*0.07;
950 d1=d*0.5;
951 d2=d*2.2;
952 xy[ 0]=cx-d2; xy[ 1]=cy-d;
953 xy[ 2]=cx+d2; xy[ 3]=cy-d;
954 xy[ 4]=cx+d1; xy[ 5]=cy;
955 xy[ 6]=cx+d1; xy[ 7]=cy+ch;
956 xy[ 8]=cx+d2; xy[ 9]=cy+ch+d;
957 xy[10]=cx-d2; xy[11]=cy+ch+d;
958 xy[12]=cx-d1; xy[13]=cy+ch;
959 xy[14]=cx-d1; xy[15]=cy;
960 painter->PaintPolygon(xy,8,curColor);
961 }
962 }
963 }
964
965
SetDragMode(DragModeType dragMode)966 void emTextField::SetDragMode(DragModeType dragMode)
967 {
968 if (DragMode!=dragMode) {
969 DragMode=dragMode;
970 InvalidatePainting();
971 RestartCursorBlinking();
972 }
973 }
974
975
RestartCursorBlinking()976 void emTextField::RestartCursorBlinking()
977 {
978 CursorBlinkTime=emGetClockMS();
979 if (!CursorBlinkOn) {
980 CursorBlinkOn=true;
981 InvalidatePainting();
982 }
983 }
984
985
ScrollToCursor()986 void emTextField::ScrollToCursor()
987 {
988 int col,row;
989 double x1,y1,x2,y2,dx,dy;
990 bool b;
991
992 if (!IsViewed() || !IsActive()) return;
993 Index2ColRow(CursorIndex,&col,&row);
994 DoTextField(TEXT_FIELD_FUNC_CR2XY,NULL,0,col-0.5,row-0.2,&x1,&y1,&b);
995 DoTextField(TEXT_FIELD_FUNC_CR2XY,NULL,0,col+0.5,row+1.2,&x2,&y2,&b);
996 b=false;
997 dx=PanelToViewX(x1)-GetView().GetCurrentX();
998 if (dx<0.0) b=true;
999 else {
1000 dx=PanelToViewX(x2)-GetView().GetCurrentX()-GetView().GetCurrentWidth();
1001 if (dx>0.0) b=true; else dx=0.0;
1002 }
1003 dy=PanelToViewY(y1)-GetView().GetCurrentY();
1004 if (dy<0.0) b=true;
1005 else {
1006 dy=PanelToViewY(y2)-GetView().GetCurrentY()-GetView().GetCurrentHeight();
1007 if (dy>0.0) b=true; else dy=0.0;
1008 }
1009 if (b) {
1010 GetView().Scroll(dx,dy);
1011 if (!IsActive()) Activate();
1012 }
1013 }
1014
1015
ColRow2Index(double column,double row,bool forCursor) const1016 int emTextField::ColRow2Index(double column, double row, bool forCursor) const
1017 {
1018 int i,j,k,n,c;
1019
1020 if (!MultiLineMode) {
1021 emMBState mbState;
1022 for (i=0; ; i+=n, column-=1.0) {
1023 if (forCursor) { if (column<0.5) break; }
1024 else { if (column<1.0) break; }
1025 n=emDecodeChar(&c,Text.Get()+i,INT_MAX,&mbState);
1026 if (c==0) break;
1027 }
1028 }
1029 else {
1030 emMBState mbState,mbState2;
1031 for (j=0, i=0; row>=1.0; ) {
1032 j+=emDecodeChar(&c,Text.Get()+j,INT_MAX,&mbState);
1033 if (c==0x0a || c==0x0d) {
1034 if (c==0x0d && Text[j]==0x0a) j++;
1035 mbState2=mbState;
1036 i=j;
1037 row-=1.0;
1038 }
1039 if (c==0) break;
1040 }
1041 for (j=0; ; i+=n, j=k) {
1042 n=emDecodeChar(&c,Text.Get()+i,INT_MAX,&mbState2);
1043 if (c==0x0a || c==0x0d || c==0) break;
1044 k=j+1;
1045 if (c==0x09) k=(k+7)&~7;
1046 if (column<=k) {
1047 if (forCursor) { if (k-column<column-j) i+=n; }
1048 else { if (column==k) i+=n; }
1049 break;
1050 }
1051 }
1052 }
1053 return i;
1054 }
1055
1056
Index2ColRow(int index,int * pColumn,int * pRow) const1057 void emTextField::Index2ColRow(int index, int * pColumn, int * pRow) const
1058 {
1059 int i,col,row,n,c;
1060
1061 if (!MultiLineMode) {
1062 col=emGetDecodedCharCount(Text,index);
1063 row=0;
1064 }
1065 else {
1066 col=0;
1067 row=0;
1068 emMBState mbState;
1069 for (i=0; i<index; i+=n) {
1070 n=emDecodeChar(&c,Text.Get()+i,INT_MAX,&mbState);
1071 if (c==0x09) {
1072 col=(col+8)&~7;
1073 }
1074 else if (c==0x0a || c==0x0d) {
1075 if (c==0x0d && Text[i+1]==0x0a) n++;
1076 col=0;
1077 row++;
1078 }
1079 else if (c==0) {
1080 break;
1081 }
1082 else {
1083 col++;
1084 }
1085 }
1086 }
1087 *pColumn=col;
1088 *pRow=row;
1089 }
1090
1091
CalcTotalColsRows(int * pCols,int * pRows) const1092 void emTextField::CalcTotalColsRows(int * pCols, int * pRows) const
1093 {
1094 int i,cols,rows,rowcols,n,c;
1095
1096 if (!MultiLineMode) {
1097 cols=emGetDecodedCharCount(Text);
1098 rows=1;
1099 }
1100 else {
1101 cols=0;
1102 rows=1;
1103 rowcols=0;
1104 emMBState mbState;
1105 for (i=0; ; i+=n) {
1106 n=emDecodeChar(&c,Text.Get()+i,INT_MAX,&mbState);
1107 if (c==0x09) {
1108 rowcols=(rowcols+8)&~7;
1109 }
1110 else if (c==0x0a || c==0x0d) {
1111 if (cols<rowcols) cols=rowcols;
1112 if (c==0x0d && Text[i+1]==0x0a) n++;
1113 rowcols=0;
1114 rows++;
1115 }
1116 else if (c==0) {
1117 break;
1118 }
1119 else {
1120 rowcols++;
1121 }
1122 }
1123 if (cols<rowcols) cols=rowcols;
1124 }
1125
1126 if (cols<1) cols=1;
1127 if (rows<1) rows=1;
1128 *pCols=cols;
1129 *pRows=rows;
1130 }
1131
1132
GetNormalizedIndex(int index) const1133 int emTextField::GetNormalizedIndex(int index) const
1134 {
1135 int i,j;
1136
1137 emMBState mbState;
1138 for (i=0; ; i=j) {
1139 j=GetNextIndex(i,&mbState);
1140 if (j>index || j==i) return i;
1141 }
1142 }
1143
1144
ModifySelection(int oldIndex,int newIndex,bool publish)1145 void emTextField::ModifySelection(int oldIndex, int newIndex, bool publish)
1146 {
1147 int d1,d2;
1148
1149 if (SelectionStartIndex<SelectionEndIndex) {
1150 d1=oldIndex-SelectionStartIndex; if (d1<0) d1=-d1;
1151 d2=oldIndex-SelectionEndIndex; if (d2<0) d2=-d2;
1152 if (d1<d2) oldIndex=SelectionEndIndex;
1153 else oldIndex=SelectionStartIndex;
1154 }
1155 if (oldIndex<newIndex) Select(oldIndex,newIndex,publish);
1156 else Select(newIndex,oldIndex,publish);
1157 }
1158
1159
GetMBStateAtIndex(int index) const1160 emMBState emTextField::GetMBStateAtIndex(int index) const
1161 {
1162 int i,j;
1163
1164 emMBState mbState;
1165 for (i=0; ; i=j) {
1166 j=GetNextIndex(i,&mbState);
1167 if (j>index || j==i) return mbState;
1168 }
1169 }
1170
1171
GetNextIndex(int index,emMBState * mbState) const1172 int emTextField::GetNextIndex(int index, emMBState * mbState) const
1173 {
1174 int c;
1175
1176 emMBState ownMBState;
1177 if (!mbState) {
1178 ownMBState=GetMBStateAtIndex(index);
1179 mbState=&ownMBState;
1180 }
1181
1182 index+=emDecodeChar(&c,Text.Get()+index,INT_MAX,mbState);
1183 if (c==0x0d && Text[index]==0x0a && MultiLineMode) index++;
1184 return index;
1185 }
1186
1187
GetPrevIndex(int index) const1188 int emTextField::GetPrevIndex(int index) const
1189 {
1190 int i,j;
1191
1192 emMBState mbState;
1193 for (i=0; ; i=j) {
1194 j=GetNextIndex(i,&mbState);
1195 if (j>=index || j==i) return i;
1196 }
1197 }
1198
1199
GetNextWordBoundaryIndex(int index,bool * pIsDelimiter,emMBState * mbState) const1200 int emTextField::GetNextWordBoundaryIndex(
1201 int index, bool * pIsDelimiter, emMBState * mbState
1202 ) const
1203 {
1204 const char * p;
1205 int i,n,c;
1206 bool prevDelim,delim,first;
1207
1208 emMBState ownMBState;
1209 if (!mbState) {
1210 ownMBState=GetMBStateAtIndex(index);
1211 mbState=&ownMBState;
1212 }
1213
1214 p=Text.Get();
1215 i=index;
1216 delim=false;
1217 first=true;
1218 for (;;) {
1219 emMBState prevMBState(*mbState);
1220 n=emDecodeChar(&c,p+i,INT_MAX,mbState);
1221 if (n<=0) {
1222 *mbState=prevMBState;
1223 delim=true;
1224 break;
1225 }
1226 prevDelim=delim;
1227 if (
1228 PasswordMode ||
1229 (c>='0' && c<='9') ||
1230 (c>='A' && c<='Z') ||
1231 (c>='a' && c<='z') ||
1232 c=='_' ||
1233 c>127
1234 ) {
1235 delim=false;
1236 }
1237 else {
1238 delim=true;
1239 }
1240 if (!first && delim!=prevDelim) {
1241 *mbState=prevMBState;
1242 break;
1243 }
1244 i+=n;
1245 first=false;
1246 }
1247 if (pIsDelimiter) *pIsDelimiter=delim;
1248 return i;
1249 }
1250
1251
GetPrevWordBoundaryIndex(int index,bool * pIsDelimiter) const1252 int emTextField::GetPrevWordBoundaryIndex(
1253 int index, bool * pIsDelimiter
1254 ) const
1255 {
1256 int i,j;
1257
1258 emMBState mbState;
1259 for (i=0; ; i=j) {
1260 j=GetNextWordBoundaryIndex(i,pIsDelimiter,&mbState);
1261 if (j>=index || j==i) return i;
1262 }
1263 }
1264
1265
GetNextWordIndex(int index,emMBState * mbState) const1266 int emTextField::GetNextWordIndex(int index, emMBState * mbState) const
1267 {
1268 bool isDelim;
1269
1270 emMBState ownMBState;
1271 if (!mbState) {
1272 ownMBState=GetMBStateAtIndex(index);
1273 mbState=&ownMBState;
1274 }
1275
1276 for (;;) {
1277 index=GetNextWordBoundaryIndex(index,&isDelim,mbState);
1278 if (!isDelim || index>=TextLen) break;
1279 }
1280 return index;
1281 }
1282
1283
GetPrevWordIndex(int index) const1284 int emTextField::GetPrevWordIndex(int index) const
1285 {
1286 int i,j;
1287
1288 emMBState mbState;
1289 for (i=0; ; i=j) {
1290 j=GetNextWordIndex(i,&mbState);
1291 if (j>=index || j==i) return i;
1292 }
1293 }
1294
1295
GetRowStartIndex(int index) const1296 int emTextField::GetRowStartIndex(int index) const
1297 {
1298 int i,j,c;
1299
1300 if (!MultiLineMode) return 0;
1301 emMBState mbState;
1302 for (i=0, j=0; ; ) {
1303 i+=emDecodeChar(&c,Text.Get()+i,INT_MAX,&mbState);
1304 if (c==0x0d && Text[i]==0x0a) i++;
1305 if (c==0 || i>index) return j;
1306 if (c==0x0a || c==0x0d) j=i;
1307 }
1308 }
1309
1310
GetRowEndIndex(int index) const1311 int emTextField::GetRowEndIndex(int index) const
1312 {
1313 int n,c;
1314
1315 if (!MultiLineMode) return TextLen;
1316 emMBState mbState=GetMBStateAtIndex(index);
1317 for (;; index+=n) {
1318 n=emDecodeChar(&c,Text.Get()+index,INT_MAX,&mbState);
1319 if (c==0 || c==0x0a || c==0x0d) return index;
1320 }
1321 }
1322
1323
GetNextRowIndex(int index,emMBState * mbState) const1324 int emTextField::GetNextRowIndex(int index, emMBState * mbState) const
1325 {
1326 int c;
1327
1328 emMBState ownMBState;
1329 if (!mbState) {
1330 ownMBState=GetMBStateAtIndex(index);
1331 mbState=&ownMBState;
1332 }
1333
1334 if (!MultiLineMode) return TextLen;
1335 for (;;) {
1336 index+=emDecodeChar(&c,Text.Get()+index,INT_MAX,mbState);
1337 if (c==0 || c==0x0a || c==0x0d) {
1338 if (c==0x0d && Text[index]==0x0a) index++;
1339 return index;
1340 }
1341 }
1342 }
1343
1344
GetPrevRowIndex(int index) const1345 int emTextField::GetPrevRowIndex(int index) const
1346 {
1347 int i,j;
1348
1349 emMBState mbState;
1350 for (i=0; ; i=j) {
1351 j=GetNextRowIndex(i,&mbState);
1352 if (j>=index || j==i) return i;
1353 }
1354 }
1355
1356
GetNextParagraphIndex(int index,emMBState * mbState) const1357 int emTextField::GetNextParagraphIndex(int index, emMBState * mbState) const
1358 {
1359 bool e;
1360
1361 if (!MultiLineMode) return TextLen;
1362
1363 emMBState ownMBState;
1364 if (!mbState) {
1365 ownMBState=GetMBStateAtIndex(index);
1366 mbState=&ownMBState;
1367 }
1368
1369 for (e=false; index<TextLen; ) {
1370 index=GetNextRowIndex(index,mbState);
1371 if (Text[index]==0x0a || Text[index]==0x0d) e=true;
1372 else if (e) break;
1373 }
1374 return index;
1375 }
1376
1377
GetPrevParagraphIndex(int index) const1378 int emTextField::GetPrevParagraphIndex(int index) const
1379 {
1380 int i,j;
1381
1382 emMBState mbState;
1383 for (i=0; ; i=j) {
1384 j=GetNextParagraphIndex(i,&mbState);
1385 if (j>=index || j==i) return i;
1386 }
1387 }
1388
1389
1390 const char * emTextField::HowToTextField=
1391 "\n"
1392 "\n"
1393 "TEXT FIELD\n"
1394 "\n"
1395 "This is a text field. In such a field, a text can be viewed and edited.\n"
1396 "\n"
1397 "Quick hint about an incompatibility against other user interfaces: For inserting\n"
1398 "selected text, press Ctrl + left mouse button instead of the middle mouse\n"
1399 "button.\n"
1400 "\n"
1401 "Mouse control:\n"
1402 "\n"
1403 " Left-Button-Click - Set cursor position, clear selection.\n"
1404 "\n"
1405 " Left-Button-Double-Click - Select a word.\n"
1406 "\n"
1407 " Left-Button-Triple-Click - Select a row.\n"
1408 "\n"
1409 " Left-Button-Quad-Click - Select all.\n"
1410 "\n"
1411 " Left-Button-Drag - Select passed characters.\n"
1412 "\n"
1413 " Shift+Left-Button-Drag - Extend or reduce selection by passed characters.\n"
1414 "\n"
1415 " Ctrl+Left-Button-Click on non-selected area - Insert a copy of common selected\n"
1416 " text.\n"
1417 "\n"
1418 " Ctrl+Left-Button-Drag on selected area - Move selected text.\n"
1419 "\n"
1420 "\n"
1421 "Keyboard control:\n"
1422 "\n"
1423 " Normal key input inserts the corresponding character at the cursor position.\n"
1424 " Any selected text is replaced by the character. Special key combinations are:\n"
1425 "\n"
1426 " Cursor-Keys - Move the cursor.\n"
1427 "\n"
1428 " Ctrl+Cursor-Keys - Move the cursor by words or paragraphs.\n"
1429 "\n"
1430 " Home or End - Move the cursor to beginning or end of row.\n"
1431 "\n"
1432 " Ctrl+Home or Ctrl+End - Move the cursor to beginning or end of all.\n"
1433 "\n"
1434 " Shift+<Cursor Movement> - Select text: Hold the Shift key while moving the\n"
1435 " cursor with one of the above key combinations, to\n"
1436 " select the passed characters.\n"
1437 "\n"
1438 " Ctrl+A - Select the whole text.\n"
1439 "\n"
1440 " Insert - Switch between insert mode and replace mode.\n"
1441 "\n"
1442 " Backspace - Delete the selected text, or the character on the\n"
1443 " left side of the cursor.\n"
1444 "\n"
1445 " Delete - Delete the selected text, or the character on the\n"
1446 " right side of the cursor.\n"
1447 "\n"
1448 " Shift+Delete or Ctrl+X - Cut operation: Copy the selected text to the\n"
1449 " clipboard and delete it.\n"
1450 "\n"
1451 " Ctrl+Insert or Ctrl+C - Copy operation: Copy the selected text to the\n"
1452 " clipboard.\n"
1453 "\n"
1454 " Shift+Insert or Ctrl+V - Paste operation: Insert text from the clipboard. Any\n"
1455 " selected text is replaced by the insertion.\n"
1456 "\n"
1457 " Ctrl+Backspace - Delete to the left until beginning of a word.\n"
1458 "\n"
1459 " Ctrl+Delete - Delete to the right until beginning of a word.\n"
1460 "\n"
1461 " Shift+Ctrl+Backspace - Delete all on the left side of the cursor.\n"
1462 "\n"
1463 " Shift+Ctrl+Delete - Delete all on the right side of the cursor.\n"
1464 ;
1465
1466
1467 const char * emTextField::HowToMultiLineOff=
1468 "\n"
1469 "\n"
1470 "MULTI-LINE: DISABLED\n"
1471 "\n"
1472 "This text field has the multi-line mode disabled. You can view or edit only\n"
1473 "a single line.\n"
1474 ;
1475
1476
1477 const char * emTextField::HowToMultiLineOn=
1478 "\n"
1479 "\n"
1480 "MULTI-LINE: ENABLED\n"
1481 "\n"
1482 "This text field has the multi-line mode enabled. You may view or edit multiple\n"
1483 "lines.\n"
1484 ;
1485
1486
1487 const char * emTextField::HowToReadOnly=
1488 "\n"
1489 "\n"
1490 "READ-ONLY\n"
1491 "\n"
1492 "This text field is read-only. You cannot edit the text.\n"
1493 ;
1494