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