libyui-ncurses  2.48.1
NCDialog.cc
1 /*
2  Copyright (C) 2000-2012 Novell, Inc
3  This library is free software; you can redistribute it and/or modify
4  it under the terms of the GNU Lesser General Public License as
5  published by the Free Software Foundation; either version 2.1 of the
6  License, or (at your option) version 3.0 of the License. This library
7  is distributed in the hope that it will be useful, but WITHOUT ANY
8  WARRANTY; without even the implied warranty of MERCHANTABILITY or
9  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10  License for more details. You should have received a copy of the GNU
11  Lesser General Public License along with this library; if not, write
12  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
13  Floor, Boston, MA 02110-1301 USA
14 */
15 
16 
17 /*-/
18 
19  File: NCDialog.cc
20 
21  Author: Michael Andres <ma@suse.de>
22 
23 /-*/
24 
25 #define YUILogComponent "ncurses"
26 #include <yui/YUILog.h>
27 #include "NCDialog.h"
28 #include "NCstring.h"
29 #include "NCPopupInfo.h"
30 #include "NCMenuButton.h"
31 #include <yui/YShortcut.h>
32 #include "NCtoY2Event.h"
33 #include <yui/YDialogSpy.h>
34 #include <yui/YDialog.h>
35 
36 #include "ncursesw.h"
37 
38 
39 static bool hiddenMenu()
40 {
41  return getenv( "Y2NCDBG" ) != NULL;
42 }
43 
44 
45 NCDialog::NCDialog( YDialogType dialogType,
46  YDialogColorMode colorMode )
47  : YDialog( dialogType, colorMode )
48  , pan( 0 )
49  , dlgstyle( 0 )
50  , inMultiDraw_i( 0 )
51  , active( false )
52  , wActive( this )
53  , ncdopts( DEFAULT )
54  , popedpos( -1 )
55 {
56  yuiDebug() << "Constructor NCDialog(YDialogType t, YDialogColorMode c)" << std::endl;
57  _init();
58 }
59 
60 
61 NCDialog::NCDialog( YDialogType dialogType, const wpos at, const bool boxed )
62  : YDialog( dialogType, YDialogNormalColor )
63  , pan( 0 )
64  , dlgstyle( 0 )
65  , inMultiDraw_i( 0 )
66  , active( false )
67  , wActive( this )
68  , ncdopts( boxed ? POPUP : POPUP | NOBOX )
69  , popedpos( at )
70 {
71  yuiDebug() << "Constructor NCDialog(YDialogType t, const wpos at, const bool boxed)" << std::endl;
72  _init();
73 }
74 
75 
76 void NCDialog::_init()
77 {
78  NCurses::RememberDlg( this );
79  // don't set text domain to ncurses - other text domains won't work (bnc #476245)
80 
81  _init_size();
82  wstate = NC::WSdumb;
83 
84  if ( colorMode() == YDialogWarnColor )
85  {
86  mystyleset = NCstyle::WarnStyle;
87  }
88  else if ( colorMode() == YDialogInfoColor )
89  {
90  mystyleset = NCstyle::InfoStyle;
91  }
92  else if ( isPopup() )
93  {
94  mystyleset = NCstyle::PopupStyle;
95  }
96  else
97  {
98  mystyleset = NCstyle::DefaultStyle;
99  }
100 
101  dlgstyle = &NCurses::style()[mystyleset];
102 
103  eventReason = YEvent::UnknownReason;
104  yuiDebug() << "+++ " << this << std::endl;
105 }
106 
107 
108 void NCDialog::_init_size()
109 {
110  defsze.H = NCurses::lines();
111  defsze.W = NCurses::cols();
112  hshaddow = vshaddow = false;
113 
114  if ( isBoxed() )
115  {
116  switch ( defsze.H )
117  {
118  case 1:
119  case 2:
120  defsze.H = 1;
121  break;
122 
123  default:
124  defsze.H -= 2;
125  break;
126  }
127 
128  switch ( defsze.W )
129  {
130  case 1:
131  case 2:
132  defsze.W = 1;
133  break;
134 
135  default:
136  defsze.W -= 2;
137  break;
138  }
139  }
140 }
141 
142 
143 NCDialog::~NCDialog()
144 {
145  NCurses::ForgetDlg( this );
146 
147  yuiDebug() << "--+START destroy " << this << std::endl;
148 
149  if ( pan && !pan->hidden() )
150  {
151  pan->hide();
152  doUpdate();
153  }
154 
155  grabActive( 0 );
156 
157  NCWidget::wDelete();
158  delete pan;
159  pan = 0;
160  yuiDebug() << "---destroyed " << this << std::endl;
161 
162 }
163 
164 
165 int NCDialog::preferredWidth()
166 {
167  if ( dialogType() == YMainDialog || ! hasChildren() )
168  return wGetDefsze().W;
169 
170  wsze csze( 0, 0 );
171 
172  if ( hasChildren() )
173  {
174  csze = wsze( firstChild()->preferredHeight(),
175  firstChild()->preferredWidth() );
176  }
177 
178  csze = wsze::min( wGetDefsze(), wsze::max( csze, wsze( 1 ) ) );
179 
180  return csze.W;
181 }
182 
183 
184 int NCDialog::preferredHeight()
185 {
186  if ( dialogType() == YMainDialog || ! hasChildren() )
187  {
188  return wGetDefsze().H;
189  }
190 
191  wsze csze( 0, 0 );
192 
193  if ( hasChildren() )
194  {
195  csze = wsze( firstChild()->preferredHeight(),
196  firstChild()->preferredWidth() );
197  }
198 
199  csze = wsze::min( wGetDefsze(),
200  wsze::max( csze, wsze( 1 ) ) );
201 
202  return csze.H;
203 }
204 
205 
206 void NCDialog::setSize( int newwidth, int newheight )
207 {
208  wRelocate( wpos( 0 ), wsze( newheight, newwidth ) );
209  yuiDebug() << "setSize() called: width: " << newwidth << " height: " << newheight << std::endl;
210  YDialog::setSize( newwidth, newheight );
211 }
212 
213 
214 void NCDialog::initDialog()
215 {
216  if ( !pan )
217  {
218  yuiDebug() << "setInitialSize() called!" << std::endl;
219  setInitialSize();
220  }
221 }
222 
223 
225 {
226  showDialog();
227 }
228 
229 
230 void NCDialog::showDialog()
231 {
232  yuiDebug() << "sd+ " << this << std::endl;
233 
234  if ( pan && pan->hidden() )
235  {
236  YPushButton *defaultB = YDialog::defaultButton();
237 
238  if ( defaultB )
239  {
240  defaultB->setKeyboardFocus();
241  }
242 
243  getVisible();
244 
245  doUpdate();
246  DumpOn( yuiDebug(), " " );
247 
248  }
249  else if ( !pan )
250  {
251  yuiMilestone() << "no pan" << std::endl;
252  }
253 
254  activate( true );
255 
256  yuiDebug() << "sd- " << this << std::endl;
257 }
258 
259 
260 void NCDialog::closeDialog()
261 {
262  yuiDebug() << "cd+ " << this << std::endl;
263  activate( false );
264 
265  if ( pan && !pan->hidden() )
266  {
267  pan->hide();
268  doUpdate();
269  yuiDebug() << this << std::endl;
270  }
271 
272  yuiDebug() << "cd+ " << this << std::endl;
273 }
274 
275 
276 void NCDialog::activate( const bool newactive )
277 {
278  if ( active != newactive || ( pan && pan->hidden() ) )
279  {
280  active = newactive;
281 
282  if ( pan )
283  {
284  pan->show(); // not getVisible() because wRedraw() follows.
285  wRedraw();
286 
287  if ( active )
288  Activate();
289  else
290  Deactivate();
291 
292  NCurses::SetStatusLine( describeFunctionKeys() );
293  doUpdate();
294  yuiDebug() << this << std::endl;
295  }
296  }
297 }
298 
299 
300 /**
301  * Implementation of YDialog::activate().
302  *
303  * This is called e.g. for the next-lower dialog in the dialog stack when the
304  * topmost dialog is destroyed: That next-lower dialog is now the active
305  * dialog.
306  **/
308 {
309  activate( true ); // Forward to NCurses-specific activate()
310 }
311 
312 
313 void NCDialog::wMoveTo( const wpos & newpos )
314 {
315  yuiDebug() << DLOC << this << newpos << std::endl;
316 }
317 
318 
319 void NCDialog::wCreate( const wrect & newrect )
320 {
321  if ( win )
322  throw NCError( "wCreate: already have win" );
323 
324  wrect panrect( newrect );
325 
326  inparent = newrect;
327 
328  if ( isBoxed() )
329  {
330  switch ( NCurses::lines() - panrect.Sze.H )
331  {
332  case 0:
333  break;
334 
335  case 1:
336  panrect.Sze.H += 1;
337  inparent.Pos.L += 1;
338  break;
339 
340  default:
341  panrect.Sze.H += 2;
342  inparent.Pos.L += 1;
343  break;
344  }
345 
346  switch ( NCurses::cols() - panrect.Sze.W )
347  {
348  case 0:
349  break;
350 
351  case 1:
352  panrect.Sze.W += 1;
353  inparent.Pos.C += 1;
354  break;
355 
356  default:
357  panrect.Sze.W += 2;
358  inparent.Pos.C += 1;
359  break;
360  }
361  }
362 
363  if ( popedpos.L >= 0 )
364  {
365  if ( popedpos.L + panrect.Sze.H <= NCurses::lines() )
366  panrect.Pos.L = popedpos.L;
367  else
368  panrect.Pos.L = NCurses::lines() - panrect.Sze.H;
369  }
370  else
371  {
372  panrect.Pos.L = ( NCurses::lines() - panrect.Sze.H ) / 2;
373  }
374 
375  if ( popedpos.C >= 0 )
376  {
377  if ( popedpos.C + panrect.Sze.W <= NCurses::cols() )
378  panrect.Pos.C = popedpos.C;
379  else
380  panrect.Pos.C = NCurses::cols() - panrect.Sze.W;
381  }
382  else
383  {
384  panrect.Pos.C = ( NCurses::cols() - panrect.Sze.W ) / 2;
385  }
386 
387  if ( panrect.Pos.L + panrect.Sze.H < NCurses::lines() )
388  {
389  ++panrect.Sze.H;
390  hshaddow = true;
391  }
392 
393  if ( panrect.Pos.C + panrect.Sze.W < NCurses::cols() )
394  {
395  ++panrect.Sze.W;
396  vshaddow = true;
397  }
398 
399  if ( pan && panrect != wrect( wpos( pan->begy(), pan->begx() ),
400  wsze( pan->maxy() + 1, pan->maxx() + 1 ) ) )
401  {
402  pan->hide();
403  doUpdate();
404  delete pan;
405  pan = 0;
406  }
407 
408  if ( !pan )
409  {
410  pan = new NCursesUserPanel<NCDialog>( panrect.Sze.H, panrect.Sze.W,
411  panrect.Pos.L, panrect.Pos.C,
412  this );
413  pan->hide();
414  doUpdate();
415  }
416 
417  win = new NCursesWindow( *pan,
418 
419  inparent.Sze.H, inparent.Sze.W,
420  inparent.Pos.L, inparent.Pos.C,
421  'r' );
422  win->nodelay( true );
423 
424  yuiDebug() << DLOC << panrect << '(' << inparent << ')'
425  << '[' << popedpos << ']' << std::endl;
426 }
427 
428 
429 void NCDialog::wRedraw()
430 {
431  if ( pan )
432  {
433  if ( isBoxed() )
434  {
435  pan->bkgdset( wStyle().getDlgBorder( active ).text );
436 
437  if ( pan->height() != NCurses::lines()
438  || pan->width() != NCurses::cols() )
439  {
440  pan->box(); // not fullscreen
441  }
442  else
443  {
444  pan->hline( 0, 0, pan->width(), ' ' );
445  pan->hline( pan->height() - 1, 0, pan->width(), ' ' );
446  pan->vline( 0, 0, pan->height(), ' ' );
447  pan->vline( 0, pan->width() - 1, pan->height(), ' ' );
448  }
449 
450  if ( hshaddow )
451  {
452  pan->copywin( *pan,
453  pan->maxy(), 0,
454  pan->maxy() - 1, 0,
455  pan->maxy() - 1, pan->maxx(), false );
456  }
457 
458  if ( vshaddow )
459  {
460  pan->copywin( *pan,
461  0, pan->maxx(),
462  0, pan->maxx() - 1,
463  pan->maxy(), pan->maxx() - 1, false );
464  }
465  }
466 
467  pan->bkgdset( A_NORMAL );
468 
469  if ( hshaddow )
470  {
471  pan->hline( pan->maxy(), 0, pan->width(), ' ' );
472  pan->transparent( pan->maxy(), 0 );
473  }
474 
475  if ( vshaddow )
476  {
477  pan->vline( 0, pan->maxx(), pan->height(), ' ' );
478  pan->transparent( 0, pan->maxx() );
479  }
480  }
481 }
482 
483 
484 void NCDialog::wRecoded()
485 {
486  if ( pan )
487  {
488  if ( &NCurses::style()[mystyleset] != dlgstyle )
489  {
490  dlgstyle = &NCurses::style()[mystyleset];
491  }
492 
493  pan->bkgdset( wStyle(). getDumb().text );
494 
495  pan->clear();
496  wRedraw();
497  }
498 }
499 
500 
501 void NCDialog::startMultipleChanges()
502 {
503  ++inMultiDraw_i;
504 }
505 
506 
507 void NCDialog::doneMultipleChanges()
508 {
509  if ( inMultiDraw_i > 1 )
510  {
511  --inMultiDraw_i;
512  }
513  else
514  {
515  inMultiDraw_i = 0;
516  NCurses::SetStatusLine( describeFunctionKeys() );
517  Update();
518  }
519 }
520 
521 void NCDialog::setStatusLine()
522 {
523  NCurses::SetStatusLine( describeFunctionKeys() );
524  doUpdate();
525 }
526 
527 void NCDialog::wUpdate( bool forced_br )
528 {
529  if ( !pan )
530  return;
531 
532  if ( !forced_br
533  && ( pan->hidden() || inMultiDraw_i ) )
534  return;
535 
536  NCWidget::wUpdate( forced_br );
537 }
538 
539 
540 void NCDialog::grabActive( NCWidget * nactive )
541 {
542  if ( wActive && wActive != static_cast<NCWidget *>( this ) )
543  wActive->grabRelease( this );
544 
545  if ( nactive && nactive != static_cast<NCWidget *>( this ) )
546  nactive->grabSet( this );
547 
548  const_cast<NCWidget *&>( wActive ) = nactive;
549 }
550 
551 
552 void NCDialog::grabNotify( NCWidget * mgrab )
553 {
554  if ( wActive && wActive == mgrab )
555  {
556  yuiDebug() << DLOC << mgrab << " active " << std::endl;
557  ActivateNext();
558 
559  if ( wActive && wActive == mgrab )
560  grabActive( this );
561  }
562 }
563 
564 
565 bool NCDialog::wantFocus( NCWidget & ngrab )
566 {
567  return Activate( ngrab );
568 }
569 
570 
571 void NCDialog::wDelete()
572 {
573  if ( pan )
574  {
575  yuiDebug() << DLOC << "+++ " << this << std::endl;
576  NCWidget::wDelete();
577  yuiDebug() << DLOC << "--- " << this << std::endl;
578  }
579 }
580 
581 
582 NCWidget & NCDialog::GetNormal( NCWidget & startwith, SeekDir Direction )
583 {
584  NCWidget * c = ( startwith.*Direction )( true )->Value();
585 
586  while ( c != &startwith && ( c->GetState() != NC::WSnormal || !c->winExist() ) )
587  {
588  if ( c->GetState() == NC::WSactive )
589  {
590  yuiWarning() << "multiple active widgets in dialog? "
591  << startwith << " <-> " << c << std::endl;
592  c->SetState( NC::WSnormal ); // what else can we do?
593  break;
594  }
595 
596  c = ( c->*Direction )( true )->Value();
597  }
598 
599  return *c;
600 }
601 
602 
603 NCWidget & NCDialog::GetNextNormal( NCWidget & startwith )
604 {
605  return GetNormal( startwith, &tnode<NCWidget *>::Next );
606 }
607 
608 
609 NCWidget & NCDialog::GetPrevNormal( NCWidget & startwith )
610 {
611  return GetNormal( startwith, &tnode<NCWidget *>::Prev );
612 }
613 
614 
615 bool NCDialog::Activate( NCWidget & nactive )
616 {
617  if ( nactive.GetState() == NC::WSactive )
618  return true;
619 
620  if ( nactive.GetState() == NC::WSnormal )
621  {
622  if ( wActive->GetState() == NC::WSactive )
623  wActive->SetState( NC::WSnormal );
624 
625  if ( active )
626  {
627  nactive.SetState( NC::WSactive );
628  }
629 
630  grabActive( &nactive );
631 
632  return true;
633  }
634 
635  return false;
636 }
637 
638 
639 void NCDialog::Activate( SeekDir Direction )
640 {
641  if ( !wActive )
642  grabActive( this );
643 
644  if ( Direction == 0 )
645  {
646  if ( Activate( *wActive ) )
647  return; // (re)activated widget
648 
649  // can't (re)activate widget, so look for next one
650  Direction = &tnode<NCWidget *>::Next;
651  }
652 
653  Activate( GetNormal( *wActive, Direction ) );
654 }
655 
656 
657 void NCDialog::Activate()
658 {
659  Activate( 0 );
660 }
661 
662 
663 void NCDialog::Deactivate()
664 {
665  if ( wActive->GetState() == NC::WSactive )
666  {
667  wActive->SetState( NC::WSnormal );
668  }
669 }
670 
671 
672 void NCDialog::ActivateNext()
673 {
674  Activate( &tnode<NCWidget *>::Next );
675 }
676 
677 
678 void NCDialog::ActivatePrev()
679 {
680  Activate( &tnode<NCWidget *>::Prev );
681 }
682 
683 
684 bool NCDialog::ActivateByKey( int key )
685 {
686  NCWidget * buddy = 0;
687 
688  for ( tnode<NCWidget*> * c = this->Next(); c; c = c->Next() )
689  {
690  switch ( c->Value()->GetState() )
691  {
692  case NC::WSnormal:
693  case NC::WSactive:
694 
695  if ( c->Value()->HasHotkey( key )
696  || c->Value()->HasFunctionHotkey( key ) )
697  {
698  Activate( *c->Value() );
699  return true;
700  }
701 
702  if ( buddy )
703  {
704  if ( c->IsDescendantOf( buddy ) )
705  {
706  yuiDebug() << "BUDDY ACTIVATION FOR " << c->Value() << std::endl;
707  Activate( *c->Value() );
708  return true;
709  }
710 
711  yuiDebug() << "DROP BUDDY on " << c->Value() << std::endl;
712 
713  buddy = 0;
714  }
715 
716  break;
717 
718  case NC::WSdumb:
719 
720  if ( c->Value()->HasHotkey( key )
721  || c->Value()->HasFunctionHotkey( key ) )
722  {
723  yuiDebug() << "DUMB HOT KEY " << key << " in " << c->Value() << std::endl;
724  buddy = c->Value();
725  }
726 
727  default:
728 
729  break;
730  }
731  }
732 
733  return false;
734 }
735 
736 
737 wint_t NCDialog::getinput()
738 {
739  wint_t got = WEOF;
740 
741  if ( NCstring::terminalEncoding() == "UTF-8" )
742  {
743  wint_t gotwch = WEOF;
744  int ret = ::get_wch( &gotwch ); // get a wide character
745 
746  if ( ret != ERR ) // get_wch() returns OK or KEY_CODE_YES on success
747  {
748  got = gotwch;
749  // UTF-8 keys (above KEY_MIN) may deliver same keycode as curses KEY_...
750  // -> mark this keys
751 
752  if ( ret == OK
753  && got > KEY_MIN )
754  {
755  got += 0xFFFF;
756  }
757  }
758  else
759  {
760  got = WEOF;
761  }
762  }
763  else
764  {
765  std::wstring to;
766  int gotch = ::getch(); // get the character in terminal encoding
767 
768  if ( gotch != -1 )
769  {
770  if (( KEY_MIN > gotch || KEY_MAX < gotch )
771  &&
772  isprint( gotch ) )
773  {
774  std::string str;
775  str += static_cast<char>( gotch );
776  // recode printable chars
777  NCstring::RecodeToWchar( str, NCstring::terminalEncoding(), &to );
778  got = to[0];
779 
780  if ( gotch != ( int )got )
781  {
782  got += 0xFFFF; // mark this key
783  }
784 
785  yuiDebug() << "Recode: " << str << " (encoding: " << NCstring::terminalEncoding() << ") "
786 
787  << "to wint_t: " << got << std::endl;
788  }
789  else
790  {
791  got = gotch;
792  }
793  }
794  else
795  {
796  got = WEOF;
797  }
798  }
799 
800  return got;
801 }
802 
803 
804 wint_t NCDialog::getch( int timeout_millisec )
805 {
806  wint_t got = WEOF;
807 
808  if ( timeout_millisec < 0 )
809  {
810  // wait for input
811  ::nodelay( ::stdscr, false );
812 
813  got = getinput();
814 
815  }
816  else if ( timeout_millisec )
817  {
818  // max halfdelay is 25 seconds (250 tenths of seconds)
819  do
820  {
821  if ( timeout_millisec > 25000 )
822  {
823  ::halfdelay( 250 );
824  timeout_millisec -= 25000;
825  }
826  else
827  {
828  if ( timeout_millisec < 100 )
829  {
830  // min halfdelay is 1/10 second (100 milliseconds)
831  ::halfdelay( 1 );
832  }
833  else
834  ::halfdelay( timeout_millisec / 100 );
835 
836  timeout_millisec = 0;
837  }
838 
839  got = getinput();
840  }
841  while ( got == WEOF && timeout_millisec > 0 );
842 
843  ::cbreak(); // stop halfdelay
844  }
845  else
846  {
847  // no wait
848  ::nodelay( ::stdscr, true );
849  got = getinput();
850  }
851 
852  if ( got == KEY_RESIZE )
853  {
854  NCurses::ResizeEvent();
855  int i = 100;
856  // after resize sometimes WEOF is returned -> skip this in no timeout mode
857 
858  do
859  {
860  got = NCDialog::getch( timeout_millisec );
861  }
862  while ( timeout_millisec < 0 && got == WEOF && --i );
863  }
864 
865  return got;
866 }
867 
868 
869 bool NCDialog::flushTypeahead()
870 {
871  // Don't throw away keys from the input buffer after a ValueChanged or
872  // SelectionChanged event but save them e.g. for input in TextEntry,
873  // MultiLineEdit or to scroll in lists ( bug #245476 )
874  if ( eventReason == YEvent::ValueChanged ||
875  eventReason == YEvent::SelectionChanged )
876  {
877  yuiDebug() << "DON't flush input buffer - reason: " << eventReason << std::endl;
878  return false;
879  }
880  else
881  {
882  yuiDebug() << "Flush input buffer" << std::endl;
883  return true;
884  }
885 }
886 
887 
888 void NCDialog::idleInput()
889 {
890  if ( !pan )
891  {
892  yuiWarning() << DLOC << " called for uninitialized " << this << std::endl;
893  ::flushinp();
894  return;
895  }
896 
897  yuiDebug() << "idle+ " << this << std::endl;
898 
899  if ( !active )
900  {
901  if ( flushTypeahead() )
902  {
903  ::flushinp();
904  }
905 
906  doUpdate();
907  }
908  else
909  {
910  yuiDebug() << "idle+ " << this << std::endl;
911  processInput( 0 );
912  yuiDebug() << "idle- " << this << std::endl;
913  }
914 }
915 
916 
917 NCursesEvent NCDialog::pollInput()
918 {
919  yuiDebug() << "poll+ " << this << std::endl;
920 
921  if ( !pan )
922  {
923  yuiWarning() << DLOC << " called for uninitialized " << this << std::endl;
924  return NCursesEvent::cancel;
925  }
926 
927  if ( pendingEvent )
928  {
929  if ( active )
930  {
931  activate( false );
932  yuiDebug() << this << " deactivate" << std::endl;
933  }
934  }
935  else
936  {
937  if ( !active )
938  {
939  activate( true );
940  yuiDebug() << this << " activate" << std::endl;
941  }
942  }
943 
944  NCursesEvent returnEvent = pendingEvent;
945 
946  eventReason = returnEvent.reason;
947  pendingEvent = NCursesEvent::none;
948 
949  yuiDebug() << "poll- " << this << '(' << returnEvent << ')' << std::endl;
950  return returnEvent;
951 }
952 
953 
954 NCursesEvent NCDialog::userInput( int timeout_millisec )
955 {
956  yuiDebug() << "user+ " << this << std::endl;
957 
958  if ( flushTypeahead() )
959  {
960  ::flushinp();
961  }
962 
963  if ( !pan )
964  {
965  yuiWarning() << DLOC << " called for uninitialized " << this << std::endl;
966  return NCursesEvent::cancel;
967  }
968 
969  processInput( timeout_millisec );
970 
971  NCursesEvent returnEvent = pendingEvent;
972  eventReason = returnEvent.reason;
973  pendingEvent = NCursesEvent::none;
974 
975  yuiDebug() << "user- " << this << '(' << returnEvent << ')' << std::endl;
976  return returnEvent;
977 }
978 
979 
980 /**
981  * Back-end for YDialog::waitForEvent()
982  **/
983 YEvent * NCDialog::waitForEventInternal( int timeout_millisec )
984 {
985  NCtoY2Event cevent;
986  activate( true );
987  cevent = userInput( timeout_millisec ? timeout_millisec : -1 );
988  activate( false );
989 
990  YEvent * yevent = cevent.propagate();
991 
992  return yevent;
993 }
994 
995 
996 /**
997  * Back-end for YDialog::pollEvent()
998  **/
1000 {
1001  // no activation here, done in pollInput, if..
1002  NCtoY2Event cevent = pollInput();
1003  YEvent * yevent = cevent.propagate();
1004 
1005  return yevent;
1006 }
1007 
1008 
1009 /**
1010  * Process input
1011  *
1012  * timeout -1 -> wait for input
1013  * timeout 0 -> immediate return
1014  * else wait for up to timeout milliseconds
1015  **/
1016 void NCDialog::processInput( int timeout_millisec )
1017 {
1018  yuiDebug() << "process+ " << this << " active " << wActive
1019  << " timeout_millisec " << timeout_millisec << std::endl;
1020 
1021  if ( pendingEvent )
1022  {
1023  yuiDebug() << this << "(return pending event)" << std::endl;
1024  doUpdate();
1025  ::flushinp();
1026  return;
1027  }
1028 
1029  // if no active item return on any input
1030  if ( wActive->GetState() != NC::WSactive )
1031  {
1032  yuiDebug() << "noactive item => reactivate!" << std::endl;
1033  Activate();
1034  }
1035 
1036  if ( wActive->GetState() != NC::WSactive )
1037  {
1038  yuiDebug() << "still noactive item!" << std::endl;
1039 
1040  if ( timeout_millisec == -1 )
1041  {
1042  pendingEvent = NCursesEvent::cancel;
1043  yuiDebug() << DLOC << this << "(std::set ET_CANCEL since noactive item on pollInput)" << std::endl;
1044  getch( -1 );
1045  }
1046  else
1047  ::flushinp();
1048 
1049  // if there is no active widget and we are in timeout, handle properly
1050  // bug #182982
1051  if ( timeout_millisec > 0 )
1052  {
1053  usleep( timeout_millisec * 1000 );
1054  pendingEvent = NCursesEvent::timeout;
1055  }
1056 
1057  return;
1058  }
1059 
1060  // get and process user input
1061  wint_t ch = 0;
1062 
1063  wint_t hch = 0;
1064 
1065  yuiDebug() << "enter loop..." << std::endl;
1066 
1067  noUpdates = true;
1068 
1069  while ( !pendingEvent.isReturnEvent() && ch != WEOF )
1070  {
1071 
1072  ch = getch( timeout_millisec );
1073 
1074  switch ( ch )
1075  {
1076  // case KEY_RESIZE: is directly handled in NCDialog::getch.
1077 
1078  case WEOF:
1079 
1080  if ( timeout_millisec == -1 )
1081  pendingEvent = NCursesEvent::cancel;
1082  else if ( timeout_millisec > 0 )
1083  pendingEvent = NCursesEvent::timeout;
1084 
1085  break;
1086 
1087  case KEY_F( 13 ): // = Shift-F1 on e.g. a linux console
1088  showHotkeyHelp();
1089  break;
1090 
1091  case KEY_F( 16 ): // = Shift-F4 on e.g. a linux console
1092  const_cast<NCstyle&>( NCurses::style() ).nextStyle();
1093 
1094  NCurses::Redraw();
1095 
1096  break;
1097 
1098  case CTRL( 'D' ):
1099  hch = getch( -1 );
1100 
1101  ::flushinp();
1102 
1103  switch ( hch )
1104  {
1105  case KEY_F( 1 ):
1106  showHotkeyHelp();
1107  break;
1108 
1109  case 'D':
1110  yuiMilestone() << "CTRL('D')-'D' DUMP+++++++++++++++++++++" << std::endl;
1111  NCurses::ScreenShot();
1112  yuiMilestone() << this << std::endl;
1113  DumpOn( yuiMilestone(), " " );
1114  yuiMilestone() << "CTRL('D')-'D' DUMP---------------------" << std::endl;
1115  break;
1116 
1117  case 'S':
1118 
1119  if ( hiddenMenu() )
1120  {
1121  yuiMilestone() << "CTRL('D')-'S' STYLEDEF+++++++++++++++++++++" << std::endl;
1122  const_cast<NCstyle&>( NCurses::style() ).changeSyle();
1123  NCurses::Redraw();
1124  yuiMilestone() << "CTRL('D')-'S' STYLEDEF---------------------" << std::endl;
1125  }
1126 
1127  break;
1128 
1129  case 'Y':
1130  YDialogSpy::showDialogSpy();
1131  break;
1132 
1133  }
1134 
1135  break;
1136 
1137  case KEY_TAB:
1138 
1139  case CTRL( 'F' ):
1140  ActivateNext();
1141  break;
1142 
1143  case KEY_BTAB:
1144 
1145  case CTRL( 'B' ):
1146  ActivatePrev();
1147  break;
1148 
1149  case CTRL( 'L' ):
1150  NCurses::Refresh();
1151  break;
1152 
1153  case CTRL( 'A' ):
1154  pendingEvent = getInputEvent( KEY_SLEFT );
1155  break;
1156 
1157  case CTRL( 'E' ):
1158  pendingEvent = getInputEvent( KEY_SRIGHT );
1159  break;
1160 
1161  case KEY_ESC:
1162 
1163  case CTRL( 'X' ):
1164  hch = getch( 0 );
1165  ::flushinp();
1166 
1167  switch ( hch )
1168  {
1169  case WEOF: // no 2nd char, handle ch
1170  pendingEvent = getInputEvent( ch );
1171  break;
1172 
1173  case KEY_ESC:
1174 
1175  case CTRL( 'X' ):
1176  pendingEvent = getInputEvent( hch );
1177  break;
1178 
1179  default:
1180  pendingEvent = getHotkeyEvent( hch );
1181  break;
1182  }
1183 
1184  break;
1185 
1186  default:
1187  if ( ch >= KEY_F( 1 ) && ch <= KEY_F( 24 ) )
1188  {
1189  pendingEvent = getHotkeyEvent( ch );
1190  }
1191  else
1192  {
1193  pendingEvent = getInputEvent( ch );
1194  }
1195 
1196  break;
1197  }
1198 
1199  doUpdate();
1200  }
1201 
1202  noUpdates = false;
1203 
1204  yuiDebug() << "process- " << this << " active " << wActive << std::endl;
1205 }
1206 
1207 
1208 NCursesEvent NCDialog::getInputEvent( wint_t ch )
1209 {
1210  NCursesEvent ret = NCursesEvent::none;
1211 
1212  if ( wActive->isValid() )
1213  {
1214  ret = wHandleInput( ch );
1215  ret.widget = wActive;
1216  }
1217 
1218  return ret;
1219 }
1220 
1221 
1222 NCursesEvent NCDialog::wHandleInput( wint_t ch )
1223 {
1224  return wActive->wHandleInput( ch );
1225 }
1226 
1227 
1228 NCursesEvent NCDialog::getHotkeyEvent( wint_t key )
1229 {
1230  NCursesEvent ret = NCursesEvent::none;
1231 
1232  if ( wActive->isValid() )
1233  {
1234  ret = wHandleHotkey( key );
1235  ret.widget = wActive;
1236  }
1237 
1238  return ret;
1239 }
1240 
1241 
1242 NCursesEvent NCDialog::wHandleHotkey( wint_t key )
1243 {
1244  if ( key >= 0 && ActivateByKey( key ) )
1245  return wActive->wHandleHotkey( key );
1246 
1247  return NCursesEvent::none;
1248 }
1249 
1250 
1251 std::ostream & operator<<( std::ostream & STREAM, const NCDialog * OBJ )
1252 {
1253  if ( OBJ )
1254  return STREAM << *OBJ;
1255 
1256  return STREAM << "(NoNCDialog)";
1257 }
1258 
1259 
1260 
1261 /**
1262  * Create description for function keys:
1263  *
1264  * Get all PushButtons and MenuButtons that have a function key std::set
1265  * (`opt(`key_Fn) in YCP) and create a std::map:
1266  * $[ 1: "Help", 2: "Info",... ]
1267  * NCurses::SetStatusLine will process this.
1268  **/
1269 std::map<int, NCstring> NCDialog::describeFunctionKeys( )
1270 {
1271  std::map<int, NCstring> fkeys;
1272 
1273  for ( tnode<NCWidget*> * c = this->Next(); c; c = c->Next() )
1274  {
1275  YWidget * w = dynamic_cast<YWidget *>( c->Value() );
1276 
1277  if ( w && w->hasFunctionKey() && w->isEnabled() )
1278  {
1279  // Retrieve the widget's "shortcut property" that describes
1280  // whatever it is - regardless of widget type (PushButton, ...)
1281 
1282  fkeys[ w->functionKey()] = NCstring(w->debugLabel());
1283  }
1284  }
1285 
1286  return fkeys;
1287 }
1288 
1289 
1290 std::ostream & operator<<( std::ostream & STREAM, const NCDialog & OBJ )
1291 {
1292  STREAM << ( const NCWidget & )OBJ << ' ' << OBJ.pan
1293  << ( OBJ.active ? "{A " : "{i " ) << OBJ.pendingEvent;
1294 
1295  if ( OBJ.pendingEvent )
1296  STREAM << OBJ.pendingEvent.widget;
1297 
1298  return STREAM << '}';
1299 }
1300 
1301 
1302 bool NCDialog::getInvisible()
1303 {
1304  if ( !pan || pan->hidden() )
1305  return false; // no change in visibility
1306 
1307  // just do it.
1308  // caller is responsible for screen update.
1309  pan->hide();
1310 
1311  return true;
1312 }
1313 
1314 
1315 bool NCDialog::getVisible()
1316 {
1317  if ( !pan || !pan->hidden() )
1318  return false; // no change in visibility
1319 
1320  // just do it.
1321  // caller is responsible for screen update.
1322  pan->show();
1323 
1324  if ( hshaddow )
1325  {
1326  pan->transparent( pan->maxy(), 0 );
1327  }
1328 
1329  if ( vshaddow )
1330  {
1331  pan->transparent( 0, pan->maxx() );
1332  }
1333 
1334  return true;
1335 }
1336 
1337 
1338 void NCDialog::resizeEvent()
1339 {
1340  _init_size();
1341 
1342  if ( pan )
1343  {
1344  setInitialSize();
1345  }
1346 }
1347 
1348 void NCDialog::showHotkeyHelp()
1349 {
1350  YDialog::showText(
1351  _( "<h1>Advanced Hotkeys:</h1>"
1352  "<p><b>Shift-F1</b> Show a list of advanced hotkeys.</p>"
1353  "<p><b>Shift-F4</b> Change color schema.</p>"
1354  "<p><b>Ctrl-\\</b> Quit the application.</p>"
1355  "<p><b>Ctrl-L</b> Refresh screen.</p>"
1356  "<p><b>Ctrl-D F1</b> Show a list of advanced hotkeys.</p>"
1357  "<p><b>Ctrl-D Shift-D</b> Dump dialog to the log file as a screen shot.</p>"
1358  "<p><b>Ctrl-D Shift-Y</b> Open YDialogSpy to see the widget hierarchy.</p>"
1359  "<p>Depending on your desktop environment some of these key combinations <br/>might not work.</p>" ),
1360  true );
1361 }
virtual void openInternal()
Internal open() method: Initialize what is left over to initialize after all dialog children have bee...
Definition: NCDialog.cc:224
C++ class for windows.
Definition: ncursesw.h:904
virtual void activate()
Activate this dialog: Make sure that it is shown as the topmost dialog of this application and that i...
Definition: NCDialog.cc:307
Definition: tnode.h:31
virtual YEvent * pollEventInternal()
Check if a user event is pending.
Definition: NCDialog.cc:999
Definition: position.h:109
void hide()
Hide the panel.
Definition: ncursesp.h:150
Helper class for translating an NCurses event to a YEvent.
Definition: NCtoY2Event.h:36
virtual YEvent * waitForEventInternal(int timeout_millisec)
Wait for a user event.
Definition: NCDialog.cc:983
Definition: position.h:154
YEvent * propagate()
The reason of existence of this class: Translate the NCursesEvent to a YEvent.
Definition: NCtoY2Event.cc:52