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