libyui-ncurses  2.48.3
NCInputField.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: NCInputField.cc
20 
21  Author: Michael Andres <ma@suse.de>
22 
23 /-*/
24 #include <climits>
25 
26 
27 #define YUILogComponent "ncurses"
28 #include <yui/YUILog.h>
29 #include "NCurses.h"
30 #include "NCInputField.h"
31 
32 #include <wctype.h> // iswalnum()
33 
34 
35 NCInputField::NCInputField( YWidget * parent,
36  const std::string & nlabel,
37  bool passwordMode,
38  unsigned maxInput,
39  unsigned maxFld )
40  : YInputField( parent, nlabel, passwordMode )
41  , NCWidget( parent )
42  , passwd( passwordMode )
43  , lwin( 0 )
44  , twin( 0 )
45  , maxFldLength( maxFld )
46  , maxInputLength( maxInput )
47  , fldstart( 0 )
48  , fldlength( 0 )
49  , curpos( 0 )
50  , fldtype( PLAIN )
51  , returnOnReturn_b( false )
52  , InputMaxLength( -1 )
53 {
54  yuiDebug() << std::endl;
55 
56  if ( maxInputLength &&
57  ( !maxFldLength || maxFldLength > maxInputLength ) )
58  {
59  maxFldLength = maxInputLength;
60  }
61 
62  setLabel( nlabel );
63 
64  hotlabel = &label;
65  // initial text isn't an argument any longer
66  //setText( ntext );
67 }
68 
69 
70 
71 NCInputField::~NCInputField()
72 {
73  delete lwin;
74  delete twin;
75  yuiDebug() << std::endl;
76 }
77 
78 
79 
80 int NCInputField::preferredWidth()
81 {
82  return wGetDefsze().W;
83 }
84 
85 
86 
87 int NCInputField::preferredHeight()
88 {
89  return wGetDefsze().H;
90 }
91 
92 
93 
94 void NCInputField::setEnabled( bool do_bv )
95 {
96  NCWidget::setEnabled( do_bv );
97  YInputField::setEnabled( do_bv );
98 }
99 
100 
101 
102 void NCInputField::setSize( int newwidth, int newheight )
103 {
104  wRelocate( wpos( 0 ), wsze( newheight, newwidth ) );
105 }
106 
107 
108 
109 void NCInputField::setDefsze()
110 {
111  unsigned defwidth = maxFldLength ? maxFldLength : 5;
112 
113  if ( label.width() > defwidth )
114  defwidth = label.width();
115 
116  defsze = wsze( label.height() + 1, defwidth );
117 }
118 
119 
120 
121 void NCInputField::wCreate( const wrect & newrect )
122 {
123  NCWidget::wCreate( newrect );
124 
125  if ( !win )
126  return;
127 
128  wrect lrect( 0, wsze::min( newrect.Sze,
129  wsze( label.height(), newrect.Sze.W ) ) );
130 
131  if ( lrect.Sze.H == newrect.Sze.H )
132  lrect.Sze.H -= 1;
133 
134  wrect trect( 0, wsze( 1, newrect.Sze.W ) );
135 
136  trect.Pos.L = lrect.Sze.H > 0 ? lrect.Sze.H : 0;
137 
138  lwin = new NCursesWindow( *win,
139  lrect.Sze.H, lrect.Sze.W,
140  lrect.Pos.L, lrect.Pos.C,
141  'r' );
142 
143  twin = new NCursesWindow( *win,
144  trect.Sze.H, trect.Sze.W,
145  trect.Pos.L, trect.Pos.C,
146  'r' );
147 
148  if ( maxFldLength && maxFldLength < ( unsigned )newrect.Sze.W )
149  trect.Sze.W = maxFldLength;
150 
151  fldlength = trect.Sze.W;
152 }
153 
154 
155 
156 void NCInputField::wDelete()
157 {
158  delete lwin;
159  delete twin;
160  lwin = 0;
161  twin = 0;
162  NCWidget::wDelete();
163 }
164 
165 
166 
167 void NCInputField::setLabel( const std::string & nlabel )
168 {
169  label = NCstring( nlabel );
170  label.stripHotkey();
171  YInputField::setLabel( nlabel );
172  setDefsze();
173  Redraw();
174 }
175 
176 
177 
178 void NCInputField::setValue( const std::string & ntext )
179 {
180  buffer = NCstring( ntext ).str();
181 
182  if ( maxInputLength && buffer.length() > maxInputLength )
183  {
184  buffer = buffer.erase( maxInputLength );
185  }
186 
187  fldstart = 0;
188 
189  curpos = buffer.length();
190  tUpdate();
191 }
192 
193 
194 
195 std::string NCInputField::value( )
196 {
197  NCstring text( buffer );
198 
199  return text.Str();
200 }
201 
202 
203 
204 void NCInputField::setValidChars( const std::string & validchars )
205 {
206  validChars = NCstring( validchars );
207  YInputField::setValidChars( validchars );
208 }
209 
210 
211 
212 bool NCInputField::validKey( wint_t key ) const
213 {
214  // private: NCstring validChars;
215  const std::wstring vwch( validChars.str() );
216 
217  if ( vwch.empty() )
218  return true;
219 
220  if ( key < 0 || WCHAR_MAX < key )
221  return false;
222 
223  return( vwch.find(( wchar_t )key ) != std::wstring::npos );
224 }
225 
226 
227 
228 void NCInputField::wRedraw()
229 {
230  if ( !win )
231  return;
232 
233  // label
234  const NCstyle::StWidget & style( widgetStyle( true ) );
235 
236  lwin->bkgd( style.plain );
237 
238  lwin->clear();
239 
240  label.drawAt( *lwin, style );
241 
242  tUpdate();
243 }
244 
245 
246 
247 inline bool NCInputField::bufferFull() const
248 {
249  return( maxInputLength && buffer.length() == maxInputLength );
250 }
251 
252 
253 
254 inline unsigned NCInputField::maxCursor() const
255 {
256  return( bufferFull() ? buffer.length() - 1 : buffer.length() );
257 }
258 
259 
260 
261 void NCInputField::tUpdate()
262 {
263  if ( !win )
264  return;
265 
266  unsigned maxc = maxCursor();
267 
268  // adjust cursor
269  if ( curpos > maxc )
270  {
271  curpos = maxc;
272  }
273 
274  // adjust fldstart that cursor is visible
275  if ( maxc < fldlength )
276  {
277  fldstart = 0;
278  }
279  else
280  {
281  if ( curpos <= fldstart )
282  {
283  fldstart = curpos ? curpos - 1 : 0;
284  }
285 
286  if ( curpos >= fldstart + fldlength - 1 )
287  {
288  fldstart = curpos + ( curpos == maxc ? 1 : 2 ) - fldlength;
289  }
290  }
291 
292  const NCstyle::StWidget & style( widgetStyle() );
293 
294  twin->bkgd( widgetStyle( true ).plain );
295 
296  twin->move( 0, 0 );
297 
298  unsigned i = 0;
299 
300  unsigned end = fldlength;
301 
302  const wchar_t * cp = buffer.data() + fldstart;
303 
304  // draw left scrollhint if
305  if ( *cp && fldstart )
306  {
307  twin->bkgdset( style.scrl );
308  twin->addch( ACS_LARROW );
309  ++i;
310  ++cp;
311  }
312 
313  // check for right scrollhint
314  if ( fldstart + fldlength <= maxc )
315  {
316  --end;
317  }
318 
319  // draw field
320  twin->bkgdset( style.data );
321 
322  for ( /*adjusted i*/; *cp && i < end; ++i )
323  {
324  if ( passwd )
325  {
326  twin->addwstr( L"*" );
327  }
328  else
329  {
330  twin->addwstr( cp, 1 );
331  }
332 
333  ++cp;
334  }
335 
336  twin->bkgdset( style.plain );
337 
338  for ( /*adjusted i*/; i < end; ++i )
339  {
340  twin->addch( ACS_CKBOARD );
341  }
342 
343  // draw right scrollhint if
344  if ( end < fldlength )
345  {
346  twin->bkgdset( style.scrl );
347  twin->addch( ACS_RARROW );
348  }
349 
350  // reverse curpos
351  if ( GetState() == NC::WSactive )
352  {
353  twin->move( 0, curpos - fldstart );
354  twin->bkgdset( wStyle().cursor );
355 
356  if ( curpos < buffer.length() )
357  twin->add_attr_char( );
358  else
359  twin->addch( ACS_CKBOARD );
360  }
361 
362  Update();
363 }
364 
365 
366 
367 NCursesEvent NCInputField::wHandleInput( wint_t key )
368 {
369  NCursesEvent ret = NCursesEvent::none;
370  bool beep = false;
371  bool update = true;
372 
373  switch ( key )
374  {
375  case '\b': //ctrl-h
376  case 0x7f: //del
377  case KEY_BACKSPACE:
378 
379  if ( bufferFull() && curpos == maxCursor() )
380  {
381  // if we're on the last char in a full buffer delete this char
382  // and not the previous one.
383  buffer.erase( curpos, 1 );
384  }
385  else if ( curpos )
386  {
387  buffer.erase( --curpos, 1 );
388  }
389  else
390  {
391  update = false;
392  beep = true;
393  }
394 
395  break;
396 
397  case KEY_DC:
398 
399  if ( curpos < buffer.length() )
400  {
401  buffer.erase( curpos, 1 );
402  }
403  else
404  {
405  update = false;
406  beep = true;
407  }
408 
409  break;
410 
411  case KEY_SLEFT:
412  case KEY_HOME:
413 
414  if ( curpos )
415  {
416  curpos = 0;
417  }
418  else
419  {
420  update = false;
421  beep = true;
422  }
423 
424  break;
425 
426  case KEY_SRIGHT:
427  case KEY_END:
428 
429  if ( curpos < maxCursor() )
430  {
431  curpos = maxCursor();
432  }
433  else
434  {
435  update = false;
436  beep = true;
437  }
438 
439  break;
440 
441  case KEY_LEFT:
442 
443  if ( curpos )
444  {
445  --curpos;
446  }
447  else
448  {
449  update = false;
450  beep = true;
451  }
452 
453  break;
454 
455  case KEY_RIGHT:
456 
457  if ( curpos < maxCursor() )
458  {
459  ++curpos;
460  }
461  else
462  {
463  update = false;
464  beep = true;
465  }
466 
467  break;
468 
469  case KEY_RETURN:
470  update = false;
471 
472  if ( notify() || returnOnReturn_b )
473  ret = NCursesEvent::Activated;
474 
475  break;
476 
477  case KEY_HOTKEY:
478  update = false;
479 
480  break;
481 
482  default:
483  bool is_special = false;
484 
485  if ( key > 0xFFFF )
486  {
487  is_special = true;
488  key -= 0xFFFF;
489  }
490 
491  if (( !is_special && KEY_MIN < key && KEY_MAX > key )
492  ||
493  !iswprint( key )
494  ||
495  // if we are at limit of input
496  ( InputMaxLength >= 0 && InputMaxLength <= ( int )buffer.length() ) )
497  {
498  update = false;
499  beep = true;
500  }
501  else if ( fldtype == NUMBER )
502  {
503  if ( bufferFull() && key != L'+' )
504  {
505  update = false;
506  beep = true;
507  }
508  else
509  {
510  switch ( key )
511  {
512  case L'0':
513  case L'1':
514  case L'2':
515  case L'3':
516  case L'4':
517  case L'5':
518  case L'6':
519  case L'7':
520  case L'8':
521  case L'9':
522 
523  if ( curpos || buffer.empty() || buffer[0] != L'-' )
524  {
525  buffer.insert( std::wstring::size_type( curpos ), 1, key );
526 
527  if ( curpos < maxCursor() )
528  ++curpos;
529  }
530  else
531  {
532  update = false;
533  beep = true;
534  }
535 
536  break;
537 
538  case L'+':
539 
540  if ( !buffer.empty() && buffer[0] == L'-' )
541  {
542  buffer.erase( std::wstring::size_type( 0 ), 1 );
543 
544  if ( curpos )
545  --curpos;
546  }
547  else
548  {
549  update = false;
550  }
551 
552  break;
553 
554  case L'-':
555 
556  if ( buffer.empty() || buffer[0] != L'-' )
557  {
558  buffer.insert( std::wstring::size_type( 0 ), 1, L'-' );
559 
560  if ( curpos < maxCursor() )
561  ++curpos;
562  }
563  else
564  {
565  update = false;
566  }
567 
568  break;
569 
570  default:
571  update = false;
572  beep = true;
573  break;
574  }
575  }
576 
577  }
578  else // PLAIN
579  {
580 
581  if ( bufferFull() || !validKey( key ) )
582  {
583  update = false;
584  beep = true;
585  }
586  else
587  {
588  buffer.insert( std::wstring::size_type( curpos ), 1, key );
589 
590  if ( curpos < maxCursor() )
591  ++curpos;
592  }
593 
594  }
595 
596  break;
597  }
598 
599  if ( update )
600  {
601  tUpdate();
602 
603  if ( notify() )
604  ret = NCursesEvent::ValueChanged;
605  }
606 
607  if ( beep )
608  ::beep();
609 
610  return ret;
611 
612 }
613 
614 
615 void NCInputField::setInputMaxLength( int numberOfChars )
616 {
617  int nr = numberOfChars;
618 
619  // if there is more text then the maximum number of chars,
620  // truncate the text and update the buffer
621 
622  if ( nr >= 0 && ( int )buffer.length() > nr )
623  {
624  buffer.erase( nr, maxCursor() - nr );
625  tUpdate();
626  curpos = buffer.length();
627  }
628 
629  InputMaxLength = nr;
630 
631  YInputField::setInputMaxLength( numberOfChars );
632 }
C++ class for windows.
Definition: ncursesw.h:903
virtual void setEnabled(bool do_bv)
Pure virtual to make sure every widget implements it.
Definition: NCInputField.cc:94
int clear()
Clear the window.
Definition: ncursesw.h:1521
int bkgd(const chtype ch)
Set the background property and apply it to the window.
Definition: ncursesw.h:1442
void bkgdset(chtype ch)
Set the background property.
Definition: ncursesw.h:1447
Definition: position.h:109
int addwstr(const wchar_t *str, int n=-1)
Write the wchar_t str to the window, stop writing if the terminating NUL or the limit n is reached.
Definition: ncursesw.cc:123
int add_attr_char(int y, int x)
Put attributed character from given position to the window.
Definition: ncursesw.cc:166
int addch(const char ch)
Put attributed character to the window.
Definition: ncursesw.h:1227
int move(int y, int x)
Move cursor the this position.
Definition: ncursesw.h:1154
virtual void setEnabled(bool do_bv)=0
Pure virtual to make sure every widget implements it.
Definition: NCWidget.cc:391
Definition: position.h:154