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: 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 }