libyui-ncurses  2.44.1
 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_HOME:
299 
300  if ( curs.C )
301  {
302  curs.C = 0;
303  }
304  break;
305 
306 
307  case KEY_END:
308 
309  if (( unsigned )curs.C < ( *cline ) )
310  {
311  curs.C = ( *cline );
312  }
313  break;
314 
315 
316  case KEY_BACKSPACE:
317  beep = !delch( true );
318  break;
319 
320  case KEY_DC:
321  beep = !delch();
322  break;
323 
324  case KEY_HOTKEY:
325  update = false;
326  break;
327 
328  default:
329  // if we are at limit of input
330 
331  if ( InputMaxLength >= 0 && InputMaxLength < ( int )getText().length() )
332  {
333  beep = true;
334  update = false;
335  }
336  else
337  {
338  beep = !insert( key );
339  }
340  break;
341  }
342 
343  cursorOn();
344 
345  if ( beep )
346  ::beep();
347 
348  if ( update )
349  setpos( curs );
350 
351  return handled;
352 }
353 
354 
355 
356 bool NCTextPad::insert( wint_t key )
357 {
358  if ( key == 10 )
359  {
360  return openLine();
361  }
362 
363  if ( key < 32 || ( key >= 127 && key < 160 ) || UCHAR_MAX < key )
364  {
365  return false;
366  }
367 
368  assertWidth( ++( *cline ) );
369 
370  cchar_t cchar;
371  attr_t attr;
372  short int color;
373  wattr_get( w, &attr, &color, NULL ); // NOTE: (w)attr_get is not probided by NCursesWindow
374 
375  wchar_t wch[2];
376  wch[0] = key;
377  wch[1] = L'\0';
378 
379  setcchar( &cchar, wch, attr, color, NULL );
380 // libncurses6 enables ext_color from struct cchar_t (see curses.h).
381 // Set ext_color to 0 to respect the settings got from attr_get (bnc#652240).
382 #ifdef NCURSES_EXT_COLORS
383  cchar.ext_color = 0;
384 #endif
385  ins_wch( curs.L, curs.C++, &cchar );
386 
387  return true;
388 }
389 
390 
391 
392 bool NCTextPad::openLine()
393 {
394  assertHeight( lines.size() + 1 );
395  std::list<unsigned>::iterator newl( cline );
396  newl = lines.insert( ++newl, 0 );
397 
398  if ( curs.C == 0 )
399  {
400  // eazy at line begin: new empty line above
401  insertln();
402 
403  ( *newl ) = ( *cline );
404  ( *cline ) = 0;
405  }
406  else
407  {
408  // new empty line below
409  move( curs.L + 1, 0 );
410  insertln();
411 
412  if (( unsigned )curs.C < ( *cline ) )
413  {
414  // copy down rest of line
415  ( *newl ) = ( *cline ) - curs.C;
416  ( *cline ) = curs.C;
417 
418  move( curs.L, curs.C );
419  copywin( *this, curs.L, curs.C, curs.L + 1, 0, curs.L + 1, ( *newl ), false );
420  clrtoeol();
421  }
422  }
423 
424  cline = newl;
425 
426  ++curs.L;
427  curs.C = 0;
428 
429  return true;
430 }
431 
432 
433 
434 bool NCTextPad::delch( bool previous )
435 {
436  if ( previous )
437  {
438  if ( curs.C )
439  --curs.C;
440  else if ( curs.L )
441  {
442  --cline;
443  --curs.L;
444  curs.C = ( *cline );
445  }
446  else
447  return false;
448  }
449 
450  if (( unsigned )curs.C < *cline )
451  {
452  // eazy not at line end
453  --( *cline );
454 
455  NCPad::delch( curs.L, curs.C );
456  }
457  else if (( unsigned )curs.L + 1 < lines.size() )
458  {
459  // at line end: join with next line
460  std::list<unsigned>::iterator nextl( cline );
461  ++nextl;
462  ( *cline ) += ( *nextl );
463  lines.erase( nextl );
464 
465  assertWidth(( *cline ) );
466  copywin( *this, curs.L + 1, 0, curs.L, curs.C, curs.L, ( *cline ), false );
467 
468  move( curs.L + 1, 0 );
469  deleteln();
470  }
471  else
472  return false;
473 
474  return true;
475 }
476 
477 
478 void NCTextPad::setText( const NCtext & ntext )
479 {
480  bkgd( MY_TEXT_STYLE );
481 
482  bool ocurs = curson;
483  if ( ocurs ) cursorOff();
484 
485  clear();
486  assertSze( wsze( ntext.Lines(), ntext.Columns() + 1 ) );
487  curs = 0;
488 
489  cchar_t cchar;
490  attr_t attr;
491  short int color;
492  wattr_get( w, &attr, &color, NULL ); // NOTE: (w)attr_get is not probided by NCursesWindow
493 
494  wchar_t wch[2];
495  wch[1] = L'\0';
496  lines.clear();
497 
498  unsigned cl = 0;
499 
500  for ( NCtext::const_iterator line = ntext.begin(); line != ntext.end(); ++line )
501  {
502  lines.push_back(( *line ).str().length() );
503 
504  unsigned cc = 0;
505 
506  for ( std::wstring::const_iterator c = line->str().begin(); c != line->str().end(); c++ )
507  {
508  //replace tabs for right arrows (#66104)
509  if ( *c == 9 ) // horizontal tabulation
510  {
511  wch[0] = 8677; // U+21E5 RIGHTWARDS ARROW TO BAR (rightward tab)
512  }
513  else
514  {
515  wch[0] = *c;
516  }
517 
518  setcchar( &cchar, wch, attr, color, NULL );
519 // libncurses6 enables ext_color from struct cchar_t (see curses.h).
520 // Set ext_color to 0 to respect the settings got from attr_get (bcn#652240).
521 #ifdef NCURSES_EXT_COLORS
522  cchar.ext_color = 0;
523 #endif
524  ins_wch( cl, cc++, &cchar );
525  }
526 
527  cl++;
528  }
529 
530  if ( lines.empty() )
531  lines.push_back( 0U );
532 
533  cline = lines.begin();
534 
535  if ( ocurs )
536  cursorOn();
537 
538  setpos( curs );
539 }
540 
541 
542 
543 std::wstring NCTextPad::getText() const
544 {
545  // just for inch(x,y) call, which isn't const due to
546  // hw cursor movement, but that's of no interest here.
547  NCTextPad * myself = const_cast<NCTextPad *>( this );
548 
549  cchar_t cchar;
550  std::wstring ret;
551  unsigned l = 0;
552  wchar_t wch[CCHARW_MAX+1];
553  attr_t attr;
554  short int colorpair;
555 
556  for ( std::list<unsigned>::const_iterator cgetl( lines.begin() ); cgetl != lines.end(); ++cgetl )
557  {
558  for ( unsigned c = 0; c < ( *cgetl ); ++c )
559  {
560  myself->in_wchar( l, c, &cchar );
561  getcchar( &cchar, wch, &attr, &colorpair, NULL );
562 
563  //replace right arrow back for horizontal tab - see setText method above (#142509)
564 
565  if ( wch[0] == 8677 )
566  wch[0] = 9;
567 
568  ret += wch[0];
569  }
570 
571  ++l;
572  // do not append \n after the very last line (bnc #573553)
573  if ( l < lines.size() )
574  {
575  ret += L"\n";
576  }
577  }
578 
579  return ret;
580 }
581 
582 
583 std::ostream & operator<<( std::ostream & STREAM, const NCTextPad & OBJ )
584 {
585  STREAM << "at " << OBJ.CurPos() << " on " << wsze( OBJ.height(), OBJ.width() )
586  << " lines " << OBJ.lines.size() << " (" << *OBJ.cline << ")";
587  return STREAM;
588 }
589 
590 void NCTextPad::setInputMaxLength( int nr )
591 {
592  // if there is more text then the maximum number of chars,
593  // truncate the text and update the buffer
594  if ( nr >= 0 && nr < ( int )getText().length() )
595  {
596  NCstring newtext = getText().substr( 0, nr );
597  setText( newtext );
598  }
599 
600  InputMaxLength = nr;
601 }
C++ class for windows.
Definition: ncursesw.h:904
Definition: NCtext.h:37
static int lines()
Definition: ncursesw.h:1042
int bkgd(const chtype ch)
Definition: ncursesw.h:1443
void bkgdset(chtype ch)
Definition: ncursesw.h:1448
int maxx() const
Definition: ncursesw.h:1090
int insertln()
Definition: ncursesw.h:1370
Definition: NCPad.h:93
int clrtoeol()
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)
Definition: ncursesw.h:1740
int height() const
Definition: ncursesw.h:1070
int add_attr_char(int y, int x)
Definition: ncursesw.cc:166
int in_wchar(cchar_t *cchar)
Definition: ncursesw.cc:153
chtype getbkgd() const
Definition: ncursesw.h:1438
int move(int y, int x)
Definition: ncursesw.h:1155
int deleteln()
Definition: ncursesw.h:1554
int maxy() const
Definition: ncursesw.h:1095
int ins_wch(int y, int x, const cchar_t *cchar)
Definition: ncursesw.h:1362
Definition: position.h:154
int width() const
Definition: ncursesw.h:1075
WINDOW * w
Definition: ncursesw.h:947