1 /*
2  * Part of WCM Commander
3  * https://github.com/corporateshark/WCMCommander
4  * wcm@linderdaum.com
5  */
6 
7 #include "globals.h"
8 #include "nc.h"
9 #include "ncfonts.h"
10 #include "ncdialogs.h"
11 #include "wcm-config.h"
12 #include "string-util.h"
13 #include "ltext.h"
14 #include "unicode_lc.h"
15 #include "panel.h"
16 #include "nceditline.h"
17 
18 bool createDialogAsChild //= false;
19    = true;
20 
NCShadowWin(Win * parent)21 NCShadowWin::NCShadowWin( Win* parent )
22 	: Win( Win::WT_CHILD, 0, parent ) //, &crect(0,0,300,100))
23 {
24 
25 }
26 
27 
Paint(wal::GC & gc,const crect & paintRect)28 void NCShadowWin::Paint( wal::GC& gc, const crect& paintRect )
29 {
30 	crect cr = ClientRect();
31 	gc.SetFillColor( 0 ); //::g_WcmConfig.whiteStyle ? 0x404040 : 0x01);
32 	gc.FillRect( cr );
33 }
34 
~NCShadowWin()35 NCShadowWin::~NCShadowWin() {}
36 
37 
CloseDialog(int cmd)38 void NCDialog::CloseDialog( int cmd )
39 {
40 	EndModal( cmd );
41 }
42 
OnCancel()43 void NCDialog::OnCancel()
44 {
45 	CloseDialog( CMD_CANCEL );
46 }
47 
48 
GetChildFont(Win * w,int fontId)49 cfont* NCDialog::GetChildFont( Win* w, int fontId )
50 {
51 	return g_DialogFont.ptr();
52 }
53 
Command(int id,int subId,Win * win,void * data)54 bool NCDialog::Command( int id, int subId, Win* win, void* data )
55 {
56 	if ( id && win && win->UiGetClassId() == uiClassButton )
57 	{
58 		if ( id == CMD_CANCEL )
59 		{
60 			OnCancel();
61 		}
62 		else
63 		{
64 			CloseDialog( id );
65 		}
66 
67 		return true;
68 	}
69 
70 	return false;
71 }
72 
73 int uiClassNCDialog = GetUiID( "NCDialog" );
74 
UiGetClassId()75 int NCDialog::UiGetClassId()
76 {
77 	return m_nId;
78 //	return uiClassNCDialog;
79 }
80 
NCDialog(bool asChild,int nId,NCDialogParent * parent,const unicode_t * headerText,ButtonDataNode * blist)81 NCDialog::NCDialog( bool asChild, int nId, NCDialogParent* parent, const unicode_t* headerText, ButtonDataNode* blist ) //, unsigned bcolor, unsigned fcolor)
82 	: OperThreadWin( asChild ? Win::WT_CHILD : WT_MAIN /*WT_POPUP*/, 0, nId, parent ), //, &crect(0,0,300,100)),
83 	  _shadow( parent ),
84 //	_fcolor(fcolor),
85 //	_bcolor(bcolor),
86 	  _header( nId, this, headerText ),
87 	  _lo( 9, 9 ),
88 	  _buttonLo( 3, 16 ),
89 	  _headerLo( 3, 3 ),
90 	  _parentLo( 3, 3 ),
91 	  enterCmd( 0 ),
92 	  m_nId( nId )
93 {
94 	Enable();
95 
96 	_lo.SetLineGrowth( 4 );
97 	_lo.SetColGrowth( 4 );
98 
99 
100 	_lo.ColSet( 0, 2 );
101 	_lo.ColSet( 1, 10 );
102 	_lo.ColSet( 2, 3 );
103 
104 	_lo.ColSet( 3, 5 );
105 	_lo.ColSet( 5, 5 );
106 
107 	_lo.ColSet( 6, 3 );
108 	_lo.ColSet( 7, 10 );
109 	_lo.ColSet( 8, 2 );
110 
111 	_lo.LineSet( 0, 2 );
112 	_lo.LineSet( 1, 10 );
113 	_lo.LineSet( 2, 3 );
114 
115 	_lo.LineSet( 3, 3 );
116 	//_lo.LineSet(5, 5);
117 
118 	_lo.LineSet( 6, 3 );
119 	_lo.LineSet( 7, 5 );
120 	_lo.LineSet( 8, 2 );
121 
122 	_lo.ColSet( 4, 16, 100000 );
123 	_lo.LineSet( 4, 16, 100000 );
124 
125 	_lo.AddRect( &_borderRect, 0, 0, 8, 8 );
126 	_lo.AddRect( &_frameRect, 2, 2, 6, 6 );
127 
128 	_headerLo.ColSet( 0, 1, 1000 );
129 	_headerLo.ColSet( 2, 1, 1000 );
130 	_headerLo.LineSet( 0, 2 );
131 	_headerLo.LineSet( 2, 2 );
132 	_headerLo.AddWin( &_header, 1, 1 );
133 	_lo.AddLayout( &_headerLo, 1, 4 );
134 
135 	_buttonLo.ColSet( 0, 10, 1000 );
136 	_buttonLo.ColSet( 15, 10, 1000 );
137 	_buttonLo.LineSet( 0, 2 );
138 	_buttonLo.LineSet( 2, 2 );
139 
140 	_parentLo.ColSet( 0, 20, 1000 );
141 	_parentLo.ColSet( 2, 20, 1000 );
142 	_parentLo.LineSet( 0, 20, 1000 );
143 	_parentLo.LineSet( 2, 20, 1000 );
144 	_parentLo.AddWin( this, 1, 1 );
145 
146 	_parentLo.SetLineGrowth( 0 );
147 	_parentLo.SetLineGrowth( 2 );
148 
149 	_parentLo.SetColGrowth( 0 );
150 	_parentLo.SetColGrowth( 2 );
151 
152 	if ( blist )
153 	{
154 		int n = 0;
155 		int minW = 0;
156 
157 		for ( ; blist->utf8text && n < 7; blist++, n++ )
158 		{
159 
160 			clPtr<Button> p = new Button( 0, this, utf8_to_unicode( _LT( carray_cat<char>( "DB>", blist->utf8text ).data(), blist->utf8text ) ).data(), blist->cmd );
161 
162 			p->Show();
163 			p->Enable();
164 
165 			if ( n > 0 )
166 			{
167 				_buttonLo.ColSet( n * 2, 5 );
168 			}
169 
170 			_buttonLo.AddWin( p.ptr(), 1, n * 2 + 1 );
171 
172 			if ( minW < p->GetLSize().x.minimal )
173 			{
174 				minW = p->GetLSize().x.minimal;
175 			}
176 
177 			_bList.append( p );
178 //break; ???
179 
180 		}
181 
182 		if ( minW > 0 )
183 			for ( int i = 0; i < _bList.count(); i++ )
184 			{
185 				LSize s = _bList[i]->GetLSize();
186 				s.x.minimal = s.x.maximal = minW;
187 				_bList[i]->SetLSize( s );
188 			};
189 
190 		if ( _bList.count() )
191 		{
192 			_bList[0]->SetFocus();
193 		}
194 
195 	}
196 
197 	_lo.AddLayout( &_buttonLo, 5, 4 );
198 
199 	_header.Enable();
200 	_header.Show();
201 
202 	SetLayout( &_lo );
203 
204 	if ( Type() == WT_CHILD && parent )
205 	{
206 		parent->AddLayout( &_parentLo );
207 	}
208 
209 
210 	SetPosition();
211 
212 	SetName( appName );
213 }
214 
GetDownButton()215 Win* NCDialog::GetDownButton()
216 {
217 	return _bList.count() > 0 ? _bList[0].ptr() : 0;
218 }
219 
220 
MaximizeIfChild(bool x,bool y)221 void NCDialog::MaximizeIfChild( bool x, bool y )
222 {
223 	if ( Type() == WT_CHILD && Parent() )
224 	{
225 		_parentLo.SetLineGrowth( 0, !y );
226 		_parentLo.SetLineGrowth( 2, !y );
227 		_parentLo.SetLineGrowth( 1, y );
228 		_parentLo.SetColGrowth( 0, !x );
229 		_parentLo.SetColGrowth( 2, !x );
230 		_parentLo.SetColGrowth( 1, x );
231 		Parent()->RecalcLayouts();
232 	}
233 }
234 
SetPosition()235 void NCDialog::SetPosition()
236 {
237 
238 	if ( Type() == WT_CHILD )
239 	{
240 		LSize ls = _lo.GetLSize();
241 //		ls.x.maximal = ls.x.minimal;
242 //		ls.y.maximal = ls.y.minimal;
243 		SetLSize( ls );
244 
245 		if ( Parent() )
246 		{
247 			Parent()->RecalcLayouts();
248 		}
249 
250 		return;
251 	}
252 
253 
254 	LSize ls = _lo.GetLSize();
255 
256 	crect r = Rect();
257 
258 	int w =  ls.x.ideal > 0 ? ls.x.ideal : 20;
259 	int h =  ls.y.ideal > 0 ? ls.y.ideal : 20;
260 
261 	r.right  = r.left + w;
262 	r.bottom = r.top + h;
263 
264 	Win* parent = Parent();
265 
266 	if ( parent )
267 	{
268 		crect pr = parent->Rect();
269 
270 		int w = r.Width();
271 		int h = r.Height();
272 
273 		int dx = ( pr.Width() - w ) / 2;
274 		int dy = ( pr.Height() - h ) / 2;
275 
276 
277 		r.left = pr.left + dx;
278 		r.right = r.left + w;
279 		r.top  = pr.top  + dy;
280 		r.bottom = r.top + h;
281 
282 	}
283 
284 	Move( r );
285 }
286 
EventClose()287 bool NCDialog::EventClose()
288 {
289 	CloseDialog( CMD_CANCEL );
290 	return false;
291 }
292 
EventSize(cevent_size * pEvent)293 void NCDialog::EventSize( cevent_size* pEvent )
294 {
295 	if ( Type() == WT_CHILD && Parent() )
296 	{
297 		SetPosition();
298 		crect r = Rect();
299 		r.left += 10;
300 		r.top += 10;
301 		r.right += 10;
302 		r.bottom += 10;
303 
304 		if ( r != _shadow.Rect() ) { _shadow.Move( r ); }
305 
306 	}
307 
308 	Win::EventSize( pEvent );
309 }
310 
311 
EventMove(cevent_move * pEvent)312 void NCDialog::EventMove( cevent_move* pEvent )
313 {
314 	if ( Type() == WT_CHILD && Parent() )
315 	{
316 		SetPosition();
317 		crect r = Rect();
318 		r.left += 10;
319 		r.top += 10;
320 		r.right += 10;
321 		r.bottom += 10;
322 
323 		if ( r != _shadow.Rect() ) { _shadow.Move( r ); }
324 
325 	}
326 
327 	Win::EventMove( pEvent );
328 }
329 
330 
EventKey(cevent_key * pEvent)331 bool NCDialog::EventKey( cevent_key* pEvent )
332 {
333 	if ( pEvent->Type() == EV_KEYDOWN && pEvent->Key() == VK_ESCAPE )
334 	{
335 		OnCancel();
336 		return true;
337 	};
338 
339 	return Win::EventKey( pEvent );
340 }
341 
GetFocusButtonNum()342 int NCDialog::GetFocusButtonNum()
343 {
344 	for ( int i = 0; i < _bList.count(); i++ )
345 		if ( _bList[i]->InFocus() ) { return i; }
346 
347 	return -1;
348 }
349 
EventChildKey(Win * child,cevent_key * pEvent)350 bool NCDialog::EventChildKey( Win* child, cevent_key* pEvent )
351 {
352 	if ( pEvent->Type() == EV_KEYDOWN )
353 	{
354 		//dbg_printf("key=0x%x\n",pEvent->Key());
355 		if ( pEvent->Key() == VK_ESCAPE )
356 		{
357 			OnCancel();
358 			return true;
359 		}
360 
361 		if ( pEvent->Key() == VK_TAB )
362 		{
363 			if ( ( pEvent->Mod() & KM_SHIFT ) != 0 )
364 			{
365 				FocusPrevChild();
366 			}
367 			else
368 			{
369 				FocusNextChild();
370 			}
371 
372 			return true;
373 		}
374 
375 // on UNIX shift-tab gives XK_ISO_Left_Tab
376 #ifdef XK_ISO_Left_Tab
377 		else if ( pEvent->Key() == XK_ISO_Left_Tab )
378 		{
379 			FocusPrevChild();
380 			return true;
381 		}
382 
383 #endif // XK_ISO_Left_Tab
384 		else if ( pEvent->Key() == VK_RETURN || pEvent->Key() == VK_NUMPAD_RETURN )
385 		{
386 			if ( enterCmd && GetFocusButtonNum() < 0 )
387 			{
388 				CloseDialog( enterCmd );
389 				return true;
390 			}
391 		}
392 		else if ( pEvent->Key() == VK_LEFT || pEvent->Key() == VK_RIGHT )
393 		{
394 			int i = GetFocusButtonNum();
395 
396 			if ( i >= 0 )
397 			{
398 				int n;
399 
400 				if ( pEvent->Key() == VK_LEFT )
401 				{
402 					n = i ? i - 1 : _bList.count() - 1;
403 				}
404 				else
405 				{
406 					n = ( ( i + 1 ) % _bList.count() );
407 				}
408 
409 				if ( n != i )
410 				{
411 					_bList[n]->SetFocus();
412 				}
413 
414 				return true;
415 			}
416 		}
417 
418 	};
419 
420 	return Win::EventChildKey( child, pEvent );
421 }
422 
423 //namespace wal {
424 //extern Display* display;
425 //};
426 
EventShow(bool show)427 bool NCDialog::EventShow( bool show )
428 {
429 	if ( show && Type() == WT_CHILD && Parent() )
430 	{
431 		SetPosition();
432 		crect r = Rect();
433 		_shadow.Move( crect( r.left + 10, r.top + 10, 10 + r.right, 10 + r.bottom ) );
434 		_shadow.Show( SHOW_INACTIVE );
435 		_shadow.OnTop();
436 	}
437 
438 	OnTop();
439 	SetFocus();
440 
441 	return Win::EventShow( show );
442 }
443 
444 
Paint(wal::GC & gc,const crect & paintRect)445 void NCDialog::Paint( wal::GC& gc, const crect& paintRect )
446 {
447 	int bcolor = UiGetColor( uiBackground, 0, 0, 0x808080 );
448 
449 	gc.SetFillColor( bcolor );
450 	gc.FillRect( _borderRect );
451 	Draw3DButtonW2( gc, _borderRect, bcolor, true );
452 	crect rect = _frameRect;
453 	Draw3DButtonW2( gc, _frameRect, bcolor, false );
454 	rect.Dec();
455 	rect.Dec();
456 	DrawBorder( gc, rect, 0 );
457 }
458 
459 
~NCDialog()460 NCDialog::~NCDialog()
461 {
462 	if ( Type() == WT_CHILD && Parent() )
463 	{
464 		( ( NCDialogParent* )Parent() )->DeleteLayout( &_parentLo );
465 	}
466 }
467 
468 /////////////////////////////////// NCVertDialog
469 
EventChildKey(Win * child,cevent_key * pEvent)470 bool NCVertDialog::EventChildKey( Win* child, cevent_key* pEvent )
471 {
472     // try to preprocess key combinations like Cntrl + VK_DOWN
473     if ( dynamic_cast<ComboBox*>(child) && child->EventKey(pEvent) )
474     {
475         return true;
476     }
477 
478 	if ( pEvent->Type() == EV_KEYDOWN )
479 	{
480 		if ( pEvent->Key() == VK_UP || pEvent->Key() == VK_DOWN )
481 		{
482 			int n = -1;
483 			int count = order.count();
484 			Win* button = GetDownButton();
485 
486 			if ( button ) { count++; }
487 
488 			for ( int i = 0; i < order.count(); i++ ) if ( order[i]->InFocus() ) { n = i; break; }
489 
490 			if ( pEvent->Key() == VK_UP )
491 			{
492 				n = ( n + count - 1 ) % count;
493 			}
494 			else if ( pEvent->Key() == VK_DOWN )
495 			{
496 				n = ( n + 1 ) % count;
497 			}
498 
499 			if ( n >= 0 && n < order.count() )
500 			{
501 				order[n]->SetFocus();
502 			}
503 			else if ( button ) { button->SetFocus(); }
504 
505 			return true;
506 		}
507 	}
508 
509     return NCDialog::EventChildKey( child, pEvent );
510 }
511 
512 
~NCVertDialog()513 NCVertDialog::~NCVertDialog() {}
514 
515 /*
516    //for ltext
517    _LT("DB>Ok")
518    _LT("DB>Cancel")
519    _LT("DB>Yes")
520    _LT("DB>No")
521 */
522 
523 char OkButtonText[] = "O&k";
524 char CancelButtonText[] = "&Cancel";
525 char PanelButtonText[] = "&Panel";
526 char YesButtonText[] = "&Yes";
527 char NoButtonText[] = "&No";
528 
529 ButtonDataNode bListOk[] = { {OkButtonText, CMD_OK}, {0, 0}};
530 ButtonDataNode bListCancel[] = { {CancelButtonText, CMD_CANCEL}, {0, 0}};
531 ButtonDataNode bListOkCancel[] = { {OkButtonText, CMD_OK}, {CancelButtonText, CMD_CANCEL}, {0, 0}};
532 ButtonDataNode bListOkCancelPanel[] = { { OkButtonText, CMD_OK }, { CancelButtonText, CMD_CANCEL }, { PanelButtonText, CMD_PUT_RESULTS_TO_TEMP_PANEL }, { 0, 0 } };
533 ButtonDataNode bListYesNoCancel[] = { {YesButtonText, CMD_YES}, {NoButtonText, CMD_NO}, {CancelButtonText, CMD_CANCEL}, {0, 0}};
534 
535 char cmdKillTxt[] = " kill ";
536 char cmdKill9Txt[] = " kill -9 ";
537 
538 ButtonDataNode bListKill[] = { {CancelButtonText, CMD_CANCEL}, {cmdKillTxt, CMD_KILL}, {cmdKill9Txt, CMD_KILL_9}, {0, 0}};
539 
540 int uiNCMessageBox = GetUiID( "messagebox" );
541 int uiNCRedMessageBox = GetUiID( "messagebox-red" );
542 
NCMessageBox(NCDialogParent * parent,const char * utf8head,const char * utf8txt,bool red,ButtonDataNode * buttonList)543 int NCMessageBox( NCDialogParent* parent, const char* utf8head, const char* utf8txt, bool red, ButtonDataNode* buttonList )
544 {
545 	std::vector<unicode_t> str = utf8_to_unicode( utf8txt );
546 	ccollect<unicode_t> buf;
547 
548 	unicode_t* s = str.data();
549 	int lLine = 0;
550 
551 	for ( ; *s; s++ )
552 	{
553 		if ( lLine > 100 )
554 		{
555 			buf.append( '\n' );
556 			lLine = 0;
557 		}
558 
559 		if ( *s == '\n' )
560 		{
561 			lLine = 0;
562 		}
563 
564 		buf.append( *s );
565 		lLine++;
566 	}
567 
568 	buf.append( 0 );
569 
570 
571 	NCDialog d( ::createDialogAsChild, red ? uiNCRedMessageBox : uiNCMessageBox, parent, utf8_to_unicode( utf8head ).data(), buttonList ); //, red ? 0xFF:0xD8E9EC, red ? 0xFFFFFF :0x1);
572 	StaticLine text( 0, &d, buf.ptr() );
573 
574 	text.Show();
575 	text.Enable();
576 	Layout lo( 3, 3 );
577 	lo.LineSet( 0, 5 );
578 	lo.LineSet( 2, 5 );
579 	lo.ColSet( 0, 15 );
580 	lo.ColSet( 2, 15 );
581 	lo.AddWin( &text, 1, 1 );
582 	d.AddLayout( &lo );
583 
584 	d.SetPosition();
585 	return d.DoModal();
586 }
587 
588 
589 class GoToDialog: public NCVertDialog
590 {
591 	EditLine edit;
592 public:
GoToDialog(int nId,NCDialogParent * parent)593 	GoToDialog( int nId, NCDialogParent* parent )
594 		:  NCVertDialog( ::createDialogAsChild, nId, parent, utf8_to_unicode( "Go to line" ).data(), bListOkCancel ), //0xD8E9EC, 0),
595 		   edit( 0, ( Win* )this, 0, 0 )
596 	{
597 		edit.Enable();
598 		edit.Show();
599 		AddWin( &edit );
600 		order.append( &edit );
601 		edit.SetFocus();
602 		SetPosition();
603 	}
604 
GetText()605 	std::vector<unicode_t> GetText() { return edit.GetText(); };
606 
607 	virtual ~GoToDialog();
608 };
609 
~GoToDialog()610 GoToDialog::~GoToDialog() {}
611 
612 
GoToLineDialog(NCDialogParent * parent)613 int GoToLineDialog( NCDialogParent* parent )
614 {
615 	GoToDialog d( 0, parent );
616 	d.SetEnterCmd( CMD_OK );
617 	int r = d.DoModal();
618 
619 	if ( r != CMD_OK ) { return -1; }
620 
621 	std::vector<unicode_t> str = d.GetText();
622 	int n = 0;
623 	unicode_t* s = str.data();
624 
625 	while ( *s == ' ' ) { s++; }
626 
627 	for ( ; *s >= '0' && *s <= '9'; s++ )
628 	{
629 		n = n * 10 + *s - '0';
630 	}
631 
632 	return n;
633 }
634 
635 class clInputStrDialogBase : public NCVertDialog
636 {
637 public:
clInputStrDialogBase(NCDialogParent * Parent,const unicode_t * Message)638 	clInputStrDialogBase( NCDialogParent* Parent, const unicode_t* Message )
639 		: NCVertDialog( ::createDialogAsChild, 0, Parent, Message, bListOkCancel )
640 	{
641 	}
~clInputStrDialogBase()642 	virtual ~clInputStrDialogBase() {}
643 
644 	virtual std::vector<unicode_t> GetText() const = 0;
645 
646 	virtual std::vector<unicode_t> ShowDialog();
647 };
648 
ShowDialog()649 std::vector<unicode_t> clInputStrDialogBase::ShowDialog()
650 {
651 	SetEnterCmd( CMD_OK );
652 
653 	if ( DoModal() != CMD_OK )
654 	{
655 		return std::vector<unicode_t>();
656 	}
657 
658 	return GetText();
659 }
660 
661 
662 class clInputStrDialog : public clInputStrDialogBase
663 {
664 private:
665 	EditLine m_StrEdit;
666 
667 public:
clInputStrDialog(NCDialogParent * Parent,const unicode_t * Message,const unicode_t * Str)668 	clInputStrDialog( NCDialogParent* Parent, const unicode_t* Message, const unicode_t* Str )
669 		: clInputStrDialogBase( Parent, Message )
670 		, m_StrEdit( 0, (Win*) this, 0, 0, 100 )
671 	{
672 		m_StrEdit.Enable();
673 		m_StrEdit.Show();
674 		AddWin( &m_StrEdit );
675 		order.append( &m_StrEdit );
676 
677 		if ( Str )
678 		{
679 			m_StrEdit.SetText( Str, true );
680 		}
681 
682 		m_StrEdit.SetFocus();
683 		SetPosition();
684 	}
~clInputStrDialog()685 	virtual ~clInputStrDialog() {}
686 
GetText() const687 	virtual std::vector<unicode_t> GetText() const override
688 	{
689 		return m_StrEdit.GetText();
690 	}
691 };
692 
693 
694 class clInputFieldDialog : public clInputStrDialogBase
695 {
696 private:
697 	clNCEditLine m_FieldEdit;
698 
699 public:
clInputFieldDialog(const char * FieldName,NCDialogParent * Parent,const unicode_t * Message,const unicode_t * Str)700 	clInputFieldDialog( const char* FieldName, NCDialogParent* Parent, const unicode_t* Message, const unicode_t* Str )
701 		: clInputStrDialogBase( Parent, Message )
702 		, m_FieldEdit( FieldName, 0, (Win*)this, 0, 100, 7 )
703 	{
704 		m_FieldEdit.Enable();
705 		m_FieldEdit.Show();
706 		AddWin( &m_FieldEdit );
707 		order.append( &m_FieldEdit );
708 
709 		if ( Str )
710 		{
711 			m_FieldEdit.SetText( Str, true );
712 		}
713 
714 		m_FieldEdit.SetFocus();
715 		SetPosition();
716 	}
~clInputFieldDialog()717 	virtual ~clInputFieldDialog() {}
718 
GetText() const719 	virtual std::vector<unicode_t> GetText() const override
720 	{
721 		return m_FieldEdit.GetText();
722 	}
723 
ShowDialog()724 	virtual std::vector<unicode_t> ShowDialog() override
725 	{
726 		std::vector<unicode_t> Res = clInputStrDialogBase::ShowDialog();
727 		if ( Res.size() > 0 )
728 		{
729 			m_FieldEdit.AddCurrentTextToHistory();
730 		}
731 
732 		return Res;
733 	}
734 };
735 
736 
InputStringDialog(NCDialogParent * Parent,const unicode_t * Message,const unicode_t * Str)737 std::vector<unicode_t> InputStringDialog( NCDialogParent* Parent, const unicode_t* Message, const unicode_t* Str )
738 {
739 	return InputStringDialog( nullptr, Parent, Message, Str );
740 }
741 
InputStringDialog(const char * FieldName,NCDialogParent * Parent,const unicode_t * Message,const unicode_t * Str)742 std::vector<unicode_t> InputStringDialog( const char* FieldName, NCDialogParent* Parent, const unicode_t* Message, const unicode_t* Str )
743 {
744 	if ( !FieldName )
745 	{
746 		clInputStrDialog Dlg( Parent, Message, Str );
747 		return Dlg.ShowDialog();
748 	}
749 
750 	clInputFieldDialog Dlg( FieldName, Parent, Message, Str );
751 	return Dlg.ShowDialog();
752 }
753 
754 int uiKillCmdDialog = GetUiID( "KillCmdDialog" );
755 
KillCmdDialog(NCDialogParent * parent,const unicode_t * cmd)756 int KillCmdDialog( NCDialogParent* parent, const unicode_t* cmd )
757 {
758 	NCDialog d( ::createDialogAsChild, uiKillCmdDialog, parent, utf8_to_unicode( "Kill command" ).data(), bListKill ); //,  0xD8E9EC, 0);
759 	StaticLine text( 0, &d, cmd );
760 
761 	text.Show();
762 	text.Enable();
763 	Layout lo( 3, 3 );
764 	lo.LineSet( 0, 5 );
765 	lo.LineSet( 2, 5 );
766 	lo.ColSet( 0, 15 );
767 	lo.ColSet( 2, 15 );
768 	lo.AddWin( &text, 1, 1 );
769 	d.AddLayout( &lo );
770 
771 	d.SetPosition();
772 	return d.DoModal();
773 
774 }
775 
776 ////////////////////////////////////////////////////////////////////////////
777 
CmdHistoryDialog(int nId,NCDialogParent * parent,NCHistory & history)778 CmdHistoryDialog::CmdHistoryDialog( int nId, NCDialogParent* parent, NCHistory& history )
779 	:  NCDialog( createDialogAsChild, nId, parent, utf8_to_unicode( " History " ).data(), bListOkCancel ),
780 	   _history( history ),
781 	   _selected( history.Count() - 1 ),
782 	   _list( Win::WT_CHILD, Win::WH_TABFOCUS | WH_CLICKFOCUS, 0, this, VListWin::SINGLE_SELECT, VListWin::BORDER_3D, 0 )
783 {
784 	for ( int i = _history.Count() - 1; i >= 0; i-- ) { _list.Append( _history[i] ); }
785 
786 	_list.Enable();
787 	_list.Show();
788 	_list.SetFocus();
789 	LSRange h( 10, 1000, 10 );
790 	LSRange w( 50, 1000, 30 );
791 	_list.SetHeightRange( h ); //in characters
792 	_list.SetWidthRange( w ); //in characters
793 
794 	if ( _history.Count() > 0 )
795 	{
796 		_list.MoveFirst( 0 );
797 		_list.MoveCurrent( _history.Count() - 1 );
798 	}
799 
800 
801 	AddWin( &_list );
802 	SetEnterCmd( CMD_OK );
803 	SetPosition();
804 };
805 
806 
Command(int id,int subId,Win * win,void * data)807 bool CmdHistoryDialog::Command( int id, int subId, Win* win, void* data )
808 {
809 	if ( id == CMD_ITEM_CLICK && win == &_list )
810 	{
811 		EndModal( CMD_OK );
812 	}
813 
814 	return NCDialog::Command( id, subId, win, data );
815 }
816 
817 ////////////////////////////////////////////////////////////////////////////
NCDialogParent(Win::WTYPE t,unsigned hints,int nId,Win * _parent,const crect * rect)818 NCDialogParent::NCDialogParent( Win::WTYPE t, unsigned hints, int nId , Win* _parent , const crect* rect )
819 	:  OperThreadWin( t, hints, nId, _parent, rect ), _layout( 1, 1 )
820 {
821 	_layout.SetLineGrowth( 0 );
822 	_layout.SetColGrowth( 0 );
823 	_layout.ColSet( 0, 32, 100000 );
824 	_layout.LineSet( 0, 32, 100000 );
825 	SetLayout( &_layout );
826 }
827 
~NCDialogParent()828 NCDialogParent::~NCDialogParent() {}
829 
830 
831 
832 ////////////////////////////////////////////  DlgMenu
833 
Add(const unicode_t * name,const unicode_t * comment1,const unicode_t * comment2,int cmd,int icon)834 void clMenuData::Add( const unicode_t* name, const unicode_t* comment1, const unicode_t* comment2, int cmd, int icon )
835 {
836 	Node node;
837 
838 	if ( name ) { node.name = new_unicode_str( name ); }
839 
840 	if ( comment1 ) { node.comment1 = new_unicode_str( comment1 ); }
841 
842 	if ( comment2 ) { node.comment2 = new_unicode_str( comment2 ); }
843 
844 	node.cmd = cmd;
845 	node.icon = icon;
846 
847 	list.append( node );
848 }
849 
Add(const char * utf8name,const char * utf8coment1,const char * utf8coment2,int cmd,int icon)850 void clMenuData::Add( const char* utf8name, const char* utf8coment1, const char* utf8coment2, int cmd, int icon )
851 {
852 	Add( utf8name ? utf8_to_unicode( utf8name ).data() : 0,
853 	     utf8coment1 ? utf8_to_unicode( utf8coment1 ).data() : 0,
854 	     utf8coment2 ? utf8_to_unicode( utf8coment2 ).data() : 0,
855 	     cmd,
856 	     icon
857 	   );
858 }
859 
AddSplitter()860 void clMenuData::AddSplitter()
861 {
862 	Node node;
863 	node.cmd = 0;
864 	list.append( node );
865 }
866 
867 class clSelectDriveDlgMenu: public Win
868 {
869 	clMenuData* _data;
870 	int _current;
871 	int _itemH;
872 	int _width;
873 	int _nameW, _comment1W, _comment2W;
874 	int _splitterH;
875 	int _splitterW;
876 public:
877 	clSelectDriveDlgMenu( Win* parent, clMenuData* data );
878 
879 	void SetCurrent( int n, bool searchUp );
880 
881 	virtual bool EventKey( cevent_key* pEvent );
882 	virtual void Paint( wal::GC& gc, const crect& paintRect );
883 	virtual bool EventMouse( cevent_mouse* pEvent );
884 	virtual bool EventShow( bool show );
885 	virtual int UiGetClassId();
886 };
887 
888 
SetCurrent(int n,bool searchUp)889 void clSelectDriveDlgMenu::SetCurrent( int n, bool searchUp )
890 {
891 	int count = _data->Count();
892 
893 	if ( count <= 0 ) { _current = -1; return; }
894 
895 	if ( n >= count ) { n = count - 1; }
896 
897 	if ( n <= 0 ) { n = 0; }
898 
899 	while ( n >= 0 && n < count )
900 	{
901 		if ( _data->list[n].cmd ) { break; }
902 
903 		n = n + ( searchUp ? -1 : 1 );
904 	}
905 
906 	_current = n;
907 }
908 
909 //int uiDlgMenu = GetUiID("DlgMenu");
UiGetClassId()910 int clSelectDriveDlgMenu::UiGetClassId()
911 {
912 	return uiClassButton/*DlgMenu*/;
913 } //чтоб диалог его востринимал как кнопку
914 
915 
EventShow(bool show)916 bool clSelectDriveDlgMenu::EventShow( bool show )
917 {
918 	if ( show ) { SetCapture(); }
919 	else { ReleaseCapture(); }
920 
921 	return true;
922 }
923 
924 
clSelectDriveDlgMenu(Win * parent,clMenuData * data)925 clSelectDriveDlgMenu::clSelectDriveDlgMenu( Win* parent, clMenuData* data )
926 	: Win( Win::WT_CHILD, Win::WH_TABFOCUS | Win::WH_CLICKFOCUS, parent )
927 	, _data( data )
928 	, _current( 0 )
929 	, _itemH( 16 )
930 	, _width( 50 )
931 	, _nameW( 10 )
932 	, _comment1W( 0 )
933 	, _comment2W( 0 )
934 	, _splitterH( 5 )
935 	, _splitterW( 1 )
936 {
937 	wal::GC gc( this );
938 	gc.Set( GetFont() );
939 
940 	int w = 0;
941 	int height = 0;
942 
943 	static unicode_t A[] = {'A', 'B', 'C'};
944 	cpoint p = gc.GetTextExtents( A, 3 );
945 	_itemH = p.y;
946 
947 	if ( _itemH < 16 ) { _itemH = 16; }
948 
949 	_splitterH = _itemH / 4;
950 
951 	if ( _splitterH < 3 ) { _splitterH = 3; }
952 
953 	for ( int i = 0 ; i < _data->Count(); i++ )
954 	{
955 		unicode_t* name = _data->list[i].name.data();
956 
957 		if ( _data->list[i].cmd != 0 )
958 		{
959 			if ( name )
960 			{
961 				cpoint p = gc.GetTextExtents( name );
962 
963 				if ( _nameW < p.x ) { _nameW = p.x; }
964 			}
965 
966 			unicode_t* comment1 = _data->list[i].comment1.data();
967 			unicode_t* comment2 = _data->list[i].comment2.data();
968 
969 			if ( comment1 )
970 			{
971 				cpoint p = gc.GetTextExtents( comment1 );
972 
973 				if ( _comment1W < p.x ) { _comment1W = p.x; }
974 			}
975 
976 			if ( comment2 )
977 			{
978 				cpoint p = gc.GetTextExtents( comment2 );
979 
980 				if ( _comment2W < p.x ) { _comment2W = p.x; }
981 			}
982 
983 			height += _itemH;
984 		}
985 		else
986 		{
987 			height += _splitterH;
988 		}
989 	}
990 
991 	w =  16 + 5 + _nameW + 5 + _comment1W + 30 + _comment2W;
992 
993 	if ( _width < w ) { _width = w; }
994 
995 	SetLSize( LSize( cpoint( _width, height ) ) );
996 }
997 
EqFirst(const unicode_t * s,int c)998 inline bool EqFirst( const unicode_t* s, int c )
999 {
1000 	return s && UnicodeLC( *s ) == c;
1001 }
1002 
EventKey(cevent_key * pEvent)1003 bool clSelectDriveDlgMenu::EventKey( cevent_key* pEvent )
1004 {
1005 	if ( _data->Count() && pEvent->Type() == EV_KEYDOWN )
1006 	{
1007 
1008 		switch ( pEvent->Key() )
1009 		{
1010 			case VK_R:
1011 			{
1012 				bool IsCtrl = ( pEvent->Mod() & KM_CTRL ) != 0;
1013 				if ( IsCtrl )
1014 				{
1015 					Command( ID_RESTART_DIALOG, 0, this, nullptr );
1016 					return false;
1017 				}
1018 				break;
1019 			}
1020 
1021 			case VK_UP:
1022 				SetCurrent( _current - 1, true );
1023 				break;
1024 
1025 			case VK_DOWN:
1026 				SetCurrent( _current + 1, false );
1027 				break;
1028 
1029 			case VK_HOME:
1030 			case VK_LEFT:
1031 				SetCurrent( 0, false );
1032 				break;
1033 
1034 			case VK_END:
1035 			case VK_RIGHT:
1036 				SetCurrent( _data->Count() - 1, true ); ;
1037 				break;
1038 
1039 			case VK_NUMPAD_RETURN:
1040 			case VK_RETURN:
1041 				if ( _current >= 0 && _current < _data->Count() && _data->list[_current].cmd != 0 )
1042 				{
1043 					Command( _data->list[_current].cmd, 0, this, 0 );
1044 				}
1045 
1046 				break;
1047 
1048 			default:
1049 			{
1050 				unicode_t c = UnicodeLC( pEvent->Char() );
1051 				int i;
1052 				int n = 0;
1053 				int count = _data->Count();
1054 
1055 				for ( i = 0; i < count; i++ )
1056 					if ( EqFirst( _data->list[i].name.data(), c ) ) { n++; }
1057 
1058 				if ( n == 1 )
1059 				{
1060 					for ( i = 0; i < count; i++ )
1061 						if ( EqFirst( _data->list[i].name.data(), c ) )
1062 						{
1063 							_current = i;
1064 							Command( _data->list[i].cmd, 0, this, 0 );
1065 							break;
1066 						};
1067 
1068 					break;
1069 				}
1070 
1071 				if ( n > 1 )
1072 				{
1073 					for ( i = _current + 1; i < count; i++ )
1074 						if ( EqFirst( _data->list[i].name.data(), c ) ) { goto t; }
1075 
1076 					for ( i = 0; i <= _current && i < count; i++ )
1077 						if ( EqFirst( _data->list[i].name.data(), c ) ) { goto t; }
1078 
1079 t:
1080 					;
1081 					_current = i;
1082 					break;
1083 				}
1084 
1085 			}
1086 
1087 			return Win::EventKey( pEvent );
1088 		}
1089 
1090 		Invalidate();
1091 	};
1092 
1093 	return Win::EventKey( pEvent );
1094 }
1095 
1096 
EventMouse(cevent_mouse * pEvent)1097 bool clSelectDriveDlgMenu::EventMouse( cevent_mouse* pEvent )
1098 {
1099 	switch ( pEvent->Type() )
1100 	{
1101 		case EV_MOUSE_MOVE:
1102 			break;
1103 
1104 		case EV_MOUSE_PRESS:
1105 		case EV_MOUSE_DOUBLE:
1106 		{
1107 			cpoint p = pEvent->Point();
1108 			int count = _data->Count();
1109 
1110 			if ( !count || p.x < 0 || p.x > _width || p.y < 0 )
1111 			{
1112 				Command( CMD_CANCEL, 0, this, 0 );
1113 				return true;
1114 			}
1115 
1116 			if ( pEvent->Button() != MB_L ) { break; }
1117 
1118 			int n = -1;
1119 			int h = 0;
1120 
1121 			for ( int i = 0; i < _data->Count(); i++ )
1122 			{
1123 				int ih = _data->list[i].cmd ? _itemH : _splitterH;
1124 
1125 				if ( p.y < h + ih )
1126 				{
1127 					if ( _data->list[i].cmd != 0 ) { n = i; }
1128 
1129 					break;
1130 				}
1131 
1132 				h += ih;
1133 			}
1134 
1135 			if ( n >= 0 )
1136 			{
1137 				_current = n;
1138 				Invalidate();
1139 				Command( _data->list[n].cmd, 0, this, 0 );
1140 			}
1141 		}
1142 		break;
1143 
1144 		case EV_MOUSE_RELEASE:
1145 			break;
1146 	};
1147 
1148 	return true;
1149 }
1150 
1151 static int uiFcColor = GetUiID( "first-char-color" );
1152 static int uiCommentColor = GetUiID( "comment-color" );
1153 
Paint(wal::GC & gc,const crect & paintRect)1154 void clSelectDriveDlgMenu::Paint( wal::GC& gc, const crect& paintRect )
1155 {
1156 	cfont* font = GetFont();
1157 	gc.Set( font );
1158 	int y = 0;
1159 
1160 	int bgColor = UiGetColor( uiBackground, 0, 0, 0xB0B000 );
1161 
1162 	int count = _data->Count();
1163 
1164 	int Splitters = 0;
1165 	int SplitterTop = 0;
1166 	int SplitterBottom = 0;
1167 
1168 	for ( int i = 0; i < count; i++ )
1169 	{
1170 		if ( _data->list[i].cmd == 0 )
1171 		{
1172 			gc.SetFillColor( bgColor );
1173 			gc.FillRect( crect( 0, y, _width, y + _splitterH ) );
1174 			crect rect( 0, y + 1, 0 + _width, y + 2 );
1175 			gc.SetFillColor( ColorTone( bgColor, -150 ) );
1176 			gc.FillRect( rect );
1177 			rect.top += 1;
1178 			rect.bottom += 1;
1179 			gc.SetFillColor( ColorTone( bgColor, +50 ) );
1180 			gc.FillRect( rect );
1181 			y += _splitterH;
1182 			Splitters++;
1183 
1184 			if ( Splitters == 1 ) { SplitterTop = y; }
1185 
1186 			if ( Splitters == 2 ) { SplitterBottom = y - _splitterH; }
1187 		}
1188 		else
1189 		{
1190 			UiCondList ucl;
1191 
1192 			if ( i == _current ) { ucl.Set( uiCurrentItem, true ); }
1193 
1194 			unsigned bg = UiGetColor( uiBackground, uiItem, &ucl, 0xFFFFFF );
1195 			unsigned textColor = UiGetColor( uiColor, uiItem, &ucl, 0 );
1196 			unsigned fcColor = UiGetColor( uiFcColor, uiItem, &ucl, 0xFF );
1197 			unsigned commentColor = UiGetColor( uiCommentColor, uiItem, &ucl, 0 );
1198 
1199 			gc.SetFillColor( bg );
1200 			gc.FillRect( crect( 0, y, _width, y + _itemH ) );
1201 
1202 			cicon icon;
1203 
1204 			if ( _data->list[i].icon >= 0 )
1205 			{
1206 				icon.Load( _data->list[i].icon, 16, 16 );
1207 			}
1208 			else
1209 			{
1210 				icon.Load( _data->list[i].cmd, 16, 16 );
1211 			}
1212 
1213 			gc.DrawIcon( 0, y, &icon );
1214 			gc.SetTextColor( textColor );
1215 			int x = 16 + 5;
1216 
1217 			const unicode_t* name = _data->list[i].name.data();
1218 			const unicode_t* comment1 = _data->list[i].comment1.data();
1219 			const unicode_t* comment2 = _data->list[i].comment2.data();
1220 
1221 			if ( name )
1222 			{
1223 				gc.TextOutF( x, y, name );
1224 				gc.SetTextColor( fcColor );
1225 				gc.TextOutF( x, y, name, 1 );
1226 			}
1227 
1228 			if ( comment1 )
1229 			{
1230 				gc.SetTextColor( commentColor );
1231 				gc.TextOutF( x + _nameW + 5, y, comment1 );
1232 			}
1233 
1234 			if ( comment2 )
1235 			{
1236 				gc.SetTextColor( commentColor );
1237 				gc.TextOutF( x + _nameW + 5 + _comment1W + 30, y, comment2 );
1238 			}
1239 
1240 			y += _itemH;
1241 		}
1242 	}
1243 
1244 	if ( _comment2W && SplitterTop && SplitterBottom )
1245 	{
1246 		int cx = _nameW + 5 + _comment1W + 30;
1247 		gc.SetFillColor( ColorTone( bgColor, -150 ) );
1248 		gc.FillRect( crect( cx, SplitterTop, cx + _splitterW, SplitterBottom ) );
1249 	}
1250 }
1251 
RunDldMenu(int nUi,NCDialogParent * parent,const char * header,clMenuData * data)1252 int RunDldMenu( int nUi, NCDialogParent* parent, const char* header, clMenuData* data )
1253 {
1254 	if ( !data || data->Count() <= 0 ) { return CMD_CANCEL; }
1255 
1256 	NCDialog dlg( true, nUi, parent, utf8_to_unicode( header ).data(), 0 ); //, ::g_WcmConfig.whiteStyle ? 0xD8E9EC : 0xB0B000, 0xFFFFFF);
1257 	clSelectDriveDlgMenu mtable( &dlg, data );
1258 	mtable.Show();
1259 	mtable.Enable();
1260 	mtable.SetFocus();
1261 	dlg.AddWin( &mtable );
1262 	int Result = dlg.DoModal();
1263 	return Result;
1264 }
1265 
1266