libyui-ncurses  2.57.2
NCPadWidget.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: NCPadWidget.cc
20 
21  Author: Michael Andres <ma@suse.de>
22 
23 /-*/
24 
25 #define YUILogComponent "ncurses"
26 #include <yui/YUILog.h>
27 #include "NCPadWidget.h"
28 
29 /**
30  * Scrollbar indicator.
31  *
32  * It's a dumb indicator: it does not react to keyboard events (class FIXME
33  * does it instead)
34  *
35  * Appearance details:
36  *
37  * Suppose we have a horizontal scrollbar 10 cells wide: ~~===~~~~~
38  * The visible part of the scrolled contents is indicated by the BAR,
39  * here 3 cells wide. (The bar is also known as "slider", "puck", "elevator")
40  *
41  * Unlike in GUIs we have no arrows at the ends of the scrollbar because we
42  * can't read the mouse clicks anyway.
43  *
44  * If the scrollbar gets shrunk to size 1 or 2, it is drawn with arrows
45  * meaning there is something in the pointed direction.
46  *
47  */
49 {
50 public:
51 
52  enum orientation { HORZ, VERT };
53 
54 private:
55 
56  chtype ch_forward; //!< draw an arrow pointing down/right
57  chtype ch_backward; //!< draw an arrow pointing up/left
58  chtype ch_barbeg; //!< draw the top/left end of the bar (elevator)
59  chtype ch_barend; //!< draw the bottom/right end of the bar (elavator)
60  chtype ch_barone; //!< draw a bar (elevator) that has the smallest visible length of 1
61 
62  const NCWidget & parw; //!< parent widget
63  NCursesWindow * win; //!< where this indicator draws itself
64  orientation type; //!< horizontal or vertical
65  unsigned len; //!< the length of this indicator in cells
66 
67  unsigned total; //!< 0 to total is the virtual size
68  unsigned visible; //!< size of the visible part
69  unsigned at; //!< position of the visible part
70 
71 private:
72 
73  // Clamp *visible* and *at* so that visible <= visible + at <= total
74  void adjust()
75  {
76  if ( visible > total )
77  {
78  // yuiDebug() << "adjust visible " << visible << " > total " << total << std::endl;
79  visible = total;
80  }
81 
82  if ( at + visible > total )
83  {
84  // yuiDebug() << "adjust at " << at << " + visible " << visible << " > total " << total << std::endl;
85  at = total - visible;
86  }
87  }
88 
89  // line starting at *p*, length *l*
90  void draw_line( unsigned p, unsigned l, chtype ch = 0 )
91  {
92  if ( !l )
93  return;
94 
95  if ( type == HORZ )
96  win->hline( 0, p, l, ch );
97  else
98  win->vline( p, 0, l, ch );
99  }
100 
101  void draw_bar( unsigned p, unsigned l )
102  {
103  if ( !l )
104  return;
105 
106  if ( l == 1 )
107  {
108  if ( type == HORZ )
109  win->addch( 0, p, ch_barone );
110  else
111  win->addch( p, 0, ch_barone );
112 
113  return;
114  }
115 
116  unsigned e = p + l - 1; // barend
117 
118  l -= 2; // inner bar
119 
120  if ( type == HORZ )
121  {
122  win->addch( 0, p, ch_barbeg );
123  win->addch( 0, e, ch_barend );
124 
125  if ( l )
126  win->hline( 0, p + 1, l );
127  }
128  else
129  {
130  win->addch( p, 0, ch_barbeg );
131  win->addch( e, 0, ch_barend );
132 
133  if ( l )
134  win->vline( p + 1, 0, l );
135  }
136  }
137 
138  void draw()
139  {
140  if ( !win )
141  return;
142 
143  bool topvis = ( at == 0 );
144 
145  bool botvis = ( at + visible == total );
146 
147  const NCstyle::StWidget & style( parw.frameStyle() );
148 
149  win->bkgdset( style.plain );
150 
151  draw_line( 0, len );
152 
153  if ( topvis && botvis )
154  {
155  // no scroll at all
156  return;
157  }
158 
159  switch ( len )
160  {
161  case 1:
162  win->bkgdset( style.scrl );
163 
164  if ( topvis == botvis )
165  {
166  // both == false; otherwise handled above
167  win->addch( 0, 0, ch_barone );
168  }
169  else
170  {
171  win->addch( 0, 0, ( topvis ? ch_forward : ch_backward ) );
172  }
173 
174  break;
175 
176  case 2:
177  win->bkgdset( style.scrl );
178 
179  if ( !topvis )
180  win->addch( 0, 0, ch_backward );
181 
182  if ( !botvis )
183  win->addch( win->maxy(), win->maxx(), ch_forward );
184 
185  break;
186 
187  default:
188 
189  case 3:
190  {
191  unsigned blen;
192  unsigned bat;
193 
194  if ( visible + 1 == total )
195  {
196  // just one invisible line
197  blen = len - 1;
198  bat = at ? 1 : 0;
199  }
200  else
201  {
202  blen = ( visible * ( len - 2 ) / total ) + 1;
203 
204  if ( topvis == botvis )
205  {
206  // both == false; otherwise handled above
207  bat = ( at * ( len - 2 ) / total ) + 1;
208  }
209  else
210  {
211  bat = ( topvis ? 0 : len - blen );
212  }
213  }
214 
215  win->bkgdset( style.plain );
216 
217  draw_line( 0, len );
218  win->bkgdset( style.scrl );
219  draw_bar( bat, blen );
220  }
221 
222  break;
223  }
224  }
225 
226 public:
227 
228  /// @param parwid parent widget
229  /// @param par window of parent widget
230  /// @param p position relative to parent window
231  /// @param l length of self (width if horizontal, height if vertical)
232  /// @param orient horizontal or vertical
233  NCScrollbar( const NCWidget & parwid, NCursesWindow & par, wpos p, unsigned l, orientation orient )
234  : ch_forward( orient == HORZ ? ACS_RARROW : ACS_DARROW )
235  , ch_backward( orient == HORZ ? ACS_LARROW : ACS_UARROW )
236  , ch_barbeg( orient == HORZ ? ACS_LTEE : ACS_TTEE )
237  , ch_barend( orient == HORZ ? ACS_RTEE : ACS_BTEE )
238  , ch_barone( orient == HORZ ? ACS_VLINE : ACS_HLINE )
239  , parw( parwid )
240  , win( 0 )
241  , type( orient )
242  , len( l ? l : 1 )
243  , total( 0 )
244  , visible( 0 )
245  , at( 0 )
246  {
247  try
248  {
249  win = new NCursesWindow( par,
250  ( type == HORZ ? 1 : len ), // height
251  ( type == VERT ? 1 : len ), // width
252  p.L, p.C,
253  'r' );
254  }
255  catch ( NCursesException & err )
256  {
257  // yuiDebug() << "NCScrollbar: " << err.message
258  // << ": at " << p << " len " << len << " in " << par << std::endl;
259  return;
260  }
261  }
262 
263  virtual ~NCScrollbar()
264  {
265  delete win;
266  }
267 
268 public:
269 
270  /// Set the indicator. The arguments use the same units,
271  /// independent of the indicator's screen size.
272  ///
273  /// @param tot total virtual size
274  /// @param vis size of the visible part
275  /// @param start position of the visible part
276  void set( unsigned tot, unsigned vis, unsigned start )
277  {
278  total = tot;
279  visible = vis;
280  at = start;
281  adjust();
282  draw();
283  }
284 
285 };
286 
287 
288 
289 
290 NCPadWidget::NCPadWidget( NCWidget * myparent )
291  : NCWidget( myparent )
292  , padwin( 0 )
293  , hsb( 0 )
294  , vsb( 0 )
295  , multidraw( false )
296  , pad( 0 )
297  , hasHeadline( false )
298  , activeLabelOnly( false )
299 {
300  // yuiDebug() << std::endl;
301  hotlabel = &label;
302  defsze = wsze( 3, 10 ) + 2;
303 }
304 
305 
306 NCPadWidget::NCPadWidget( YWidget * myparent )
307  : NCWidget( myparent )
308  , padwin( 0 )
309  , hsb( 0 )
310  , vsb( 0 )
311  , multidraw( false )
312  , pad( 0 )
313  , hasHeadline( false )
314  , activeLabelOnly( false )
315 {
316  // yuiDebug() << std::endl;
317  hotlabel = &label;
318  defsze = wsze( 3, 10 ) + 2;
319 }
320 
321 
322 NCPadWidget::~NCPadWidget()
323 {
324  delete pad;
325 
326  if ( padwin != win )
327  delete padwin;
328 
329  // yuiDebug() << std::endl;
330 }
331 
332 
333 void NCPadWidget::wCreate( const wrect & newrect )
334 {
335  const int bsize = 2; // space allocated for the pad border
336 
337  NCWidget::wCreate( newrect );
338 
339  if ( win )
340  {
341  wrect padrect( newrect.inside() );
342 
343  if ( hasHeadline )
344  {
345  if ( padrect.Sze.H > 1 )
346  {
347  padrect.Pos.L += 1;
348  padrect.Sze.H -= 1;
349  }
350  else
351  hasHeadline = false;
352  }
353 
354  padwin = new NCursesWindow( *win,
355  padrect.Sze.H, padrect.Sze.W,
356  padrect.Pos.L, padrect.Pos.C,
357  'r' );
358 
359  // The scrollbar has to be at least one character large otherwise ncurses window
360  // for the scrollbar will fail to create and we end with an exception which
361  // crashes the whole UI consequently.
362  //
363  // The scrollbar size is lowered by -2 because there is an overhead for frames etc.
364  if (win->width() - bsize)
365  {
366  hsb = new NCScrollbar( *this, *win, wpos( win->maxy(), 1 ), win->width() - bsize, NCScrollbar::HORZ );
367  }
368  else
369  {
370  // no space -> no scrollbar, scrolling still works using arrows
371  hsb = nullptr;
372  }
373 
374  if (win->height() - bsize)
375  {
376  // we have enough space for a vertical scrollbar
377  vsb = new NCScrollbar( *this, *win, wpos( 1, win->maxx() ), win->height() - bsize, NCScrollbar::VERT );
378  }
379  else
380  {
381  // no space -> no scrollbar, scrolling still works using arrows
382  vsb = nullptr;
383  }
384  }
385  else
386  {
387  padwin = 0;
388  hsb = 0;
389  vsb = 0;
390  }
391 }
392 
393 
394 void NCPadWidget::wDelete()
395 {
396  if ( pad )
397  {
398  pad->Destwin( 0 );
399  }
400 
401  if ( padwin )
402  {
403  if ( padwin != win )
404  {
405  delete padwin;
406  }
407 
408  padwin = 0;
409  }
410 
411  delete hsb;
412 
413  hsb = 0;
414  delete vsb;
415  vsb = 0;
416  NCWidget::wDelete();
417 }
418 
419 
420 void NCPadWidget::InitPad()
421 {
422  if ( pad )
423  return;
424 
425  pad = CreatePad();
426  pad->SendSchrollCB( this );
427  AdjustPad( wsze( pad->height(), pad->width() ) );
428  DrawPad();
429 }
430 
431 
432 void NCPadWidget::AdjustPadSize( wsze & minsze )
433 {
434  minPadSze = minsze;
435  minsze = wsze::max( minsze, defPadSze() );
436 }
437 
438 
439 void NCPadWidget::AdjustPad( wsze nsze )
440 {
441  if ( !pad )
442  return;
443 
444  pad->resize( nsze );
445 }
446 
447 
448 void NCPadWidget::DelPad()
449 {
450  delete pad;
451  pad = 0;
452 }
453 
454 
455 void NCPadWidget::setLabel( const NClabel & nlabel )
456 {
457  label = nlabel;
458  label.stripHotkey();
459  Redraw();
460 }
461 
462 
463 void NCPadWidget::wRedraw()
464 {
465  if ( !win )
466  return;
467 
468  // yuiDebug() << "wRedraw called for: " << win << std::endl;
469 
470  const NCstyle::StWidget & style( frameStyle() );
471 
472  win->bkgdset( style.plain );
473 
474  win->box();
475 
476  if ( !activeLabelOnly || GetState() == NC::WSactive )
477  label.drawAt( *win, style, wpos( 0, 1 ),
478  wsze( 1, win->width() - 2 ), NC::TOPLEFT, false );
479 
480  InitPad();
481 
482  if ( !pad->Destwin() )
483  {
484  AdjustPad( minPadSze );
485  pad->Destwin( padwin );
486  }
487  else
488  {
489  pad->setDirty();
490  pad->setpos();
491  pad->SendHead();
492  }
493 }
494 
495 
496 void NCPadWidget::wRecoded()
497 {
498  if ( pad )
499  pad->wRecoded();
500 
501  wRedraw();
502 }
503 
504 
505 void NCPadWidget::HScroll( unsigned total, unsigned visible, unsigned start )
506 {
507  // horizontal scroll bar might got disabled because of lack of space. See
508  // NCPadWidget::wCreate
509  if (hsb)
510  {
511  hsb->set( total, visible, start );
512  }
513 }
514 
515 
516 void NCPadWidget::VScroll( unsigned total, unsigned visible, unsigned start )
517 {
518  // vertical scroll bar might got disabled because of lack of space. See
519  // NCPadWidget::wCreate
520  if (vsb)
521  {
522  vsb->set( total, visible, start );
523  }
524 }
525 
526 
527 void NCPadWidget::ScrollHead( NCursesWindow & w, unsigned ccol )
528 {
529  if ( hasHeadline && win )
530  {
531  w.copywin( *win, 0, ccol, 1, 1, 1, win->width() - 2, false );
532  }
533 }
534 
535 
536 NCPad * NCPadWidget::CreatePad()
537 {
538  wsze psze( defPadSze() );
539  NCPad * npad = new NCPad( psze.H, psze.W, *this );
540  npad->bkgd( wStyle().list.item.plain );
541 
542  return npad;
543 }
544 
545 
546 void NCPadWidget::DrawPad()
547 {
548  if ( pad && !inMultidraw() )
549  {
550  pad->update();
551  Redraw();
552  }
553 }
554 
555 
556 bool NCPadWidget::handleInput( wint_t key )
557 {
558  return pad->handleInput( key );
559 }
NCursesWindow::addch
int addch(const char ch)
Put attributed character to the window.
Definition: ncursesw.h:1230
wsze
Screen dimension (screen size) in the order height, width: (H, W)
Definition: position.h:154
NCursesWindow::hline
int hline(int len, chtype ch=0)
Draw a horizontal line of len characters with the given character.
Definition: ncursesw.h:1487
NCScrollbar::set
void set(unsigned tot, unsigned vis, unsigned start)
Set the indicator.
Definition: NCPadWidget.cc:276
NCPadWidget::VScroll
virtual void VScroll(unsigned total, unsigned visible, unsigned start)
Definition: NCPadWidget.cc:516
NCursesWindow
C++ class for windows.
Definition: ncursesw.h:907
NCWidget::win
NCursesWindow * win
(owned)
Definition: NCWidget.h:103
NClabel
Multi-line string, with optional hotkey, drawable.
Definition: NCtext.h:82
NCursesWindow::copywin
int copywin(NCursesWindow &win, int sminrow, int smincol, int dminrow, int dmincol, int dmaxrow, int dmaxcol, bool overlay=TRUE)
Overlay or overwrite the rectangle in win given by dminrow,dmincol, dmaxrow,dmaxcol with the rectangl...
Definition: ncursesw.h:1734
NCPadWidget::HScroll
virtual void HScroll(unsigned total, unsigned visible, unsigned start)
Definition: NCPadWidget.cc:505
NCursesWindow::box
int box()
Draw a box around the window with the given vertical and horizontal drawing characters.
Definition: ncursesw.h:1464
NCWidget
Definition: NCWidget.h:46
NCursesWindow::maxy
int maxy() const
Largest y coord in window.
Definition: ncursesw.h:1097
NCstyle::StWidget
Definition: NCstyle.h:358
NCursesWindow::width
int width() const
Number of columns in this window.
Definition: ncursesw.h:1077
NCPad
A virtual window with a real viewport (which is NCursesWindow) and a scrolling mechanism.
Definition: NCPad.h:113
wpos
Screen position pair in the order line, column: (L, C)
Definition: position.h:110
NCursesWindow::vline
int vline(int len, chtype ch=0)
Draw a vertical line of len characters with the given character.
Definition: ncursesw.h:1501
NCursesWindow::bkgd
int bkgd(const chtype ch)
Set the background property and apply it to the window.
Definition: ncursesw.h:1445
NCursesWindow::height
int height() const
Number of lines in this window.
Definition: ncursesw.h:1072
NCScrollbar
Scrollbar indicator.
Definition: NCPadWidget.cc:49
NCPad::setpos
virtual int setpos(const wpos &newpos)
Set the visible position to newpos (but clamp by maxspos), then update.
Definition: NCPad.cc:158
NCScrollbar::NCScrollbar
NCScrollbar(const NCWidget &parwid, NCursesWindow &par, wpos p, unsigned l, orientation orient)
Definition: NCPadWidget.cc:233
wrect
A rectangle is defined by its position and size: wpos Pos, wsze Sze.
Definition: position.h:194
NCursesWindow::bkgdset
void bkgdset(chtype ch)
Set the background property.
Definition: ncursesw.h:1450
NCScrollHint::SendSchrollCB
void SendSchrollCB(NCSchrollCB *dest)
Set the receiver of callbacks to dest
Definition: NCPad.h:97
NCursesWindow::maxx
int maxx() const
Largest x coord in window.
Definition: ncursesw.h:1092