libyui-ncurses  2.44.1
/usr/src/RPM/BUILD/libyui-ncurses-2.44.1/src/NCInputField.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:       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 }
 All Classes Functions Variables