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