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