1 /*
2    Copyright (c) by Valery Goryachev (Wal)
3 */
4 
5 #include "swl.h"
6 
7 #include <algorithm>
8 
9 namespace wal
10 {
11 
12 /////////////////////////////////////////////////   EditBuf
13 
SetSize(int n)14 	void EditBuf::SetSize( int n )
15 	{
16 		if ( size >= n ) { return; }
17 
18 		n = ( ( n + STEP - 1 ) / STEP ) * STEP;
19 
20 		std::vector<unicode_t> p( n );
21 
22 		if ( count > 0 )
23 		{
24 			memcpy( p.data(), data.data(), count * sizeof( unicode_t ) );
25 		}
26 
27 		size = n;
28 		data = p;
29 	}
30 
InsertBlock(int pos,int n)31 	void EditBuf::InsertBlock( int pos, int n )
32 	{
33 		ASSERT( pos >= 0 && pos <= count && n > 0 );
34 		SetSize( count + n );
35 
36 		if ( pos < count )
37 		{
38 			memmove( data.data() + pos + n, data.data() + pos, ( count - pos ) * sizeof( unicode_t ) );
39 		}
40 
41 		count += n;
42 	}
43 
DeleteBlock(int pos,int n)44 	void EditBuf::DeleteBlock( int pos, int n )
45 	{
46 		ASSERT( pos >= 0 && pos < count && n > 0 );
47 
48 		if ( pos + n > count )
49 		{
50 			n = count - pos;
51 		}
52 
53 		if ( pos + n < count )
54 		{
55 			memmove( data.data() + pos, data.data() + pos + n, ( count - ( pos + n ) ) * sizeof( unicode_t ) );
56 		}
57 
58 		count -= n;
59 	}
60 
DelMarked()61 	bool EditBuf::DelMarked()
62 	{
63 		if ( cursor == marker ) { return false; }
64 
65 		int a, b;
66 
67 		if ( cursor < marker ) { a = cursor; b = marker; }
68 		else { a = marker; b = cursor; }
69 
70 		int n = b - a;
71 		DeleteBlock( a, n );
72 		cursor = marker = a;
73 		return true;
74 	}
75 
Insert(unicode_t t)76 	void EditBuf::Insert( unicode_t t )
77 	{
78 		DelMarked();
79 		InsertBlock( cursor, 1 );
80 		data[cursor] = t;
81 		cursor++;
82 		marker = cursor;
83 	}
84 
Insert(const unicode_t * txt)85 	void EditBuf::Insert( const unicode_t* txt )
86 	{
87 		DelMarked();
88 
89 		if ( !txt || !*txt ) { return; }
90 
91 		int n = unicode_strlen( txt );
92 		InsertBlock( cursor, n );
93 
94 		for ( ; *txt; txt++, cursor++ )
95 		{
96 			data[cursor] = *txt;
97 		}
98 
99 		marker = cursor;
100 	}
101 
Del(bool DeleteWord)102 	void EditBuf::Del( bool DeleteWord )
103 	{
104 		if ( DelMarked() ) { return; }
105 
106 		if ( DeleteWord )
107 		{
108 			int PrevCursor = cursor;
109 
110 			int group = cursor < count ? EditBuf::GetCharGroup( data[cursor] ) : -1;
111 
112 			int CharsToDelete = 0;
113 
114 			while ( cursor < count && EditBuf::GetCharGroup( data[cursor] ) == group )
115 			{
116 				cursor++;
117 				CharsToDelete++;
118 			}
119 
120 			cursor = PrevCursor;
121 
122 			CharsToDelete = std::min( CharsToDelete, count - cursor );
123 
124 			if ( CharsToDelete > 0 ) { DeleteBlock( cursor, CharsToDelete ); }
125 		}
126 		else if ( cursor < count )
127 		{
128 			DeleteBlock( cursor, 1 );
129 		}
130 	}
131 
Backspace(bool DeleteWord)132 	void EditBuf::Backspace( bool DeleteWord )
133 	{
134 		if ( DelMarked() ) { return; }
135 
136 		int CharsToDelete = 1;
137 
138 		if ( DeleteWord )
139 		{
140 			int PrevCursor = cursor;
141 
142 			if ( cursor > 0 ) { cursor--; }
143 
144 			int group = cursor < count ? EditBuf::GetCharGroup( data[cursor] ) : -1;
145 
146 			while ( cursor > 0 && EditBuf::GetCharGroup( data[cursor - 1] ) == group )
147 			{
148 				cursor--;
149 			}
150 
151 			CharsToDelete = PrevCursor - cursor;
152 		}
153 		else if ( cursor > 0 )
154 		{
155 			cursor--;
156 		}
157 
158 		marker = cursor;
159 		DeleteBlock( cursor, CharsToDelete );
160 	}
161 
Set(const unicode_t * s,bool mark)162 	void EditBuf::Set( const unicode_t* s, bool mark )
163 	{
164 		marker = cursor = count = 0;
165 
166 		if ( !s || !*s ) { return; }
167 
168 		int n = unicode_strlen( s );
169 		SetSize( n );
170 		memcpy( data.data(), s, n * sizeof( unicode_t ) );
171 		cursor = count = n;
172 		marker = mark ? 0 : cursor;
173 	}
174 
CtrlLeft(bool mark)175 	void EditBuf::CtrlLeft  ( bool mark )
176 	{
177 		if ( cursor > 0 ) { cursor--; }
178 
179 		int group = cursor < count ? EditBuf::GetCharGroup( data[cursor] ) : -1;
180 
181 		while ( cursor > 0 && EditBuf::GetCharGroup( data[cursor - 1] ) == group )
182 		{
183 			cursor--;
184 		}
185 
186 		if ( !mark ) { marker = cursor; }
187 	}
188 
CtrlRight(bool mark)189 	void EditBuf::CtrlRight ( bool mark )
190 	{
191 		int group = cursor < count ? EditBuf::GetCharGroup( data[cursor] ) : -1;
192 
193 //	if (cursor < count) cursor++;
194 
195 		while ( cursor < count )
196 		{
197 			int nextGroup = cursor + 1 < count ? EditBuf::GetCharGroup( data[cursor + 1] ) : -1;
198 			cursor++;
199 
200 			if ( nextGroup != group ) { break; }
201 		}
202 
203 		if ( !mark ) { marker = cursor; }
204 	}
205 
GetCharGroup(unicode_t c)206 	int EditBuf::GetCharGroup( unicode_t c )
207 	{
208 		if ( c <= ' ' || ( c >= 0x7F && c <= 0xA0 ) )
209 		{
210 			return 0;
211 		}
212 
213 //нада, все-таки, нормально юникод применить
214 		switch ( c )
215 		{
216 			case '!':
217 			case '"':
218 			case '#':
219 			case '$':
220 			case '%':
221 			case '&':
222 			case '\'':
223 			case '(':
224 			case ')':
225 			case '*':
226 			case '+':
227 			case ',':
228 			case '-':
229 			case '.':
230 			case ':':
231 			case ';':
232 			case '<':
233 			case '=':
234 			case '>':
235 			case '?':
236 			case '@':
237 			case '[':
238 			case '\\':
239 			case '/':
240 			case ']':
241 			case '^':
242 
243 //	case '_':
244 			case '`':
245 			case '{':
246 			case '|':
247 			case '}':
248 				return 1;
249 		};
250 
251 		return 100;
252 	}
253 
254 
255 /////////////////////////////////////////////////////////// EditLine
256 
257 	int uiClassEditLine = GetUiID( "EditLine" );
UiGetClassId()258 	int EditLine::UiGetClassId() { return uiClassEditLine; }
259 
OnChangeStyles()260 	void EditLine::OnChangeStyles()
261 	{
262 		GC gc( this );
263 		gc.Set( GetFont() );
264 
265 		cpoint ts = gc.GetTextExtents( ABCString );
266 		charW = ts.x / ABCStringLen;
267 		charH = ts.y;
268 
269 		int w = ( ts.x / ABCStringLen ) * _chars;
270 
271 		int h = ts.y + 2;
272 
273 		if ( frame3d )
274 		{
275 			w += 8;
276 			h += 8;
277 		}
278 
279 		LSize ls;
280 		ls.x.minimal = ls.x.ideal = w;
281 		ls.x.maximal = 16000;
282 		ls.y.minimal = ls.y.maximal = ls.y.ideal = h;
283 		SetLSize( ls );
284 	}
285 
EditLine(int nId,Win * parent,const crect * rect,const unicode_t * txt,int chars,bool frame,unsigned flags)286 	EditLine::EditLine( int nId, Win* parent, const crect* rect, const unicode_t* txt, int chars, bool frame, unsigned flags )
287 		: Win( Win::WT_CHILD, Win::WH_TABFOCUS | WH_CLICKFOCUS, parent, rect, nId )
288 		, _use_alt_symbols( false )
289 		, _flags( flags )
290 		, text( txt )
291 		, _chars( chars > 0 ? chars : 10 )
292 		, cursorVisible( false )
293 		, passwordMode( false )
294 		, showSpaces( true )
295 		, doAcceptAltKeys( false )
296 		, first( 0 )
297 		, frame3d( frame )
298 		, charH( 0 )
299 		, charW( 0 )
300 		, m_ReplaceMode( false )
301 	{
302 		text.End();
303 
304 		if ( !rect )
305 		{
306 			OnChangeStyles();
307 		}
308 	};
309 
310 	static unicode_t passwordSymbol = '*';
311 
DrawCursor(GC & gc)312 	void EditLine::DrawCursor( GC& gc )
313 	{
314 		int cursor = text.Cursor();
315 
316 		if ( cursor < first ) { return; }
317 
318 		crect cr = ClientRect();
319 
320 		if ( frame3d ) { cr.Dec( 4 ); }
321 
322 		int x = cr.left;
323 		int y = cr.bottom - charH / 5;
324 
325 		gc.Set( GetFont() );
326 
327 
328 		cpoint prevSize( 0, 0 );
329 
330 		if ( cursor > first )
331 		{
332 			if ( passwordMode )
333 			{
334 				prevSize = gc.GetTextExtents( &passwordSymbol, 1 );
335 				prevSize.x *= cursor - first;
336 			}
337 			else
338 			{
339 				prevSize = gc.GetTextExtents( text.Ptr() + first, cursor - first );
340 			}
341 		}
342 
343 		if ( prevSize.x >= cr.Width() ) { return; }
344 
345 		x += prevSize.x;
346 
347 		bool marked = text.Marked( cursor );
348 		unsigned bColor = /*GetColor(*/marked ? UiGetColor( uiMarkBackground, 0, 0, 0x800000 ) : UiGetColor( uiBackground, 0, 0, 0xFFFFFF ); //UiIC_EDIT_STEXT_BG : IC_EDIT_TEXT_BG);
349 		unsigned fColor = /*GetColor(*/marked ? UiGetColor( uiMarkColor, 0, 0, 0xFFFFFF ) : UiGetColor( uiColor, 0, 0, 0 ); //IC_EDIT_STEXT : IC_EDIT_TEXT);
350 
351 		cpoint csize( 0, 0 );
352 
353 		if ( cursor < text.Count() )
354 		{
355 			csize = gc.GetTextExtents( text.Ptr() + cursor, 1 );
356 		}
357 
358 		if ( csize.x < charW )
359 		{
360 			csize.x = charW;
361 		}
362 
363 		gc.SetFillColor( bColor );
364 		gc.FillRect( crect( x, y, x + csize.x, cr.bottom ) );
365 
366 		if ( cursor < text.Count() )
367 		{
368 			gc.SetTextColor( fColor );
369 			gc.TextOutF( x, cr.top + ( cr.Height() - csize.y ) / 2 , text.Ptr() + cursor, 1 );
370 		}
371 
372 		if ( cursorVisible )
373 		{
374 			gc.SetFillColor( fColor );
375 			gc.FillRect( crect( x, y, x + charW, cr.bottom ) );
376 		}
377 	}
378 
CheckCursorPos()379 	bool EditLine::CheckCursorPos()
380 	{
381 		int cursor = text.Cursor();
382 
383 		if ( first == cursor ) { return false; }
384 
385 		int oldFirst = first;
386 
387 		if ( cursor < first )
388 		{
389 			first = cursor - 8;
390 
391 			if ( first < 0 ) { first = 0; }
392 		}
393 
394 		if ( first == cursor ) { return oldFirst != first; }
395 
396 		crect cr = ClientRect();
397 
398 		if ( frame3d ) { cr.Dec( 4 ); }
399 
400 		GC gc( this );
401 		gc.Set( GetFont() );
402 
403 		if ( passwordMode )
404 		{
405 			cpoint size = gc.GetTextExtents( &passwordSymbol, 1 );
406 			int n = cursor - first;
407 			int m = size.x != 0 ? cr.Width() / size.x : 0;
408 
409 			if ( n >= m )
410 			{
411 				if ( m > 0 ) { m--; }
412 
413 				first = cursor - m;
414 			}
415 		}
416 		else
417 		{
418 			cpoint size = gc.GetTextExtents( text.Ptr() + first, cursor - first );
419 
420 //temp (not optimized)
421 			for ( ; size.x >= cr.Width() && first < cursor; first++ )
422 			{
423 				size = gc.GetTextExtents( text.Ptr() + first, cursor - first );
424 			}
425 		}
426 
427 		return oldFirst != first;
428 	}
429 
GetText() const430 	std::vector<unicode_t> EditLine::GetText() const
431 	{
432 		int count = text.Count();
433 		std::vector<unicode_t> p( count + 1 );
434 
435 		if ( count > 0 ) { memcpy( p.data(), text.Ptr(), sizeof( unicode_t )*count ); }
436 
437 		p[count] = 0;
438 		return p;
439 	}
440 
GetTextStr() const441 	std::string EditLine::GetTextStr() const
442 	{
443 		std::vector<unicode_t> V = GetText();
444 
445 		return unicode_to_utf8_string( V.data() );
446 	}
447 
EventSize(cevent_size * pEvent)448 	void EditLine::EventSize( cevent_size* pEvent )
449 	{
450 		first = 0;
451 		CheckCursorPos();
452 		Invalidate();
453 	}
454 
EventTimer(int tid)455 	void EditLine::EventTimer( int tid )
456 	{
457 		cursorVisible = !cursorVisible;
458 		wal::GC gc( this );
459 		DrawCursor( gc );
460 	}
461 
EventFocus(bool recv)462 	bool EditLine::EventFocus( bool recv )
463 	{
464 		if ( !IsReadOnly() )
465 		{
466 			cursorVisible = recv;
467 
468 			if ( recv )
469 			{
470 				SetTimer( 1, 500 );
471 			}
472 			else
473 			{
474 				DelTimer( 1 );
475 			}
476 		}
477 
478 		Invalidate();
479 		return true;
480 	}
481 
InFocus()482 	bool EditLine::InFocus()
483 	{
484 		if ( UseParentFocus() )
485 		{
486 			return Parent()->InFocus();
487 		}
488 
489 		return Win::InFocus();
490 	}
491 
SetFocus()492 	void EditLine::SetFocus()
493 	{
494 		if ( UseParentFocus() )
495 		{
496 			Parent()->SetFocus();
497 			return;
498 		}
499 
500 		Win::SetFocus();
501 	}
502 
Paint(GC & gc,const crect & paintRect)503 	void EditLine::Paint( GC& gc, const crect& paintRect )
504 	{
505 		crect cr = ClientRect();
506 		crect rect = cr;
507 
508 		unsigned frameColor = UiGetColor( uiFrameColor, 0, 0, 0xFFFFFF );
509 
510 		if ( frame3d )
511 		{
512 			DrawBorder( gc, rect, ColorTone( frameColor, +20 ) );
513 			rect.Dec();
514 			Draw3DButtonW2( gc, rect, frameColor, false );
515 			rect.Dec();
516 			rect.Dec();
517 			DrawBorder( gc, rect, ColorTone( frameColor, IsEnabled() ? -200 : -80 ) );
518 			rect.Dec();
519 		}
520 
521 		unsigned colorBg = UiGetColor( uiBackground, 0, 0, 0xFFFFFF );
522 
523 		int x = rect.left;
524 
525 		gc.SetClipRgn( &rect );
526 
527 		if ( first < text.Count() )
528 		{
529 			gc.Set( GetFont() );
530 
531 			int cH = gc.GetTextExtents( text.Ptr() + first, 1 ).y;
532 			int y = cr.top + ( cr.Height() - cH ) / 2;
533 
534 			int cnt = text.Count() - first;
535 			int i = first;
536 
537 			std::vector<unicode_t> pwTextArray;
538 			unicode_t* pwText = 0;
539 
540 			if ( passwordMode && cnt > 0 )
541 			{
542 				pwTextArray.resize( cnt );
543 
544 				for ( int i = 0; i < cnt; i++ ) { pwTextArray[i] = passwordSymbol; }
545 
546 				pwText = pwTextArray.data();
547 			}
548 
549 			int color = UiGetColor( uiColor, 0, 0, 0 );
550 			int background = UiGetColor( uiBackground, 0, 0, 0xFFFFFF );
551 
552 			int mark_color = UiGetColor( uiMarkColor, 0, 0, 0xFFFFFF );
553 			int mark_background = UiGetColor( uiMarkBackground, 0, 0, 0 );
554 
555 			while ( cnt > 0 )
556 			{
557 				bool mark = text.Marked( i );
558 
559 				int j;
560 
561 				for ( j = i + 1; j < text.Count() && text.Marked( j ) == mark; ) { j++; }
562 
563 				int n = j - i;
564 				cpoint size = gc.GetTextExtents( passwordMode ? pwText : ( text.Ptr() + i ), n );
565 
566 				gc.SetFillColor( mark ? mark_background : background ); //GetColor(InFocus() && mark ? IC_EDIT_STEXT_BG : IC_EDIT_TEXT_BG));
567 				gc.FillRect( crect( x, cr.top, x + size.x, cr.bottom ) );
568 				gc.SetTextColor( mark ? mark_color : color ); //GetColor(InFocus() &&  mark ? IC_EDIT_STEXT : (IsEnabled() ? IC_EDIT_TEXT : IC_GRAY_TEXT)));
569 
570 				std::vector<unicode_t> VisibleText = new_unicode_str( passwordMode ? pwText : ( text.Ptr() + i ) );
571 
572 				// https://github.com/corporateshark/WCMCommander/issues/187
573 				if ( showSpaces )
574 				{
575 					ReplaceSpaces( &VisibleText );
576 				}
577 
578 				gc.TextOutF( x, y, VisibleText.data(), n );
579 				cnt -= n;
580 				x += size.x;
581 				i += n;
582 			}
583 		}
584 
585 		if ( x < cr.right )
586 		{
587 			gc.SetFillColor( colorBg ); //GetColor(IC_EDIT_TEXT_BG));
588 			cr.left = x;
589 			gc.FillRect( cr );
590 		}
591 
592 
593 		if ( InFocus() && !IsReadOnly() )
594 		{
595 			DrawCursor( gc );
596 		}
597 
598 		return;
599 	}
600 
EventMouse(cevent_mouse * pEvent)601 	bool EditLine::EventMouse( cevent_mouse* pEvent )
602 	{
603 		switch ( pEvent->Type() )
604 		{
605 			case EV_MOUSE_MOVE:
606 				if ( IsCaptured() )
607 				{
608 					int n = GetCharPos( pEvent->Point() );
609 					text.SetCursor( first + n, true );
610 					cursorVisible = true;
611 					CheckCursorPos();
612 					Invalidate();
613 					return true;
614 				}
615 
616 				break;
617 
618 			case EV_MOUSE_DOUBLE:
619 			case EV_MOUSE_PRESS:
620 			{
621 				if ( pEvent->Button() != MB_L )
622 				{
623 					break;
624 				}
625 
626 				int n = GetCharPos( pEvent->Point() );
627 				text.SetCursor( first + n );
628 				cursorVisible = true;
629 				CheckCursorPos();
630 				Invalidate();
631 
632 				SetCapture( &captureSD );
633 				return true;
634 			}
635 			break;
636 
637 			case EV_MOUSE_RELEASE:
638 				if ( pEvent->Button() != MB_L )
639 				{
640 					break;
641 				}
642 
643 				ReleaseCapture( &captureSD );
644 				return true;
645 		};
646 
647 		return Win::EventMouse( pEvent );
648 	}
649 
EventKey(cevent_key * pEvent)650 	bool EditLine::EventKey( cevent_key* pEvent )
651 	{
652 		if ( !doAcceptAltKeys && ( pEvent->Mod() & KM_ALT ) != 0 )
653 		{
654 			return false;
655 		}
656 
657 		if ( pEvent->Type() == EV_KEYDOWN )
658 		{
659 
660 			bool shift = ( pEvent->Mod() & KM_SHIFT ) != 0;
661 			bool ctrl  = ( pEvent->Mod() & KM_CTRL ) != 0;
662 			bool alt   = ( pEvent->Mod() & KM_ALT ) != 0;
663 
664 			if ( ctrl )
665 			{
666 				switch ( pEvent->Key() )
667 				{
668 					case VK_A:
669 						text.Begin( false );
670 						text.End( true );
671 						CheckCursorPos();
672 						Invalidate();
673 						return true;
674 
675 					case VK_C:
676 						ClipboardCopy();
677 						return true;
678 
679 					case VK_V:
680 						if ( !IsReadOnly() )
681 						{
682 							ClipboardPaste();
683 						}
684 
685 						return true;
686 
687 					case VK_X:
688 						if ( !IsReadOnly() )
689 						{
690 							ClipboardCut();
691 						}
692 
693 						return true;
694 				}
695 			}
696 
697 			switch ( pEvent->Key() )
698 			{
699 				case VK_BACK:
700 				{
701 					if ( IsReadOnly() || text.Cursor() == 0 )
702 					{
703 						return true;
704 					}
705 
706 					text.Backspace( ctrl );
707 					SendCommand( SCMD_EDITLINE_DELETED );
708 					Changed();
709 				}
710 				break;
711 
712 				case VK_DELETE:
713 				{
714 					if ( IsReadOnly() || text.Cursor() > text.Count() )
715 					{
716 						return true;
717 					}
718 
719 					text.Del( ctrl );
720 					SendCommand( SCMD_EDITLINE_DELETED );
721 					Changed();
722 				}
723 				break;
724 
725 				case VK_LEFT:
726 				{
727 					if ( text.Marked() == shift && text.Cursor() == 0 )
728 					{
729 						return true;
730 					}
731 
732 					if ( ctrl )
733 					{
734 						text.CtrlLeft( shift );
735 					}
736 					else
737 					{
738 						text.Left( shift );
739 					}
740 				};
741 
742 				break;
743 
744 				case VK_RIGHT:
745 				{
746 					if ( text.Marked() == shift && text.Cursor() == text.Count() )
747 					{
748 						return true;
749 					}
750 
751 					if ( ctrl )
752 					{
753 						text.CtrlRight( shift );
754 					}
755 					else
756 					{
757 						text.Right( shift );
758 					}
759 				};
760 
761 				break;
762 
763 				case VK_HOME:
764 				{
765 					if ( text.Marked() == shift && text.Cursor() == 0 )
766 					{
767 						return true;
768 					}
769 
770 					text.Begin( shift );
771 				}
772 				break;
773 
774 				case VK_END:
775 				{
776 					if ( text.Marked() == shift && text.Cursor() == text.Count() )
777 					{
778 						return true;
779 					}
780 
781 					text.End( shift );
782 				}
783 				break;
784 
785 				case VK_INSERT:
786 					if ( shift )
787 					{
788 						if ( IsReadOnly() )
789 						{
790 							return true;
791 						}
792 
793 						ClipboardPaste();
794 					}
795 					else if ( ctrl && text.Marked() )
796 					{
797 						ClipboardCopy();
798 					}
799 
800 					break;
801 
802 				default:
803 					wchar_t c = pEvent->Char();
804 					std::vector<unicode_t> oldtext = GetText();
805 
806 					if ( c && c >= 0x20 && ( !alt || _use_alt_symbols ) )
807 					{
808 						if ( IsReadOnly() )
809 						{
810 							return true;
811 						}
812 
813 						if ( m_ReplaceMode )
814 						{
815 							text.Del( false );
816 						}
817 
818 						text.Insert( c );
819 
820 						if ( m_Validator && !m_Validator->IsValid( GetText() ) )
821 						{
822 							SetText( oldtext.data(), false );
823 						}
824 
825 						SendCommand( SCMD_EDITLINE_INSERTED );
826 						Changed();
827 					}
828 					else
829 					{
830 						return false;
831 					}
832 
833 					break;
834 			}
835 
836 			cursorVisible = true;
837 			CheckCursorPos();
838 			Invalidate();
839 			return true;
840 		}
841 
842 		return Win::EventKey( pEvent );
843 	}
844 
ClipboardCopy()845 	void EditLine::ClipboardCopy()
846 	{
847 		ClipboardText ctx;
848 		int a = text.Cursor();
849 		int b = text.Marker();
850 
851 		if ( a > b ) { int t = a; a = b; b = t; }
852 
853 		for ( int i = a; i < b; i++ ) { ctx.Append( text[i] ); }
854 
855 		ClipboardSetText( this, ctx );
856 	}
857 
858 
ClipboardPaste()859 	void EditLine::ClipboardPaste()
860 	{
861 		ClipboardText ctx;
862 		ClipboardGetText( this, &ctx );
863 		int count = ctx.Count();
864 
865 		if ( count <= 0 ) { return; }
866 
867 		for ( int i = 0; i < count; i++ )
868 		{
869 			unicode_t c = ctx[i];
870 
871 			if ( c == 9 || c == 10 || c == 13 ) { c = ' '; }
872 
873 			if ( c < 32 ) { break; }
874 
875 			text.Insert( c );
876 		}
877 
878 		CheckCursorPos();
879 		Changed();
880 		Invalidate();
881 	}
882 
ClipboardCut()883 	void EditLine::ClipboardCut()
884 	{
885 		if ( text.Marked() )
886 		{
887 			ClipboardCopy();
888 			text.Del( false );
889 			CheckCursorPos();
890 			Invalidate();
891 		}
892 	}
893 
Clear()894 	void EditLine::Clear()
895 	{
896 		first = 0;
897 		text.Clear();
898 		Invalidate();
899 	}
900 
SetText(const unicode_t * txt,bool mark)901 	void EditLine::SetText( const unicode_t* txt, bool mark )
902 	{
903 		first = 0;
904 		cursorVisible = true;
905 		text.Set( txt, mark );
906 		Invalidate();
907 	}
908 
SetText(const std::string & utf8txt,bool mark)909 	void EditLine::SetText( const std::string& utf8txt, bool mark )
910 	{
911 		SetText( utf8str_to_unicode(utf8txt).data(), mark );
912 	}
913 
Insert(unicode_t t)914 	void EditLine::Insert( unicode_t t )
915 	{
916 		cursorVisible = true;
917 		text.Insert( t );
918 		CheckCursorPos();
919 		Invalidate();
920 	}
921 
Insert(const unicode_t * txt)922 	void EditLine::Insert( const unicode_t* txt )
923 	{
924 		cursorVisible = true;
925 		text.Insert( txt );
926 		Invalidate();
927 	}
928 
GetCharPos(cpoint p)929 	int EditLine::GetCharPos( cpoint p )
930 	{
931 		if ( !text.Count() ) { return 0; }
932 
933 		crect cr = ClientRect();
934 
935 		if ( frame3d ) { cr.Dec( 4 ); }
936 
937 		if ( p.x < cr.left ) { return -1; }
938 
939 		GC gc( this );
940 		gc.Set( GetFont() );
941 		int n = text.Count() - first;
942 
943 		for ( int i = 0; i < n; i++ )
944 		{
945 			cpoint size = gc.GetTextExtents( text.Ptr() + first + i, i + 1 );
946 
947 			if ( cr.left + size.x > p.x ) { return i; }
948 		}
949 
950 		return text.Count();
951 	}
952 
~EditLine()953 	EditLine::~EditLine() {}
954 
955 
956 }; // namespace wal
957