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