libyui-ncurses
2.44.1
|
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 }