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: NCWidget.cc 00020 00021 Author: Michael Andres <ma@suse.de> 00022 00023 /-*/ 00024 00025 #include <climits> 00026 00027 #define YUILogComponent "ncurses" 00028 #include <yui/YUILog.h> 00029 #include "tnode.h" 00030 #include "NCWidget.h" 00031 #include <yui/YWidget.h> 00032 00033 00034 NCWidget::NCWidget( YWidget * parent ) 00035 : tnode<NCWidget*>( this ) 00036 , magic( YWIDGET_MAGIC ) 00037 , grabedBy( 0 ) 00038 , win( 0 ) 00039 , defsze( 11, 45 ) 00040 , framedim( 0, 0 ) 00041 , inparent( -1, -1 ) 00042 , noUpdates( false ) 00043 , skipNoDimWin( true ) 00044 , wstate( NC::WSnormal ) 00045 , hotlabel( 0 ) 00046 { 00047 NCWidget * myparent = dynamic_cast<NCWidget *>( parent ); 00048 00049 if ( myparent ) 00050 { 00051 ReparentTo( *myparent ); 00052 00053 yuiDebug() << "CCC " << this << " parent " << myparent << std::endl; 00054 } 00055 } 00056 00057 00058 NCWidget::NCWidget( NCWidget * myparent ) 00059 : tnode<NCWidget*>( this ) 00060 , magic( YWIDGET_MAGIC ) 00061 , grabedBy( 0 ) 00062 , win( 0 ) 00063 , defsze( 11, 45 ) 00064 , framedim( 0, 0 ) 00065 , inparent( -1, -1 ) 00066 , noUpdates( false ) 00067 , skipNoDimWin( true ) 00068 , wstate( NC::WSnormal ) 00069 , hotlabel( 0 ) 00070 { 00071 if ( myparent ) 00072 { 00073 ReparentTo( *myparent ); 00074 } 00075 00076 yuiDebug() << "CCC " << this << " parent " << myparent << std::endl; 00077 } 00078 00079 00080 00081 NCWidget::~NCWidget() 00082 { 00083 yuiDebug() << "DD+ " << this << std::endl; 00084 wDelete(); 00085 00086 while ( Fchild() ) 00087 Fchild()->Disconnect(); 00088 00089 Disconnect(); 00090 00091 invalidate(); 00092 00093 yuiDebug() << "DD- " << this << std::endl; 00094 } 00095 00096 00097 00098 00099 void NCWidget::PreDisconnect() 00100 { 00101 grabRelease( 0 ); 00102 } 00103 00104 00105 00106 void NCWidget::PostDisconnect() 00107 {} 00108 00109 00110 00111 void NCWidget::PreReparent() 00112 {} 00113 00114 00115 00116 void NCWidget::PostReparent() 00117 {} 00118 00119 00120 00121 bool NCWidget::grabFocus() 00122 { 00123 return Top().Value()->wantFocus( *this ); 00124 } 00125 00126 00127 00128 // Actualy perform sreen update. 00129 void NCWidget::wUpdate( bool forced_br ) 00130 { 00131 if ( !win ) 00132 return; 00133 00134 if ( noUpdates && !forced_br ) 00135 return; 00136 00137 NCurses::Update(); 00138 } 00139 00140 00141 00142 // Redirect Update request to topmost widget 00143 void NCWidget::Update() 00144 { 00145 if ( noUpdates ) 00146 return; 00147 00148 if ( Parent() ) 00149 { 00150 Parent()->Value()->Update(); 00151 } 00152 else 00153 { 00154 wUpdate(); 00155 } 00156 } 00157 00158 00159 00160 NCursesWindow * NCWidget::ParentWin() 00161 { 00162 if ( !Parent() ) 00163 { 00164 return 0; 00165 } 00166 00167 return Parent()->Value()->win; 00168 } 00169 00170 00171 00172 void NCWidget::wMoveChildTo( NCWidget & child, const wpos & newpos ) 00173 { 00174 yuiDebug() << "mc+ " << DLOC << child << " -> " << newpos << " in " << this << std::endl; 00175 00176 try 00177 { 00178 child.wMoveTo( newpos ); 00179 Redraw( true ); 00180 } 00181 catch ( NCursesError & err ) 00182 { 00183 yuiError() << DLOC << child << " -> " << newpos << " in " << this << std::endl; 00184 yuiError() << err << std::endl; 00185 ::endwin(); 00186 abort(); 00187 } 00188 00189 yuiDebug() << "mc- " << DLOC << child << std::endl; 00190 } 00191 00192 00193 00194 void NCWidget::wRelocate( const wrect & newrect ) 00195 { 00196 yuiDebug() << "rl+ " << this << " -> " << newrect << std::endl; 00197 00198 try 00199 { 00200 if ( win ) 00201 { 00202 wDelete(); 00203 } 00204 00205 wCreate( newrect ); 00206 SetState( wstate, true ); 00207 } 00208 catch ( NCursesError & err ) 00209 { 00210 yuiError() << *this << std::endl; 00211 yuiError() << err << std::endl; 00212 ::endwin(); 00213 abort(); 00214 } 00215 00216 yuiDebug() << "rl- " << this << std::endl; 00217 } 00218 00219 00220 00221 void NCWidget::wMoveTo( const wpos & newpos ) 00222 { 00223 if ( !win ) 00224 { 00225 yuiDebug() << "No win to move: " << this << " -> " << newpos << std::endl; 00226 return; 00227 } 00228 00229 if ( !Parent() ) 00230 throw NCError( "wMoveTo: got no parent" ); 00231 00232 if ( skipNoDimWin && inparent.Sze.H == 0 ) 00233 { 00234 yuiDebug() << "Skip widget with zero height: " << this << ' ' << inparent << " par " << Parent()->Value() << std::endl; 00235 return; 00236 } 00237 00238 if ( skipNoDimWin && inparent.Sze.W == 0 ) 00239 { 00240 yuiDebug() << "Skip widget with zero width: " << this << ' ' << inparent << " par " << Parent()->Value() << std::endl; 00241 return; 00242 } 00243 00244 if ( inparent.Pos != newpos ) 00245 { 00246 yuiDebug() << "mv+ " << this << " -> " << newpos << " par " << Parent()->Value() << std::endl; 00247 NCWidget & p( *Parent()->Value() ); 00248 p.win->mvsubwin( win, 00249 newpos.L + Parent()->Value()->framedim.Pos.L, 00250 newpos.C + Parent()->Value()->framedim.Pos.C ); 00251 inparent.Pos = newpos; 00252 yuiDebug() << "mv- " << this << std::endl; 00253 } 00254 } 00255 00256 00257 00258 void NCWidget::wCreate( const wrect & newrect ) 00259 { 00260 if ( win ) 00261 throw NCError( "wCreate: already have win" ); 00262 00263 if ( !Parent() ) 00264 throw NCError( "wCreate: got no parent" ); 00265 00266 inparent = newrect; 00267 00268 if ( skipNoDimWin && inparent.Sze == wsze( 0, 0 ) ) 00269 { 00270 yuiDebug() << "Skip nodim widget: " << this << ' ' << inparent << " par " << Parent()->Value() << std::endl; 00271 return; 00272 } 00273 00274 if ( skipNoDimWin && inparent.Sze.H == 0 ) 00275 { 00276 yuiDebug() << "Skip widget with zero height: " << this << ' ' << inparent << " par " << Parent()->Value() << std::endl; 00277 return; 00278 } 00279 00280 if ( skipNoDimWin && inparent.Sze.W == 0 ) 00281 { 00282 yuiDebug() << "Skip widget with zero width: " << this << ' ' << inparent << " par " << Parent()->Value() << std::endl; 00283 return; 00284 } 00285 00286 NCursesWindow * parw = ParentWin(); 00287 00288 if ( Parent() && !parw ) 00289 { 00290 yuiError() << "Can't create widget in nodim parent: " << this << ' ' << inparent << " par " << Parent()->Value() << std::endl; 00291 inparent.Sze = wsze( 0, 0 ); 00292 return; 00293 } 00294 00295 yuiDebug() << "cw+ " << this << ' ' << inparent << " par " << Parent()->Value() << std::endl; 00296 00297 if ( parw ) 00298 { 00299 try 00300 { 00301 win = new NCursesWindow( *parw, 00302 inparent.Sze.H, inparent.Sze.W, 00303 inparent.Pos.L + Parent()->Value()->framedim.Pos.L, 00304 inparent.Pos.C + Parent()->Value()->framedim.Pos.C, 00305 'r' ); 00306 } 00307 catch ( ... ) 00308 { 00309 try 00310 { 00311 win = new NCursesWindow( *parw, 00312 inparent.Sze.H, inparent.Sze.W, 00313 inparent.Pos.L, 00314 inparent.Pos.C, 00315 'r' ); 00316 } 00317 catch ( ... ) 00318 { 00319 inparent.Sze = wsze( 1, 1 ); 00320 inparent.Pos = wpos( 0, 0 ); 00321 win = new NCursesWindow( *parw, 1, 1, 0, 0, 'r' ); 00322 } 00323 } 00324 } 00325 else 00326 { 00327 win = new NCursesWindow( inparent.Sze.H, inparent.Sze.W, 00328 inparent.Pos.L, inparent.Pos.C ); 00329 } 00330 00331 yuiDebug() << "cw- " << this << ' ' << inparent << std::endl; 00332 } 00333 00334 00335 00336 void NCWidget::wDelete() 00337 { 00338 if ( win ) 00339 { 00340 yuiDebug() << "wd+ " << this << std::endl; 00341 00342 for ( tnode<NCWidget *> * ch = Fchild(); ch; ch = ch->Nsibling() ) 00343 { 00344 ch->Value()->wDelete(); 00345 } 00346 00347 win->clear(); 00348 00349 delete win; 00350 win = 0; 00351 inparent = wrect( -1, -1 ); 00352 yuiDebug() << "wd- " << this << std::endl; 00353 } 00354 } 00355 00356 00357 00358 wpos NCWidget::ScreenPos() const 00359 { 00360 if ( !win ) 00361 return -1; 00362 00363 if ( Parent() ) 00364 { 00365 return Parent()->Value()->ScreenPos() + inparent.Pos; 00366 } 00367 00368 return wsze( win->begy(), win->begx() ); 00369 } 00370 00371 00372 00373 void NCWidget::SetState( const NC::WState newstate, const bool force ) 00374 { 00375 if ( newstate != wstate || force ) 00376 { 00377 yuiDebug() << DLOC << wstate << " -> " << newstate << std::endl; 00378 wstate = newstate; 00379 00380 if ( win ) 00381 { 00382 win->bkgd( wStyle().getWidget( wstate ).plain ); 00383 } 00384 00385 Redraw(); 00386 } 00387 } 00388 00389 00390 00391 void NCWidget::setEnabled( bool do_bv ) 00392 { 00393 yuiDebug() << DLOC << this << ' ' << do_bv << ' ' << wstate << std::endl; 00394 00395 tnode<NCWidget*> *c = this; 00396 00397 // If widget has children ([HV]Boxes, alignments,...), disable all of 00398 // them recursively (#256707). 00399 00400 if ( c->HasChildren() ) 00401 { 00402 yuiMilestone() << this << "setEnabled children recursively" << std::endl; 00403 00404 for ( c = this->Next(); 00405 c && c->IsDescendantOf( this ); 00406 c = c->Next() ) 00407 { 00408 if ( c->Value()->GetState() != NC::WSdumb ) 00409 c->Value()->setEnabled( do_bv ); 00410 } 00411 } 00412 00413 else 00414 { 00415 if ( wstate == NC::WSdumb ) 00416 return; 00417 00418 if ( do_bv && wstate == NC::WSdisabeled ) 00419 { 00420 SetState( NC::WSnormal ); 00421 } 00422 else if ( !do_bv && wstate != NC::WSdisabeled ) 00423 { 00424 if ( wstate == NC::WSactive ) 00425 grabRelease( 0 ); 00426 00427 SetState( NC::WSdisabeled ); 00428 } 00429 } 00430 } 00431 00432 00433 00434 void NCWidget::Redraw( const bool sub ) 00435 { 00436 if ( !win ) 00437 { 00438 return; 00439 } 00440 00441 bool savNoUpdates = noUpdates; 00442 00443 noUpdates = true; 00444 00445 if ( sub ) 00446 { 00447 win->clear(); 00448 wRedraw(); 00449 00450 for ( tnode<NCWidget *> * ch = Fchild(); ch; ch = ch->Nsibling() ) 00451 { 00452 ch->Value()->Redraw( sub ); 00453 } 00454 } 00455 else 00456 { 00457 wRedraw(); 00458 } 00459 00460 noUpdates = savNoUpdates; 00461 00462 Update(); 00463 } 00464 00465 00466 00467 void NCWidget::wRedraw() 00468 { 00469 } 00470 00471 00472 00473 void NCWidget::Recoded() 00474 { 00475 if ( !win ) 00476 { 00477 return; 00478 } 00479 00480 bool savNoUpdates = noUpdates; 00481 00482 noUpdates = true; 00483 wRecoded(); 00484 00485 for ( tnode<NCWidget *> * ch = Fchild(); ch; ch = ch->Nsibling() ) 00486 { 00487 ch->Value()->Recoded(); 00488 } 00489 00490 noUpdates = savNoUpdates; 00491 00492 Update(); 00493 } 00494 00495 00496 00497 void NCWidget::wRecoded() 00498 { 00499 wRedraw(); 00500 } 00501 00502 00503 00504 bool NCWidget::HasHotkey( int key ) 00505 { 00506 if ( key < 0 || UCHAR_MAX < key ) 00507 return false; 00508 00509 if ( !( hotlabel && hotlabel->hasHotkey() ) ) 00510 return false; 00511 00512 return( tolower( key ) == tolower( hotlabel->hotkey() ) ); 00513 } 00514 00515 00516 00517 bool NCWidget::HasFunctionHotkey( int key ) const 00518 { 00519 const YWidget * w = dynamic_cast<const YWidget *>( this ); 00520 00521 if ( w ) 00522 { 00523 if ( key < 0 || ( ! w->hasFunctionKey() ) ) 00524 return false; 00525 00526 return( key == KEY_F( w->functionKey() ) ); 00527 } 00528 else 00529 { 00530 yuiError() << "No YWidget" << std::endl; 00531 return false; 00532 } 00533 } 00534 00535 00536 00537 NCursesEvent NCWidget::wHandleHotkey( wint_t /*key*/ ) 00538 { 00539 return wHandleInput( KEY_HOTKEY ); 00540 } 00541 00542 00543 00544 NCursesEvent NCWidget::wHandleInput( wint_t /*key*/ ) 00545 { 00546 return NCursesEvent::none; 00547 } 00548 00549 00550 std::ostream & operator<<( std::ostream & STREAM, const NCWidget * OBJ ) 00551 { 00552 if ( OBJ && OBJ->isValid() ) 00553 return STREAM << *OBJ; 00554 00555 return STREAM << "(NoNCWidget)"; 00556 } 00557 00558 00559 std::ostream & operator<<( std::ostream & STREAM, const NCWidget & OBJ ) 00560 { 00561 if ( OBJ.isValid() ) 00562 return STREAM << OBJ.location() << ( void* )&OBJ 00563 << '(' << OBJ.win 00564 << ' ' << OBJ.inparent 00565 << ' ' << OBJ.wstate 00566 << ')'; 00567 00568 return STREAM << "( invalid NCWidget)"; 00569 } 00570 00571 00572 00573 void NCWidget::DumpOn( std::ostream & str, std::string prfx ) const 00574 { 00575 str 00576 //<< prfx << "|" << std::endl 00577 << prfx << "+-" << this << std::endl; 00578 prfx += ( Nsibling() ? "| " : " " ); 00579 00580 for ( const tnode<NCWidget *> * ch = Fchild(); ch; ch = ch->Nsibling() ) 00581 { 00582 ch->Value()->DumpOn( str, prfx ); 00583 } 00584 } 00585