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: NCTextPad.cc 00020 00021 Author: Michael Andres <ma@suse.de> 00022 00023 /-*/ 00024 00025 #define YUILogComponent "ncurses" 00026 #include <yui/YUILog.h> 00027 #include "NCTextPad.h" 00028 00029 #include <limits.h> 00030 00031 using std::endl; 00032 00033 // FLAW: if notification is enabled the dialog gets disabled and reenabled 00034 // when procesing the event. This causes noticable flicker if the enabled/disabled 00035 // attriutes differ. That's why 'nonactive' style is used. 00036 #define MY_TEXT_STYLE ( parw.widgetStyle( /*nonactive*/true ).data ) 00037 00038 NCTextPad::NCTextPad( int l, int c, const NCWidget & p ) 00039 : NCPad( l, c, p ) 00040 , lines( 1U, 0 ) 00041 , cline( lines.begin() ) 00042 , curson( false ) 00043 , InputMaxLength( -1 ) 00044 { 00045 bkgd( MY_TEXT_STYLE ); 00046 } 00047 00048 00049 00050 NCTextPad::~NCTextPad() 00051 { 00052 } 00053 00054 00055 00056 void NCTextPad::resize( wsze nsze ) 00057 { 00058 SetPadSize( nsze ); // might be enlarged by NCPadWidget if redirected 00059 00060 if ( nsze.H != height() 00061 || nsze.W != width() ) 00062 { 00063 NCursesWindow * odest = Destwin(); 00064 00065 if ( odest ) 00066 Destwin( 0 ); 00067 00068 NCursesPad::resize( nsze.H, nsze.W ); 00069 00070 if ( odest ) 00071 Destwin( odest ); 00072 } 00073 } 00074 00075 00076 00077 void NCTextPad::assertSze( wsze minsze ) 00078 { 00079 if ( minsze.W > width() 00080 || minsze.H > height() ) 00081 resize( minsze ); 00082 } 00083 00084 00085 00086 void NCTextPad::assertWidth( unsigned minw ) 00087 { 00088 if ( minw >= ( unsigned )width() ) // == for the '\n' 00089 resize( wsze( height(), minw + 10 ) ); 00090 } 00091 00092 00093 00094 void NCTextPad::assertHeight( unsigned minh ) 00095 { 00096 if ( minh > ( unsigned )height() ) 00097 resize( wsze( minh + 10, width() ) ); 00098 } 00099 00100 00101 00102 wpos NCTextPad::CurPos() const 00103 { 00104 return curs; 00105 } 00106 00107 00108 00109 void NCTextPad::cursor( bool on ) 00110 { 00111 if ( on != curson ) 00112 { 00113 if (( curson = on ) ) 00114 { 00115 bkgdset( parw.wStyle().cursor ); 00116 add_attr_char( curs.L, curs.C ); 00117 bkgdset( MY_TEXT_STYLE ); 00118 } 00119 else 00120 { 00121 add_attr_char( curs.L, curs.C ); 00122 } 00123 } 00124 } 00125 00126 00127 00128 int NCTextPad::setpos() 00129 { 00130 // BUG?: bkgd does not change the color attibute of nonwhite characters 00131 // on the pad so we repaint them in the new color in case it changed. 00132 chtype oldbkgd = NCattribute::getColor( getbkgd() ); 00133 bkgd( MY_TEXT_STYLE ); 00134 00135 if ( NCattribute::getColor( getbkgd() ) != oldbkgd ) 00136 { 00137 // repaint text 00138 for ( int l = 0; l < height(); ++l ) 00139 for ( int c = 0; c < width(); ++ c ) 00140 { 00141 add_attr_char( l, c ); 00142 } 00143 } 00144 cursor( parw.GetState() == NC::WSactive ); 00145 return setpos( CurPos() ); 00146 } 00147 00148 00149 00150 int NCTextPad::setpos( const wpos & newpos ) 00151 { 00152 wpos npos( newpos.between( 0, wpos( maxy(), maxx() ) ) ); 00153 00154 if (( unsigned )npos.L >= lines.size() ) 00155 { 00156 npos.L = lines.size() - 1; 00157 cline = lines.end(); 00158 --cline; 00159 } 00160 else if ( npos.L != curs.L ) 00161 { 00162 advance( cline, npos.L - curs.L ); 00163 } 00164 00165 if (( unsigned )npos.C > *cline ) 00166 { 00167 npos.C = *cline; 00168 } 00169 00170 bool ocurs = curson; 00171 00172 if ( ocurs ) cursorOff(); 00173 00174 curs = npos; 00175 00176 if ( ocurs ) cursorOn(); 00177 00178 wpos padpos( curs ); 00179 00180 if ( drect.Sze > wsze( 0 ) ) 00181 { 00182 padpos = ( padpos / drect.Sze ) * drect.Sze; 00183 } 00184 00185 return NCPad::setpos( padpos ); 00186 } 00187 00188 00189 00190 bool NCTextPad::handleInput( wint_t key ) 00191 { 00192 bool handled = true; 00193 bool beep = false; 00194 bool update = true; 00195 00196 cursorOff(); 00197 00198 switch ( key ) 00199 { 00200 case KEY_LEFT: 00201 00202 if ( curs.C ) 00203 { 00204 --curs.C; 00205 } 00206 else if ( curs.L ) 00207 { 00208 --cline; 00209 --curs.L; 00210 curs.C = ( *cline ); 00211 } 00212 else 00213 { 00214 beep = true; 00215 update = false; 00216 } 00217 break; 00218 00219 00220 case KEY_UP: 00221 00222 if ( curs.L ) 00223 { 00224 --cline; 00225 --curs.L; 00226 } 00227 else 00228 { 00229 beep = true; 00230 update = false; 00231 } 00232 break; 00233 00234 00235 case KEY_RIGHT: 00236 00237 if (( unsigned )curs.C < ( *cline ) ) 00238 { 00239 ++curs.C; 00240 } 00241 else if (( unsigned )curs.L + 1 < lines.size() ) 00242 { 00243 ++cline; 00244 ++curs.L; 00245 curs.C = 0; 00246 } 00247 else 00248 { 00249 beep = true; 00250 update = false; 00251 } 00252 break; 00253 00254 00255 case KEY_DOWN: 00256 00257 if (( unsigned )curs.L + 1 < lines.size() ) 00258 { 00259 ++cline; 00260 ++curs.L; 00261 } 00262 else 00263 { 00264 beep = true; 00265 update = false; 00266 } 00267 break; 00268 00269 00270 case KEY_PPAGE: 00271 00272 if ( curs.L ) 00273 { 00274 setpos( wpos( curs.L - 3, curs.C ) ); 00275 } 00276 else 00277 { 00278 beep = true; 00279 update = false; 00280 } 00281 break; 00282 00283 00284 case KEY_NPAGE: 00285 00286 if (( unsigned )curs.L + 1 < lines.size() ) 00287 { 00288 setpos( wpos( curs.L + 3, curs.C ) ); 00289 } 00290 else 00291 { 00292 beep = true; 00293 update = false; 00294 } 00295 break; 00296 00297 00298 case KEY_HOME: 00299 00300 if ( curs.C ) 00301 { 00302 curs.C = 0; 00303 } 00304 break; 00305 00306 00307 case KEY_END: 00308 00309 if (( unsigned )curs.C < ( *cline ) ) 00310 { 00311 curs.C = ( *cline ); 00312 } 00313 break; 00314 00315 00316 case KEY_BACKSPACE: 00317 beep = !delch( true ); 00318 break; 00319 00320 case KEY_DC: 00321 beep = !delch(); 00322 break; 00323 00324 case KEY_HOTKEY: 00325 update = false; 00326 break; 00327 00328 default: 00329 // if we are at limit of input 00330 00331 if ( InputMaxLength >= 0 && InputMaxLength < ( int )getText().length() ) 00332 { 00333 beep = true; 00334 update = false; 00335 } 00336 else 00337 { 00338 beep = !insert( key ); 00339 } 00340 break; 00341 } 00342 00343 cursorOn(); 00344 00345 if ( beep ) 00346 ::beep(); 00347 00348 if ( update ) 00349 setpos( curs ); 00350 00351 return handled; 00352 } 00353 00354 00355 00356 bool NCTextPad::insert( wint_t key ) 00357 { 00358 if ( key == 10 ) 00359 { 00360 return openLine(); 00361 } 00362 00363 if ( key < 32 || ( key >= 127 && key < 160 ) || UCHAR_MAX < key ) 00364 { 00365 return false; 00366 } 00367 00368 assertWidth( ++( *cline ) ); 00369 00370 cchar_t cchar; 00371 attr_t attr; 00372 short int color; 00373 wattr_get( w, &attr, &color, NULL ); // NOTE: (w)attr_get is not probided by NCursesWindow 00374 00375 wchar_t wch[2]; 00376 wch[0] = key; 00377 wch[1] = L'\0'; 00378 00379 setcchar( &cchar, wch, attr, color, NULL ); 00380 // libncurses6 enables ext_color from struct cchar_t (see curses.h). 00381 // Set ext_color to 0 to respect the settings got from attr_get (bnc#652240). 00382 #ifdef NCURSES_EXT_COLORS 00383 cchar.ext_color = 0; 00384 #endif 00385 ins_wch( curs.L, curs.C++, &cchar ); 00386 00387 return true; 00388 } 00389 00390 00391 00392 bool NCTextPad::openLine() 00393 { 00394 assertHeight( lines.size() + 1 ); 00395 std::list<unsigned>::iterator newl( cline ); 00396 newl = lines.insert( ++newl, 0 ); 00397 00398 if ( curs.C == 0 ) 00399 { 00400 // eazy at line begin: new empty line above 00401 insertln(); 00402 00403 ( *newl ) = ( *cline ); 00404 ( *cline ) = 0; 00405 } 00406 else 00407 { 00408 // new empty line below 00409 move( curs.L + 1, 0 ); 00410 insertln(); 00411 00412 if (( unsigned )curs.C < ( *cline ) ) 00413 { 00414 // copy down rest of line 00415 ( *newl ) = ( *cline ) - curs.C; 00416 ( *cline ) = curs.C; 00417 00418 move( curs.L, curs.C ); 00419 copywin( *this, curs.L, curs.C, curs.L + 1, 0, curs.L + 1, ( *newl ), false ); 00420 clrtoeol(); 00421 } 00422 } 00423 00424 cline = newl; 00425 00426 ++curs.L; 00427 curs.C = 0; 00428 00429 return true; 00430 } 00431 00432 00433 00434 bool NCTextPad::delch( bool previous ) 00435 { 00436 if ( previous ) 00437 { 00438 if ( curs.C ) 00439 --curs.C; 00440 else if ( curs.L ) 00441 { 00442 --cline; 00443 --curs.L; 00444 curs.C = ( *cline ); 00445 } 00446 else 00447 return false; 00448 } 00449 00450 if (( unsigned )curs.C < *cline ) 00451 { 00452 // eazy not at line end 00453 --( *cline ); 00454 00455 NCPad::delch( curs.L, curs.C ); 00456 } 00457 else if (( unsigned )curs.L + 1 < lines.size() ) 00458 { 00459 // at line end: join with next line 00460 std::list<unsigned>::iterator nextl( cline ); 00461 ++nextl; 00462 ( *cline ) += ( *nextl ); 00463 lines.erase( nextl ); 00464 00465 assertWidth(( *cline ) ); 00466 copywin( *this, curs.L + 1, 0, curs.L, curs.C, curs.L, ( *cline ), false ); 00467 00468 move( curs.L + 1, 0 ); 00469 deleteln(); 00470 } 00471 else 00472 return false; 00473 00474 return true; 00475 } 00476 00477 00478 void NCTextPad::setText( const NCtext & ntext ) 00479 { 00480 bkgd( MY_TEXT_STYLE ); 00481 00482 bool ocurs = curson; 00483 if ( ocurs ) cursorOff(); 00484 00485 clear(); 00486 assertSze( wsze( ntext.Lines(), ntext.Columns() + 1 ) ); 00487 curs = 0; 00488 00489 cchar_t cchar; 00490 attr_t attr; 00491 short int color; 00492 wattr_get( w, &attr, &color, NULL ); // NOTE: (w)attr_get is not probided by NCursesWindow 00493 00494 wchar_t wch[2]; 00495 wch[1] = L'\0'; 00496 lines.clear(); 00497 00498 unsigned cl = 0; 00499 00500 for ( NCtext::const_iterator line = ntext.begin(); line != ntext.end(); ++line ) 00501 { 00502 lines.push_back(( *line ).str().length() ); 00503 00504 unsigned cc = 0; 00505 00506 for ( std::wstring::const_iterator c = line->str().begin(); c != line->str().end(); c++ ) 00507 { 00508 //replace tabs for right arrows (#66104) 00509 if ( *c == 9 ) // horizontal tabulation 00510 { 00511 wch[0] = 8677; // U+21E5 RIGHTWARDS ARROW TO BAR (rightward tab) 00512 } 00513 else 00514 { 00515 wch[0] = *c; 00516 } 00517 00518 setcchar( &cchar, wch, attr, color, NULL ); 00519 // libncurses6 enables ext_color from struct cchar_t (see curses.h). 00520 // Set ext_color to 0 to respect the settings got from attr_get (bcn#652240). 00521 #ifdef NCURSES_EXT_COLORS 00522 cchar.ext_color = 0; 00523 #endif 00524 ins_wch( cl, cc++, &cchar ); 00525 } 00526 00527 cl++; 00528 } 00529 00530 if ( lines.empty() ) 00531 lines.push_back( 0U ); 00532 00533 cline = lines.begin(); 00534 00535 if ( ocurs ) 00536 cursorOn(); 00537 00538 setpos( curs ); 00539 } 00540 00541 00542 00543 std::wstring NCTextPad::getText() const 00544 { 00545 // just for inch(x,y) call, which isn't const due to 00546 // hw cursor movement, but that's of no interest here. 00547 NCTextPad * myself = const_cast<NCTextPad *>( this ); 00548 00549 cchar_t cchar; 00550 std::wstring ret; 00551 unsigned l = 0; 00552 wchar_t wch[CCHARW_MAX+1]; 00553 attr_t attr; 00554 short int colorpair; 00555 00556 for ( std::list<unsigned>::const_iterator cgetl( lines.begin() ); cgetl != lines.end(); ++cgetl ) 00557 { 00558 for ( unsigned c = 0; c < ( *cgetl ); ++c ) 00559 { 00560 myself->in_wchar( l, c, &cchar ); 00561 getcchar( &cchar, wch, &attr, &colorpair, NULL ); 00562 00563 //replace right arrow back for horizontal tab - see setText method above (#142509) 00564 00565 if ( wch[0] == 8677 ) 00566 wch[0] = 9; 00567 00568 ret += wch[0]; 00569 } 00570 00571 ++l; 00572 // do not append \n after the very last line (bnc #573553) 00573 if ( l < lines.size() ) 00574 { 00575 ret += L"\n"; 00576 } 00577 } 00578 00579 return ret; 00580 } 00581 00582 00583 std::ostream & operator<<( std::ostream & STREAM, const NCTextPad & OBJ ) 00584 { 00585 STREAM << "at " << OBJ.CurPos() << " on " << wsze( OBJ.height(), OBJ.width() ) 00586 << " lines " << OBJ.lines.size() << " (" << *OBJ.cline << ")"; 00587 return STREAM; 00588 } 00589 00590 void NCTextPad::setInputMaxLength( int nr ) 00591 { 00592 // if there is more text then the maximum number of chars, 00593 // truncate the text and update the buffer 00594 if ( nr >= 0 && nr < ( int )getText().length() ) 00595 { 00596 NCstring newtext = getText().substr( 0, nr ); 00597 setText( newtext ); 00598 } 00599 00600 InputMaxLength = nr; 00601 }