libyui-ncurses  2.47.6
 All Classes Functions Variables
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;
374  short int color;
375  wattr_get( w, &attr, &color, NULL ); // NOTE: (w)attr_get is not probided by NCursesWindow
376 
377  wchar_t wch[2];
378  wch[0] = key;
379  wch[1] = L'\0';
380 
381  setcchar( &cchar, wch, attr, color, NULL );
382 // libncurses6 enables ext_color from struct cchar_t (see curses.h).
383 // Set ext_color to 0 to respect the settings got from attr_get (bnc#652240).
384 #ifdef NCURSES_EXT_COLORS
385  cchar.ext_color = 0;
386 #endif
387  ins_wch( curs.L, curs.C++, &cchar );
388 
389  return true;
390 }
391 
392 
393 
394 bool NCTextPad::openLine()
395 {
396  assertHeight( lines.size() + 1 );
397  std::list<unsigned>::iterator newl( cline );
398  newl = lines.insert( ++newl, 0 );
399 
400  if ( curs.C == 0 )
401  {
402  // eazy at line begin: new empty line above
403  insertln();
404 
405  ( *newl ) = ( *cline );
406  ( *cline ) = 0;
407  }
408  else
409  {
410  // new empty line below
411  move( curs.L + 1, 0 );
412  insertln();
413 
414  if (( unsigned )curs.C < ( *cline ) )
415  {
416  // copy down rest of line
417  ( *newl ) = ( *cline ) - curs.C;
418  ( *cline ) = curs.C;
419 
420  move( curs.L, curs.C );
421  copywin( *this, curs.L, curs.C, curs.L + 1, 0, curs.L + 1, ( *newl ), false );
422  clrtoeol();
423  }
424  }
425 
426  cline = newl;
427 
428  ++curs.L;
429  curs.C = 0;
430 
431  return true;
432 }
433 
434 
435 
436 bool NCTextPad::delch( bool previous )
437 {
438  if ( previous )
439  {
440  if ( curs.C )
441  --curs.C;
442  else if ( curs.L )
443  {
444  --cline;
445  --curs.L;
446  curs.C = ( *cline );
447  }
448  else
449  return false;
450  }
451 
452  if (( unsigned )curs.C < *cline )
453  {
454  // eazy not at line end
455  --( *cline );
456 
457  NCPad::delch( curs.L, curs.C );
458  }
459  else if (( unsigned )curs.L + 1 < lines.size() )
460  {
461  // at line end: join with next line
462  std::list<unsigned>::iterator nextl( cline );
463  ++nextl;
464  ( *cline ) += ( *nextl );
465  lines.erase( nextl );
466 
467  assertWidth(( *cline ) );
468  copywin( *this, curs.L + 1, 0, curs.L, curs.C, curs.L, ( *cline ), false );
469 
470  move( curs.L + 1, 0 );
471  deleteln();
472  }
473  else
474  return false;
475 
476  return true;
477 }
478 
479 
480 void NCTextPad::setText( const NCtext & ntext )
481 {
482  bkgd( MY_TEXT_STYLE );
483 
484  bool ocurs = curson;
485  if ( ocurs ) cursorOff();
486 
487  clear();
488  assertSze( wsze( ntext.Lines(), ntext.Columns() + 1 ) );
489  curs = 0;
490 
491  cchar_t cchar;
492  attr_t attr;
493  short int color;
494  wattr_get( w, &attr, &color, NULL ); // NOTE: (w)attr_get is not probided by NCursesWindow
495 
496  wchar_t wch[2];
497  wch[1] = L'\0';
498  lines.clear();
499 
500  unsigned cl = 0;
501 
502  for ( NCtext::const_iterator line = ntext.begin(); line != ntext.end(); ++line )
503  {
504  lines.push_back(( *line ).str().length() );
505 
506  unsigned cc = 0;
507 
508  for ( std::wstring::const_iterator c = line->str().begin(); c != line->str().end(); c++ )
509  {
510  //replace tabs for right arrows (#66104)
511  if ( *c == 9 ) // horizontal tabulation
512  {
513  wch[0] = 8677; // U+21E5 RIGHTWARDS ARROW TO BAR (rightward tab)
514  }
515  else
516  {
517  wch[0] = *c;
518  }
519 
520  setcchar( &cchar, wch, attr, color, NULL );
521 // libncurses6 enables ext_color from struct cchar_t (see curses.h).
522 // Set ext_color to 0 to respect the settings got from attr_get (bcn#652240).
523 #ifdef NCURSES_EXT_COLORS
524  cchar.ext_color = 0;
525 #endif
526  ins_wch( cl, cc++, &cchar );
527  }
528 
529  cl++;
530  }
531 
532  if ( lines.empty() )
533  lines.push_back( 0U );
534 
535  cline = lines.begin();
536 
537  if ( ocurs )
538  cursorOn();
539 
540  setpos( curs );
541 }
542 
543 
544 
545 std::wstring NCTextPad::getText() const
546 {
547  // just for inch(x,y) call, which isn't const due to
548  // hw cursor movement, but that's of no interest here.
549  NCTextPad * myself = const_cast<NCTextPad *>( this );
550 
551  cchar_t cchar;
552  std::wstring ret;
553  unsigned l = 0;
554  wchar_t wch[CCHARW_MAX+1];
555  attr_t attr;
556  short int colorpair;
557 
558  for ( std::list<unsigned>::const_iterator cgetl( lines.begin() ); cgetl != lines.end(); ++cgetl )
559  {
560  for ( unsigned c = 0; c < ( *cgetl ); ++c )
561  {
562  myself->in_wchar( l, c, &cchar );
563  getcchar( &cchar, wch, &attr, &colorpair, NULL );
564 
565  //replace right arrow back for horizontal tab - see setText method above (#142509)
566 
567  if ( wch[0] == 8677 )
568  wch[0] = 9;
569 
570  ret += wch[0];
571  }
572 
573  ++l;
574  // do not append \n after the very last line (bnc #573553)
575  if ( l < lines.size() )
576  {
577  ret += L"\n";
578  }
579  }
580 
581  return ret;
582 }
583 
584 
585 std::ostream & operator<<( std::ostream & STREAM, const NCTextPad & OBJ )
586 {
587  STREAM << "at " << OBJ.CurPos() << " on " << wsze( OBJ.height(), OBJ.width() )
588  << " lines " << OBJ.lines.size() << " (" << *OBJ.cline << ")";
589  return STREAM;
590 }
591 
592 void NCTextPad::setInputMaxLength( int nr )
593 {
594  // if there is more text then the maximum number of chars,
595  // truncate the text and update the buffer
596  if ( nr >= 0 && nr < ( int )getText().length() )
597  {
598  NCstring newtext = getText().substr( 0, nr );
599  setText( newtext );
600  }
601 
602  InputMaxLength = nr;
603 }
C++ class for windows.
Definition: ncursesw.h:904
int clear()
Clear the window.
Definition: ncursesw.h:1522
Definition: NCtext.h:37
static int lines()
Number of lines on terminal, not window.
Definition: ncursesw.h:1042
int bkgd(const chtype ch)
Set the background property and apply it to the window.
Definition: ncursesw.h:1443
void bkgdset(chtype ch)
Set the background property.
Definition: ncursesw.h:1448
int maxx() const
Largest x coord in window.
Definition: ncursesw.h:1090
int delch()
Delete character under the cursor.
Definition: ncursesw.h:1543
int insertln()
Insert an empty line above the current line.
Definition: ncursesw.h:1370
Definition: NCPad.h:93
int clrtoeol()
Clear to the end of the line.
Definition: ncursesw.h:1538
Definition: position.h:109
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:1740
int height() const
Number of lines in this window.
Definition: ncursesw.h:1070
int add_attr_char(int y, int x)
Put attributed character from given position to the window.
Definition: ncursesw.cc:166
int in_wchar(cchar_t *cchar)
Retrieve combined character under the current cursor position.
Definition: ncursesw.cc:153
chtype getbkgd() const
Get current background setting.
Definition: ncursesw.h:1438
int move(int y, int x)
Move cursor the this position.
Definition: ncursesw.h:1155
int deleteln()
Delete the current line.
Definition: ncursesw.h:1554
int maxy() const
Largest y coord in window.
Definition: ncursesw.h:1095
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:1362
Definition: position.h:154
int width() const
Number of columns in this window.
Definition: ncursesw.h:1075
WINDOW * w
the curses WINDOW
Definition: ncursesw.h:947