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