libyui-ncurses  2.44.1
/usr/src/RPM/BUILD/libyui-ncurses-2.44.1/src/NCDialog.cc
00001 /*
00002   Copyright (C) 2000-2012 Novell, Inc
00003   This library is free software; you can redistribute it and/or modify
00004   it under the terms of the GNU Lesser General Public License as
00005   published by the Free Software Foundation; either version 2.1 of the
00006   License, or (at your option) version 3.0 of the License. This library
00007   is distributed in the hope that it will be useful, but WITHOUT ANY
00008   WARRANTY; without even the implied warranty of MERCHANTABILITY or
00009   FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
00010   License for more details. You should have received a copy of the GNU
00011   Lesser General Public License along with this library; if not, write
00012   to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
00013   Floor, Boston, MA 02110-1301 USA
00014 */
00015 
00016 
00017 /*-/
00018 
00019    File:       NCDialog.cc
00020 
00021    Author:     Michael Andres <ma@suse.de>
00022 
00023 /-*/
00024 
00025 #define  YUILogComponent "ncurses"
00026 #include <yui/YUILog.h>
00027 #include "NCDialog.h"
00028 #include "NCstring.h"
00029 #include "NCPopupInfo.h"
00030 #include "NCMenuButton.h"
00031 #include <yui/YShortcut.h>
00032 #include "NCi18n.h"
00033 #include "NCtoY2Event.h"
00034 #include <yui/YDialogSpy.h>
00035 
00036 #include "ncursesw.h"
00037 
00038 
00039 /*
00040   Textdomain "ncurses"
00041  */
00042 
00043 
00044 static bool hiddenMenu()
00045 {
00046     return getenv( "Y2NCDBG" ) != NULL;
00047 }
00048 
00049 
00050 NCDialog::NCDialog( YDialogType         dialogType,
00051                     YDialogColorMode    colorMode )
00052     : YDialog( dialogType, colorMode )
00053     , pan( 0 )
00054     , dlgstyle( 0 )
00055     , inMultiDraw_i( 0 )
00056     , active( false )
00057     , wActive( this )
00058     , ncdopts( DEFAULT )
00059     , popedpos( -1 )
00060 {
00061     yuiDebug() << "Constructor NCDialog(YDialogType t, YDialogColorMode c)" << std::endl;
00062     _init();
00063 }
00064 
00065 
00066 NCDialog::NCDialog( YDialogType dialogType, const wpos at, const bool boxed )
00067         : YDialog( dialogType, YDialogNormalColor )
00068         , pan( 0 )
00069         , dlgstyle( 0 )
00070         , inMultiDraw_i( 0 )
00071         , active( false )
00072         , wActive( this )
00073         , ncdopts( boxed ? POPUP : POPUP | NOBOX )
00074         , popedpos( at )
00075 {
00076     yuiDebug() << "Constructor NCDialog(YDialogType t, const wpos at, const bool boxed)" << std::endl;
00077     _init();
00078 }
00079 
00080 
00081 void NCDialog::_init()
00082 {
00083     NCurses::RememberDlg( this );
00084     // don't set text domain to ncurses - other text domains won't work (bnc #476245)
00085     // setTextdomain( "ncurses" );
00086     _init_size();
00087     wstate = NC::WSdumb;
00088 
00089     if ( colorMode() == YDialogWarnColor )
00090     {
00091         mystyleset = NCstyle::WarnStyle;
00092     }
00093     else if ( colorMode() == YDialogInfoColor )
00094     {
00095         mystyleset = NCstyle::InfoStyle;
00096     }
00097     else if ( isPopup() )
00098     {
00099         mystyleset = NCstyle::PopupStyle;
00100     }
00101     else
00102     {
00103         mystyleset = NCstyle::DefaultStyle;
00104     }
00105 
00106     dlgstyle = &NCurses::style()[mystyleset];
00107 
00108     eventReason = YEvent::UnknownReason;
00109     yuiDebug() << "+++ " << this << std::endl;
00110 }
00111 
00112 
00113 void NCDialog::_init_size()
00114 {
00115     defsze.H = NCurses::lines();
00116     defsze.W = NCurses::cols();
00117     hshaddow = vshaddow = false;
00118 
00119     if ( isBoxed() )
00120     {
00121         switch ( defsze.H )
00122         {
00123             case 1:
00124             case 2:
00125                 defsze.H = 1;
00126                 break;
00127 
00128             default:
00129                 defsze.H -= 2;
00130                 break;
00131         }
00132 
00133         switch ( defsze.W )
00134         {
00135             case 1:
00136             case 2:
00137                 defsze.W = 1;
00138                 break;
00139 
00140             default:
00141                 defsze.W -= 2;
00142                 break;
00143         }
00144     }
00145 }
00146 
00147 
00148 NCDialog::~NCDialog()
00149 {
00150     NCurses::ForgetDlg( this );
00151 
00152     yuiDebug() << "--+START destroy " << this << std::endl;
00153 
00154     if ( pan && !pan->hidden() )
00155     {
00156         pan->hide();
00157         doUpdate();
00158     }
00159 
00160     grabActive( 0 );
00161 
00162     NCWidget::wDelete();
00163     delete pan;
00164     pan = 0;
00165     yuiDebug() << "---destroyed " << this << std::endl;
00166 
00167 }
00168 
00169 
00170 int NCDialog::preferredWidth()
00171 {
00172     if ( dialogType() == YMainDialog || ! hasChildren() )
00173         return  wGetDefsze().W;
00174 
00175     wsze csze( 0, 0 );
00176 
00177     if ( hasChildren() )
00178     {
00179         csze = wsze( firstChild()->preferredHeight(),
00180                      firstChild()->preferredWidth() );
00181     }
00182 
00183     csze = wsze::min( wGetDefsze(), wsze::max( csze, wsze( 1 ) ) );
00184 
00185     return csze.W;
00186 }
00187 
00188 
00189 int NCDialog::preferredHeight()
00190 {
00191     if ( dialogType() == YMainDialog || ! hasChildren() )
00192     {
00193         return wGetDefsze().H;
00194     }
00195 
00196     wsze csze( 0, 0 );
00197 
00198     if ( hasChildren() )
00199     {
00200         csze = wsze( firstChild()->preferredHeight(),
00201                      firstChild()->preferredWidth() );
00202     }
00203 
00204     csze = wsze::min( wGetDefsze(),
00205                       wsze::max( csze, wsze( 1 ) ) );
00206 
00207     return csze.H;
00208 }
00209 
00210 
00211 void NCDialog::setSize( int newwidth, int newheight )
00212 {
00213     wRelocate( wpos( 0 ), wsze( newheight, newwidth ) );
00214     yuiDebug() << "setSize() called: width: " << newwidth << "   height: " << newheight << std::endl;
00215     YDialog::setSize( newwidth, newheight );
00216 }
00217 
00218 
00219 void NCDialog::initDialog()
00220 {
00221     if ( !pan )
00222     {
00223         yuiDebug() << "setInitialSize() called!" << std::endl;
00224         setInitialSize();
00225     }
00226 }
00227 
00228 
00229 void NCDialog::openInternal()
00230 {
00231     showDialog();
00232 }
00233 
00234 
00235 void NCDialog::showDialog()
00236 {
00237     yuiDebug() << "sd+ " << this << std::endl;
00238 
00239     if ( pan && pan->hidden() )
00240     {
00241         YPushButton *defaultB = YDialog::defaultButton();
00242 
00243         if ( defaultB )
00244         {
00245             defaultB->setKeyboardFocus();
00246         }
00247 
00248         getVisible();
00249 
00250         doUpdate();
00251         DumpOn( yuiDebug(), " " );
00252 
00253     }
00254     else if ( !pan )
00255     {
00256         yuiMilestone() << "no pan" << std::endl;
00257     }
00258 
00259     activate( true );
00260 
00261     yuiDebug() << "sd- " << this << std::endl;
00262 }
00263 
00264 
00265 void NCDialog::closeDialog()
00266 {
00267     yuiDebug() << "cd+ " << this << std::endl;
00268     activate( false );
00269 
00270     if ( pan && !pan->hidden() )
00271     {
00272         pan->hide();
00273         doUpdate();
00274         yuiDebug() << this << std::endl;
00275     }
00276 
00277     yuiDebug() << "cd+ " << this << std::endl;
00278 }
00279 
00280 
00281 void NCDialog::activate( const bool newactive )
00282 {
00283     if ( active != newactive || ( pan && pan->hidden() ) )
00284     {
00285         active = newactive;
00286 
00287         if ( pan )
00288         {
00289             pan->show(); // not getVisible() because wRedraw() follows.
00290             wRedraw();
00291 
00292             if ( active )
00293                 Activate();
00294             else
00295                 Deactivate();
00296 
00297             NCurses::SetStatusLine( describeFunctionKeys() );
00298             doUpdate();
00299             yuiDebug() << this << std::endl;
00300         }
00301     }
00302 }
00303 
00304 
00305 /**
00306  * Implementation of YDialog::activate().
00307  *
00308  * This is called e.g. for the next-lower dialog in the dialog stack when the
00309  * topmost dialog is destroyed: That next-lower dialog is now the active
00310  * dialog.
00311  **/
00312 void NCDialog::activate()
00313 {
00314     activate( true ); // Forward to NCurses-specific activate()
00315 }
00316 
00317 
00318 void NCDialog::wMoveTo( const wpos & newpos )
00319 {
00320     yuiDebug() << DLOC << this << newpos << std::endl;
00321 }
00322 
00323 
00324 void NCDialog::wCreate( const wrect & newrect )
00325 {
00326     if ( win )
00327         throw NCError( "wCreate: already have win" );
00328 
00329     wrect panrect( newrect );
00330 
00331     inparent = newrect;
00332 
00333     if ( isBoxed() )
00334     {
00335         switch ( NCurses::lines() - panrect.Sze.H )
00336         {
00337             case 0:
00338                 break;
00339 
00340             case 1:
00341                 panrect.Sze.H += 1;
00342                 inparent.Pos.L += 1;
00343                 break;
00344 
00345             default:
00346                 panrect.Sze.H += 2;
00347                 inparent.Pos.L += 1;
00348                 break;
00349         }
00350 
00351         switch ( NCurses::cols() - panrect.Sze.W )
00352         {
00353             case 0:
00354                 break;
00355 
00356             case 1:
00357                 panrect.Sze.W += 1;
00358                 inparent.Pos.C += 1;
00359                 break;
00360 
00361             default:
00362                 panrect.Sze.W += 2;
00363                 inparent.Pos.C += 1;
00364                 break;
00365         }
00366     }
00367 
00368     if ( popedpos.L >= 0 )
00369     {
00370         if ( popedpos.L + panrect.Sze.H <= NCurses::lines() )
00371             panrect.Pos.L = popedpos.L;
00372         else
00373             panrect.Pos.L = NCurses::lines() - panrect.Sze.H;
00374     }
00375     else
00376     {
00377         panrect.Pos.L = ( NCurses::lines() - panrect.Sze.H ) / 2;
00378     }
00379 
00380     if ( popedpos.C >= 0 )
00381     {
00382         if ( popedpos.C + panrect.Sze.W <= NCurses::cols() )
00383             panrect.Pos.C = popedpos.C;
00384         else
00385             panrect.Pos.C = NCurses::cols() - panrect.Sze.W;
00386     }
00387     else
00388     {
00389         panrect.Pos.C = ( NCurses::cols() - panrect.Sze.W ) / 2;
00390     }
00391 
00392     if ( panrect.Pos.L + panrect.Sze.H < NCurses::lines() )
00393     {
00394         ++panrect.Sze.H;
00395         hshaddow = true;
00396     }
00397 
00398     if ( panrect.Pos.C + panrect.Sze.W < NCurses::cols() )
00399     {
00400         ++panrect.Sze.W;
00401         vshaddow = true;
00402     }
00403 
00404     if ( pan && panrect != wrect( wpos( pan->begy(), pan->begx() ),
00405                                   wsze( pan->maxy() + 1, pan->maxx() + 1 ) ) )
00406     {
00407         pan->hide();
00408         doUpdate();
00409         delete pan;
00410         pan = 0;
00411     }
00412 
00413     if ( !pan )
00414     {
00415         pan = new NCursesUserPanel<NCDialog>( panrect.Sze.H, panrect.Sze.W,
00416                                               panrect.Pos.L, panrect.Pos.C,
00417                                               this );
00418         pan->hide();
00419         doUpdate();
00420     }
00421 
00422     win = new NCursesWindow( *pan,
00423 
00424                              inparent.Sze.H, inparent.Sze.W,
00425                              inparent.Pos.L, inparent.Pos.C,
00426                              'r' );
00427     win->nodelay( true );
00428 
00429     yuiDebug() << DLOC << panrect << '(' << inparent << ')'
00430     << '[' << popedpos << ']' << std::endl;
00431 }
00432 
00433 
00434 void NCDialog::wRedraw()
00435 {
00436     if ( pan )
00437     {
00438         if ( isBoxed() )
00439         {
00440             pan->bkgdset( wStyle().getDlgBorder( active ).text );
00441 
00442             if ( pan->height() != NCurses::lines()
00443                  || pan->width() != NCurses::cols() )
00444             {
00445                 pan->box();     // not fullscreen
00446             }
00447             else
00448             {
00449                 pan->hline( 0, 0, pan->width(), ' ' );
00450                 pan->hline( pan->height() - 1, 0, pan->width(), ' ' );
00451                 pan->vline( 0, 0, pan->height(), ' ' );
00452                 pan->vline( 0, pan->width() - 1, pan->height(), ' ' );
00453             }
00454 
00455             if ( hshaddow )
00456             {
00457                 pan->copywin( *pan,
00458                               pan->maxy(), 0,
00459                               pan->maxy() - 1, 0,
00460                               pan->maxy() - 1, pan->maxx(), false );
00461             }
00462 
00463             if ( vshaddow )
00464             {
00465                 pan->copywin( *pan,
00466                               0, pan->maxx(),
00467                               0, pan->maxx() - 1,
00468                               pan->maxy(), pan->maxx() - 1, false );
00469             }
00470         }
00471 
00472         pan->bkgdset( A_NORMAL );
00473 
00474         if ( hshaddow )
00475         {
00476             pan->hline( pan->maxy(), 0, pan->width(), ' ' );
00477             pan->transparent( pan->maxy(), 0 );
00478         }
00479 
00480         if ( vshaddow )
00481         {
00482             pan->vline( 0, pan->maxx(), pan->height(), ' ' );
00483             pan->transparent( 0, pan->maxx() );
00484         }
00485     }
00486 }
00487 
00488 
00489 void NCDialog::wRecoded()
00490 {
00491     if ( pan )
00492     {
00493         if ( &NCurses::style()[mystyleset] != dlgstyle )
00494         {
00495             dlgstyle = &NCurses::style()[mystyleset];
00496         }
00497 
00498         pan->bkgdset( wStyle(). getDumb().text );
00499 
00500         pan->clear();
00501         wRedraw();
00502     }
00503 }
00504 
00505 
00506 void NCDialog::startMultipleChanges()
00507 {
00508     ++inMultiDraw_i;
00509 }
00510 
00511 
00512 void NCDialog::doneMultipleChanges()
00513 {
00514     if ( inMultiDraw_i > 1 )
00515     {
00516         --inMultiDraw_i;
00517     }
00518     else
00519     {
00520         inMultiDraw_i = 0;
00521         NCurses::SetStatusLine( describeFunctionKeys() );
00522         Update();
00523     }
00524 }
00525 
00526 void NCDialog::setStatusLine()
00527 {
00528     NCurses::SetStatusLine( describeFunctionKeys() );
00529     doUpdate();
00530 }
00531 
00532 void NCDialog::wUpdate( bool forced_br )
00533 {
00534     if ( !pan )
00535         return;
00536 
00537     if ( !forced_br
00538          && ( pan->hidden() || inMultiDraw_i ) )
00539         return;
00540 
00541     NCWidget::wUpdate( forced_br );
00542 }
00543 
00544 
00545 void NCDialog::grabActive( NCWidget * nactive )
00546 {
00547     if ( wActive && wActive != static_cast<NCWidget *>( this ) )
00548         wActive->grabRelease( this );
00549 
00550     if ( nactive && nactive != static_cast<NCWidget *>( this ) )
00551         nactive->grabSet( this );
00552 
00553     const_cast<NCWidget *&>( wActive ) = nactive;
00554 }
00555 
00556 
00557 void NCDialog::grabNotify( NCWidget * mgrab )
00558 {
00559     if ( wActive && wActive == mgrab )
00560     {
00561         yuiDebug() << DLOC << mgrab << " active " << std::endl;
00562         ActivateNext();
00563 
00564         if ( wActive && wActive == mgrab )
00565             grabActive( this );
00566     }
00567 }
00568 
00569 
00570 bool NCDialog::wantFocus( NCWidget & ngrab )
00571 {
00572     return Activate( ngrab );
00573 }
00574 
00575 
00576 void NCDialog::wDelete()
00577 {
00578     if ( pan )
00579     {
00580         yuiDebug() << DLOC << "+++ " << this << std::endl;
00581         NCWidget::wDelete();
00582         yuiDebug() << DLOC << "--- " << this << std::endl;
00583     }
00584 }
00585 
00586 
00587 NCWidget & NCDialog::GetNormal( NCWidget & startwith, SeekDir Direction )
00588 {
00589     NCWidget * c = ( startwith.*Direction )( true )->Value();
00590 
00591     while ( c != &startwith && ( c->GetState() != NC::WSnormal || !c->winExist() ) )
00592     {
00593         if ( c->GetState() == NC::WSactive )
00594         {
00595             yuiWarning() << "multiple active widgets in dialog? "
00596             << startwith << " <-> " << c << std::endl;
00597             c->SetState( NC::WSnormal ); // what else can we do?
00598             break;
00599         }
00600 
00601         c = ( c->*Direction )( true )->Value();
00602     }
00603 
00604     return *c;
00605 }
00606 
00607 
00608 NCWidget & NCDialog::GetNextNormal( NCWidget & startwith )
00609 {
00610     return GetNormal( startwith, &tnode<NCWidget *>::Next );
00611 }
00612 
00613 
00614 NCWidget & NCDialog::GetPrevNormal( NCWidget & startwith )
00615 {
00616     return GetNormal( startwith, &tnode<NCWidget *>::Prev );
00617 }
00618 
00619 
00620 bool NCDialog::Activate( NCWidget & nactive )
00621 {
00622     if ( nactive.GetState() == NC::WSactive )
00623         return true;
00624 
00625     if ( nactive.GetState() == NC::WSnormal )
00626     {
00627         if ( wActive->GetState() == NC::WSactive )
00628             wActive->SetState( NC::WSnormal );
00629 
00630         if ( active )
00631         {
00632             nactive.SetState( NC::WSactive );
00633         }
00634 
00635         grabActive( &nactive );
00636 
00637         return true;
00638     }
00639 
00640     return false;
00641 }
00642 
00643 
00644 void NCDialog::Activate( SeekDir Direction )
00645 {
00646     if ( !wActive )
00647         grabActive( this );
00648 
00649     if ( Direction == 0 )
00650     {
00651         if ( Activate( *wActive ) )
00652             return;   // (re)activated widget
00653 
00654         // can't (re)activate widget, so look for next one
00655         Direction = &tnode<NCWidget *>::Next;
00656     }
00657 
00658     Activate( GetNormal( *wActive, Direction ) );
00659 }
00660 
00661 
00662 void NCDialog::Activate()
00663 {
00664     Activate( 0 );
00665 }
00666 
00667 
00668 void NCDialog::Deactivate()
00669 {
00670     if ( wActive->GetState() == NC::WSactive )
00671     {
00672         wActive->SetState( NC::WSnormal );
00673     }
00674 }
00675 
00676 
00677 void NCDialog::ActivateNext()
00678 {
00679     Activate( &tnode<NCWidget *>::Next );
00680 }
00681 
00682 
00683 void NCDialog::ActivatePrev()
00684 {
00685     Activate( &tnode<NCWidget *>::Prev );
00686 }
00687 
00688 
00689 bool NCDialog::ActivateByKey( int key )
00690 {
00691     NCWidget * buddy = 0;
00692 
00693     for ( tnode<NCWidget*> * c = this->Next(); c; c = c->Next() )
00694     {
00695         switch ( c->Value()->GetState() )
00696         {
00697             case NC::WSnormal:
00698             case NC::WSactive:
00699 
00700                 if ( c->Value()->HasHotkey( key )
00701                      || c->Value()->HasFunctionHotkey( key ) )
00702                 {
00703                     Activate( *c->Value() );
00704                     return true;
00705                 }
00706 
00707                 if ( buddy )
00708                 {
00709                     if ( c->IsDescendantOf( buddy ) )
00710                     {
00711                         yuiDebug() << "BUDDY ACTIVATION FOR " << c->Value() << std::endl;
00712                         Activate( *c->Value() );
00713                         return true;
00714                     }
00715 
00716                     yuiDebug() << "DROP BUDDY on " << c->Value() << std::endl;
00717 
00718                     buddy = 0;
00719                 }
00720 
00721                 break;
00722 
00723             case NC::WSdumb:
00724 
00725                 if ( c->Value()->HasHotkey( key )
00726                      || c->Value()->HasFunctionHotkey( key ) )
00727                 {
00728                     yuiDebug() << "DUMB HOT KEY " << key << " in " << c->Value() << std::endl;
00729                     buddy = c->Value();
00730                 }
00731 
00732             default:
00733 
00734                 break;
00735         }
00736     }
00737 
00738     return false;
00739 }
00740 
00741 
00742 wint_t NCDialog::getinput()
00743 {
00744     wint_t got = WEOF;
00745 
00746     if ( NCstring::terminalEncoding() == "UTF-8" )
00747     {
00748         wint_t gotwch = WEOF;
00749         int ret = ::get_wch( &gotwch ); // get a wide character
00750 
00751         if ( ret != ERR )       // get_wch() returns OK or KEY_CODE_YES on success
00752         {
00753             got = gotwch;
00754             // UTF-8 keys (above KEY_MIN) may deliver same keycode as curses KEY_...
00755             // -> mark this keys
00756 
00757             if ( ret == OK
00758                  && got > KEY_MIN )
00759             {
00760                 got += 0xFFFF;
00761             }
00762         }
00763         else
00764         {
00765             got = WEOF;
00766         }
00767     }
00768     else
00769     {
00770         std::wstring to;
00771         int gotch = ::getch();  // get the character in terminal encoding
00772 
00773         if ( gotch != -1 )
00774         {
00775             if (( KEY_MIN > gotch || KEY_MAX < gotch )
00776                 &&
00777                 isprint( gotch ) )
00778             {
00779                 std::string str;
00780                 str += static_cast<char>( gotch );
00781                 // recode printable chars
00782                 NCstring::RecodeToWchar( str, NCstring::terminalEncoding(), &to );
00783                 got = to[0];
00784 
00785                 if ( gotch != ( int )got )
00786                 {
00787                     got += 0xFFFF;                      // mark this key
00788                 }
00789 
00790                 yuiDebug() << "Recode: " << str << " (encoding: " << NCstring::terminalEncoding() << ") "
00791 
00792                 << "to wint_t: " << got << std::endl;
00793             }
00794             else
00795             {
00796                 got = gotch;
00797             }
00798         }
00799         else
00800         {
00801             got = WEOF;
00802         }
00803     }
00804 
00805     return got;
00806 }
00807 
00808 
00809 wint_t NCDialog::getch( int timeout_millisec )
00810 {
00811     wint_t got = WEOF;
00812 
00813     if ( timeout_millisec < 0 )
00814     {
00815         // wait for input
00816         ::nodelay( ::stdscr, false );
00817 
00818         got = getinput();
00819 
00820     }
00821     else if ( timeout_millisec )
00822     {
00823         // max halfdelay is 25 seconds (250 tenths of seconds)
00824         do
00825         {
00826             if ( timeout_millisec > 25000 )
00827             {
00828                 ::halfdelay( 250 );
00829                 timeout_millisec -= 25000;
00830             }
00831             else
00832             {
00833                 if ( timeout_millisec < 100 )
00834                 {
00835                     // min halfdelay is 1/10 second (100 milliseconds)
00836                     ::halfdelay( 1 );
00837                 }
00838                 else
00839                     ::halfdelay( timeout_millisec / 100 );
00840 
00841                 timeout_millisec = 0;
00842             }
00843 
00844             got = getinput();
00845         }
00846         while ( got == WEOF && timeout_millisec > 0 );
00847 
00848         ::cbreak(); // stop halfdelay
00849     }
00850     else
00851     {
00852         // no wait
00853         ::nodelay( ::stdscr, true );
00854         got = getinput();
00855     }
00856 
00857     if ( got == KEY_RESIZE )
00858     {
00859         NCurses::ResizeEvent();
00860         int i = 100;
00861         // after resize sometimes WEOF is returned -> skip this in no timeout mode
00862 
00863         do
00864         {
00865             got =  NCDialog::getch( timeout_millisec );
00866         }
00867         while ( timeout_millisec < 0 && got == WEOF && --i );
00868     }
00869 
00870     return got;
00871 }
00872 
00873 
00874 bool NCDialog::flushTypeahead()
00875 {
00876     // Don't throw away keys from the input buffer after a ValueChanged or
00877     // SelectionChanged event but save them e.g. for input in TextEntry,
00878     // MultiLineEdit or to scroll in lists ( bug #245476 )
00879     if ( eventReason == YEvent::ValueChanged ||
00880          eventReason == YEvent::SelectionChanged )
00881     {
00882         yuiDebug() << "DON't flush input buffer - reason: " << eventReason << std::endl;
00883         return false;
00884     }
00885     else
00886     {
00887         yuiDebug() << "Flush input buffer" << std::endl;
00888         return true;
00889     }
00890 }
00891 
00892 
00893 void NCDialog::idleInput()
00894 {
00895     if ( !pan )
00896     {
00897         yuiWarning() << DLOC << " called for uninitialized " << this << std::endl;
00898         ::flushinp();
00899         return;
00900     }
00901 
00902     yuiDebug() << "idle+ " << this << std::endl;
00903 
00904     if ( !active )
00905     {
00906         if ( flushTypeahead() )
00907         {
00908             ::flushinp();
00909         }
00910 
00911         doUpdate();
00912     }
00913     else
00914     {
00915         yuiDebug() << "idle+ " << this << std::endl;
00916         processInput( 0 );
00917         yuiDebug() << "idle- " << this << std::endl;
00918     }
00919 }
00920 
00921 
00922 NCursesEvent NCDialog::pollInput()
00923 {
00924     yuiDebug() << "poll+ " << this << std::endl;
00925 
00926     if ( !pan )
00927     {
00928         yuiWarning() << DLOC << " called for uninitialized " << this << std::endl;
00929         return NCursesEvent::cancel;
00930     }
00931 
00932     if ( pendingEvent )
00933     {
00934         if ( active )
00935         {
00936             activate( false );
00937             yuiDebug() << this << " deactivate" << std::endl;
00938         }
00939     }
00940     else
00941     {
00942         if ( !active )
00943         {
00944             activate( true );
00945             yuiDebug() << this << " activate" << std::endl;
00946         }
00947     }
00948 
00949     NCursesEvent returnEvent = pendingEvent;
00950 
00951     eventReason = returnEvent.reason;
00952     pendingEvent = NCursesEvent::none;
00953 
00954     yuiDebug() << "poll- " << this << '(' << returnEvent << ')' << std::endl;
00955     return returnEvent;
00956 }
00957 
00958 
00959 NCursesEvent NCDialog::userInput( int timeout_millisec )
00960 {
00961     yuiDebug() << "user+ " << this << std::endl;
00962 
00963     if ( flushTypeahead() )
00964     {
00965         ::flushinp();
00966     }
00967 
00968     if ( !pan )
00969     {
00970         yuiWarning() << DLOC << " called for uninitialized " << this << std::endl;
00971         return NCursesEvent::cancel;
00972     }
00973 
00974     processInput( timeout_millisec );
00975 
00976     NCursesEvent returnEvent = pendingEvent;
00977     eventReason = returnEvent.reason;
00978     pendingEvent = NCursesEvent::none;
00979 
00980     yuiDebug() << "user- " << this << '(' << returnEvent << ')' << std::endl;
00981     return returnEvent;
00982 }
00983 
00984 
00985 /**
00986  * Back-end for YDialog::waitForEvent()
00987  **/
00988 YEvent * NCDialog::waitForEventInternal( int timeout_millisec )
00989 {
00990     NCtoY2Event cevent;
00991     activate( true );
00992     cevent = userInput( timeout_millisec ? timeout_millisec : -1 );
00993     activate( false );
00994 
00995     YEvent * yevent = cevent.propagate();
00996 
00997     return yevent;
00998 }
00999 
01000 
01001 /**
01002  * Back-end for YDialog::pollEvent()
01003  **/
01004 YEvent * NCDialog::pollEventInternal()
01005 {
01006     // no activation here, done in pollInput, if..
01007     NCtoY2Event cevent = pollInput();
01008     YEvent * yevent = cevent.propagate();
01009 
01010     return yevent;
01011 }
01012 
01013 
01014 /**
01015  * Process input
01016  *
01017  * timeout -1 -> wait for input
01018  * timeout  0 -> immediate return
01019  * else wait for up to timeout milliseconds
01020  **/
01021 void NCDialog::processInput( int timeout_millisec )
01022 {
01023     yuiDebug() << "process+ " << this << " active " << wActive
01024     << " timeout_millisec " << timeout_millisec << std::endl;
01025 
01026     if ( pendingEvent )
01027     {
01028         yuiDebug() << this << "(return pending event)" << std::endl;
01029         doUpdate();
01030         ::flushinp();
01031         return;
01032     }
01033 
01034     // if no active item return on any input
01035     if ( wActive->GetState() != NC::WSactive )
01036     {
01037         yuiDebug() << "noactive item => reactivate!" << std::endl;
01038         Activate();
01039     }
01040 
01041     if ( wActive->GetState() != NC::WSactive )
01042     {
01043         yuiDebug() << "still noactive item!" << std::endl;
01044 
01045         if ( timeout_millisec == -1 )
01046         {
01047             pendingEvent = NCursesEvent::cancel;
01048             yuiDebug() << DLOC << this << "(std::set ET_CANCEL since noactive item on pollInput)" << std::endl;
01049             getch( -1 );
01050         }
01051         else
01052             ::flushinp();
01053 
01054         // if there is no active widget and we are in timeout, handle properly
01055         // bug #182982
01056         if ( timeout_millisec > 0 )
01057         {
01058             usleep( timeout_millisec * 1000 );
01059             pendingEvent = NCursesEvent::timeout;
01060         }
01061 
01062         return;
01063     }
01064 
01065     // get and process user input
01066     wint_t ch = 0;
01067 
01068     wint_t hch = 0;
01069 
01070     yuiDebug() << "enter loop..." << std::endl;
01071 
01072     noUpdates = true;
01073 
01074     while ( !pendingEvent.isReturnEvent() && ch != WEOF )
01075     {
01076 
01077         ch = getch( timeout_millisec );
01078 
01079         switch ( ch )
01080         {
01081             // case KEY_RESIZE: is directly handled in NCDialog::getch.
01082 
01083             case WEOF:
01084 
01085                 if ( timeout_millisec == -1 )
01086                     pendingEvent = NCursesEvent::cancel;
01087                 else if ( timeout_millisec > 0 )
01088                     pendingEvent = NCursesEvent::timeout;
01089 
01090                 break;
01091 
01092             case KEY_F( 16 ):
01093                 const_cast<NCstyle&>( NCurses::style() ).nextStyle();
01094 
01095                 NCurses::Redraw();
01096 
01097                 break;
01098 
01099             case CTRL( 'D' ):
01100                 hch = getch( -1 );
01101 
01102                 ::flushinp();
01103 
01104                 switch ( hch )
01105                 {
01106                     case 'D':
01107                         yuiMilestone() << "CTRL('D')-'D' DUMP+++++++++++++++++++++" << std::endl;
01108                         NCurses::ScreenShot();
01109                         yuiMilestone() << this << std::endl;
01110                         DumpOn( yuiMilestone(), " " );
01111                         yuiMilestone() << "CTRL('D')-'D' DUMP---------------------" << std::endl;
01112                         break;
01113 
01114                     case 'S':
01115 
01116                         if ( hiddenMenu() )
01117                         {
01118                             yuiMilestone() << "CTRL('D')-'S' STYLEDEF+++++++++++++++++++++" << std::endl;
01119                             const_cast<NCstyle&>( NCurses::style() ).changeSyle();
01120                             NCurses::Redraw();
01121                             yuiMilestone() << "CTRL('D')-'S' STYLEDEF---------------------" << std::endl;
01122                         }
01123 
01124                         break;
01125 
01126                     case 'Y':
01127                         YDialogSpy::showDialogSpy();
01128                         break;
01129 
01130                 }
01131 
01132                 break;
01133 
01134             case KEY_TAB:
01135 
01136             case CTRL( 'F' ):
01137                 ActivateNext();
01138                 break;
01139 
01140             case KEY_BTAB:
01141 
01142             case CTRL( 'B' ):
01143                 ActivatePrev();
01144                 break;
01145 
01146             case CTRL( 'L' ):
01147                 NCurses::Refresh();
01148                 break;
01149 
01150             case CTRL( 'A' ):
01151                 pendingEvent = getInputEvent( KEY_SLEFT );
01152                 break;
01153 
01154             case CTRL( 'E' ):
01155                 pendingEvent = getInputEvent( KEY_SRIGHT );
01156                 break;
01157 
01158             case KEY_ESC:
01159 
01160             case CTRL( 'X' ):
01161                 hch = getch( 0 );
01162                 ::flushinp();
01163 
01164                 switch ( hch )
01165                 {
01166                     case WEOF: // no 2nd char, handle ch
01167                         pendingEvent = getInputEvent( ch );
01168                         break;
01169 
01170                     case KEY_ESC:
01171 
01172                     case CTRL( 'X' ):
01173                         pendingEvent = getInputEvent( hch );
01174                         break;
01175 
01176                     default:
01177                         pendingEvent = getHotkeyEvent( hch );
01178                         break;
01179                 }
01180 
01181                 break;
01182 
01183             default:
01184                 if ( ch >= KEY_F( 1 ) && ch <= KEY_F( 24 ) )
01185                 {
01186                     pendingEvent = getHotkeyEvent( ch );
01187                 }
01188                 else
01189                 {
01190                     pendingEvent = getInputEvent( ch );
01191                 }
01192 
01193                 break;
01194         }
01195 
01196         doUpdate();
01197     }
01198 
01199     noUpdates = false;
01200 
01201     yuiDebug() << "process- " << this << " active " << wActive << std::endl;
01202 }
01203 
01204 
01205 NCursesEvent NCDialog::getInputEvent( wint_t ch )
01206 {
01207     NCursesEvent ret = NCursesEvent::none;
01208 
01209     if ( wActive->isValid() )
01210     {
01211         ret = wHandleInput( ch );
01212         ret.widget = wActive;
01213     }
01214 
01215     return ret;
01216 }
01217 
01218 
01219 NCursesEvent NCDialog::wHandleInput( wint_t ch )
01220 {
01221     return wActive->wHandleInput( ch );
01222 }
01223 
01224 
01225 NCursesEvent NCDialog::getHotkeyEvent( wint_t key )
01226 {
01227     NCursesEvent ret = NCursesEvent::none;
01228 
01229     if ( wActive->isValid() )
01230     {
01231         ret = wHandleHotkey( key );
01232         ret.widget = wActive;
01233     }
01234 
01235     return ret;
01236 }
01237 
01238 
01239 NCursesEvent NCDialog::wHandleHotkey( wint_t key )
01240 {
01241     if ( key >= 0 && ActivateByKey( key ) )
01242         return wActive->wHandleHotkey( key );
01243 
01244     return NCursesEvent::none;
01245 }
01246 
01247 
01248 std::ostream & operator<<( std::ostream & STREAM, const NCDialog * OBJ )
01249 {
01250     if ( OBJ )
01251         return STREAM << *OBJ;
01252 
01253     return STREAM << "(NoNCDialog)";
01254 }
01255 
01256 
01257 
01258 /**
01259  * Create description for function keys:
01260  *
01261  * Get all PushButtons and MenuButtons that have a function key std::set
01262  * (`opt(`key_Fn) in YCP) and create a std::map:
01263  * $[ 1: "Help", 2: "Info",... ]
01264  * NCurses::SetStatusLine will process this.
01265  **/
01266 std::map<int, std::string> NCDialog::describeFunctionKeys( )
01267 {
01268     std::map<int, std::string> fkeys;
01269 
01270     for ( tnode<NCWidget*> * c = this->Next(); c; c = c->Next() )
01271     {
01272         YWidget * w = dynamic_cast<YWidget *>( c->Value() );
01273 
01274         if ( w && w->hasFunctionKey() && w->isEnabled() )
01275         {
01276             // Retrieve the widget's "shortcut property" that describes
01277             // whatever it is - regardless of widget type (PushButton, ...)
01278 
01279             fkeys[ w->functionKey()] = w->debugLabel();
01280         }
01281     }
01282 
01283     return fkeys;
01284 }
01285 
01286 
01287 std::ostream & operator<<( std::ostream & STREAM, const NCDialog & OBJ )
01288 {
01289     STREAM << ( const NCWidget & )OBJ << ' ' << OBJ.pan
01290     << ( OBJ.active ? "{A " : "{i " ) << OBJ.pendingEvent;
01291 
01292     if ( OBJ.pendingEvent )
01293         STREAM << OBJ.pendingEvent.widget;
01294 
01295     return STREAM << '}';
01296 }
01297 
01298 
01299 bool NCDialog::getInvisible()
01300 {
01301     if ( !pan || pan->hidden() )
01302         return false; // no change in visibility
01303 
01304     // just do it.
01305     // caller is responsible for screen update.
01306     pan->hide();
01307 
01308     return true;
01309 }
01310 
01311 
01312 bool NCDialog::getVisible()
01313 {
01314     if ( !pan || !pan->hidden() )
01315         return false; // no change in visibility
01316 
01317     // just do it.
01318     // caller is responsible for screen update.
01319     pan->show();
01320 
01321     if ( hshaddow )
01322     {
01323         pan->transparent( pan->maxy(), 0 );
01324     }
01325 
01326     if ( vshaddow )
01327     {
01328         pan->transparent( 0, pan->maxx() );
01329     }
01330 
01331     return true;
01332 }
01333 
01334 
01335 void NCDialog::resizeEvent()
01336 {
01337     _init_size();
01338 
01339     if ( pan )
01340     {
01341         setInitialSize();
01342     }
01343 }
 All Classes Functions Variables