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