1 /*
2  * Part of WCM Commander
3  * https://github.com/corporateshark/WCMCommander
4  * wcm@linderdaum.com
5  */
6 
7 #if !defined( NOMINMAX )
8 #define NOMINMAX
9 #endif
10 
11 #include "globals.h"
12 #include "nc.h"
13 #include "ncedit.h"
14 #include "ncwin.h"
15 #include "wcm-config.h"
16 #include "color-style.h"
17 #include "string-util.h"
18 #include "charsetdlg.h"
19 #include "ltext.h"
20 #include "globals.h"
21 #include "unicode_lc.h"
22 
23 #include <algorithm>
24 
25 int uiClassEditor = GetUiID( "Editor" );
26 static int uiShlDEF  = GetUiID( "DEF" );
27 static int uiShlKEYWORD = GetUiID( "KEYWORD" );
28 static int uiShlCOMMENT = GetUiID( "COMMENT" );
29 static int uiShlSTRING  = GetUiID( "STRING" );
30 static int uiShlPRE  = GetUiID( "PRE" );
31 static int uiShlNUM  = GetUiID( "NUM" );
32 static int uiShlOPER    = GetUiID( "OPER" );
33 static int uiShlATTN    = GetUiID( "ATTN" );
34 static int uiShl  = GetUiID( "shl" );
35 static int uiColorCtrl  = GetUiID( "ctrl-color" );
36 static int uiColorCursor = GetUiID( "cursor-color" );
37 
38 
OnChangeStyles()39 void EditWin::OnChangeStyles()
40 {
41 	shlDEF      = UiGetColor( uiShlDEF,     uiShl, 0, 0x000000 );
42 	shlKEYWORD  = UiGetColor( uiShlKEYWORD, uiShl, 0, 0x00FFFF );
43 	shlCOMMENT  = UiGetColor( uiShlCOMMENT, uiShl, 0, 0x808080 );
44 	shlSTRING   = UiGetColor( uiShlSTRING,  uiShl, 0, 0xFFFF00 );
45 	shlPRE      = UiGetColor( uiShlPRE,     uiShl, 0, 0xFF00FF );
46 	shlNUM      = UiGetColor( uiShlNUM,     uiShl, 0, 0xFFFFFF );
47 	shlOPER  = UiGetColor( uiShlOPER,    uiShl, 0, 0xFF80FF );
48 	shlATTN     = UiGetColor( uiShlATTN,    uiShl, 0, 0x0000FF );
49 	color_text  = UiGetColor( uiColor, 0, 0, 0 );
50 	color_background = UiGetColor( uiBackground, 0, 0, 0xFFFFFF );
51 	color_mark_text   = UiGetColor( uiMarkColor, 0, 0, 0 );
52 	color_mark_background = UiGetColor( uiMarkBackground, 0, 0, 0xFFFFFF );
53 	color_ctrl  = UiGetColor( uiColorCtrl, 0, 0, 0xFF0000 );
54 	color_cursor   = UiGetColor( uiColorCursor, 0, 0, 0x00FFFF );
55 
56 	wal::GC gc( this );
57 	gc.Set( GetFont() );
58 	cpoint p = gc.GetTextExtents( ABCString );
59 	charW = p.x / ABCStringLen;
60 	charH = p.y;
61 
62 	if ( !charW ) { charW = 10; }
63 
64 	if ( !charH ) { charH = 10; }
65 
66 //как в EventSize !!!
67 	rows = editRect.Height() / charH;
68 	cols = editRect.Width() / charW;
69 
70 	if ( rows <= 0 ) { rows = 1; }
71 
72 	if ( cols <= 0 ) { cols = 1; }
73 
74 	CalcScroll();
75 
76 	{
77 		int r = ( editRect.Height() + charH - 1 ) / charH;
78 		int c = ( editRect.Width() + charW - 1 ) / charW;
79 
80 		if ( r < 1 ) { r = 1; }
81 
82 		if ( c < 1 ) { c = 1; }
83 
84 		screen.Alloc( r, c );
85 		__RefreshScreenData();
86 		Invalidate();
87 	}
88 
89 }
90 
EditWin(Win * parent)91 EditWin::EditWin( Win* parent )
92 	:   Win( WT_CHILD, 0, parent ),
93 	    _lo( 2, 2 ),
94 	    charset( charset_table[GetFirstOperCharsetId()] ), //EditCSLatin1),
95 	    vscroll( 0, this, true, false ),
96 	    tabSize( g_WcmConfig.editTabSize ),
97 	    autoIdent( g_WcmConfig.editAutoIdent ),
98 	    firstLine( 0 ),
99 	    colOffset( 0 ),
100 	    rows( 0 ),
101 	    cols( 0 ),
102 	    charH( 1 ),
103 	    charW( 1 ),
104 	    recomendedCursorCol( -1 ),
105 
106 	    _shl( 0 ),
107 	    _shlLine( -1 ),
108 
109 	    _changed( false )
110 {
111 	vscroll.Enable();
112 	vscroll.Show();
113 	vscroll.SetManagedWin( this );
114 	_lo.AddWin( &vscroll, 0, 1 );
115 	_lo.AddRect( &editRect, 0, 0 );
116 	_lo.SetColGrowth( 0 );
117 	SetLayout( &_lo );
118 	LSRange lr( 0, 10000, 1000 );
119 	LSize ls;
120 	ls.x = ls.y = lr;
121 	SetLSize( ls );
122 
123 	OnChangeStyles();
124 
125 	SetTimer( 0, 500 );
126 }
127 
UiGetClassId()128 int EditWin::UiGetClassId() { return uiClassEditor; }
129 
CursorToScreen()130 void  EditWin::CursorToScreen()
131 {
132 	int f = firstLine;
133 
134 	if ( cursor.line >= firstLine + rows )
135 	{
136 		firstLine = cursor.line - rows + 1;
137 	}
138 
139 	if ( cursor.line < firstLine )
140 	{
141 		firstLine = cursor.line;
142 	}
143 
144 	if ( f != firstLine )
145 	{
146 		CalcScroll();
147 	}
148 
149 	int c = GetCursorCol();
150 	int n = cols > 4 ? cols / 4 : 1;
151 
152 	if ( colOffset + cols <= c )
153 	{
154 		colOffset = c + n - cols;
155 
156 		if ( colOffset > c ) { colOffset = c; }
157 	}
158 
159 	if ( c < colOffset ) { colOffset = c - n; }
160 
161 	if ( colOffset < 0 ) { colOffset = 0; }
162 }
163 
CursorToScreen_forReplace()164 void  EditWin::CursorToScreen_forReplace()
165 {
166 	int f = firstLine;
167 	firstLine = cursor.line - 2;
168 
169 	if ( firstLine < 0 ) { firstLine = 0; }
170 
171 	int c = GetCursorCol();
172 	colOffset = ( c < cols ) ? 0 : c - cols;
173 
174 	if ( f != firstLine )
175 	{
176 		CalcScroll();
177 	}
178 }
179 
180 
181 
CursorLeft(bool mark)182 void EditWin::CursorLeft( bool mark )
183 {
184 	ASSERT( cursor.line >= 0 && cursor.line < text.Count() );
185 	ASSERT( cursor.pos >= 0 && cursor.pos <= text.Get( cursor.line ).Len() );
186 
187 	recomendedCursorCol = -1;
188 	char* t = charset->GetPrev( text.Get( cursor.line ).Get() + cursor.pos, text.Get( cursor.line ).Get() );
189 
190 	bool refresh = false;
191 
192 	if ( t )
193 	{
194 		cursor.pos = t - text.Get( cursor.line ).Get();
195 		refresh = true;
196 		SendChanges();
197 	}
198 	else
199 	{
200 		if ( cursor.line > 0 )
201 		{
202 			cursor.line--;
203 			cursor.pos = text.Get( cursor.line ).Len();
204 			refresh = true;
205 			SendChanges();
206 		}
207 	}
208 
209 	CursorToScreen();
210 
211 	if ( !mark ) { marker = cursor; }
212 
213 	if ( refresh ) { Refresh(); }
214 }
215 
SetCursorPos(EditPoint p)216 void EditWin::SetCursorPos( EditPoint p )
217 {
218 	if ( p.line >= text.Count() ) { p.line = text.Count() - 1; p.pos = 0; }
219 
220 	if ( p.line < 0 ) { p.line = 0; p.pos = 0; }
221 
222 	int l = text.Get( p.line ).Len();
223 
224 	if ( p.pos > l ) { p.pos = l; }
225 
226 	if ( p.pos < 0 ) { p.pos = 0; }
227 
228 	marker = cursor = p;
229 
230 	CursorToScreen();
231 	SendChanges();
232 	Refresh();
233 }
234 
CursorHome(bool mark)235 void EditWin::CursorHome( bool mark )
236 {
237 	recomendedCursorCol = -1;
238 
239 	if ( cursor.pos > 0 )
240 	{
241 		cursor.pos = 0;
242 	}
243 
244 	CursorToScreen();
245 	SendChanges();
246 
247 	if ( !mark ) { marker = cursor; }
248 
249 	Refresh();
250 }
251 
CursorEnd(bool mark)252 void EditWin::CursorEnd( bool mark )
253 {
254 	recomendedCursorCol = -1;
255 	ASSERT( cursor.line >= 0 && cursor.line < text.Count() );
256 
257 	if ( cursor.pos < text.Get( cursor.line ).Len() )
258 	{
259 		cursor.pos = text.Get( cursor.line ).Len();
260 	}
261 
262 	CursorToScreen();
263 	SendChanges();
264 
265 	if ( !mark ) { marker = cursor; }
266 
267 	Refresh();
268 }
269 
CursorRight(bool mark)270 void EditWin::CursorRight( bool mark )
271 {
272 	recomendedCursorCol = -1;
273 	ASSERT( cursor.line >= 0 && cursor.line < text.Count() );
274 
275 	if ( cursor.pos >= text.Get( cursor.line ).Len() )
276 	{
277 		if ( cursor.line + 1 < text.Count() )
278 		{
279 			cursor.line++;
280 			cursor.pos = 0;
281 			CursorToScreen();
282 			SendChanges();
283 
284 			if ( !mark ) { marker = cursor; }
285 
286 			Refresh();
287 		}
288 
289 		return;
290 	}
291 
292 	//bool tab;
293 	char* s = text.Get( cursor.line ).Get() + cursor.pos;
294 	char* end = text.Get( cursor.line ).Get() + text.Get( cursor.line ).Len();
295 	char* t = charset->GetNext( s, end );
296 	cursor.pos = t ? ( t - text.Get( cursor.line ).Get() ) : text.Get( cursor.line ).Len();
297 	CursorToScreen();
298 	SendChanges();
299 
300 	if ( !mark ) { marker = cursor; }
301 
302 	Refresh();
303 }
304 
305 
CursorDown(bool mark)306 void EditWin::CursorDown( bool mark )
307 {
308 	if ( cursor.line + 1 < text.Count() )
309 	{
310 		if ( recomendedCursorCol < 0 )
311 		{
312 			recomendedCursorCol = GetColFromPos( cursor.line, cursor.pos );
313 		}
314 
315 		cursor.pos = GetPosFromCol( cursor.line + 1, recomendedCursorCol );
316 		cursor.line++;
317 		CursorToScreen();
318 		SendChanges();
319 
320 		if ( !mark ) { marker = cursor; }
321 
322 		Refresh();
323 	}
324 }
325 
CursorUp(bool mark)326 void EditWin::CursorUp( bool mark )
327 {
328 	if ( cursor.line > 0 )
329 	{
330 		if ( recomendedCursorCol < 0 )
331 		{
332 			recomendedCursorCol = GetColFromPos( cursor.line, cursor.pos );
333 		}
334 
335 		cursor.pos = GetPosFromCol( cursor.line - 1, recomendedCursorCol );
336 		cursor.line--;
337 		CursorToScreen();
338 		SendChanges();
339 
340 		if ( !mark ) { marker = cursor; }
341 
342 		Refresh();
343 	}
344 }
345 
StepLeft(EditPoint * p,unicode_t * c)346 bool EditWin::StepLeft( EditPoint* p, unicode_t* c )
347 {
348 	if ( p->line < 0 || p->line >= text.Count() ) { return false; }
349 
350 	if ( p->pos < 0 || p->pos > text.Get( p->line ).Len() ) { return false; }
351 
352 	EditString& str = text.Get( p->line );
353 	char* t = charset->GetPrev( str.Get() + p->pos, str.Get() );
354 
355 	if ( t )
356 	{
357 		p->pos = t - text.Get( p->line ).Get();
358 		*c = charset->GetChar( t, str.Get() + str.Len() );
359 		return true;
360 	}
361 
362 	if ( p->line <= 0 ) { return false; }
363 
364 	p->line--;
365 	p->pos = text.Get( p->line ).Len();
366 	*c = ' ';
367 	return true;
368 }
369 
StepRight(EditPoint * p,unicode_t * c)370 bool EditWin::StepRight( EditPoint* p, unicode_t* c )
371 {
372 	if ( p->line < 0 || p->line >= text.Count() ) { return false; }
373 
374 	if ( p->pos < 0 ) { return false; }
375 
376 
377 	if ( p->pos >= text.Get( p->line ).Len() )
378 	{
379 		if ( p->line + 1 >= text.Count() ) { return false; }
380 
381 		p->line++;
382 		p->pos = 0;
383 	}
384 	else
385 	{
386 		char* begin = text.Get( p->line ).Get();
387 		int len = text.Get( p->line ).Len();
388 		char* s = begin + p->pos;
389 		char* end = begin + len;
390 		char* t = charset->GetNext( s, end );
391 		p->pos = t ? ( t - begin ) : len;
392 	}
393 
394 	EditString& str = text.Get( p->line );
395 	*c = str.Len() > p->pos ? charset->GetChar( str.Get() + p->pos, str.Get() + str.Len() ) : ' ';
396 	return true;
397 }
398 
CursorCtrlLeft(bool mark)399 void EditWin::CursorCtrlLeft( bool mark )
400 {
401 	EditPoint p = cursor;
402 	unicode_t c;
403 
404 	if ( !StepLeft( &p, &c ) ) { return; }
405 
406 	int group = EditBuf::GetCharGroup( c );
407 	cursor = p;
408 
409 	while ( StepLeft( &p, &c ) && EditBuf::GetCharGroup( c ) == group )
410 	{
411 		if ( cursor.pos > 0 )
412 		{
413 			cursor = p;
414 		}
415 		else
416 		{
417 			cursor.pos = 0;
418 		}
419 	}
420 
421 	recomendedCursorCol = -1;
422 	SendChanges();
423 	CursorToScreen();
424 
425 	if ( !mark ) { marker = cursor; }
426 
427 	Refresh();
428 }
429 
CursorCtrlRight(bool mark)430 void EditWin::CursorCtrlRight( bool mark )
431 {
432 	EditPoint p = cursor;
433 
434 	if ( p.line < 0 || p.line >= text.Count() ) { return; }
435 
436 	if ( p.pos < 0 || p.pos > text.Get( p.line ).Len() ) { return; }
437 
438 	EditString& str = text.Get( p.line );
439 	unicode_t c = str.Len() > 0 ? charset->GetChar( str.Get() + p.pos, str.Get() + str.Len() ) : ' ';
440 
441 	int group = EditBuf::GetCharGroup( c );
442 
443 	while ( StepRight( &p, &c ) )
444 	{
445 		if ( p.line > cursor.line )
446 		{
447 			cursor = p;
448 			cursor.pos = 0;
449 			break;
450 		}
451 		else
452 		{
453 			cursor = p;
454 		}
455 
456 		if ( EditBuf::GetCharGroup( c ) != group ) { break; }
457 	}
458 
459 	recomendedCursorCol = -1;
460 	SendChanges();
461 	CursorToScreen();
462 
463 	if ( !mark ) { marker = cursor; }
464 
465 	Refresh();
466 }
467 
468 
PageDown(bool mark)469 void EditWin::PageDown( bool mark )
470 {
471 	CursorToScreen();
472 
473 	if ( recomendedCursorCol < 0 )
474 	{
475 		recomendedCursorCol = GetColFromPos( cursor.line, cursor.pos );
476 	}
477 
478 	int lines = text.Count();
479 
480 	if ( firstLine + rows >= lines )
481 	{
482 		if ( lines > 0 && cursor.line + 1 < lines )
483 		{
484 			cursor.line = lines - 1;
485 			cursor.pos = GetPosFromCol( cursor.line, recomendedCursorCol );
486 			SendChanges();
487 
488 			if ( !mark ) { marker = cursor; }
489 
490 			Refresh();
491 			return;
492 		}
493 	}
494 
495 	int addLines = rows - 1;
496 
497 	if ( firstLine + addLines + rows > lines )
498 	{
499 		addLines = lines - rows - firstLine;
500 	}
501 
502 	if ( firstLine + addLines < 0 )
503 	{
504 		addLines = -firstLine;
505 	}
506 
507 	//ASSERT(addLines >= 0);
508 	firstLine += addLines;
509 
510 	if ( firstLine < 0 ) { firstLine = 0; }
511 
512 	if ( firstLine >= lines ) { firstLine = lines - 1; }
513 
514 	cursor.line += addLines;
515 
516 	if ( cursor.line < 0 ) { cursor.line = 0; }
517 
518 	if ( cursor.line >= lines ) { cursor.line = lines - 1; }
519 
520 	cursor.pos = GetPosFromCol( cursor.line, recomendedCursorCol );
521 	CalcScroll();
522 	SendChanges();
523 
524 	if ( !mark ) { marker = cursor; }
525 
526 	Refresh();
527 }
528 
PageUp(bool mark)529 void EditWin::PageUp( bool mark )
530 {
531 	CursorToScreen();
532 
533 	if ( recomendedCursorCol < 0 )
534 	{
535 		recomendedCursorCol = GetColFromPos( cursor.line, cursor.pos );
536 	}
537 
538 	if ( firstLine == 0 )
539 	{
540 		if ( cursor.line > 0 )
541 		{
542 			cursor.line = 0;
543 			cursor.pos = GetPosFromCol( cursor.line, recomendedCursorCol );
544 			SendChanges();
545 
546 			if ( !mark ) { marker = cursor; }
547 
548 			Refresh();
549 			return;
550 		}
551 	}
552 
553 	int minus = rows - 1;
554 
555 	if ( firstLine < minus )
556 	{
557 		minus = firstLine;
558 	}
559 
560 	firstLine -= minus;
561 	cursor.line -= minus;
562 	cursor.pos = GetPosFromCol( cursor.line, recomendedCursorCol );
563 	CalcScroll();
564 	SendChanges();
565 
566 	if ( !mark ) { marker = cursor; }
567 
568 	Refresh();
569 }
570 
CtrlPageDown(bool mark)571 void EditWin::CtrlPageDown( bool mark )
572 {
573 	if ( !text.Count() ) { return; }
574 
575 	cursor.line = text.Count() - 1;
576 	cursor.pos = text.Get( cursor.line ).Len();
577 
578 	CalcScroll();
579 	SendChanges();
580 	CursorToScreen();
581 
582 	if ( !mark ) { marker = cursor; }
583 
584 	Refresh();
585 }
586 
CtrlPageUp(bool mark)587 void EditWin::CtrlPageUp( bool mark )
588 {
589 	cursor.line = 0;
590 	cursor.pos = 0;
591 
592 	CalcScroll();
593 	SendChanges();
594 	CursorToScreen();
595 
596 	if ( !mark ) { marker = cursor; }
597 
598 	Refresh();
599 }
600 
601 
SelectAll()602 void EditWin::SelectAll()
603 {
604 	marker.Set( 0, 0 );
605 	int n = text.Count() - 1;
606 	cursor.Set( n, text.Get( n ).len );
607 	CalcScroll();
608 	CursorToScreen();
609 	SendChanges();
610 	Refresh();
611 }
612 
GetCursorCol()613 int EditWin::GetCursorCol()
614 {
615 	return GetColFromPos( cursor.line, cursor.pos );
616 }
617 
GetCursorSymbol()618 int32_t EditWin::GetCursorSymbol()
619 {
620 	if ( cursor.line >= text.Count() ) { return -1; }
621 
622 	ASSERT( cursor.line >= 0 && cursor.line < text.Count() );
623 	EditString& str = text.Get( cursor.line );
624 
625 	if ( cursor.pos >= str.len ) { return -1; }
626 
627 	char* s = str.Get();
628 	unicode_t c = charset->GetChar( s + cursor.pos, s + str.len );
629 	return c;
630 }
631 
Undo()632 bool EditWin::Undo()
633 {
634 	UndoBlock* u = undoList.GetUndo();
635 
636 	if ( !u ) { return false; }
637 
638 	try
639 	{
640 		for ( UndoRec* r = u->last; r; r = r->prev )
641 		{
642 			if ( _shlLine > r->line ) { _shlLine = r->line; }
643 
644 			switch ( r->type )
645 			{
646 
647 				case UndoRec::ATTR:
648 				{
649 					EditString& str = text.Get( r->line );
650 					str.flags = r->prevAttr;
651 				}
652 				break;
653 
654 				case UndoRec::INSTEXT:
655 				{
656 					EditString& str = text.Get( r->line );
657 					str.Delete( r->pos, r->dataSize );
658 				}
659 				break;
660 
661 				case UndoRec::DELTEXT:
662 				{
663 					EditString& str = text.Get( r->line );
664 					str.Insert( r->data.data(), r->pos, r->dataSize );
665 				}
666 				break;
667 
668 				case UndoRec::DELLINE:
669 				{
670 					int n = r->line;
671 					text.Insert( n, 1, r->attr );
672 					text.Get( n ).Set( r->data.data(), r->dataSize );
673 				}
674 				break;
675 
676 				case UndoRec::ADDLINE:
677 				{
678 					int n = r->line;
679 					text.Delete( n, 1 );
680 				}
681 				break;
682 
683 				default:
684 					NCMessageBox( ( NCDialogParent* )Parent(), "bad oper", "undo", true );
685 					undoList.Clear();
686 					return false;
687 			}
688 		}
689 
690 		cursor = u->beginCursor;
691 		marker = u->beginMarker;
692 		_changed = u->editorChanged;
693 	}
694 	catch ( ... )
695 	{
696 		undoList.Clear();
697 		throw;
698 	}
699 
700 	CursorToScreen();
701 	CalcScroll();
702 	SendChanges();
703 	Refresh();
704 	return true;
705 }
706 
Redo()707 bool EditWin::Redo()
708 {
709 	bool chg;
710 	UndoBlock* u = undoList.GetRedo( &chg );
711 
712 	if ( !u ) { return false; }
713 
714 	try
715 	{
716 		for ( UndoRec* r = u->first; r; r = r->next )
717 		{
718 			if ( _shlLine > r->line ) { _shlLine = r->line; }
719 
720 			switch ( r->type )
721 			{
722 
723 				case UndoRec::ATTR:
724 				{
725 					EditString& str = text.Get( r->line );
726 					str.flags = r->attr;
727 				}
728 				break;
729 
730 				case UndoRec::INSTEXT:
731 				{
732 					EditString& str = text.Get( r->line );
733 					str.Insert( r->data.data(), r->pos, r->dataSize );
734 				}
735 				break;
736 
737 				case UndoRec::DELTEXT:
738 				{
739 					EditString& str = text.Get( r->line );
740 					str.Delete( r->pos, r->dataSize );
741 				}
742 				break;
743 
744 				case UndoRec::DELLINE:
745 				{
746 					int n = r->line;
747 					text.Delete( n, 1 );
748 				}
749 				break;
750 
751 				case UndoRec::ADDLINE:
752 				{
753 					int n = r->line;
754 					text.Insert( n, 1, r->attr );
755 					text.Get( n ).Set( r->data.data(), r->dataSize );
756 				}
757 				break;
758 
759 				default:
760 					NCMessageBox( ( NCDialogParent* )Parent(), "bad oper", "Redo", true );
761 					undoList.Clear();
762 					return false;
763 			}
764 		}
765 
766 		cursor = u->endCursor;
767 		marker = u->endMarker;
768 		_changed = chg;
769 	}
770 	catch ( ... )
771 	{
772 		undoList.Clear();
773 		throw;
774 	}
775 
776 	CursorToScreen();
777 	CalcScroll();
778 	SendChanges();
779 	Refresh();
780 
781 
782 	return true;
783 }
784 
InsChar(unicode_t ch)785 void EditWin::InsChar( unicode_t ch ) //!Undo
786 {
787 	char buf[0x100];
788 	int n = charset->SetChar( buf, ch );
789 
790 	if ( n <= 0 )
791 	{
792 		return;
793 	}
794 
795 	clPtr<UndoBlock> undoBlock = new UndoBlock( true, _changed );
796 	undoBlock->SetBeginPos( cursor, marker );
797 
798 	try
799 	{
800 
801 		SetChanged( cursor.line );
802 		ASSERT( cursor.line >= 0 && cursor.line < text.Count() );
803 		EditString& str = text.Get( cursor.line );
804 		str.Insert( buf, cursor.pos, n );
805 		undoBlock->InsText( cursor.line, cursor.pos, buf, n );
806 
807 		cursor.pos += n;
808 		SendChanges();
809 		marker = cursor;
810 
811 		undoBlock->SetEndPos( cursor, marker );
812 		undoList.Append( undoBlock );
813 
814 	}
815 	catch ( ... )
816 	{
817 		undoList.Clear();
818 		throw;
819 	}
820 
821 	CursorToScreen();
822 	CalcScroll();
823 	SendChanges();
824 	Refresh();
825 }
826 
DelMarked()827 bool EditWin::DelMarked() //!Undo
828 {
829 	if ( cursor == marker ) { return false; }
830 
831 	clPtr<UndoBlock> undoBlock = new UndoBlock( false, _changed );
832 	undoBlock->SetBeginPos( cursor, marker );
833 
834 	EditPoint begin, end;
835 
836 	if ( cursor < marker )
837 	{
838 		begin = cursor;
839 		end = marker;
840 	}
841 	else
842 	{
843 		begin = marker;
844 		end = cursor;
845 	}
846 
847 	SetChanged( begin.line );
848 
849 	try
850 	{
851 
852 		if ( begin.line == end.line )
853 		{
854 			EditString& line = text.Get( begin.line );
855 			int count = end.pos - begin.pos;
856 			undoBlock->DelText( begin.line, begin.pos, line.Get() + begin.pos, count );
857 			line.Delete( begin.pos, count );
858 			cursor = begin;
859 		}
860 		else
861 		{
862 			EditString& bLine = text.Get( begin.line );
863 			EditString& eLine = text.Get( end.line );
864 
865 			if ( begin.pos < bLine.len )
866 			{
867 				undoBlock->DelText( begin.line, begin.pos, bLine.Get() + begin.pos, bLine.len - begin.pos );
868 				bLine.Delete( begin.pos, bLine.len - begin.pos );
869 			}
870 
871 			if ( end.pos < eLine.len )
872 			{
873 				int count = eLine.len - end.pos;
874 				bLine.Insert( eLine.Get() + end.pos, begin.pos, count );
875 				undoBlock->InsText( begin.line, begin.pos, bLine.Get() + begin.pos, count );
876 			}
877 
878 			undoBlock->Attr( begin.line, bLine.flags, eLine.flags );
879 			bLine.flags = eLine.flags;
880 
881 			int delCount = end.line - begin.line;
882 
883 			for ( int i = 0; i < delCount; i++ )
884 			{
885 				EditString& line = text.Get( begin.line + i + 1 );
886 				undoBlock->DelLine( begin.line + 1 /*!!! без i*/, line.flags, line.Get(), line.Len() );
887 			}
888 
889 			text.Delete( begin.line + 1, delCount );
890 			cursor = begin;
891 		}
892 
893 		marker = cursor;
894 
895 		undoBlock->SetEndPos( cursor, marker );
896 		undoList.Append( undoBlock );
897 
898 		CursorToScreen();
899 		CalcScroll();
900 		SendChanges();
901 		Refresh();
902 
903 	}
904 	catch ( ... )
905 	{
906 		undoList.Clear();
907 		throw;
908 	}
909 
910 	return true;
911 }
912 
_ToClipboardText(char * s,int count,charset_struct * cs,ClipboardText & ctx)913 inline void _ToClipboardText( char* s, int count, charset_struct* cs, ClipboardText& ctx )
914 {
915 	if ( count <= 0 )
916 	{
917 //printf("??? count= %i\n", count);
918 		return;
919 	}
920 
921 	char* endPos = s + count;
922 
923 	while ( s )
924 	{
925 		//bool tab;
926 		unicode_t c = cs->GetChar( s, endPos );
927 		ctx.Append( c );
928 		s = cs->GetNext( s, endPos );
929 	}
930 }
931 
ToClipboard()932 void EditWin::ToClipboard()
933 {
934 	if ( cursor == marker ) { return; }
935 
936 	ClipboardText ctx;
937 
938 	EditPoint begin, end;
939 
940 	if ( cursor < marker )
941 	{
942 		begin = cursor;
943 		end = marker;
944 	}
945 	else
946 	{
947 		begin = marker;
948 		end = cursor;
949 	}
950 
951 	if ( begin.line == end.line )
952 	{
953 		EditString& line = text.Get( begin.line );
954 		_ToClipboardText( line.Get() + begin.pos, end.pos - begin.pos, charset, ctx );
955 		//cursor = begin;
956 	}
957 	else
958 	{
959 		EditString& bLine = text.Get( begin.line );
960 		_ToClipboardText( bLine.Get() + begin.pos, bLine.len - begin.pos, charset, ctx );
961 		ctx.Append( '\n' );
962 
963 		for ( int i = begin.line + 1; i < end.line; i++ )
964 		{
965 			EditString& line = text.Get( i );
966 			_ToClipboardText( line.Get(), line.len, charset, ctx );
967 			ctx.Append( '\n' );
968 		}
969 
970 //		EditString& eLine = text.Get( end.line );
971 
972 		if ( end.pos > 0 )
973 		{
974 			EditString& eLine = text.Get( end.line );
975 			_ToClipboardText( eLine.Get(), end.pos, charset, ctx );
976 		}
977 	}
978 
979 	ClipboardSetText( this, ctx );
980 }
981 
FromClipboard()982 void EditWin::FromClipboard() //!Undo
983 {
984 	ClipboardText ctx;
985 	ClipboardGetText( this, &ctx );
986 	int ctxLen = ctx.Count();
987 
988 	if ( ctxLen <= 0 ) { return; }
989 
990 	clPtr<UndoBlock> undoBlock = new UndoBlock( false, _changed );
991 	undoBlock->SetBeginPos( cursor, marker );
992 
993 	try
994 	{
995 
996 		recomendedCursorCol = -1;
997 		SetChanged( cursor.line );
998 
999 		int ctxPos = 0;
1000 
1001 		// insert clipboard text (ctx) into editor buffer (text) line by line
1002 		while ( ctxPos < ctxLen )
1003 		{
1004 			char buf[1024];
1005 			int bufPos = 0;
1006 			bool newline = false;
1007 
1008 			// find next newline char
1009 			for ( ; ctxPos < ctxLen && bufPos < 1024 - 32; ctxPos++ )
1010 			{
1011 				unicode_t ch = ctx[ctxPos];
1012 
1013 				if ( ch == '\n' )
1014 				{
1015 					newline = true;
1016 					ctxPos++;
1017 					break;
1018 				}
1019 
1020 				bufPos += charset->SetChar( buf + bufPos, ch );
1021 			}
1022 
1023 			EditString& line = text.Get( cursor.line );
1024 
1025 			if ( bufPos > 0 ) // insert clipboard fragment up to newline to cursor pos
1026 			{
1027 				line.Insert( buf, cursor.pos, bufPos );
1028 				undoBlock->InsText( cursor.line, cursor.pos, buf, bufPos );
1029 			}
1030 
1031 			cursor.pos += bufPos;
1032 
1033 			if ( newline ) // then we need to add new line to edit buffer
1034 			{
1035 				EditString& str = text.Get( cursor.line );
1036 				text.Insert( cursor.line + 1, 1, line.flags );
1037 
1038 				if ( cursor.pos < str.len ) // move original text that was after cursor on current line to a new line
1039 				{
1040 					char* textAfterCursor = str.Get() + cursor.pos;
1041 					int lenTextAfterCursor = str.len - cursor.pos;
1042 					undoBlock->AddLine( cursor.line + 1, line.flags, textAfterCursor, lenTextAfterCursor );
1043 					// copy the aftercursor text to new line
1044 					text.Get( cursor.line + 1 ).Set( textAfterCursor, lenTextAfterCursor );
1045 					// remove the aftercursor text from current line
1046 					str.len = cursor.pos;
1047 					undoBlock->DelText( cursor.line, cursor.pos, textAfterCursor, lenTextAfterCursor );
1048 				}
1049 				else // we have added an empty line
1050 				{
1051 					undoBlock->AddLine( cursor.line + 1, line.flags,  0, 0 );
1052 				}
1053 
1054 				cursor.line++;
1055 				cursor.pos = 0;
1056 			}
1057 		}
1058 
1059 		marker = cursor;
1060 
1061 		undoBlock->SetEndPos( cursor, marker );
1062 		undoList.Append( undoBlock );
1063 
1064 		CalcScroll();
1065 		CursorToScreen();
1066 		SendChanges();
1067 		Refresh();
1068 
1069 	}
1070 	catch ( ... )
1071 	{
1072 		undoList.Clear();
1073 		throw;
1074 	}
1075 }
1076 
Cut()1077 void EditWin::Cut()
1078 {
1079 	if ( cursor == marker ) { return; }
1080 
1081 	ToClipboard();
1082 	DelMarked();
1083 }
1084 
Del(bool DeleteWord)1085 void EditWin::Del( bool DeleteWord ) //!Undo
1086 {
1087 	ASSERT( cursor.line >= 0 && cursor.line < text.Count() );
1088 	ASSERT( cursor.pos >= 0 && cursor.pos <= text.Get( cursor.line ).Len() );
1089 
1090 	if ( DelMarked() )
1091 	{
1092 		return;
1093 	}
1094 
1095 	clPtr<UndoBlock> undoBlock = new UndoBlock( true, _changed );
1096 	undoBlock->SetBeginPos( cursor, marker );
1097 
1098 	try
1099 	{
1100 		EditString& str = text.Get( cursor.line );
1101 
1102 		if ( cursor.pos < str.len )
1103 		{
1104 			SetChanged( cursor.line );
1105 
1106 			char* s = str.Get() + cursor.pos;
1107 			char* end = str.Get() + str.Len();
1108 
1109 			int totalDelCount = 0;
1110 
1111 			if ( DeleteWord )
1112 			{
1113 				EditPoint oldcursor = cursor;
1114 				EditPoint p = cursor;
1115 
1116 				if ( p.line < 0 || p.line >= text.Count() ) { return; }
1117 
1118 				if ( p.pos < 0 || p.pos > text.Get( p.line ).Len() ) { return; }
1119 
1120 				EditString& str = text.Get( p.line );
1121 				unicode_t c = str.Len() > 0 ? charset->GetChar( str.Get() + p.pos, str.Get() + str.Len() ) : ' ';
1122 
1123 				int group = EditBuf::GetCharGroup( c );
1124 
1125 				while ( StepRight( &p, &c ) )
1126 				{
1127 					cursor = p;
1128 
1129 					if ( EditBuf::GetCharGroup( c ) != group ) { break; }
1130 				}
1131 
1132 				totalDelCount = cursor.pos - oldcursor.pos;
1133 
1134 				cursor = oldcursor;
1135 			}
1136 			else
1137 			{
1138 				char* t = charset->GetNext( s, end );
1139 				int delCount = t ? t - s : str.len - cursor.pos;
1140 
1141 				totalDelCount += delCount;
1142 			}
1143 
1144 			undoBlock->DelText( cursor.line, cursor.pos, s, totalDelCount );
1145 
1146 			str.Delete( cursor.pos, totalDelCount );
1147 		}
1148 		else
1149 		{
1150 			if ( cursor.line + 1 < text.Count() )
1151 			{
1152 				SetChanged( cursor.line );
1153 
1154 				EditString& str_1 = text.Get( cursor.line + 1 );
1155 
1156 				str.Insert( str_1.Get(), cursor.pos, str_1.len );
1157 				undoBlock->InsText( cursor.line, cursor.pos, str_1.Get(), str_1.len );
1158 
1159 				undoBlock->Attr( cursor.line, str.flags, str_1.flags );
1160 				str.flags = str_1.flags;
1161 
1162 				undoBlock->DelLine( cursor.line + 1, str_1.flags, str_1.Get(), str_1.len );
1163 				text.Delete( cursor.line + 1, 1 );
1164 			}
1165 		}
1166 
1167 		marker = cursor;
1168 
1169 		undoBlock->SetEndPos( cursor, marker );
1170 		undoList.Append( undoBlock );
1171 
1172 		CalcScroll();
1173 		SendChanges();
1174 		Refresh();
1175 
1176 	}
1177 	catch ( ... )
1178 	{
1179 		undoList.Clear();
1180 		throw;
1181 	}
1182 
1183 }
1184 
Backspace(bool DeleteWord)1185 void EditWin::Backspace( bool DeleteWord ) //!Undo
1186 {
1187 	ASSERT( cursor.line >= 0 && cursor.line < text.Count() );
1188 	ASSERT( cursor.pos >= 0 && cursor.pos <= text.Get( cursor.line ).Len() );
1189 
1190 	recomendedCursorCol = -1;
1191 
1192 	if ( DelMarked() )
1193 	{
1194 		return;
1195 	}
1196 
1197 	clPtr<UndoBlock> undoBlock = new UndoBlock( true, _changed );
1198 	undoBlock->SetBeginPos( cursor, marker );
1199 
1200 	try
1201 	{
1202 
1203 		EditString& str = text.Get( cursor.line );
1204 
1205 		if ( cursor.pos > 0 )
1206 		{
1207 			SetChanged( cursor.line );
1208 
1209 			if ( DeleteWord )
1210 			{
1211 				EditPoint oldcursor = cursor;
1212 				EditPoint p = cursor;
1213 				unicode_t c;
1214 
1215 				if ( !StepLeft( &p, &c ) ) { return; }
1216 
1217 				int group = EditBuf::GetCharGroup( c );
1218 				cursor = p;
1219 
1220 				while ( StepLeft( &p, &c ) && EditBuf::GetCharGroup( c ) == group )
1221 				{
1222 					if ( cursor.line == p.line )
1223 					{
1224 						cursor = p;
1225 					}
1226 					else
1227 					{
1228 						// just stay at the beginning of this line
1229 						cursor.pos = 0;
1230 						break;
1231 					}
1232 				}
1233 
1234 				int totalDelCount = oldcursor.pos - cursor.pos;
1235 
1236 				char* s = str.Get() + cursor.pos;
1237 
1238 				undoBlock->DelText( cursor.line, cursor.pos, s, totalDelCount );
1239 
1240 				str.Delete( cursor.pos, totalDelCount );
1241 			}
1242 			else
1243 			{
1244 				char* s = str.Get() + cursor.pos;
1245 				char* t = charset->GetPrev( s, str.Get() );
1246 
1247 				if ( t )
1248 				{
1249 					undoBlock->DelText( cursor.line, t - str.Get(), t, s - t );
1250 					str.Delete( t - str.Get(), s - t );
1251 					cursor.pos -= s - t;
1252 				}
1253 				else
1254 				{
1255 					undoBlock->DelText( cursor.line, 0, str.Get(), cursor.pos );
1256 					str.Delete( 0, cursor.pos );
1257 					cursor.pos = 0;
1258 				}
1259 			}
1260 		}
1261 		else
1262 		{
1263 			if ( cursor.line > 0 )
1264 			{
1265 				SetChanged( cursor.line - 1 );
1266 				EditString& str_1 = text.Get( cursor.line - 1 );
1267 				int l = str_1.len;
1268 
1269 
1270 				undoBlock->InsText( cursor.line - 1, str_1.len, str.Get(), str.Len() ); //пока не поменялся str_1.len
1271 				str_1.Insert( str.Get(), str_1.len, str.len );
1272 
1273 				undoBlock->Attr( cursor.line - 1, str_1.flags, str.flags );
1274 				str_1.flags = str.flags;
1275 
1276 				undoBlock->DelLine( cursor.line, str.flags, str.Get(), str.Len() );
1277 				text.Delete( cursor.line, 1 );
1278 
1279 				cursor.line--;
1280 				cursor.pos = l;
1281 			}
1282 		}
1283 
1284 		marker = cursor;
1285 
1286 		undoBlock->SetEndPos( cursor, marker );
1287 		undoList.Append( undoBlock );
1288 
1289 		CursorToScreen();
1290 		SendChanges();
1291 		Refresh();
1292 
1293 	}
1294 	catch ( ... )
1295 	{
1296 		undoList.Clear();
1297 		throw;
1298 	}
1299 
1300 }
1301 
Ident(EditString & str)1302 char* EditWin::Ident( EditString& str )
1303 {
1304 	if ( !str.len )
1305 	{
1306 		return 0;
1307 	}
1308 
1309 	char* s = str.Get();
1310 	char* end = s + str.len;
1311 
1312 	while ( true )
1313 	{
1314 		unicode_t c = charset->GetChar( s, end );
1315 
1316 		if ( c != ' '  && c != '\t' )
1317 		{
1318 			break;
1319 		}
1320 
1321 		//bool tab;
1322 		s = charset->GetNext( s, end );
1323 
1324 		if ( !s )
1325 		{
1326 			return 0;
1327 		}
1328 	}
1329 
1330 	return s;
1331 }
1332 
SetCharset(charset_struct * cs)1333 void EditWin::SetCharset( charset_struct* cs )
1334 {
1335 	ASSERT( cursor.line >= 0 && cursor.line < text.Count() );
1336 	ASSERT( cursor.pos >= 0 && cursor.pos <= text.Get( cursor.line ).Len() );
1337 	charset = cs;
1338 	CursorRight( false );
1339 	CursorLeft( false );
1340 	SendChanges();
1341 	marker = cursor;
1342 	EnableShl( g_WcmConfig.editShl );
1343 	Refresh();
1344 }
1345 
DeleteLine()1346 void EditWin::DeleteLine() //!Undo
1347 {
1348 	ASSERT( cursor.line >= 0 && cursor.line < text.Count() );
1349 	ASSERT( cursor.pos >= 0 && cursor.pos <= text.Get( cursor.line ).Len() );
1350 	recomendedCursorCol = -1;
1351 
1352 	clPtr<UndoBlock> undoBlock = new UndoBlock( false, _changed );
1353 	undoBlock->SetBeginPos( cursor, marker );
1354 
1355 	EditString& str = text.Get( cursor.line );
1356 
1357 	try
1358 	{
1359 		if ( cursor.line + 1 >= text.Count() )
1360 		{
1361 			if ( str.len == 0 )
1362 			{
1363 				return;
1364 			}
1365 
1366 			undoBlock->DelText( cursor.line, 0, str.Get(), str.len );
1367 			str.len = 0; //!!!
1368 			cursor.pos = 0;
1369 		}
1370 		else
1371 		{
1372 			undoBlock->DelLine( cursor.line, str.flags, str.Get(), str.len );
1373 			text.Delete( cursor.line, 1 );
1374 			cursor.pos = 0;
1375 		}
1376 
1377 		SetChanged( cursor.line - 1 );
1378 
1379 		marker = cursor;
1380 
1381 		undoBlock->SetEndPos( cursor, marker );
1382 		undoList.Append( undoBlock );
1383 
1384 		CursorToScreen();
1385 		SendChanges();
1386 		Refresh();
1387 	}
1388 	catch ( ... )
1389 	{
1390 		undoList.Clear();
1391 		throw;
1392 	}
1393 }
1394 
Enter()1395 void EditWin::Enter() //!Undo
1396 {
1397 	ASSERT( cursor.line >= 0 && cursor.line < text.Count() );
1398 	ASSERT( cursor.pos >= 0 && cursor.pos <= text.Get( cursor.line ).Len() );
1399 
1400 	recomendedCursorCol = -1;
1401 
1402 	clPtr<UndoBlock> undoBlock = new UndoBlock( true, _changed );
1403 	undoBlock->SetBeginPos( cursor, marker );
1404 
1405 	try
1406 	{
1407 		SetChanged( cursor.line );
1408 
1409 		EditString& str = text.Get( cursor.line );
1410 		text.Insert( cursor.line + 1, 1, str.flags );
1411 
1412 		if ( cursor.pos < str.len )
1413 		{
1414 			text.Get( cursor.line + 1 ).Set( str.Get() + cursor.pos, str.len - cursor.pos );
1415 			undoBlock->AddLine( cursor.line + 1, str.flags, str.Get() + cursor.pos, str.len - cursor.pos );
1416 			undoBlock->DelText( cursor.line, cursor.pos, str.Get() + cursor.pos, str.len - cursor.pos );
1417 			str.len = cursor.pos;
1418 		}
1419 		else
1420 		{
1421 			undoBlock->AddLine( cursor.line + 1, str.flags, 0, 0 );
1422 		}
1423 
1424 		cursor.line++;
1425 		cursor.pos = 0;
1426 
1427 		if ( autoIdent )
1428 		{
1429 			for ( int i = cursor.line - 1; i >= 0; i-- )
1430 			{
1431 				char* s = Ident( text.Get( i ) );
1432 
1433 				if ( s )
1434 				{
1435 					char* p = text.Get( i ).Get();
1436 					EditString& cstr = text.Get( cursor.line );
1437 					char* t = Ident( cstr );
1438 
1439 					if ( t )
1440 					{
1441 						undoBlock->DelText( cursor.line, 0, cstr.Get() , t - cstr.Get() );
1442 						cstr.Delete( 0, t - cstr.Get() );
1443 						cursor.pos = 0;
1444 					}
1445 
1446 					undoBlock->InsText( cursor.line, 0, p, s - p );
1447 					cstr.Insert( p, 0, s - p );
1448 					cursor.pos = s - p;
1449 					break;
1450 				}
1451 			}
1452 		}
1453 
1454 		marker = cursor;
1455 
1456 		undoBlock->SetEndPos( cursor, marker );
1457 		undoList.Append( undoBlock );
1458 
1459 		CursorToScreen();
1460 		SendChanges();
1461 		Refresh();
1462 
1463 	}
1464 	catch ( ... )
1465 	{
1466 		undoList.Clear();
1467 		throw;
1468 	}
1469 
1470 }
1471 
GetScrollCtx() const1472 sEditorScrollCtx EditWin::GetScrollCtx() const
1473 {
1474 	sEditorScrollCtx Ctx;
1475 	Ctx.m_Point = this->GetCursorPos();
1476 	Ctx.m_FirstLine = firstLine;
1477 	return Ctx;
1478 }
1479 
SetScrollCtx(const sEditorScrollCtx & Ctx)1480 void EditWin::SetScrollCtx( const sEditorScrollCtx& Ctx )
1481 {
1482 	recomendedCursorCol = -1;
1483 	int MaxLine = std::max( 0, text.Count() - rows );
1484 	SetCursorPos( Ctx.m_Point );
1485 	firstLine = Ctx.m_FirstLine;
1486 	firstLine = std::min( firstLine, MaxLine );
1487 	colOffset = 0;
1488 	marker = cursor;
1489 	SendChanges();
1490 	Refresh();
1491 }
1492 
CalcScroll()1493 void EditWin::CalcScroll()
1494 {
1495 	ScrollInfo vsi;
1496 	vsi.m_PageSize = rows;
1497 	vsi.m_Size = text.Count();
1498 	vsi.m_Pos = firstLine;
1499 	bool vVisible = vscroll.IsVisible();
1500 	vscroll.Command( CMD_SCROLL_INFO, SCMD_SCROLL_VCHANGE, this, &vsi );
1501 
1502 	if ( vVisible != vscroll.IsVisible() )
1503 	{
1504 		this->RecalcLayouts();
1505 	}
1506 }
1507 
1508 
Command(int id,int subId,Win * win,void * data)1509 bool EditWin::Command( int id, int subId, Win* win, void* data )
1510 {
1511 	if ( id != CMD_SCROLL_INFO )
1512 	{
1513 		return false;
1514 	}
1515 
1516 	int n = firstLine;
1517 
1518 	switch ( subId )
1519 	{
1520 		case SCMD_SCROLL_LINE_UP:
1521 			n--;
1522 			break;
1523 
1524 		case SCMD_SCROLL_LINE_DOWN:
1525 			n++;
1526 			break;
1527 
1528 		case SCMD_SCROLL_PAGE_UP:
1529 			n -= rows;
1530 			break;
1531 
1532 		case SCMD_SCROLL_PAGE_DOWN:
1533 			n += rows;
1534 			break;
1535 
1536 		case SCMD_SCROLL_TRACK:
1537 			n = ( ( int* )data )[0];
1538 			break;
1539 	}
1540 
1541 	if ( n + rows > text.Count() )
1542 	{
1543 		n = text.Count() - rows;
1544 	}
1545 
1546 	if ( n < 0 ) { n = 0; }
1547 
1548 	if ( n != firstLine )
1549 	{
1550 		firstLine = n;
1551 		CalcScroll();
1552 		SendChanges();
1553 		Refresh();
1554 	}
1555 
1556 	return true;
1557 }
1558 
Broadcast(int id,int subId,Win * win,void * data)1559 bool EditWin::Broadcast( int id, int subId, Win* win, void* data )
1560 {
1561 	if ( id == ID_CHANGED_CONFIG_BROADCAST )
1562 	{
1563 		autoIdent = g_WcmConfig.editAutoIdent;
1564 		tabSize = g_WcmConfig.editTabSize;
1565 
1566 		if ( IsVisible() ) { Invalidate(); }
1567 
1568 		return true;
1569 	}
1570 
1571 	return false;
1572 }
1573 
1574 
ColorById(int id)1575 unsigned EditWin::ColorById( int id )
1576 {
1577 	switch ( id )
1578 	{
1579 		case COLOR_DEF_ID:
1580 			return shlDEF;
1581 
1582 		case COLOR_KEYWORD_ID:
1583 			return shlKEYWORD;
1584 
1585 		case COLOR_COMMENT_ID:
1586 			return shlCOMMENT;
1587 
1588 		case COLOR_STRING_ID:
1589 			return shlSTRING;
1590 
1591 		case COLOR_PRE_ID:
1592 			return shlPRE;
1593 
1594 		case COLOR_NUM_ID:
1595 			return shlNUM;
1596 
1597 		case COLOR_OPER_ID:
1598 			return shlOPER;
1599 
1600 		case COLOR_ATTN_ID:
1601 			return shlATTN;
1602 	}
1603 
1604 //printf("color id ?(%i)\n", id);
1605 	return shlDEF;
1606 }
1607 
1608 #ifdef _WIN32
1609 #include "w32util.h"
1610 #endif
1611 
CheckAsciiSymbol(charset_struct * cs,unsigned char c)1612 static bool CheckAsciiSymbol( charset_struct* cs, unsigned char c )
1613 {
1614 	char buf[64];
1615 	int n = cs->SetChar( buf, c );
1616 	return n == 1 && buf[0] == c;
1617 }
1618 
CheckAscii(charset_struct * cs)1619 static bool CheckAscii( charset_struct* cs )
1620 {
1621 	for ( int i = 1; i < 128; i++ )
1622 		if ( !CheckAsciiSymbol( cs, i ) )
1623 		{
1624 			return false;
1625 		}
1626 
1627 	return true;
1628 }
1629 
EnableShl(bool on)1630 void EditWin::EnableShl( bool on )
1631 {
1632 	_shl = 0;
1633 	_shlLine = -1;
1634 	_shlConf = 0;
1635 
1636 	if ( on )
1637 	{
1638 
1639 		if ( !CheckAscii( charset ) )
1640 		{
1641 			return;
1642 		}
1643 
1644 		std::unordered_map< std::string, int > colors;
1645 		colors["DEF"   ] = COLOR_DEF_ID;
1646 		colors["KEYWORD"] = COLOR_KEYWORD_ID;
1647 		colors["COMMENT"] = COLOR_COMMENT_ID;
1648 		colors["STRING"   ] = COLOR_STRING_ID;
1649 		colors["PRE"   ] = COLOR_PRE_ID;
1650 		colors["NUM"   ] = COLOR_NUM_ID;
1651 		colors["OPER"  ] = COLOR_OPER_ID;
1652 		colors["ATTN"  ] = COLOR_ATTN_ID;
1653 
1654 		std::vector<char> firstLine;
1655 
1656 		if ( text.Count() > 0 )
1657 		{
1658 			EditString& str = text.Get( EditList::Pos() );
1659 			int len = str.len;
1660 
1661 			firstLine.resize( len + 1 );
1662 
1663 			char* s = firstLine.data();
1664 
1665 			if ( len > 0 )
1666 			{
1667 				memcpy( firstLine.data(), str.Get(), len );
1668 			}
1669 
1670 			firstLine[len] = 0;
1671 
1672 			char* ns = 0;
1673 
1674 			for ( ; *s; s++ )
1675 				if ( *s <= 0 || *s > ' ' )
1676 				{
1677 					ns = s;
1678 				}
1679 
1680 			if ( ns ) { ns[1] = 0; }
1681 		}
1682 
1683 		_shlConf = new SHL::ShlConf();
1684 #ifdef _WIN32
1685 		std::vector<wchar_t> path = GetAppPath();
1686 		_shlConf->Parze( carray_cat<wchar_t>( GetAppPath().data(), utf8_to_sys( "\\shl\\config.cfg" ).data() ).data() );
1687 #else
1688 		_shlConf->Parze( ( sys_char_t* ) UNIX_CONFIG_DIR_PATH "/shl/config.cfg" );
1689 #endif
1690 		_shlLine = -1;
1691 		//надо сделать не utf8 а текущий cs
1692 		_shl = _shlConf->Get( _path.GetUnicode() , utf8_to_unicode( firstLine.data() ).data(), colors );
1693 	}
1694 
1695 	__RefreshScreenData();
1696 	Invalidate();
1697 }
1698 
Load(clPtr<FS> fs,FSPath & path,MemFile & f)1699 void EditWin::Load( clPtr<FS> fs, FSPath& path, MemFile& f )
1700 {
1701 	Clear();
1702 	text.Load( f );
1703 	_fs = fs;
1704 	_path = path;
1705 	CalcScroll();
1706 
1707 	_changed = false;
1708 
1709 	EnableShl( g_WcmConfig.editShl );
1710 }
1711 
Clear()1712 void EditWin::Clear()
1713 {
1714 	text.Clear();
1715 	undoList.Clear();
1716 	cursor.Set( 0, 0 );
1717 	marker = cursor;
1718 	firstLine = 0;
1719 	colOffset = 0;
1720 	_path.Clear();
1721 	_fs = 0;
1722 	recomendedCursorCol = -1;
1723 }
1724 
Save(MemFile & f)1725 void EditWin::Save( MemFile& f )
1726 {
1727 	f.Clear();
1728 	text.Save( f );
1729 	if ( g_WcmConfig.editClearHistoryAfterSaving ) undoList.Clear();
1730 //	changed = false;
1731 }
1732 
SetChanged(int minLine)1733 void EditWin::SetChanged( int minLine )
1734 {
1735 	_changed = true;
1736 
1737 	if ( _shlLine > minLine ) { _shlLine = minLine; }
1738 }
1739 
RefreshShl(int n)1740 void EditWin::RefreshShl( int n )
1741 {
1742 	if ( _shl && n > _shlLine && text.Count() > 0 )
1743 	{
1744 		int first = _shlLine;
1745 
1746 		int count = text.Count();
1747 
1748 		if ( first < 0 )
1749 		{
1750 			text.Get( 0 ).shlId = _shl->GetStartId();
1751 			first = 0;
1752 			_shlLine = 0;
1753 		}
1754 
1755 		int last = n;
1756 
1757 		if ( last >= count ) { last = count - 1; }
1758 
1759 		if ( first < last )
1760 		{
1761 			EditList::Pos pos( first );
1762 			int statId = text.Get( pos ).shlId;
1763 
1764 			for ( ; pos <= last ; pos.Inc() )
1765 			{
1766 				EditString& str   = text.Get( pos );
1767 				char* begin = str.Get(), *s = begin, *end = s + str.Len();
1768 
1769 				if ( pos != first ) { str.shlId = statId; }
1770 
1771 				if ( pos != last )
1772 				{
1773 					statId = _shl->ScanLine( ( unsigned char* )begin, ( unsigned char* )end, statId );
1774 				}
1775 			}
1776 		}
1777 
1778 		_shlLine = last;
1779 	}
1780 }
1781 
__RefreshScreenData()1782 void EditWin::__RefreshScreenData()
1783 {
1784 	if ( screen.Rows() <= 0 || screen.Cols() <= 0 ) { return; }
1785 
1786 	//EditorColors colors = *editorColors;
1787 
1788 	int r;
1789 
1790 	for ( r = 0; r < screen.Rows(); r++ )
1791 	{
1792 		int line = r + firstLine;
1793 
1794 		if ( line < 0 || line >= text.Count() )
1795 		{
1796 			screen.Set( r, 0, screen.Cols(), ' ', 0, color_background );
1797 			continue;
1798 		}
1799 
1800 		EditString& str   = text.Get( line );
1801 		char* begin = str.Get(), *s = begin, *end = s + str.Len();
1802 		bool tab = charset->IsTab( s, end );
1803 		int col = 0;
1804 
1805 		if ( str.len )
1806 		{
1807 
1808 //TEMP
1809 			std::vector<char> colId( str.len + 1 );
1810 			memset( colId.data(), -1, str.len + 1 );
1811 
1812 			if ( _shl )
1813 			{
1814 				RefreshShl( line );
1815 				_shl->ScanLine( ( unsigned char* )str.Get(), colId.data(), str.len, str.shlId );
1816 			}
1817 
1818 			int ce = col;
1819 
1820 			while ( s )
1821 			{
1822 				ce = ( tab ) ? col + tabSize - col % tabSize : col + 1;
1823 
1824 				if ( ce > colOffset ) { break; }
1825 
1826 				s = charset->GetNext( s, end );
1827 				tab = charset->IsTab( s, end );
1828 				col = ce;
1829 			}
1830 
1831 			while ( s && col - colOffset < screen.Cols() )
1832 			{
1833 				bool marked = InMark( EditPoint( line, s - begin ) );
1834 
1835 				if ( s >= end )
1836 				{
1837 					printf( "s>=end (%i)\n", int( s - end ) );
1838 				}
1839 
1840 				unsigned COL =    _shl ? ColorById( colId[s - begin] ) : color_text;
1841 
1842 				if ( tab )
1843 				{
1844 					ce = col + tabSize - col % tabSize;
1845 
1846 
1847 					screen.Set( r, col - colOffset, ce, ' ', 0, marked ? color_mark_background : color_background );
1848 					col = ce;
1849 				}
1850 				else
1851 				{
1852 					unicode_t ch = charset->GetChar( s, end );
1853 					screen.Set( r, col - colOffset, col - colOffset + 1, ( ch < 32 /*|| ch>=0x80 && ch< 0xA0*/ ) ? '.' : ch,
1854 					            ( ch < 32 /*|| ch>=0x80 && ch< 0xA0*/ ) ? 0xFF3030 : ( marked ? color_mark_text : /*colors.fg*/ COL ),
1855 					            marked ? color_mark_background : color_background );
1856 					col++;
1857 				}
1858 
1859 				s = charset->GetNext( s, end );
1860 				tab = charset->IsTab( s, end );
1861 			}
1862 		}
1863 
1864 		if ( col - colOffset < screen.Cols() )
1865 		{
1866 			screen.Set( r, col - colOffset, screen.Cols(), ' ', 0, InMark( EditPoint( line, end - begin ) ) ? color_mark_background : color_background );
1867 		}
1868 	}
1869 
1870 	screen.SetCursor( cursor.line - firstLine, GetCursorCol() - colOffset );
1871 }
1872 
1873 
1874 #define PBSIZE (0x100)
1875 
__DrawChanges()1876 void EditWin::__DrawChanges()
1877 {
1878 	if ( screen.Rows() <= 0 && screen.Cols() <= 0 ) { return; }
1879 
1880 	wal::GC gc( this );
1881 	gc.Set( GetFont() );
1882 
1883 	if ( screen.prevCursor != screen.cursor &&
1884 	     screen.prevCursor.line >= 0 && screen.prevCursor.line < screen.Rows() &&
1885 	     screen.prevCursor.pos >= 0 && screen.prevCursor.pos < screen.Cols() )
1886 	{
1887 		screen.Line( screen.prevCursor.line )[screen.prevCursor.pos].changed = true;
1888 	}
1889 
1890 	for ( int r = 0; r < screen.Rows(); r++ )
1891 	{
1892 		int c = 0;
1893 		EditScreenChar* p = screen.Line( r );
1894 
1895 		if ( !p ) { continue; }
1896 
1897 		EditScreenChar* pe = p + screen.Cols();
1898 		int y = editRect.top + r * charH;
1899 
1900 		while ( p < pe )
1901 		{
1902 			if ( !p->changed )
1903 			{
1904 				while ( p < pe && !p->changed ) { p++; c++; }
1905 
1906 				continue;
1907 			}
1908 
1909 			int x = editRect.left + c * charW;
1910 
1911 			if ( p->ch == ' ' )
1912 			{
1913 				EditScreenChar* t = p + 1;
1914 				p->changed = false;
1915 
1916 				for ( ; t < pe && t->ch == ' ' && t->changed && t->bColor == p->bColor; t++ )
1917 				{
1918 					t->changed = false;
1919 				}
1920 
1921 				int n = t - p;
1922 				gc.SetFillColor( p->bColor );
1923 				gc.FillRect( crect( x, y, x + n * charW, y + charH ) );
1924 				p = t;
1925 				c += n;
1926 				continue;
1927 			}
1928 
1929 			EditScreenChar* t = p + 1;
1930 			p->changed = false;
1931 
1932 			for ( ; t < pe && t->changed  && t->bColor == p->bColor && t->fColor == p->fColor; t++ )
1933 			{
1934 				t->changed = false;
1935 			}
1936 
1937 			int n = t - p;
1938 			gc.SetFillColor( p->bColor );
1939 			gc.SetTextColor( p->fColor );
1940 
1941 			while ( n > 0 )
1942 			{
1943 				unicode_t buf[PBSIZE];
1944 				int count = n > PBSIZE ? PBSIZE : n;
1945 
1946 				for ( int i = 0; i < count; i++ ) { buf[i] = p[i].ch; }
1947 
1948 				gc.TextOutF( x, y, buf, count );
1949 				n -= count;
1950 				p += count;
1951 				x += count * charW;
1952 				c += count;
1953 			}
1954 		}
1955 	}
1956 
1957 
1958 //перерисовать курсор всегда //  if (screen.prevCursor != screen.cursor)
1959 	DrawCursor( gc );
1960 }
1961 
DrawCursor(wal::GC & gc)1962 void EditWin::DrawCursor( wal::GC& gc )
1963 {
1964 	int curR = screen.cursor.line;
1965 	int curC = screen.cursor.pos;
1966 
1967 	if ( curR >= 0 && curR < screen.Rows() && curC >= 0 && curC < screen.Cols() )
1968 	{
1969 		int y = editRect.top + curR * charH;
1970 		int x = editRect.left + curC * charW;
1971 		gc.SetFillColor( color_cursor/*0xFFFF00*/ );
1972 		gc.FillRectXor( GetCursorRect( x, y ) );
1973 	}
1974 
1975 	screen.prevCursor = screen.cursor;
1976 }
1977 
Paint(wal::GC & gc,const crect & paintRect)1978 void EditWin::Paint( wal::GC& gc, const crect& paintRect )
1979 {
1980 	int r1 = ( paintRect.top - editRect.top ) / charH;
1981 	int r2 = ( paintRect.bottom - editRect.top + charH - 1 ) / charH;
1982 	int c1 = ( paintRect.left - editRect.left ) / charW;
1983 	int c2 = ( paintRect.right - editRect.left + charW - 1 ) / charW;
1984 
1985 	if ( r1 < 0 ) { r1 = 0; }
1986 
1987 	if ( r2 > screen.Rows() ) { r2 = screen.Rows(); }
1988 
1989 	if ( c1 < 0 ) { c1 = 0; }
1990 
1991 	if ( c2 > screen.Cols() ) { c2 = screen.Cols(); }
1992 
1993 	if ( r1 >= r2 || c1 >= c2 ) { return; }
1994 
1995 	gc.Set( GetFont() );
1996 
1997 	for ( int r = r1; r < r2; r++ )
1998 	{
1999 		int c = c1;
2000 		EditScreenChar* p = screen.Line( r ) + c;
2001 
2002 		if ( !p ) { continue; }
2003 
2004 		EditScreenChar* pe = p + c2 - c1;
2005 		int y = editRect.top + r * charH;
2006 
2007 		while ( p < pe )
2008 		{
2009 			int x = editRect.left + c * charW;
2010 
2011 			if ( p->ch == ' ' )
2012 			{
2013 				EditScreenChar* t = p + 1;
2014 				p->changed = false;
2015 
2016 				for ( ; t < pe && t->ch == ' ' && t->bColor == p->bColor; t++ )
2017 				{
2018 					t->changed = false;
2019 				}
2020 
2021 				int n = t - p;
2022 				gc.SetFillColor( p->bColor );
2023 				gc.FillRect( crect( x, y, x + n * charW, y + charH ) );
2024 				p = t;
2025 				c += n;
2026 				continue;
2027 			}
2028 
2029 			EditScreenChar* t = p + 1;
2030 			p->changed = false;
2031 
2032 			for ( ; t < pe && t->bColor == p->bColor && t->fColor == p->fColor; t++ )
2033 			{
2034 				t->changed = false;
2035 			}
2036 
2037 			int n = t - p;
2038 			gc.SetFillColor( p->bColor );
2039 			gc.SetTextColor( p->fColor );
2040 
2041 			while ( n > 0 )
2042 			{
2043 				unicode_t buf[PBSIZE];
2044 				int count = n > PBSIZE ? PBSIZE : n;
2045 
2046 				for ( int i = 0; i < count; i++ ) { buf[i] = p[i].ch; }
2047 
2048 				gc.TextOutF( x, y, buf, count );
2049 				n -= count;
2050 				p += count;
2051 				x += count * charW;
2052 				c += count;
2053 			}
2054 		}
2055 	}
2056 
2057 	DrawCursor( gc );
2058 }
2059 
GetCursorRect(int x,int y) const2060 crect EditWin::GetCursorRect( int x, int y ) const
2061 {
2062 	return crect( x, y + charH - charH / 5, x + charW, y + charH );
2063 }
2064 
SetPath(clPtr<FS> fs,FSPath & p)2065 void EditWin::SetPath( clPtr<FS> fs, FSPath& p )
2066 {
2067 	_fs = fs;
2068 	_path = p;
2069 }
2070 
GetCharsetId()2071 int EditWin::GetCharsetId()
2072 {
2073 	return charset->id;
2074 }
2075 
NextCharset()2076 void EditWin::NextCharset()
2077 {
2078 	SetCharset( charset_table[GetNextOperCharsetId( charset->id )] );
2079 }
2080 
SetCharset(int n)2081 void EditWin::SetCharset( int n )
2082 {
2083 	SetCharset( charset_table[n] );
2084 }
2085 
EventKey(cevent_key * pEvent)2086 bool EditWin::EventKey( cevent_key* pEvent )
2087 {
2088 	if ( pEvent->Type() == EV_KEYDOWN )
2089 	{
2090 		bool shift = ( pEvent->Mod() & KM_SHIFT ) != 0;
2091 		bool ctrl = ( pEvent->Mod() & KM_CTRL ) != 0;
2092 		bool alt = ( pEvent->Mod() & KM_ALT ) != 0;
2093 
2094 		if ( ctrl )
2095 		{
2096 			switch ( pEvent->Key() )
2097 			{
2098 				case VK_UP:
2099 					if (pEvent->IsFromMouseWheel())
2100 					{
2101 						if ( g_MainWin ) g_MainWin->IncreaseFontSize(NCWin::EDIT);
2102 						return true;
2103 					}
2104 					break;
2105 
2106 				case VK_DOWN:
2107 					if (pEvent->IsFromMouseWheel())
2108 					{
2109 						if ( g_MainWin ) g_MainWin->DecreaseFontSize(NCWin::EDIT);
2110 						return true;
2111 					}
2112 					break;
2113 
2114 				case VK_0:
2115 				case VK_1:
2116 				case VK_2:
2117 				case VK_3:
2118 				case VK_4:
2119 				case VK_5:
2120 				case VK_6:
2121 				case VK_7:
2122 				case VK_8:
2123 				case VK_9:
2124 				{
2125 					int Slot = pEvent->Key() - VK_0;
2126 					bool LeftCtrl = ( pEvent->ExtMod() & EXT_KM_LCTRL ) != 0;
2127 					if ( LeftCtrl )
2128 					{
2129 						// go to bookmark
2130 						sEditorScrollCtx Ctx;
2131 						if ( m_ScrollCtxStorage.Get( Slot, &Ctx ) )
2132 						{
2133 							this->SetScrollCtx( Ctx );
2134 						}
2135 					}
2136 					else
2137 					{
2138 						// set bookmark
2139 						sEditorScrollCtx Ctx = this->GetScrollCtx();
2140 						m_ScrollCtxStorage.Put(Slot, &Ctx);
2141 					}
2142 					return true;
2143 				}
2144 
2145 				case VK_Y:
2146 					DeleteLine();
2147 					return true;
2148 
2149 				case VK_X:
2150 					Cut();
2151 					return true;
2152 
2153 				case VK_C:
2154 					ToClipboard();
2155 					return true;
2156 
2157 				case VK_V:
2158 					DelMarked();
2159 					FromClipboard();
2160 					return true;
2161 
2162 				case VK_Z:
2163 					if ( shift ) { Redo(); }
2164 					else { Undo(); }
2165 
2166 					return true;
2167 			}
2168 		}
2169 
2170 
2171 		switch ( pEvent->Key() )
2172 		{
2173 			case VK_RIGHT:
2174 				if ( ctrl )
2175 				{
2176 					CursorCtrlRight( shift );
2177 				}
2178 				else
2179 				{
2180 					CursorRight( shift );
2181 				}
2182 
2183 				break;
2184 
2185 			case VK_LEFT:
2186 				if ( ctrl )
2187 				{
2188 					CursorCtrlLeft( shift );
2189 				}
2190 				else
2191 				{
2192 					CursorLeft( shift );
2193 				}
2194 
2195 				break;
2196 
2197 			case VK_DOWN:
2198 #if defined( __APPLE__)
2199 				if ( ctrl ) { PageDown( shift ); }
2200 				else
2201 #endif
2202 					CursorDown( shift );
2203 
2204 				break;
2205 
2206 			case VK_UP:
2207 #if defined( __APPLE__)
2208 				if ( ctrl ) { PageUp( shift ); }
2209 				else
2210 #endif
2211 					CursorUp( shift );
2212 
2213 				break;
2214 
2215 			case VK_HOME:
2216 				if ( ctrl ) { CtrlPageUp( shift ); }
2217 				else { CursorHome( shift ); }
2218 
2219 				break;
2220 
2221 			case VK_END:
2222 				if ( ctrl ) { CtrlPageDown( shift ); }
2223 				else { CursorEnd( shift ); }
2224 
2225 				break;
2226 
2227 			case VK_NEXT:
2228 				if ( ctrl ) { CtrlPageDown( shift ); }
2229 				else { PageDown( shift ); }
2230 
2231 				break;
2232 
2233 			case VK_PRIOR:
2234 				if ( ctrl ) { CtrlPageUp( shift ); }
2235 				else { PageUp( shift ); }
2236 
2237 				break;
2238 
2239 			case VK_DELETE:
2240 				if ( ctrl ) { Del( true ); return true; }
2241 
2242 				if ( shift ) { Cut(); return true; }
2243 
2244 				Del( false );
2245 				break;
2246 
2247 			case VK_BACK:
2248 				if ( alt )
2249 				{
2250 					Undo();
2251 				}
2252 				else
2253 				{
2254 					Backspace( ctrl );
2255 				}
2256 
2257 				break;
2258 
2259 			case VK_NUMPAD_RETURN:
2260 			case VK_RETURN:
2261 				DelMarked();
2262 				Enter();
2263 				break;
2264 
2265 			case VK_INSERT:
2266 				if ( shift )
2267 				{
2268 					DelMarked();
2269 					FromClipboard();
2270 					return true;
2271 				}
2272 
2273 				if ( ctrl ) { ToClipboard(); return true; }
2274 
2275 				break;
2276 
2277 			default:
2278 				if ( ctrl && pEvent->Key() == VK_A ) { SelectAll(); break; }
2279 
2280 				if ( pEvent->Char() == '\t' || pEvent->Char() >= ' ' )
2281 				{
2282 					DelMarked();
2283 					InsChar( pEvent->Char() );
2284 					return true;
2285 				}
2286 
2287 				return false;
2288 		};
2289 
2290 		return true;
2291 	}
2292 
2293 	return false;
2294 }
2295 
EventSize(cevent_size * pEvent)2296 void EditWin::EventSize( cevent_size* pEvent )
2297 {
2298 	Win::EventSize( pEvent );
2299 	rows = editRect.Height() / charH;
2300 	cols = editRect.Width() / charW;
2301 
2302 	if ( rows <= 0 ) { rows = 1; }
2303 
2304 	if ( cols <= 0 ) { cols = 1; }
2305 
2306 	CalcScroll();
2307 
2308 	{
2309 		int r = ( editRect.Height() + charH - 1 ) / charH;
2310 		int c = ( editRect.Width() + charW - 1 ) / charW;
2311 		screen.Alloc( r, c );
2312 		__RefreshScreenData();
2313 		Invalidate();
2314 	}
2315 }
2316 
2317 
GetColFromPos(int line,int pos)2318 int EditWin::GetColFromPos( int line, int pos )
2319 {
2320 	if ( line < 0 || line >= text.Count() ) { return 0; }
2321 
2322 	EditString& str = text.Get( line );
2323 
2324 	char* s = str.Get(), *end = s + str.Len();
2325 
2326 	bool tab = charset->IsTab( s, end );
2327 	int col = 0;
2328 
2329 	while ( s )
2330 	{
2331 		if ( pos <= 0 ) { break; }
2332 
2333 		col += tab ? tabSize - col % tabSize : 1;
2334 		char* t = charset->GetNext( s, end );
2335 		tab = charset->IsTab( t, end );
2336 
2337 		if ( t ) { pos -= t - s; }
2338 
2339 		s = t;
2340 	}
2341 
2342 	return col;
2343 }
2344 
2345 
GetPosFromCol(int line,int nCol)2346 int EditWin::GetPosFromCol( int line, int nCol )
2347 {
2348 	if ( line < 0 || line >= text.Count() ) { return 0; }
2349 
2350 	EditString& str = text.Get( line );
2351 
2352 	char* s = str.Get(), *end = s + str.Len();
2353 
2354 	bool tab = charset->IsTab( s, end );
2355 
2356 	int pos = 0, col = 0;
2357 
2358 	while ( s )
2359 	{
2360 		int step = ( tab ? tabSize - ( col % tabSize ) : 1 );
2361 
2362 		if ( step > nCol - col )
2363 		{
2364 			break;
2365 		}
2366 
2367 		col += step;
2368 		char* t = charset->GetNext( s, end );
2369 		tab = charset->IsTab( t, end );
2370 
2371 		if ( t )
2372 		{
2373 			pos += t - s;
2374 		}
2375 		else
2376 		{
2377 			pos = str.Len();
2378 		}
2379 
2380 		s = t;
2381 	}
2382 
2383 	return pos;
2384 }
2385 
SetCursor(cpoint p,bool mark)2386 void EditWin::SetCursor( cpoint p, bool mark )
2387 {
2388 	int r = ( p.y - editRect.top ) / charH;
2389 	int c = ( p.x - editRect.left ) / charW;
2390 	r += firstLine;
2391 	c += colOffset;
2392 
2393 	if ( p.y < 0 ) { r--; }
2394 
2395 	if ( p.x < 0 ) { c--; }
2396 
2397 	int line = r;
2398 
2399 	if ( line >= text.Count() ) { line = text.Count() - 1; }
2400 
2401 	if ( line < 0 ) { line = 0; }
2402 
2403 //	EditString& str = text.Get( line );
2404 	int pos = GetPosFromCol( line, c );
2405 	cursor.Set( line, pos );
2406 
2407 	if ( !mark ) { marker = cursor; }
2408 
2409 	CursorToScreen();
2410 	SendChanges();
2411 	Refresh();
2412 }
2413 
2414 
EventTimer(int id)2415 void EditWin::EventTimer( int id )
2416 {
2417 	if ( id == 0 )
2418 	{
2419 		wal::GC gc( this );
2420 		DrawCursor( gc );
2421 		return;
2422 	}
2423 
2424 	SetCursor( lastMousePoint, true );
2425 }
2426 
2427 
EventMouse(cevent_mouse * pEvent)2428 bool EditWin::EventMouse( cevent_mouse* pEvent )
2429 {
2430 	lastMousePoint = pEvent->Point();
2431 
2432 	switch ( pEvent->Type() )
2433 	{
2434 		case EV_MOUSE_MOVE:
2435 			if ( IsCaptured() )
2436 			{
2437 				SetCursor( lastMousePoint, true );
2438 			}
2439 
2440 			break;
2441 
2442 		case EV_MOUSE_PRESS:
2443 		{
2444 			if ( pEvent->Button() == MB_X1 )
2445 			{
2446 				PageUp( false );
2447 				break;
2448 			}
2449 
2450 			if ( pEvent->Button() == MB_X2 )
2451 			{
2452 				PageDown( false );
2453 				break;
2454 			}
2455 
2456 			if ( pEvent->Button() != MB_L )
2457 			{
2458 				break;
2459 			}
2460 
2461 			SetCapture();
2462 			SetCursor( lastMousePoint, false );
2463 
2464 			SetTimer( 1, 100 );
2465 		}
2466 		break;
2467 
2468 
2469 		case EV_MOUSE_RELEASE:
2470 			if ( pEvent->Button() != MB_L )
2471 			{
2472 				break;
2473 			}
2474 
2475 			DelTimer( 1 );
2476 
2477 			ReleaseCapture();
2478 			break;
2479 	};
2480 
2481 	return false;
2482 }
2483 
Search(const unicode_t * arg,bool sens)2484 bool EditWin::Search( const unicode_t* arg, bool sens )
2485 {
2486 	std::vector<unicode_t> search = new_unicode_str( arg );
2487 
2488 	if ( !sens )
2489 		for ( unicode_t* u = search.data(); *u; u++ ) { *u = UnicodeLC( *u ); }
2490 
2491 	int line =  cursor.line;
2492 
2493 	EditString& str = text.Get( line );
2494 	char* begin = str.Get(), *end = begin + str.Len();
2495 	char* s = begin + cursor.pos;
2496 
2497 	//bool tab;
2498 	if ( s < end )
2499 	{
2500 		s = charset->GetNext( s, end );
2501 	}
2502 
2503 	while ( true )
2504 	{
2505 		while ( s )
2506 		{
2507 			const unicode_t* sPtr = search.data();
2508 
2509 			for ( char* p = s; ; p = charset->GetNext( p, end ), sPtr++ )
2510 			{
2511 				if ( !*sPtr )
2512 				{
2513 					cursor.Set( line, s - begin );
2514 					marker = cursor;
2515 					CursorToScreen();
2516 					SendChanges();
2517 					Refresh();
2518 					return true;
2519 				}
2520 
2521 				if ( !p ) { break; }
2522 
2523 				unicode_t c = charset->GetChar( p, end );
2524 
2525 				if ( sens )
2526 				{
2527 					if ( c != *sPtr ) { break; }
2528 				}
2529 				else
2530 				{
2531 					if ( UnicodeLC( c ) != *sPtr ) { break; }
2532 				}
2533 			}
2534 
2535 			s = charset->GetNext( s, end );
2536 		}
2537 
2538 		line++;
2539 
2540 		if ( line >= text.Count() ) { break; }
2541 
2542 		EditString& str = text.Get( line );
2543 		s = begin = str.Get();
2544 		end = begin + str.Len();
2545 	}
2546 
2547 	return false;
2548 }
2549 
2550 #define CMD_REPLACE 1000
2551 #define CMD_ALL 1001
2552 #define CMD_SKIP 1002
2553 
2554 static ButtonDataNode bReplaceAllSkipCancel[] = { {"&Replace", CMD_REPLACE}, { "&All", CMD_ALL}, { "&Skip", CMD_SKIP}, {"&Cancel", CMD_CANCEL}, {0, 0}};
2555 
Replace(const unicode_t * from,const unicode_t * to,bool sens)2556 bool EditWin::Replace( const unicode_t* from, const unicode_t* to, bool sens )
2557 {
2558 	std::vector<unicode_t> search = new_unicode_str( from );
2559 
2560 	if ( !sens )
2561 		for ( unicode_t* u = search.data(); *u; u++ ) { *u = UnicodeLC( *u ); }
2562 
2563 	ccollect<char> rep;
2564 	charset_struct* cs = charset;
2565 
2566 	for ( ; *to; to++ )
2567 	{
2568 		char buf[32];
2569 		int n = cs->SetChar( buf, *to );
2570 
2571 		for ( int i = 0; i < n; i++ )
2572 		{
2573 			rep.append( buf[i] );
2574 		}
2575 	}
2576 
2577 	int line =  cursor.line;
2578 
2579 	EditString& str = text.Get( line );
2580 	char* begin = str.Get(), *end = begin + str.Len();
2581 	char* s = begin + cursor.pos;
2582 
2583 	if ( s < end )
2584 	{
2585 		s = charset->GetNext( s, end );
2586 	}
2587 
2588 	bool all = false;
2589 	int foundCount = 0;
2590 
2591 	clPtr<UndoBlock> undoBlock = new UndoBlock( false, _changed );
2592 	undoBlock->SetBeginPos( cursor, marker );
2593 
2594 	try
2595 	{
2596 		while ( true )
2597 		{
2598 			while ( s )
2599 			{
2600 
2601 restart:
2602 
2603 				const unicode_t* sPtr = search.data();
2604 
2605 				for ( char* p = s; ; p = charset->GetNext( p, end ), sPtr++ )
2606 				{
2607 					if ( !*sPtr )
2608 					{
2609 						char* blockEnd = ( p ? p : end );
2610 
2611 						foundCount++;
2612 
2613 						if ( !all )
2614 						{
2615 							marker.Set( line, s - begin );
2616 							cursor.Set( line, blockEnd - begin );
2617 							CursorToScreen_forReplace();
2618 							SendChanges();
2619 							Refresh();
2620 
2621 							int ret = NCMessageBox( ( NCDialogParent* )Parent(), _LT( "Replace" ), _LT( "Replace it?" ), false, bReplaceAllSkipCancel );
2622 
2623 							if ( ret == CMD_ALL ) { all = true; }
2624 
2625 							if ( ret == CMD_SKIP ) { continue; }
2626 
2627 							if ( ret != CMD_ALL && ret != CMD_REPLACE )
2628 							{
2629 								marker = cursor;
2630 
2631 								//!!
2632 								undoBlock->SetEndPos( cursor, marker );
2633 								undoList.Append( undoBlock );
2634 
2635 								CursorToScreen();
2636 								SendChanges();
2637 								Refresh();
2638 								return true;
2639 							}
2640 						}
2641 
2642 						{
2643 							//replace
2644 							int pos = s - begin;
2645 							int size = blockEnd - s;
2646 							SetChanged( line );
2647 
2648 							EditString& str = text.Get( line );
2649 
2650 							undoBlock->DelText( line, pos, str.Get() + pos, size );
2651 							str.Delete( pos, size );
2652 
2653 							if ( rep.count() > 0 )
2654 							{
2655 								str.Insert( rep.ptr(), pos, rep.count() );
2656 								undoBlock->InsText( line, pos, rep.ptr(), rep.count() );
2657 							}
2658 
2659 							begin = str.Get();
2660 							end = begin + str.Len();
2661 							s = begin + pos + rep.count();
2662 
2663 							cursor.Set( line, s - begin );
2664 							marker = cursor;
2665 
2666 							if ( !p ) { break; }
2667 
2668 							goto restart;
2669 						}
2670 					}
2671 
2672 					if ( !p ) { break; }
2673 
2674 					unicode_t c = charset->GetChar( p, end );
2675 
2676 					if ( sens )
2677 					{
2678 						if ( c != *sPtr ) { break; }
2679 					}
2680 					else
2681 					{
2682 						if ( UnicodeLC( c ) != *sPtr ) { break; }
2683 					}
2684 				}
2685 
2686 				s = charset->GetNext( s, end );
2687 			}
2688 
2689 			line++;
2690 
2691 			if ( line >= text.Count() ) { break; }
2692 
2693 			EditString& str = text.Get( line );
2694 			s = begin = str.Get();
2695 			end = begin + str.Len();
2696 		}
2697 
2698 		marker = cursor;
2699 
2700 		undoBlock->SetEndPos( cursor, marker );
2701 		undoList.Append( undoBlock );
2702 
2703 		CursorToScreen();
2704 		SendChanges();
2705 		Refresh();
2706 
2707 	}
2708 	catch ( ... )
2709 	{
2710 		undoList.Clear();
2711 		throw;
2712 	}
2713 
2714 	return foundCount > 0;
2715 }
2716 
2717 
~EditWin()2718 EditWin::~EditWin()
2719 {
2720 	DelTimer( 0 );
2721 }
2722 
2723 
2724