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: NCInputField.cc 00020 00021 Author: Michael Andres <ma@suse.de> 00022 00023 /-*/ 00024 #include <climits> 00025 00026 00027 #define YUILogComponent "ncurses" 00028 #include <yui/YUILog.h> 00029 #include "NCurses.h" 00030 #include "NCInputField.h" 00031 00032 #include <wctype.h> // iswalnum() 00033 00034 00035 NCInputField::NCInputField( YWidget * parent, 00036 const std::string & nlabel, 00037 bool passwordMode, 00038 unsigned maxInput, 00039 unsigned maxFld ) 00040 : YInputField( parent, nlabel, passwordMode ) 00041 , NCWidget( parent ) 00042 , passwd( passwordMode ) 00043 , lwin( 0 ) 00044 , twin( 0 ) 00045 , maxFldLength( maxFld ) 00046 , maxInputLength( maxInput ) 00047 , fldstart( 0 ) 00048 , fldlength( 0 ) 00049 , curpos( 0 ) 00050 , fldtype( PLAIN ) 00051 , returnOnReturn_b( false ) 00052 , InputMaxLength( -1 ) 00053 { 00054 yuiDebug() << std::endl; 00055 00056 if ( maxInputLength && 00057 ( !maxFldLength || maxFldLength > maxInputLength ) ) 00058 { 00059 maxFldLength = maxInputLength; 00060 } 00061 00062 setLabel( nlabel ); 00063 00064 hotlabel = &label; 00065 // initial text isn't an argument any longer 00066 //setText( ntext ); 00067 } 00068 00069 00070 00071 NCInputField::~NCInputField() 00072 { 00073 delete lwin; 00074 delete twin; 00075 yuiDebug() << std::endl; 00076 } 00077 00078 00079 00080 int NCInputField::preferredWidth() 00081 { 00082 return wGetDefsze().W; 00083 } 00084 00085 00086 00087 int NCInputField::preferredHeight() 00088 { 00089 return wGetDefsze().H; 00090 } 00091 00092 00093 00094 void NCInputField::setEnabled( bool do_bv ) 00095 { 00096 NCWidget::setEnabled( do_bv ); 00097 YInputField::setEnabled( do_bv ); 00098 } 00099 00100 00101 00102 void NCInputField::setSize( int newwidth, int newheight ) 00103 { 00104 wRelocate( wpos( 0 ), wsze( newheight, newwidth ) ); 00105 } 00106 00107 00108 00109 void NCInputField::setDefsze() 00110 { 00111 unsigned defwidth = maxFldLength ? maxFldLength : 5; 00112 00113 if ( label.width() > defwidth ) 00114 defwidth = label.width(); 00115 00116 defsze = wsze( label.height() + 1, defwidth ); 00117 } 00118 00119 00120 00121 void NCInputField::wCreate( const wrect & newrect ) 00122 { 00123 NCWidget::wCreate( newrect ); 00124 00125 if ( !win ) 00126 return; 00127 00128 wrect lrect( 0, wsze::min( newrect.Sze, 00129 wsze( label.height(), newrect.Sze.W ) ) ); 00130 00131 if ( lrect.Sze.H == newrect.Sze.H ) 00132 lrect.Sze.H -= 1; 00133 00134 wrect trect( 0, wsze( 1, newrect.Sze.W ) ); 00135 00136 trect.Pos.L = lrect.Sze.H > 0 ? lrect.Sze.H : 0; 00137 00138 lwin = new NCursesWindow( *win, 00139 lrect.Sze.H, lrect.Sze.W, 00140 lrect.Pos.L, lrect.Pos.C, 00141 'r' ); 00142 00143 twin = new NCursesWindow( *win, 00144 trect.Sze.H, trect.Sze.W, 00145 trect.Pos.L, trect.Pos.C, 00146 'r' ); 00147 00148 if ( maxFldLength && maxFldLength < ( unsigned )newrect.Sze.W ) 00149 trect.Sze.W = maxFldLength; 00150 00151 fldlength = trect.Sze.W; 00152 } 00153 00154 00155 00156 void NCInputField::wDelete() 00157 { 00158 delete lwin; 00159 delete twin; 00160 lwin = 0; 00161 twin = 0; 00162 NCWidget::wDelete(); 00163 } 00164 00165 00166 00167 void NCInputField::setLabel( const std::string & nlabel ) 00168 { 00169 label = NCstring( nlabel ); 00170 label.stripHotkey(); 00171 YInputField::setLabel( nlabel ); 00172 setDefsze(); 00173 Redraw(); 00174 } 00175 00176 00177 00178 void NCInputField::setValue( const std::string & ntext ) 00179 { 00180 buffer = NCstring( ntext ).str(); 00181 00182 if ( maxInputLength && buffer.length() > maxInputLength ) 00183 { 00184 buffer = buffer.erase( maxInputLength ); 00185 } 00186 00187 fldstart = 0; 00188 00189 curpos = buffer.length(); 00190 tUpdate(); 00191 } 00192 00193 00194 00195 std::string NCInputField::value( ) 00196 { 00197 NCstring text( buffer ); 00198 00199 return text.Str(); 00200 } 00201 00202 00203 00204 void NCInputField::setValidChars( const std::string & validchars ) 00205 { 00206 validChars = NCstring( validchars ); 00207 YInputField::setValidChars( validchars ); 00208 } 00209 00210 00211 00212 bool NCInputField::validKey( wint_t key ) const 00213 { 00214 // private: NCstring validChars; 00215 const std::wstring vwch( validChars.str() ); 00216 00217 if ( vwch.empty() ) 00218 return true; 00219 00220 if ( key < 0 || WCHAR_MAX < key ) 00221 return false; 00222 00223 return( vwch.find(( wchar_t )key ) != std::wstring::npos ); 00224 } 00225 00226 00227 00228 void NCInputField::wRedraw() 00229 { 00230 if ( !win ) 00231 return; 00232 00233 // label 00234 const NCstyle::StWidget & style( widgetStyle( true ) ); 00235 00236 lwin->bkgd( style.plain ); 00237 00238 lwin->clear(); 00239 00240 label.drawAt( *lwin, style ); 00241 00242 tUpdate(); 00243 } 00244 00245 00246 00247 inline bool NCInputField::bufferFull() const 00248 { 00249 return( maxInputLength && buffer.length() == maxInputLength ); 00250 } 00251 00252 00253 00254 inline unsigned NCInputField::maxCursor() const 00255 { 00256 return( bufferFull() ? buffer.length() - 1 : buffer.length() ); 00257 } 00258 00259 00260 00261 void NCInputField::tUpdate() 00262 { 00263 if ( !win ) 00264 return; 00265 00266 unsigned maxc = maxCursor(); 00267 00268 // adjust cursor 00269 if ( curpos > maxc ) 00270 { 00271 curpos = maxc; 00272 } 00273 00274 // adjust fldstart that cursor is visible 00275 if ( maxc < fldlength ) 00276 { 00277 fldstart = 0; 00278 } 00279 else 00280 { 00281 if ( curpos <= fldstart ) 00282 { 00283 fldstart = curpos ? curpos - 1 : 0; 00284 } 00285 00286 if ( curpos >= fldstart + fldlength - 1 ) 00287 { 00288 fldstart = curpos + ( curpos == maxc ? 1 : 2 ) - fldlength; 00289 } 00290 } 00291 00292 const NCstyle::StWidget & style( widgetStyle() ); 00293 00294 twin->bkgd( widgetStyle( true ).plain ); 00295 00296 twin->move( 0, 0 ); 00297 00298 unsigned i = 0; 00299 00300 unsigned end = fldlength; 00301 00302 const wchar_t * cp = buffer.data() + fldstart; 00303 00304 // draw left scrollhint if 00305 if ( *cp && fldstart ) 00306 { 00307 twin->bkgdset( style.scrl ); 00308 twin->addch( ACS_LARROW ); 00309 ++i; 00310 ++cp; 00311 } 00312 00313 // check for right scrollhint 00314 if ( fldstart + fldlength <= maxc ) 00315 { 00316 --end; 00317 } 00318 00319 // draw field 00320 twin->bkgdset( style.data ); 00321 00322 for ( /*adjusted i*/; *cp && i < end; ++i ) 00323 { 00324 if ( passwd ) 00325 { 00326 twin->addwstr( L"*" ); 00327 } 00328 else 00329 { 00330 twin->addwstr( cp, 1 ); 00331 } 00332 00333 ++cp; 00334 } 00335 00336 twin->bkgdset( style.plain ); 00337 00338 for ( /*adjusted i*/; i < end; ++i ) 00339 { 00340 twin->addch( ACS_CKBOARD ); 00341 } 00342 00343 // draw right scrollhint if 00344 if ( end < fldlength ) 00345 { 00346 twin->bkgdset( style.scrl ); 00347 twin->addch( ACS_RARROW ); 00348 } 00349 00350 // reverse curpos 00351 if ( GetState() == NC::WSactive ) 00352 { 00353 twin->move( 0, curpos - fldstart ); 00354 twin->bkgdset( wStyle().cursor ); 00355 00356 if ( curpos < buffer.length() ) 00357 twin->add_attr_char( ); 00358 else 00359 twin->addch( ACS_CKBOARD ); 00360 } 00361 00362 Update(); 00363 } 00364 00365 00366 00367 NCursesEvent NCInputField::wHandleInput( wint_t key ) 00368 { 00369 NCursesEvent ret = NCursesEvent::none; 00370 bool beep = false; 00371 bool update = true; 00372 00373 switch ( key ) 00374 { 00375 case KEY_BACKSPACE: 00376 00377 if ( bufferFull() && curpos == maxCursor() ) 00378 { 00379 // if we're on the last char in a full buffer delete this char 00380 // and not the previous one. 00381 buffer.erase( curpos, 1 ); 00382 } 00383 else if ( curpos ) 00384 { 00385 buffer.erase( --curpos, 1 ); 00386 } 00387 else 00388 { 00389 update = false; 00390 beep = true; 00391 } 00392 00393 break; 00394 00395 case KEY_DC: 00396 00397 if ( curpos < buffer.length() ) 00398 { 00399 buffer.erase( curpos, 1 ); 00400 } 00401 else 00402 { 00403 update = false; 00404 beep = true; 00405 } 00406 00407 break; 00408 00409 case KEY_HOME: 00410 00411 if ( curpos ) 00412 { 00413 curpos = 0; 00414 } 00415 else 00416 { 00417 update = false; 00418 beep = true; 00419 } 00420 00421 break; 00422 00423 case KEY_END: 00424 00425 if ( curpos < maxCursor() ) 00426 { 00427 curpos = maxCursor(); 00428 } 00429 else 00430 { 00431 update = false; 00432 beep = true; 00433 } 00434 00435 break; 00436 00437 case KEY_LEFT: 00438 00439 if ( curpos ) 00440 { 00441 --curpos; 00442 } 00443 else 00444 { 00445 update = false; 00446 beep = true; 00447 } 00448 00449 break; 00450 00451 case KEY_RIGHT: 00452 00453 if ( curpos < maxCursor() ) 00454 { 00455 ++curpos; 00456 } 00457 else 00458 { 00459 update = false; 00460 beep = true; 00461 } 00462 00463 break; 00464 00465 case KEY_RETURN: 00466 update = false; 00467 00468 if ( notify() || returnOnReturn_b ) 00469 ret = NCursesEvent::Activated; 00470 00471 break; 00472 00473 case KEY_HOTKEY: 00474 update = false; 00475 00476 break; 00477 00478 default: 00479 bool is_special = false; 00480 00481 if ( key > 0xFFFF ) 00482 { 00483 is_special = true; 00484 key -= 0xFFFF; 00485 } 00486 00487 if (( !is_special && KEY_MIN < key && KEY_MAX > key ) 00488 || 00489 !iswprint( key ) 00490 || 00491 // if we are at limit of input 00492 ( InputMaxLength >= 0 && InputMaxLength <= ( int )buffer.length() ) ) 00493 { 00494 update = false; 00495 beep = true; 00496 } 00497 else if ( fldtype == NUMBER ) 00498 { 00499 if ( bufferFull() && key != L'+' ) 00500 { 00501 update = false; 00502 beep = true; 00503 } 00504 else 00505 { 00506 switch ( key ) 00507 { 00508 case L'0': 00509 case L'1': 00510 case L'2': 00511 case L'3': 00512 case L'4': 00513 case L'5': 00514 case L'6': 00515 case L'7': 00516 case L'8': 00517 case L'9': 00518 00519 if ( curpos || buffer.empty() || buffer[0] != L'-' ) 00520 { 00521 buffer.insert( std::wstring::size_type( curpos ), 1, key ); 00522 00523 if ( curpos < maxCursor() ) 00524 ++curpos; 00525 } 00526 else 00527 { 00528 update = false; 00529 beep = true; 00530 } 00531 00532 break; 00533 00534 case L'+': 00535 00536 if ( !buffer.empty() && buffer[0] == L'-' ) 00537 { 00538 buffer.erase( std::wstring::size_type( 0 ), 1 ); 00539 00540 if ( curpos ) 00541 --curpos; 00542 } 00543 else 00544 { 00545 update = false; 00546 } 00547 00548 break; 00549 00550 case L'-': 00551 00552 if ( buffer.empty() || buffer[0] != L'-' ) 00553 { 00554 buffer.insert( std::wstring::size_type( 0 ), 1, L'-' ); 00555 00556 if ( curpos < maxCursor() ) 00557 ++curpos; 00558 } 00559 else 00560 { 00561 update = false; 00562 } 00563 00564 break; 00565 00566 default: 00567 update = false; 00568 beep = true; 00569 break; 00570 } 00571 } 00572 00573 } 00574 else // PLAIN 00575 { 00576 00577 if ( bufferFull() || !validKey( key ) ) 00578 { 00579 update = false; 00580 beep = true; 00581 } 00582 else 00583 { 00584 buffer.insert( std::wstring::size_type( curpos ), 1, key ); 00585 00586 if ( curpos < maxCursor() ) 00587 ++curpos; 00588 } 00589 00590 } 00591 00592 break; 00593 } 00594 00595 if ( update ) 00596 { 00597 tUpdate(); 00598 00599 if ( notify() ) 00600 ret = NCursesEvent::ValueChanged; 00601 } 00602 00603 if ( beep ) 00604 ::beep(); 00605 00606 return ret; 00607 00608 } 00609 00610 00611 void NCInputField::setInputMaxLength( int numberOfChars ) 00612 { 00613 int nr = numberOfChars; 00614 00615 // if there is more text then the maximum number of chars, 00616 // truncate the text and update the buffer 00617 00618 if ( nr >= 0 && ( int )buffer.length() > nr ) 00619 { 00620 buffer.erase( nr, maxCursor() - nr ); 00621 tUpdate(); 00622 curpos = buffer.length(); 00623 } 00624 00625 InputMaxLength = nr; 00626 00627 YInputField::setInputMaxLength( numberOfChars ); 00628 }