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