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