libyui-ncurses  2.57.2
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 )
173  cursorOff();
174 
175  curs = npos;
176 
177  if ( ocurs )
178  cursorOn();
179 
180  wpos padpos( curs );
181 
182  if ( drect.Sze > wsze( 0 ) )
183  {
184  padpos = ( padpos / drect.Sze ) * drect.Sze;
185  }
186 
187  return NCPad::setpos( padpos );
188 }
189 
190 
191 
192 bool NCTextPad::handleInput( wint_t key )
193 {
194  bool handled = true;
195  bool beep = false;
196  bool update = true;
197 
198  cursorOff();
199 
200  switch ( key )
201  {
202  case KEY_LEFT:
203 
204  if ( curs.C )
205  {
206  --curs.C;
207  }
208  else if ( curs.L )
209  {
210  --cline;
211  --curs.L;
212  curs.C = ( *cline );
213  }
214  else
215  {
216  beep = true;
217  update = false;
218  }
219  break;
220 
221 
222  case KEY_UP:
223 
224  if ( curs.L )
225  {
226  --cline;
227  --curs.L;
228  }
229  else
230  {
231  beep = true;
232  update = false;
233  }
234  break;
235 
236 
237  case KEY_RIGHT:
238 
239  if ( (unsigned) curs.C < ( *cline ) )
240  {
241  ++curs.C;
242  }
243  else if ( (unsigned) curs.L + 1 < lines.size() )
244  {
245  ++cline;
246  ++curs.L;
247  curs.C = 0;
248  }
249  else
250  {
251  beep = true;
252  update = false;
253  }
254  break;
255 
256 
257  case KEY_DOWN:
258 
259  if ( (unsigned) curs.L + 1 < lines.size() )
260  {
261  ++cline;
262  ++curs.L;
263  }
264  else
265  {
266  beep = true;
267  update = false;
268  }
269  break;
270 
271 
272  case KEY_PPAGE:
273 
274  if ( curs.L )
275  {
276  setpos( wpos( curs.L - 3, curs.C ) );
277  }
278  else
279  {
280  beep = true;
281  update = false;
282  }
283  break;
284 
285 
286  case KEY_NPAGE:
287 
288  if ( (unsigned) curs.L + 1 < lines.size() )
289  {
290  setpos( wpos( curs.L + 3, curs.C ) );
291  }
292  else
293  {
294  beep = true;
295  update = false;
296  }
297  break;
298 
299 
300  case KEY_SLEFT:
301  case KEY_HOME:
302 
303  if ( curs.C )
304  {
305  curs.C = 0;
306  }
307  break;
308 
309 
310  case KEY_SRIGHT:
311  case KEY_END:
312 
313  if ( (unsigned) curs.C < ( *cline ) )
314  {
315  curs.C = ( *cline );
316  }
317  break;
318 
319 
320  case KEY_BACKSPACE:
321  beep = !delch( true );
322  break;
323 
324  case KEY_DC:
325  beep = !delch();
326  break;
327 
328  case KEY_HOTKEY:
329  update = false;
330  break;
331 
332  default:
333  // if we are at limit of input
334 
335  if ( InputMaxLength >= 0 && InputMaxLength < (int) getText().length() )
336  {
337  beep = true;
338  update = false;
339  }
340  else
341  {
342  beep = !insert( key );
343  }
344  break;
345  }
346 
347  cursorOn();
348 
349  if ( beep )
350  ::beep();
351 
352  if ( update )
353  setpos( curs );
354 
355  return handled;
356 }
357 
358 
359 
360 bool NCTextPad::insert( wint_t key )
361 {
362  if ( key == 10 )
363  {
364  return openLine();
365  }
366 
367  if ( key < 32 || ( key >= 127 && key < 160 ) || UCHAR_MAX < key )
368  {
369  return false;
370  }
371 
372  assertWidth( ++( *cline ) );
373 
374  cchar_t cchar;
375  attr_t attr = 0;
376  short int color = 0;
377  int ret = wattr_get( w, &attr, &color, NULL ); // NOTE: (w)attr_get is not provided by NCursesWindow
378  if (ret != OK)
379  return false;
380 
381  wchar_t wch[2];
382  wch[0] = key;
383  wch[1] = L'\0';
384 
385  ret = setcchar( &cchar, wch, attr, color, NULL );
386  if (ret != OK)
387  return false;
388 
389 // libncurses6 enables ext_color from struct cchar_t (see curses.h).
390 // Set ext_color to 0 to respect the settings got from attr_get (bnc#652240).
391 #ifdef NCURSES_EXT_COLORS
392  cchar.ext_color = 0;
393 #endif
394  ret = ins_wch( curs.L, curs.C++, &cchar );
395 
396  return (ret == OK);
397 }
398 
399 
400 
401 bool NCTextPad::openLine()
402 {
403  assertHeight( lines.size() + 1 );
404  std::list<unsigned>::iterator newl( cline );
405  newl = lines.insert( ++newl, 0 );
406 
407  if ( curs.C == 0 )
408  {
409  // eazy at line begin: new empty line above
410  insertln();
411 
412  ( *newl ) = ( *cline );
413  ( *cline ) = 0;
414  }
415  else
416  {
417  // new empty line below
418  move( curs.L + 1, 0 );
419  insertln();
420 
421  if ( (unsigned) curs.C < ( *cline ) )
422  {
423  // copy down rest of line
424  ( *newl ) = ( *cline ) - curs.C;
425  ( *cline ) = curs.C;
426 
427  move( curs.L, curs.C );
428  copywin( *this, curs.L, curs.C, curs.L + 1, 0, curs.L + 1, ( *newl ), false );
429  clrtoeol();
430  }
431  }
432 
433  cline = newl;
434 
435  ++curs.L;
436  curs.C = 0;
437 
438  return true;
439 }
440 
441 
442 
443 bool NCTextPad::delch( bool previous )
444 {
445  if ( previous )
446  {
447  if ( curs.C )
448  --curs.C;
449  else if ( curs.L )
450  {
451  --cline;
452  --curs.L;
453  curs.C = ( *cline );
454  }
455  else
456  return false;
457  }
458 
459  if ( (unsigned) curs.C < *cline )
460  {
461  // eazy not at line end
462  --( *cline );
463 
464  NCPad::delch( curs.L, curs.C );
465  }
466  else if ( (unsigned) curs.L + 1 < lines.size() )
467  {
468  // at line end: join with next line
469  std::list<unsigned>::iterator nextl( cline );
470  ++nextl;
471  ( *cline ) += ( *nextl );
472  lines.erase( nextl );
473 
474  assertWidth(( *cline ) );
475  copywin( *this, curs.L + 1, 0, curs.L, curs.C, curs.L, ( *cline ), false );
476 
477  move( curs.L + 1, 0 );
478  deleteln();
479  }
480  else
481  return false;
482 
483  return true;
484 }
485 
486 
487 void NCTextPad::setText( const NCtext & ntext )
488 {
489  bkgd( MY_TEXT_STYLE );
490 
491  bool ocurs = curson;
492 
493  if ( ocurs )
494  cursorOff();
495 
496  clear();
497  assertSze( wsze( ntext.Lines(), ntext.Columns() + 1 ) );
498  curs = 0;
499 
500  cchar_t cchar;
501  attr_t attr = 0;
502  short int color = 0;
503  wattr_get( w, &attr, &color, NULL ); // NOTE: (w)attr_get is not provided by NCursesWindow
504 
505  wchar_t wch[2];
506  wch[1] = L'\0';
507  lines.clear();
508 
509  unsigned cl = 0;
510 
511  for ( NCtext::const_iterator line = ntext.begin(); line != ntext.end(); ++line )
512  {
513  lines.push_back(( *line ).str().length() );
514 
515  unsigned cc = 0;
516 
517  for ( std::wstring::const_iterator c = line->str().begin(); c != line->str().end(); c++ )
518  {
519  //replace tabs for right arrows (#66104)
520  if ( *c == 9 ) // horizontal tabulation
521  {
522  wch[0] = 8677; // U+21E5 RIGHTWARDS ARROW TO BAR (rightward tab)
523  }
524  else
525  {
526  wch[0] = *c;
527  }
528 
529  setcchar( &cchar, wch, attr, color, NULL );
530 // libncurses6 enables ext_color from struct cchar_t (see curses.h).
531 // Set ext_color to 0 to respect the settings got from attr_get (bcn#652240).
532 #ifdef NCURSES_EXT_COLORS
533  cchar.ext_color = 0;
534 #endif
535  ins_wch( cl, cc++, &cchar );
536  }
537 
538  cl++;
539  }
540 
541  if ( lines.empty() )
542  lines.push_back( 0U );
543 
544  cline = lines.begin();
545 
546  if ( ocurs )
547  cursorOn();
548 
549  setpos( curs );
550 }
551 
552 
553 
554 std::wstring NCTextPad::getText() const
555 {
556  // just for inch(x,y) call, which isn't const due to
557  // hw cursor movement, but that's of no interest here.
558  NCTextPad * myself = const_cast<NCTextPad *>( this );
559 
560  cchar_t cchar;
561  std::wstring ret;
562  unsigned l = 0;
563  wchar_t wch[CCHARW_MAX+1];
564  attr_t attr;
565  short int colorpair;
566 
567  for ( std::list<unsigned>::const_iterator cgetl( lines.begin() ); cgetl != lines.end(); ++cgetl )
568  {
569  for ( unsigned c = 0; c < ( *cgetl ); ++c )
570  {
571  myself->in_wchar( l, c, &cchar );
572  getcchar( &cchar, wch, &attr, &colorpair, NULL );
573 
574  //replace right arrow back for horizontal tab - see setText method above (#142509)
575 
576  if ( wch[0] == 8677 )
577  wch[0] = 9;
578 
579  ret += wch[0];
580  }
581 
582  ++l;
583  // do not append \n after the very last line (bnc #573553)
584  if ( l < lines.size() )
585  {
586  ret += L"\n";
587  }
588  }
589 
590  return ret;
591 }
592 
593 
594 std::ostream & operator<<( std::ostream & str, const NCTextPad & obj )
595 {
596  str << "at " << obj.CurPos() << " on " << wsze( obj.height(), obj.width() )
597  << " lines " << obj.lines.size() << " (" << *obj.cline << ")";
598  return str;
599 }
600 
601 void NCTextPad::setInputMaxLength( int nr )
602 {
603  // if there is more text then the maximum number of chars,
604  // truncate the text and update the buffer
605  if ( nr >= 0 && nr < (int) getText().length() )
606  {
607  NCstring newtext = getText().substr( 0, nr );
608  setText( newtext );
609  }
610 
611  InputMaxLength = nr;
612 }
NCTextPad
Definition: NCTextPad.h:36
wsze
Screen dimension (screen size) in the order height, width: (H, W)
Definition: position.h:154
NCstring
A string with an optional hot key.
Definition: NCstring.h:36
NCTextPad::setpos
virtual int setpos(const wpos &newpos)
Set the visible position to newpos (but clamp by maxspos), then update.
Definition: NCTextPad.cc:150
NCursesWindow
C++ class for windows.
Definition: ncursesw.h:907
NCursesWindow::delch
int delch()
Delete character under the cursor.
Definition: ncursesw.h:1545
NCursesWindow::add_attr_char
int add_attr_char(int y, int x)
Put attributed character from given position to the window.
Definition: ncursesw.cc:167
NCursesWindow::getbkgd
chtype getbkgd() const
Get current background setting.
Definition: ncursesw.h:1440
NCursesWindow::deleteln
int deleteln()
Delete the current line.
Definition: ncursesw.h:1556
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:1734
wpair::between
wpair between(const wpair &Min, const wpair &Max) const
a copy of this clamped between Min and Max
Definition: position.h:87
NCursesWindow::clear
int clear()
Clear the window.
Definition: ncursesw.h:1524
NCtext
Multi-line string.
Definition: NCtext.h:38
NCursesWindow::w
WINDOW * w
the curses WINDOW
Definition: ncursesw.h:949
NCWidget
Definition: NCWidget.h:46
NCursesWindow::maxy
int maxy() const
Largest y coord in window.
Definition: ncursesw.h:1097
NCursesWindow::clrtoeol
int clrtoeol()
Clear to the end of the line.
Definition: ncursesw.h:1540
NCursesWindow::width
int width() const
Number of columns in this window.
Definition: ncursesw.h:1077
NCPad
A virtual window with a real viewport (which is NCursesWindow) and a scrolling mechanism.
Definition: NCPad.h:113
NCursesWindow::move
int move(int y, int x)
Move cursor the this position.
Definition: ncursesw.h:1157
wpos
Screen position pair in the order line, column: (L, C)
Definition: position.h:110
NCursesWindow::in_wchar
int in_wchar(cchar_t *cchar)
Retrieve combined character under the current cursor position.
Definition: ncursesw.cc:154
NCursesWindow::bkgd
int bkgd(const chtype ch)
Set the background property and apply it to the window.
Definition: ncursesw.h:1445
NCursesWindow::height
int height() const
Number of lines in this window.
Definition: ncursesw.h:1072
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:1364
NCPad::setpos
virtual int setpos(const wpos &newpos)
Set the visible position to newpos (but clamp by maxspos), then update.
Definition: NCPad.cc:158
NCursesWindow::bkgdset
void bkgdset(chtype ch)
Set the background property.
Definition: ncursesw.h:1450
NCursesWindow::insertln
int insertln()
Insert an empty line above the current line.
Definition: ncursesw.h:1372
NCursesWindow::maxx
int maxx() const
Largest x coord in window.
Definition: ncursesw.h:1092