libyui-ncurses  2.44.1
 All Classes Functions Variables
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_HOME:
457 
458  if ( curpos && ( mayedit || fldstart ) )
459  {
460  curpos = 0;
461  }
462  else
463  {
464  update = false;
465  beep = true;
466  }
467 
468  break;
469 
470  case KEY_END:
471 
472  if ( curpos < buffer.length() && ( mayedit || fldstart + fldlength <= buffer.length() ) )
473  {
474  curpos = buffer.length();
475  }
476  else
477  {
478  update = false;
479  beep = true;
480  }
481 
482  break;
483 
484  case KEY_LEFT:
485 
486  if ( curpos )
487  {
488  if ( mayedit )
489  --curpos;
490  else if ( fldstart )
491  curpos = fldstart - 1;
492  else
493  {
494  update = false;
495  beep = true;
496  }
497  }
498  else
499  {
500  update = false;
501  beep = true;
502  }
503 
504  break;
505 
506  case KEY_RIGHT:
507 
508  if ( mayedit && curpos < buffer.length() )
509  {
510  ++curpos;
511  }
512  else if ( fldstart + fldlength <= buffer.length() )
513  {
514  curpos = fldstart + fldlength;
515  }
516  else
517  {
518  update = false;
519  beep = true;
520  }
521 
522  break;
523 
524  case KEY_HOTKEY:
525 
526  if ( mayedit )
527  break;
528 
529  // else fallthrough
530 
531  case KEY_DOWN:
532  listPopup();
533 
534  break;
535 
536  default:
537  bool is_special = false;
538 
539  if ( key > 0xFFFF )
540  {
541  is_special = true;
542  key -= 0xFFFF;
543  }
544 
545  if ( !mayedit || !validKey( key )
546  ||
547  ( !is_special && KEY_MIN < key && KEY_MAX > key )
548  ||
549  !iswprint( key )
550  ||
551  // if we are at limit of input
552  ( InputMaxLength >= 0 && InputMaxLength <= ( int )buffer.length() ) )
553  {
554  update = false;
555  beep = true;
556  }
557  else
558  {
559  buffer.insert( curpos, 1, key );
560  modified = true;
561  ++curpos;
562  }
563 
564  break;
565  }
566 
567  if ( update )
568  tUpdate();
569 
570  if ( beep )
571  ::beep();
572 
573  //if ( notify() && oval != buffer )
574  // to be conform to qt UI send event even if value hasn't changed
575  if ( notify() )
576  ret = NCursesEvent::ValueChanged;
577 
578  return ret;
579 
580 }
581 
582 
583 int NCComboBox::listPopup()
584 {
585  int idx = -1;
586 
587  if ( !deflist.empty() )
588  {
589  wpos at( ScreenPos() + wpos( win->height(), -1 ) );
590  NCPopupList * dialog = new NCPopupList( at, "", deflist, index );
591  YUI_CHECK_NEW( dialog );
592  idx = dialog->post();
593 
594  if ( idx != -1 )
595  setCurrentItem( idx );
596 
597  YDialog::deleteTopmostDialog();
598  }
599 
600  return idx;
601 }
602 
603 
604 void NCComboBox::deleteAllItems()
605 {
606  YComboBox::deleteAllItems();
607  deflist.clear();
608  setText( "" );
609 }
610 
611 
612 void NCComboBox::setInputMaxLength( int nr )
613 {
614  // if there is more text then the maximum number of chars,
615  // truncate the text and update the buffer
616  if ( nr >= 0 && ( int )buffer.length() > nr )
617  {
618  buffer.erase( nr, buffer.length() - nr );
619  tUpdate();
620  curpos = buffer.length();
621  }
622 
623  YComboBox::setInputMaxLength( nr );
624 }
C++ class for windows.
Definition: ncursesw.h:904
int bkgd(const chtype ch)
Definition: ncursesw.h:1443
void bkgdset(chtype ch)
Definition: ncursesw.h:1448
int maxx() const
Definition: ncursesw.h:1090
Definition: position.h:109
int addwstr(const wchar_t *str, int n=-1)
Definition: ncursesw.cc:123
int height() const
Definition: ncursesw.h:1070
int add_attr_char(int y, int x)
Definition: ncursesw.cc:166
int addch(const char ch)
Definition: ncursesw.h:1228
int move(int y, int x)
Definition: ncursesw.h:1155
virtual void setEnabled(bool do_bv)=0
Definition: NCWidget.cc:391
Definition: position.h:154
virtual void setEnabled(bool do_bv)
Definition: NCComboBox.cc:76
int add_wch(const cchar_t *cch)
Definition: ncursesw.h:1244