libyui-ncurses  2.48.3
NCTextPad.cc
1 /*
2  Copyright (C) 2000-2012 Novell, Inc
3  This library is free software; you can redistribute it and/or modify
4  it under the terms of the GNU Lesser General Public License as
5  published by the Free Software Foundation; either version 2.1 of the
6  License, or (at your option) version 3.0 of the License. This library
7  is distributed in the hope that it will be useful, but WITHOUT ANY
8  WARRANTY; without even the implied warranty of MERCHANTABILITY or
9  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10  License for more details. You should have received a copy of the GNU
11  Lesser General Public License along with this library; if not, write
12  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
13  Floor, Boston, MA 02110-1301 USA
14 */
15 
16 
17 /*-/
18 
19  File: NCTextPad.cc
20 
21  Author: Michael Andres <ma@suse.de>
22 
23 /-*/
24 
25 #define YUILogComponent "ncurses"
26 #include <yui/YUILog.h>
27 #include "NCTextPad.h"
28 
29 #include <limits.h>
30 
31 using std::endl;
32 
33 // FLAW: if notification is enabled the dialog gets disabled and reenabled
34 // when procesing the event. This causes noticable flicker if the enabled/disabled
35 // attriutes differ. That's why 'nonactive' style is used.
36 #define MY_TEXT_STYLE ( parw.widgetStyle( /*nonactive*/true ).data )
37 
38 NCTextPad::NCTextPad( int l, int c, const NCWidget & p )
39  : NCPad( l, c, p )
40  , lines( 1U, 0 )
41  , cline( lines.begin() )
42  , curson( false )
43  , InputMaxLength( -1 )
44 {
45  bkgd( MY_TEXT_STYLE );
46 }
47 
48 
49 
50 NCTextPad::~NCTextPad()
51 {
52 }
53 
54 
55 
56 void NCTextPad::resize( wsze nsze )
57 {
58  SetPadSize( nsze ); // might be enlarged by NCPadWidget if redirected
59 
60  if ( nsze.H != height()
61  || nsze.W != width() )
62  {
63  NCursesWindow * odest = Destwin();
64 
65  if ( odest )
66  Destwin( 0 );
67 
68  NCursesPad::resize( nsze.H, nsze.W );
69 
70  if ( odest )
71  Destwin( odest );
72  }
73 }
74 
75 
76 
77 void NCTextPad::assertSze( wsze minsze )
78 {
79  if ( minsze.W > width()
80  || minsze.H > height() )
81  resize( minsze );
82 }
83 
84 
85 
86 void NCTextPad::assertWidth( unsigned minw )
87 {
88  if ( minw >= ( unsigned )width() ) // == for the '\n'
89  resize( wsze( height(), minw + 10 ) );
90 }
91 
92 
93 
94 void NCTextPad::assertHeight( unsigned minh )
95 {
96  if ( minh > ( unsigned )height() )
97  resize( wsze( minh + 10, width() ) );
98 }
99 
100 
101 
102 wpos NCTextPad::CurPos() const
103 {
104  return curs;
105 }
106 
107 
108 
109 void NCTextPad::cursor( bool on )
110 {
111  if ( on != curson )
112  {
113  if (( curson = on ) )
114  {
115  bkgdset( parw.wStyle().cursor );
116  add_attr_char( curs.L, curs.C );
117  bkgdset( MY_TEXT_STYLE );
118  }
119  else
120  {
121  add_attr_char( curs.L, curs.C );
122  }
123  }
124 }
125 
126 
127 
128 int NCTextPad::setpos()
129 {
130  // BUG?: bkgd does not change the color attibute of nonwhite characters
131  // on the pad so we repaint them in the new color in case it changed.
132  chtype oldbkgd = NCattribute::getColor( getbkgd() );
133  bkgd( MY_TEXT_STYLE );
134 
135  if ( NCattribute::getColor( getbkgd() ) != oldbkgd )
136  {
137  // repaint text
138  for ( int l = 0; l < height(); ++l )
139  for ( int c = 0; c < width(); ++ c )
140  {
141  add_attr_char( l, c );
142  }
143  }
144  cursor( parw.GetState() == NC::WSactive );
145  return setpos( CurPos() );
146 }
147 
148 
149 
150 int NCTextPad::setpos( const wpos & newpos )
151 {
152  wpos npos( newpos.between( 0, wpos( maxy(), maxx() ) ) );
153 
154  if (( unsigned )npos.L >= lines.size() )
155  {
156  npos.L = lines.size() - 1;
157  cline = lines.end();
158  --cline;
159  }
160  else if ( npos.L != curs.L )
161  {
162  advance( cline, npos.L - curs.L );
163  }
164 
165  if (( unsigned )npos.C > *cline )
166  {
167  npos.C = *cline;
168  }
169 
170  bool ocurs = curson;
171 
172  if ( ocurs ) cursorOff();
173 
174  curs = npos;
175 
176  if ( ocurs ) cursorOn();
177 
178  wpos padpos( curs );
179 
180  if ( drect.Sze > wsze( 0 ) )
181  {
182  padpos = ( padpos / drect.Sze ) * drect.Sze;
183  }
184 
185  return NCPad::setpos( padpos );
186 }
187 
188 
189 
190 bool NCTextPad::handleInput( wint_t key )
191 {
192  bool handled = true;
193  bool beep = false;
194  bool update = true;
195 
196  cursorOff();
197 
198  switch ( key )
199  {
200  case KEY_LEFT:
201 
202  if ( curs.C )
203  {
204  --curs.C;
205  }
206  else if ( curs.L )
207  {
208  --cline;
209  --curs.L;
210  curs.C = ( *cline );
211  }
212  else
213  {
214  beep = true;
215  update = false;
216  }
217  break;
218 
219 
220  case KEY_UP:
221 
222  if ( curs.L )
223  {
224  --cline;
225  --curs.L;
226  }
227  else
228  {
229  beep = true;
230  update = false;
231  }
232  break;
233 
234 
235  case KEY_RIGHT:
236 
237  if (( unsigned )curs.C < ( *cline ) )
238  {
239  ++curs.C;
240  }
241  else if (( unsigned )curs.L + 1 < lines.size() )
242  {
243  ++cline;
244  ++curs.L;
245  curs.C = 0;
246  }
247  else
248  {
249  beep = true;
250  update = false;
251  }
252  break;
253 
254 
255  case KEY_DOWN:
256 
257  if (( unsigned )curs.L + 1 < lines.size() )
258  {
259  ++cline;
260  ++curs.L;
261  }
262  else
263  {
264  beep = true;
265  update = false;
266  }
267  break;
268 
269 
270  case KEY_PPAGE:
271 
272  if ( curs.L )
273  {
274  setpos( wpos( curs.L - 3, curs.C ) );
275  }
276  else
277  {
278  beep = true;
279  update = false;
280  }
281  break;
282 
283 
284  case KEY_NPAGE:
285 
286  if (( unsigned )curs.L + 1 < lines.size() )
287  {
288  setpos( wpos( curs.L + 3, curs.C ) );
289  }
290  else
291  {
292  beep = true;
293  update = false;
294  }
295  break;
296 
297 
298  case KEY_SLEFT:
299  case KEY_HOME:
300 
301  if ( curs.C )
302  {
303  curs.C = 0;
304  }
305  break;
306 
307 
308  case KEY_SRIGHT:
309  case KEY_END:
310 
311  if (( unsigned )curs.C < ( *cline ) )
312  {
313  curs.C = ( *cline );
314  }
315  break;
316 
317 
318  case KEY_BACKSPACE:
319  beep = !delch( true );
320  break;
321 
322  case KEY_DC:
323  beep = !delch();
324  break;
325 
326  case KEY_HOTKEY:
327  update = false;
328  break;
329 
330  default:
331  // if we are at limit of input
332 
333  if ( InputMaxLength >= 0 && InputMaxLength < ( int )getText().length() )
334  {
335  beep = true;
336  update = false;
337  }
338  else
339  {
340  beep = !insert( key );
341  }
342  break;
343  }
344 
345  cursorOn();
346 
347  if ( beep )
348  ::beep();
349 
350  if ( update )
351  setpos( curs );
352 
353  return handled;
354 }
355 
356 
357 
358 bool NCTextPad::insert( wint_t key )
359 {
360  if ( key == 10 )
361  {
362  return openLine();
363  }
364 
365  if ( key < 32 || ( key >= 127 && key < 160 ) || UCHAR_MAX < key )
366  {
367  return false;
368  }
369 
370  assertWidth( ++( *cline ) );
371 
372  cchar_t cchar;
373  attr_t attr = 0;
374  short int color = 0;
375  int ret = wattr_get( w, &attr, &color, NULL ); // NOTE: (w)attr_get is not provided by NCursesWindow
376  if (ret != OK)
377  return false;
378 
379  wchar_t wch[2];
380  wch[0] = key;
381  wch[1] = L'\0';
382 
383  ret = setcchar( &cchar, wch, attr, color, NULL );
384  if (ret != OK)
385  return false;
386 
387 // libncurses6 enables ext_color from struct cchar_t (see curses.h).
388 // Set ext_color to 0 to respect the settings got from attr_get (bnc#652240).
389 #ifdef NCURSES_EXT_COLORS
390  cchar.ext_color = 0;
391 #endif
392  ret = ins_wch( curs.L, curs.C++, &cchar );
393 
394  return (ret == OK);
395 }
396 
397 
398 
399 bool NCTextPad::openLine()
400 {
401  assertHeight( lines.size() + 1 );
402  std::list<unsigned>::iterator newl( cline );
403  newl = lines.insert( ++newl, 0 );
404 
405  if ( curs.C == 0 )
406  {
407  // eazy at line begin: new empty line above
408  insertln();
409 
410  ( *newl ) = ( *cline );
411  ( *cline ) = 0;
412  }
413  else
414  {
415  // new empty line below
416  move( curs.L + 1, 0 );
417  insertln();
418 
419  if (( unsigned )curs.C < ( *cline ) )
420  {
421  // copy down rest of line
422  ( *newl ) = ( *cline ) - curs.C;
423  ( *cline ) = curs.C;
424 
425  move( curs.L, curs.C );
426  copywin( *this, curs.L, curs.C, curs.L + 1, 0, curs.L + 1, ( *newl ), false );
427  clrtoeol();
428  }
429  }
430 
431  cline = newl;
432 
433  ++curs.L;
434  curs.C = 0;
435 
436  return true;
437 }
438 
439 
440 
441 bool NCTextPad::delch( bool previous )
442 {
443  if ( previous )
444  {
445  if ( curs.C )
446  --curs.C;
447  else if ( curs.L )
448  {
449  --cline;
450  --curs.L;
451  curs.C = ( *cline );
452  }
453  else
454  return false;
455  }
456 
457  if (( unsigned )curs.C < *cline )
458  {
459  // eazy not at line end
460  --( *cline );
461 
462  NCPad::delch( curs.L, curs.C );
463  }
464  else if (( unsigned )curs.L + 1 < lines.size() )
465  {
466  // at line end: join with next line
467  std::list<unsigned>::iterator nextl( cline );
468  ++nextl;
469  ( *cline ) += ( *nextl );
470  lines.erase( nextl );
471 
472  assertWidth(( *cline ) );
473  copywin( *this, curs.L + 1, 0, curs.L, curs.C, curs.L, ( *cline ), false );
474 
475  move( curs.L + 1, 0 );
476  deleteln();
477  }
478  else
479  return false;
480 
481  return true;
482 }
483 
484 
485 void NCTextPad::setText( const NCtext & ntext )
486 {
487  bkgd( MY_TEXT_STYLE );
488 
489  bool ocurs = curson;
490  if ( ocurs ) cursorOff();
491 
492  clear();
493  assertSze( wsze( ntext.Lines(), ntext.Columns() + 1 ) );
494  curs = 0;
495 
496  cchar_t cchar;
497  attr_t attr = 0;
498  short int color = 0;
499  wattr_get( w, &attr, &color, NULL ); // NOTE: (w)attr_get is not provided by NCursesWindow
500 
501  wchar_t wch[2];
502  wch[1] = L'\0';
503  lines.clear();
504 
505  unsigned cl = 0;
506 
507  for ( NCtext::const_iterator line = ntext.begin(); line != ntext.end(); ++line )
508  {
509  lines.push_back(( *line ).str().length() );
510 
511  unsigned cc = 0;
512 
513  for ( std::wstring::const_iterator c = line->str().begin(); c != line->str().end(); c++ )
514  {
515  //replace tabs for right arrows (#66104)
516  if ( *c == 9 ) // horizontal tabulation
517  {
518  wch[0] = 8677; // U+21E5 RIGHTWARDS ARROW TO BAR (rightward tab)
519  }
520  else
521  {
522  wch[0] = *c;
523  }
524 
525  setcchar( &cchar, wch, attr, color, NULL );
526 // libncurses6 enables ext_color from struct cchar_t (see curses.h).
527 // Set ext_color to 0 to respect the settings got from attr_get (bcn#652240).
528 #ifdef NCURSES_EXT_COLORS
529  cchar.ext_color = 0;
530 #endif
531  ins_wch( cl, cc++, &cchar );
532  }
533 
534  cl++;
535  }
536 
537  if ( lines.empty() )
538  lines.push_back( 0U );
539 
540  cline = lines.begin();
541 
542  if ( ocurs )
543  cursorOn();
544 
545  setpos( curs );
546 }
547 
548 
549 
550 std::wstring NCTextPad::getText() const
551 {
552  // just for inch(x,y) call, which isn't const due to
553  // hw cursor movement, but that's of no interest here.
554  NCTextPad * myself = const_cast<NCTextPad *>( this );
555 
556  cchar_t cchar;
557  std::wstring ret;
558  unsigned l = 0;
559  wchar_t wch[CCHARW_MAX+1];
560  attr_t attr;
561  short int colorpair;
562 
563  for ( std::list<unsigned>::const_iterator cgetl( lines.begin() ); cgetl != lines.end(); ++cgetl )
564  {
565  for ( unsigned c = 0; c < ( *cgetl ); ++c )
566  {
567  myself->in_wchar( l, c, &cchar );
568  getcchar( &cchar, wch, &attr, &colorpair, NULL );
569 
570  //replace right arrow back for horizontal tab - see setText method above (#142509)
571 
572  if ( wch[0] == 8677 )
573  wch[0] = 9;
574 
575  ret += wch[0];
576  }
577 
578  ++l;
579  // do not append \n after the very last line (bnc #573553)
580  if ( l < lines.size() )
581  {
582  ret += L"\n";
583  }
584  }
585 
586  return ret;
587 }
588 
589 
590 std::ostream & operator<<( std::ostream & STREAM, const NCTextPad & OBJ )
591 {
592  STREAM << "at " << OBJ.CurPos() << " on " << wsze( OBJ.height(), OBJ.width() )
593  << " lines " << OBJ.lines.size() << " (" << *OBJ.cline << ")";
594  return STREAM;
595 }
596 
597 void NCTextPad::setInputMaxLength( int nr )
598 {
599  // if there is more text then the maximum number of chars,
600  // truncate the text and update the buffer
601  if ( nr >= 0 && nr < ( int )getText().length() )
602  {
603  NCstring newtext = getText().substr( 0, nr );
604  setText( newtext );
605  }
606 
607  InputMaxLength = nr;
608 }
NCTextPad
Definition: NCTextPad.h:35
wsze
Definition: position.h:154
NCstring
Definition: NCstring.h:32
NCursesWindow
C++ class for windows.
Definition: ncursesw.h:903
NCursesWindow::delch
int delch()
Delete character under the cursor.
Definition: ncursesw.h:1542
NCursesWindow::add_attr_char
int add_attr_char(int y, int x)
Put attributed character from given position to the window.
Definition: ncursesw.cc:166
NCursesWindow::getbkgd
chtype getbkgd() const
Get current background setting.
Definition: ncursesw.h:1437
NCursesWindow::deleteln
int deleteln()
Delete the current line.
Definition: ncursesw.h:1553
NCursesWindow::copywin
int copywin(NCursesWindow &win, int sminrow, int smincol, int dminrow, int dmincol, int dmaxrow, int dmaxcol, bool overlay=TRUE)
Overlay or overwrite the rectangle in win given by dminrow,dmincol, dmaxrow,dmaxcol with the rectangl...
Definition: ncursesw.h:1731
NCursesWindow::clear
int clear()
Clear the window.
Definition: ncursesw.h:1521
NCtext
Definition: NCtext.h:37
NCursesWindow::w
WINDOW * w
the curses WINDOW
Definition: ncursesw.h:946
NCWidget
Definition: NCWidget.h:43
NCursesWindow::maxy
int maxy() const
Largest y coord in window.
Definition: ncursesw.h:1094
NCursesWindow::clrtoeol
int clrtoeol()
Clear to the end of the line.
Definition: ncursesw.h:1537
NCursesWindow::width
int width() const
Number of columns in this window.
Definition: ncursesw.h:1074
NCPad
Definition: NCPad.h:93
NCursesWindow::move
int move(int y, int x)
Move cursor the this position.
Definition: ncursesw.h:1154
wpos
Definition: position.h:109
NCursesWindow::in_wchar
int in_wchar(cchar_t *cchar)
Retrieve combined character under the current cursor position.
Definition: ncursesw.cc:153
NCursesWindow::bkgd
int bkgd(const chtype ch)
Set the background property and apply it to the window.
Definition: ncursesw.h:1442
NCursesWindow::height
int height() const
Number of lines in this window.
Definition: ncursesw.h:1069
NCursesWindow::ins_wch
int ins_wch(int y, int x, const cchar_t *cchar)
Move cursor to requested position and then insert the attributed character before that position.
Definition: ncursesw.h:1361
NCursesWindow::bkgdset
void bkgdset(chtype ch)
Set the background property.
Definition: ncursesw.h:1447
NCursesWindow::insertln
int insertln()
Insert an empty line above the current line.
Definition: ncursesw.h:1369
NCursesWindow::maxx
int maxx() const
Largest x coord in window.
Definition: ncursesw.h:1089