libyui-ncurses  2.57.2
NCWidget.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: NCWidget.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 "tnode.h"
30 #include "NCWidget.h"
31 #include <yui/YWidget.h>
32 
33 
34 NCWidget::NCWidget( YWidget * parent )
35  : tnode<NCWidget*>( this )
36  , magic( YWIDGET_MAGIC )
37  , grabedBy( 0 )
38  , win( 0 )
39  , defsze( 11, 45 )
40  , framedim( 0, 0 )
41  , inparent( -1, -1 )
42  , noUpdates( false )
43  , skipNoDimWin( true )
44  , wstate( NC::WSnormal )
45  , hotlabel( 0 )
46 {
47  NCWidget * myparent = dynamic_cast<NCWidget *>( parent );
48 
49  if ( myparent )
50  {
51  ReparentTo( *myparent );
52 
53  // yuiDebug() << "CCC " << this << " parent " << myparent << std::endl;
54  }
55 }
56 
57 
58 NCWidget::NCWidget( NCWidget * myparent )
59  : tnode<NCWidget*>( this )
60  , magic( YWIDGET_MAGIC )
61  , grabedBy( 0 )
62  , win( 0 )
63  , defsze( 11, 45 )
64  , framedim( 0, 0 )
65  , inparent( -1, -1 )
66  , noUpdates( false )
67  , skipNoDimWin( true )
68  , wstate( NC::WSnormal )
69  , hotlabel( 0 )
70 {
71  if ( myparent )
72  {
73  ReparentTo( *myparent );
74  }
75 
76  // yuiDebug() << "CCC " << this << " parent " << myparent << std::endl;
77 }
78 
79 
80 
81 NCWidget::~NCWidget()
82 {
83  // yuiDebug() << "DD+ " << this << std::endl;
84  wDelete();
85 
86  while ( Fchild() )
87  Fchild()->Disconnect();
88 
89  Disconnect();
90 
91  invalidate();
92 
93  // yuiDebug() << "DD- " << this << std::endl;
94 }
95 
96 
97 
98 
99 void NCWidget::PreDisconnect()
100 {
101  grabRelease( 0 );
102 }
103 
104 
105 
106 void NCWidget::PostDisconnect()
107 {}
108 
109 
110 
111 void NCWidget::PreReparent()
112 {}
113 
114 
115 
116 void NCWidget::PostReparent()
117 {}
118 
119 
120 
121 bool NCWidget::grabFocus()
122 {
123  return Top().Value()->wantFocus( *this );
124 }
125 
126 
127 
128 // Actualy perform sreen update.
129 void NCWidget::wUpdate( bool forced_br )
130 {
131  if ( !win )
132  return;
133 
134  if ( noUpdates && !forced_br )
135  return;
136 
137  NCurses::Update();
138 }
139 
140 
141 
142 // Redirect Update request to topmost widget
143 void NCWidget::Update()
144 {
145  if ( noUpdates )
146  return;
147 
148  if ( Parent() )
149  {
150  Parent()->Value()->Update();
151  }
152  else
153  {
154  wUpdate();
155  }
156 }
157 
158 
159 
160 NCursesWindow * NCWidget::ParentWin()
161 {
162  if ( !Parent() )
163  {
164  return 0;
165  }
166 
167  return Parent()->Value()->win;
168 }
169 
170 
171 
172 void NCWidget::wMoveChildTo( NCWidget & child, const wpos & newpos )
173 {
174  // yuiDebug() << "mc+ " << DLOC << child << " -> " << newpos << " in " << this << std::endl;
175 
176  try
177  {
178  child.wMoveTo( newpos );
179  Redraw( true );
180  }
181  catch ( NCursesError & err )
182  {
183  yuiError() << DLOC << child << " -> " << newpos << " in " << this << std::endl;
184  yuiError() << err << std::endl;
185  ::endwin();
186  abort();
187  }
188 
189  // yuiDebug() << "mc- " << DLOC << child << std::endl;
190 }
191 
192 
193 
194 void NCWidget::wRelocate( const wrect & newrect )
195 {
196  // yuiDebug() << "rl+ " << this << " -> " << newrect << std::endl;
197 
198  try
199  {
200  if ( win )
201  {
202  wDelete();
203  }
204 
205  wCreate( newrect );
206  SetState( wstate, true );
207  }
208  catch ( NCursesError & err )
209  {
210  yuiError() << *this << std::endl;
211  yuiError() << err << std::endl;
212  ::endwin();
213  abort();
214  }
215 
216  // yuiDebug() << "rl- " << this << std::endl;
217 }
218 
219 
220 
221 void NCWidget::wMoveTo( const wpos & newpos )
222 {
223  if ( !win )
224  {
225  // yuiDebug() << "No win to move: " << this << " -> " << newpos << std::endl;
226  return;
227  }
228 
229  if ( !Parent() )
230  throw NCError( "wMoveTo: got no parent" );
231 
232  if ( skipNoDimWin && inparent.Sze.H == 0 )
233  {
234  // yuiDebug() << "Skip widget with zero height: " << this << ' ' << inparent << " par " << Parent()->Value() << std::endl;
235  return;
236  }
237 
238  if ( skipNoDimWin && inparent.Sze.W == 0 )
239  {
240  // yuiDebug() << "Skip widget with zero width: " << this << ' ' << inparent << " par " << Parent()->Value() << std::endl;
241  return;
242  }
243 
244  if ( inparent.Pos != newpos )
245  {
246  // yuiDebug() << "mv+ " << this << " -> " << newpos << " par " << Parent()->Value() << std::endl;
247  NCWidget & p( *Parent()->Value() );
248  p.win->mvsubwin( win,
249  newpos.L + Parent()->Value()->framedim.Pos.L,
250  newpos.C + Parent()->Value()->framedim.Pos.C );
251  inparent.Pos = newpos;
252  // yuiDebug() << "mv- " << this << std::endl;
253  }
254 }
255 
256 
257 
258 void NCWidget::wCreate( const wrect & newrect )
259 {
260  if ( win )
261  throw NCError( "wCreate: already have win" );
262 
263  if ( !Parent() )
264  throw NCError( "wCreate: got no parent" );
265 
266  inparent = newrect;
267 
268  if ( skipNoDimWin && inparent.Sze == wsze( 0, 0 ) )
269  {
270  // yuiDebug() << "Skip nodim widget: " << this << ' ' << inparent << " par " << Parent()->Value() << std::endl;
271  return;
272  }
273 
274  if ( skipNoDimWin && inparent.Sze.H == 0 )
275  {
276  // yuiDebug() << "Skip widget with zero height: " << this << ' ' << inparent << " par " << Parent()->Value() << std::endl;
277  return;
278  }
279 
280  if ( skipNoDimWin && inparent.Sze.W == 0 )
281  {
282  // yuiDebug() << "Skip widget with zero width: " << this << ' ' << inparent << " par " << Parent()->Value() << std::endl;
283  return;
284  }
285 
286  NCursesWindow * parw = ParentWin();
287 
288  if ( Parent() && !parw )
289  {
290  yuiError() << "Can't create widget in nodim parent: " << this
291  << ' ' << inparent << " par " << Parent()->Value() << std::endl;
292  inparent.Sze = wsze( 0, 0 );
293  return;
294  }
295 
296  // yuiDebug() << "cw+ " << this << ' ' << inparent << " par " << Parent()->Value() << std::endl;
297 
298  if ( parw )
299  {
300  try
301  {
302  win = new NCursesWindow( *parw,
303  inparent.Sze.H, inparent.Sze.W,
304  inparent.Pos.L + Parent()->Value()->framedim.Pos.L,
305  inparent.Pos.C + Parent()->Value()->framedim.Pos.C,
306  'r' );
307  }
308  catch ( ... )
309  {
310  try
311  {
312  win = new NCursesWindow( *parw,
313  inparent.Sze.H, inparent.Sze.W,
314  inparent.Pos.L,
315  inparent.Pos.C,
316  'r' );
317  }
318  catch ( ... )
319  {
320  inparent.Sze = wsze( 1, 1 );
321  inparent.Pos = wpos( 0, 0 );
322  win = new NCursesWindow( *parw, 1, 1, 0, 0, 'r' );
323  }
324  }
325  }
326  else
327  {
328  win = new NCursesWindow( inparent.Sze.H, inparent.Sze.W,
329  inparent.Pos.L, inparent.Pos.C );
330  }
331 
332  // yuiDebug() << "cw- " << this << ' ' << inparent << std::endl;
333 }
334 
335 
336 
337 void NCWidget::wDelete()
338 {
339  if ( win )
340  {
341  // yuiDebug() << "wd+ " << this << std::endl;
342 
343  for ( tnode<NCWidget *> * ch = Fchild(); ch; ch = ch->Nsibling() )
344  {
345  ch->Value()->wDelete();
346  }
347 
348  win->clear();
349 
350  delete win;
351  win = 0;
352  inparent = wrect( -1, -1 );
353  // yuiDebug() << "wd- " << this << std::endl;
354  }
355 }
356 
357 
358 
359 wpos NCWidget::ScreenPos() const
360 {
361  if ( !win )
362  return -1;
363 
364  if ( Parent() )
365  {
366  return Parent()->Value()->ScreenPos() + inparent.Pos;
367  }
368 
369  return wsze( win->begy(), win->begx() );
370 }
371 
372 
373 
374 void NCWidget::SetState( const NC::WState newstate, bool force )
375 {
376  if ( newstate != wstate || force )
377  {
378  // yuiDebug() << DLOC << wstate << " -> " << newstate << std::endl;
379  wstate = newstate;
380 
381  if ( win )
382  {
383  win->bkgd( wStyle().getWidget( wstate ).plain );
384  }
385 
386  Redraw();
387  }
388 }
389 
390 
391 
392 void NCWidget::setEnabled( bool do_bv )
393 {
394  // yuiDebug() << DLOC << this << ' ' << do_bv << ' ' << wstate << std::endl;
395 
396  tnode<NCWidget*> *c = this;
397 
398  // If widget has children ([HV]Boxes, alignments,...), disable all of
399  // them recursively (#256707).
400 
401  if ( c->HasChildren() )
402  {
403  yuiDebug() << this << "setEnabled children recursively" << std::endl;
404 
405  for ( c = this->Next();
406  c && c->IsDescendantOf( this );
407  c = c->Next() )
408  {
409  if ( c->Value()->GetState() != NC::WSdumb )
410  c->Value()->setEnabled( do_bv );
411  }
412  }
413 
414  else
415  {
416  if ( wstate == NC::WSdumb )
417  return;
418 
419  if ( do_bv && wstate == NC::WSdisabled )
420  {
421  SetState( NC::WSnormal );
422  }
423  else if ( !do_bv && wstate != NC::WSdisabled )
424  {
425  if ( wstate == NC::WSactive )
426  grabRelease( 0 );
427 
428  SetState( NC::WSdisabled );
429  }
430  }
431 }
432 
433 
434 
435 void NCWidget::Redraw( bool sub )
436 {
437  if ( !win )
438  {
439  return;
440  }
441 
442  bool savNoUpdates = noUpdates;
443 
444  noUpdates = true;
445 
446  if ( sub )
447  {
448  win->clear();
449  wRedraw();
450 
451  for ( tnode<NCWidget *> * ch = Fchild(); ch; ch = ch->Nsibling() )
452  {
453  ch->Value()->Redraw( sub );
454  }
455  }
456  else
457  {
458  wRedraw();
459  }
460 
461  noUpdates = savNoUpdates;
462 
463  Update();
464 }
465 
466 
467 
468 void NCWidget::wRedraw()
469 {
470 }
471 
472 
473 
474 void NCWidget::Recoded()
475 {
476  if ( !win )
477  {
478  return;
479  }
480 
481  bool savNoUpdates = noUpdates;
482 
483  noUpdates = true;
484  wRecoded();
485 
486  for ( tnode<NCWidget *> * ch = Fchild(); ch; ch = ch->Nsibling() )
487  {
488  ch->Value()->Recoded();
489  }
490 
491  noUpdates = savNoUpdates;
492 
493  Update();
494 }
495 
496 
497 
498 void NCWidget::wRecoded()
499 {
500  wRedraw();
501 }
502 
503 
504 
505 bool NCWidget::HasHotkey( int key )
506 {
507  if ( key < 0 || UCHAR_MAX < key )
508  return false;
509 
510  if ( !( hotlabel && hotlabel->hasHotkey() ) )
511  return false;
512 
513  return( tolower( key ) == tolower( hotlabel->hotkey() ) );
514 }
515 
516 
517 
518 bool NCWidget::HasFunctionHotkey( int key ) const
519 {
520  const YWidget * w = dynamic_cast<const YWidget *>( this );
521 
522  if ( w )
523  {
524  if ( key < 0 || ( ! w->hasFunctionKey() ) )
525  return false;
526 
527  return( key == KEY_F( w->functionKey() ) );
528  }
529  else
530  {
531  yuiError() << "No YWidget" << std::endl;
532  return false;
533  }
534 }
535 
536 
537 
538 NCursesEvent NCWidget::wHandleHotkey( wint_t /*key*/ )
539 {
540  return wHandleInput( KEY_HOTKEY );
541 }
542 
543 
544 
545 NCursesEvent NCWidget::wHandleInput( wint_t /*key*/ )
546 {
547  return NCursesEvent::none;
548 }
549 
550 
551 std::ostream & operator<<( std::ostream & str, const NCWidget * obj )
552 {
553  if ( obj && obj->isValid() )
554  return str << *obj;
555 
556  return str << "(NoNCWidget)";
557 }
558 
559 
560 std::ostream & operator<<( std::ostream & str, const NCWidget & obj )
561 {
562  if ( obj.isValid() )
563  return str << obj.location() << ( void* )&obj
564  << '(' << obj.win
565  << ' ' << obj.inparent
566  << ' ' << obj.wstate
567  << ')';
568 
569  return str << "( invalid NCWidget)";
570 }
571 
572 
573 
574 void NCWidget::DumpOn( std::ostream & str, std::string prfx ) const
575 {
576  str
577  //<< prfx << "|" << std::endl
578  << prfx << "+-" << this << std::endl;
579  prfx += ( Nsibling() ? "| " : " " );
580 
581  for ( const tnode<NCWidget *> * ch = Fchild(); ch; ch = ch->Nsibling() )
582  {
583  ch->Value()->DumpOn( str, prfx );
584  }
585 }
586 
wsze
Screen dimension (screen size) in the order height, width: (H, W)
Definition: position.h:154
NCursesError
Definition: NCurses.h:51
tnode< NCWidget * >::Next
self * Next(bool restart=false)
Next node: depth first, pre-order.
Definition: tnode.h:337
NCursesWindow::parent
NCursesWindow * parent()
Get my parent.
Definition: ncursesw.h:1771
NCursesWindow
C++ class for windows.
Definition: ncursesw.h:907
tnode< NCWidget * >::Fchild
self * Fchild()
First child.
Definition: tnode.h:267
NCWidget::win
NCursesWindow * win
(owned)
Definition: NCWidget.h:103
NCursesWindow::begy
int begy() const
Line of top left corner relative to stdscr.
Definition: ncursesw.h:1087
NCWidget::setEnabled
virtual void setEnabled(bool do_bv)=0
Pure virtual to make sure every widget implements it.
Definition: NCWidget.cc:392
tnode< NCWidget * >::Top
self & Top()
Root of the tree.
Definition: tnode.h:324
tnode::Disconnect
void Disconnect()
Disconnect from the parent and siblings, but keep children.
Definition: tnode.h:194
NCursesWindow::clear
int clear()
Clear the window.
Definition: ncursesw.h:1524
tnode
Tree node.
Definition: tnode.h:44
NCWidget
Definition: NCWidget.h:46
tnode::Nsibling
self * Nsibling()
Next sibling.
Definition: tnode.h:261
wpos
Screen position pair in the order line, column: (L, C)
Definition: position.h:110
NCursesWindow::bkgd
int bkgd(const chtype ch)
Set the background property and apply it to the window.
Definition: ncursesw.h:1445
NCursesWindow::begx
int begx() const
Column of top left corner relative to stdscr.
Definition: ncursesw.h:1082
NC
A sad little namespace.
Definition: NCtypes.h:32
NCursesEvent
Definition: NCurses.h:73
wrect
A rectangle is defined by its position and size: wpos Pos, wsze Sze.
Definition: position.h:194