00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "OSDLWidget.h"
00028
00029 #include "OSDLFont.h"
00030 #include "OSDLFixedFont.h"
00031
00032
00033
00034 using std::string ;
00035
00036 using namespace Ceylan::Log ;
00037
00038 using namespace OSDL::Video ;
00039 using namespace OSDL::Video::TwoDimensional ;
00040
00041
00042 #ifdef OSDL_USES_CONFIG_H
00043 #include <OSDLConfig.h>
00044 #endif // OSDL_USES_CONFIG_H
00045
00046
00047
00048
00049 RedrawRequestEvent::RedrawRequestEvent( Ceylan::EventSource & source ) :
00050 SurfaceEvent( source )
00051 {
00052
00053 }
00054
00055
00056
00057 RedrawRequestEvent::~RedrawRequestEvent() throw()
00058 {
00059
00060 }
00061
00062
00063
00064
00065 Pixels::ColorDefinition Widget::_EdgeColor = Pixels::Grey ;
00066 Pixels::ColorDefinition Widget::_TitleColor = Pixels::Black ;
00067
00068
00069 Text::HorizontalAlignment Widget::_TitleHorizontalAlignment
00070 = Text::WidthCentered ;
00071
00072 Text::VerticalAlignment Widget::_TitleVerticalAlignment
00073 = Text::HeightCentered ;
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085 Length Widget::_ClientOffsetWidth = 2 ;
00086
00087
00088
00089 Length Widget::_ClientOffsetHeight = 1 ;
00090
00091
00092
00093 Coordinate Widget::_TitleOffsetAbscissa = 5 ;
00094 Coordinate Widget::_TitleOffsetOrdinate = 5 ;
00095 Coordinate Widget::_TitleBarOffsetOrdinate = 15 ;
00096
00097 std::string Widget::_DefaultTitle = "(anonymous widget)" ;
00098
00099
00100
00101
00102 Widget::Widget( Surface & container, const Point2D & relativePosition,
00103 Length width, Length height, BaseColorMode baseColorMode,
00104 Pixels::ColorDefinition baseColor,
00105 const string & title, bool minMaximizable, bool draggable,
00106 bool wrappable, bool closable ) :
00107 Surface(
00108 container.getFlags(),
00109 width,
00110 height,
00111 container.getBitsPerPixel(),
00112 container.getPixelFormat().Rmask,
00113 container.getPixelFormat().Gmask,
00114 container.getPixelFormat().Bmask,
00115 container.getPixelFormat().Amask ),
00116 EventListener( container ),
00117 _upperLeftCorner( relativePosition ),
00118 _clientArea( 0, 0, getWidth(), getHeight() ),
00119 _decorated( false ),
00120 _title( title ),
00121 _minMaximizable( minMaximizable ),
00122 _draggable( draggable ),
00123 _wrappable( wrappable ),
00124 _closable( closable ),
00125 _hasFocus( false ),
00126 _baseColorMode( NotInitialized ),
00127 _baseColor( Pixels::Black ),
00128 _actualBaseColor()
00129 {
00130
00131 #if OSDL_DEBUG_WIDGET
00132 LogPlug::trace( "Widget constructor" ) ;
00133 #endif // OSDL_DEBUG_WIDGET
00134
00135
00136
00137
00138 setBaseColorMode( baseColorMode, baseColor ) ;
00139
00140
00141
00142
00143
00144
00145 convertToDisplay(
00146 ( getFlags() & Surface::AlphaBlendingBlit ) != 0 ) ;
00147
00148 updateDecorationFlag() ;
00149
00150 updateClientArea() ;
00151
00152
00153 getContainer().setRedrawState( true ) ;
00154
00155 }
00156
00157
00158
00159 Widget::~Widget() throw()
00160 {
00161
00162 #if OSDL_DEBUG_WIDGET
00163 LogPlug::trace( "Widget destructor" ) ;
00164 #endif // OSDL_DEBUG_WIDGET
00165
00166
00167
00168
00169
00170
00171
00172 }
00173
00174
00175
00176 void Widget::setWidth( Length newWidth )
00177 {
00178
00179 resize( newWidth, getHeight() ) ;
00180
00181 }
00182
00183
00184
00185 void Widget::setHeight( Length newHeight )
00186 {
00187
00188 resize( getWidth(), newHeight ) ;
00189
00190 }
00191
00192
00193
00194 void Widget::resize( Length newWidth, Length newHeight, bool ignored )
00195 {
00196
00197
00198
00199
00200
00201
00202 if ( ( newWidth == getWidth() ) && ( newHeight == getHeight() ) )
00203 return ;
00204
00205
00206 Surface::resize( newWidth, newHeight ) ;
00207
00208 updateClientArea() ;
00209
00210 }
00211
00212
00213
00214 Widget::BaseColorMode Widget::getBaseColorMode() const
00215 {
00216
00217 return _baseColorMode ;
00218
00219 }
00220
00221
00222
00223 void Widget::setBaseColorMode( BaseColorMode newBaseColorMode,
00224 Pixels::ColorDefinition newBaseColor )
00225 {
00226
00227 bool mustUpdateColor = ( newBaseColorMode != NotInitialized ) ||
00228 ! Pixels::areEqual( newBaseColor, _baseColor, true ) ;
00229
00230 bool mustUpdateColorKey = false ;
00231
00232
00233 if ( newBaseColorMode != _baseColorMode )
00234 {
00235
00236
00237
00238
00239 if ( _baseColorMode == Colorkey )
00240 {
00241
00242 setColorKey( 0,
00243 _actualBaseColor ) ;
00244
00245 }
00246 else
00247 {
00248
00249
00250 if ( newBaseColorMode == Colorkey )
00251 mustUpdateColorKey = true ;
00252
00253 }
00254
00255 _baseColorMode = newBaseColorMode ;
00256
00257 }
00258 else
00259 {
00260
00261
00262 if ( ( _baseColorMode == Colorkey ) && mustUpdateColor )
00263 mustUpdateColorKey = true ;
00264
00265 }
00266
00267 if ( mustUpdateColor )
00268 {
00269
00270 _baseColor = newBaseColor ;
00271 _actualBaseColor = Pixels::convertColorDefinitionToPixelColor(
00272 getContainer().getPixelFormat(), _baseColor ) ;
00273
00274 setRedrawState( true ) ;
00275
00276 }
00277
00278
00279 if ( mustUpdateColorKey )
00280 {
00281
00282 setColorKey( ColorkeyBlit | RLEColorkeyBlit, _actualBaseColor ) ;
00283
00284 setRedrawState( true ) ;
00285
00286 }
00287
00288 }
00289
00290
00291
00292 Pixels::ColorDefinition Widget::getBaseColor() const
00293 {
00294
00295 return _baseColor ;
00296
00297 }
00298
00299
00300
00301 void Widget::setDecorationStatus( bool newDecorationStatus )
00302 {
00303
00304 _decorated = newDecorationStatus ;
00305
00306 }
00307
00308
00309
00310 const UprightRectangle & Widget::getClientArea() const
00311 {
00312
00313 return _clientArea ;
00314
00315 }
00316
00317
00318
00319 bool Widget::clean()
00320 {
00321
00322 #if OSDL_DEBUG_WIDGET
00323 LogPlug::trace( "Widget::clean" ) ;
00324 #endif // OSDL_DEBUG_WIDGET
00325
00326
00327 switch( _baseColorMode )
00328 {
00329
00330
00331 case BackgroundColor:
00332 case Colorkey:
00333 return ( fill( _baseColor ) ) ;
00334 break ;
00335
00336 case None:
00337 return true ;
00338 break ;
00339
00340 case NotInitialized:
00341 LogPlug::error(
00342 "Widget::clean: base color mode not initialized." ) ;
00343 return false ;
00344
00345 default:
00346 LogPlug::error( "Widget::clean: unknown base color mode." ) ;
00347 return false ;
00348 break ;
00349
00350 }
00351
00352 }
00353
00354
00355
00356 void Widget::beNotifiedOf( const Ceylan::Event & newEvent )
00357 {
00358
00359 const RedrawRequestEvent * redrawRequestEvent
00360 = dynamic_cast<const RedrawRequestEvent *>( & newEvent ) ;
00361
00362 if ( redrawRequestEvent != 0 )
00363 {
00364
00365 #if OSDL_DEBUG_WIDGET
00366 LogPlug::trace( "Widget::beNotifiedOf: redraw event received" ) ;
00367 #endif // OSDL_DEBUG_WIDGET
00368
00369
00370 redraw() ;
00371
00372 return ;
00373 }
00374
00375 LogPlug::error( "Widget::beNotifiedOf: unexpected event received: "
00376 + newEvent.toString( Ceylan::high ) ) ;
00377
00378 }
00379
00380
00381
00382 void Widget::setRedrawState( bool needsToBeRedrawn )
00383 {
00384
00385
00386
00387
00388
00389
00390 if ( ( ! getRedrawState() ) && needsToBeRedrawn )
00391 getContainer().setRedrawState( true ) ;
00392
00393 Surface::setRedrawState( needsToBeRedrawn ) ;
00394
00395 }
00396
00397
00398
00399 void Widget::redraw()
00400 {
00401
00402 #if OSDL_DEBUG_WIDGET
00403
00404 LogPlug::trace( "Widget::redraw: needs redraw attribute is "
00405 + Ceylan::toString( getRedrawState() ) + "." ) ;
00406
00407 #endif // OSDL_DEBUG_WIDGET
00408
00409
00410
00411
00412
00413
00414 Surface::redraw() ;
00415
00416
00417 try
00418 {
00419
00420 #if OSDL_DEBUG_WIDGET
00421 LogPlug::trace( "Widget::redraw: blitting to container" ) ;
00422 #endif // OSDL_DEBUG_WIDGET
00423
00424 blitTo( getContainer().getWidgetRenderTarget(), _upperLeftCorner ) ;
00425
00426 }
00427 catch( const VideoException & e )
00428 {
00429 LogPlug::error( "Widget::redraw: blit to container failed: "
00430 + e.toString() ) ;
00431 }
00432
00433 }
00434
00435
00436
00437 void Widget::redrawInternal()
00438 {
00439
00440 #if OSDL_DEBUG_WIDGET
00441 LogPlug::trace( "Widget::redrawInternal" ) ;
00442 #endif // OSDL_DEBUG_WIDGET
00443
00444 drawFundamentals( *this ) ;
00445
00446
00447 if ( _decorated )
00448 drawDecorations( *this ) ;
00449
00450
00451
00452
00453
00454
00455
00456 setRedrawState( false ) ;
00457
00458 }
00459
00460
00461
00462 const string Widget::toString( Ceylan::VerbosityLevels level ) const
00463 {
00464
00465 std::list<string> widgetList ;
00466
00467 if ( getRedrawState() )
00468 widgetList.push_back( "Needs to be redrawn." ) ;
00469 else
00470 widgetList.push_back( "Does not need to be redrawn." ) ;
00471
00472
00473 widgetList.push_back( "Upper-left corner located at "
00474 + _upperLeftCorner.toString( Ceylan::medium )
00475 + " in the referential of its container." ) ;
00476
00477 widgetList.push_back( "Widget dimensions: ( width = "
00478 + Ceylan::toString( getWidth() )
00479 + " ; height = " + Ceylan::toString( getHeight() ) + " )" ) ;
00480
00481 if ( _decorated )
00482 widgetList.push_back( "Widget is decorated." ) ;
00483 else
00484 widgetList.push_back( "Widget is not decorated." ) ;
00485
00486 widgetList.push_back( "Widget client area: " + _clientArea.toString() ) ;
00487
00488 if ( _title.empty() )
00489 widgetList.push_back( "Widget has no title." ) ;
00490 else
00491 widgetList.push_back( "The widget title is '" + _title + "'." ) ;
00492
00493 if ( _minMaximizable )
00494 widgetList.push_back(
00495 "Widget can be minimized and maximized by the user." ) ;
00496 else
00497 widgetList.push_back(
00498 "Widget cannot be minimized and maximized by the user." ) ;
00499
00500 if ( _draggable )
00501 widgetList.push_back( "Widget can be dragged by the user." ) ;
00502 else
00503 widgetList.push_back( "Widget cannot be dragged by the user." ) ;
00504
00505 if ( _wrappable )
00506 widgetList.push_back( "Widget can be wrapped by the user." ) ;
00507 else
00508 widgetList.push_back( "Widget cannot be wrapped by the user." ) ;
00509
00510 if ( _closable )
00511 widgetList.push_back( "Widget can be closed by the user." ) ;
00512 else
00513 widgetList.push_back( "Widget cannot be closed by the user. " ) ;
00514
00515 if ( _hasFocus )
00516 widgetList.push_back( "Widget has the focus." ) ;
00517 else
00518 widgetList.push_back( "Widget does not have the focus." ) ;
00519
00520
00521 switch( _baseColorMode )
00522 {
00523
00524 case BackgroundColor:
00525 widgetList.push_back( "Widget uses a background color, which is "
00526 + Pixels::toString( _baseColor ) ) ;
00527 break ;
00528
00529 case Colorkey:
00530 widgetList.push_back( "Widget uses a colorkey, which is "
00531 + Pixels::toString( _baseColor ) ) ;
00532 break ;
00533
00534 case None:
00535 widgetList.push_back(
00536 "Widget does not use its base color (which is "
00537 + Pixels::toString( _baseColor ) + ")" ) ;
00538 break ;
00539
00540 default:
00541 widgetList.push_back( "Unknown base color mode (abnormal)" ) ;
00542 break ;
00543
00544 }
00545
00546
00547 widgetList.push_back( "Widget internal "
00548 + Surface::toString( Ceylan::medium ) ) ;
00549
00550
00551 widgetList.push_back( "Widget container is: "
00552 + getConstContainer().toString( Ceylan::low ) ) ;
00553
00554 return "Widget: " + Ceylan::formatStringList( widgetList ) ;
00555
00556 }
00557
00558
00559
00560
00561
00562
00563
00564
00565 Pixels::ColorDefinition Widget::GetEdgeColor()
00566 {
00567
00568 return _EdgeColor ;
00569
00570 }
00571
00572
00573
00574 void Widget::SetEdgeColor( Pixels::ColorDefinition edgeColorDef )
00575 {
00576
00577 _EdgeColor = edgeColorDef ;
00578
00579 }
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589 void Widget::updateDecorationFlag()
00590 {
00591
00592
00593 if ( ! _decorated &&
00594 ( _minMaximizable || _draggable || _wrappable || _closable
00595 || ( ! _title.empty() ) ) )
00596 _decorated = true ;
00597
00598 }
00599
00600
00601
00602 void Widget::updateClientArea()
00603 {
00604
00605
00606
00607
00608
00609
00610
00611 _clientArea.setUpperLeftAbscissa( _ClientOffsetWidth ) ;
00612
00613 _clientArea.setWidth( getWidth() - 2 * _ClientOffsetWidth ) ;
00614
00615 if ( _decorated )
00616 {
00617
00618 _clientArea.setUpperLeftOrdinate( _TitleBarOffsetOrdinate
00619 + _ClientOffsetHeight ) ;
00620
00621 _clientArea.setHeight( getHeight() - _TitleBarOffsetOrdinate
00622 - 2 * _ClientOffsetHeight ) ;
00623
00624 }
00625 else
00626 {
00627
00628 _clientArea.setUpperLeftOrdinate( _ClientOffsetHeight ) ;
00629 _clientArea.setHeight( getHeight() - 2 * _ClientOffsetHeight ) ;
00630
00631 }
00632
00633 }
00634
00635
00636
00637 Surface & Widget::getContainer()
00638 {
00639
00640
00641
00642 #if OSDL_DEBUG_WIDGET
00643
00644 if ( _sources.size() != 1 )
00645 Ceylan::emergencyShutdown( "Widget::getContainer: "
00646 "not exactly one registered source: "
00647 + Ceylan::toString( _sources.size() )
00648 + " sources in listener list." ) ;
00649
00650 #endif // OSDL_DEBUG_WIDGET
00651
00652
00653
00654 Surface * container = dynamic_cast<Surface *>( _sources.back() ) ;
00655
00656 if ( container == 0 )
00657 Ceylan::emergencyShutdown( "Widget::getContainer: "
00658 "listener source was not a surface container." ) ;
00659
00660 return * container ;
00661
00662 }
00663
00664
00665
00666 const Surface & Widget::getConstContainer() const
00667 {
00668
00669
00670
00671 #if OSDL_DEBUG_WIDGET
00672
00673 if ( _sources.size() != 1 )
00674 Ceylan::emergencyShutdown( "Widget::getConstContainer: "
00675 "not exactly one registered source: "
00676 + Ceylan::toString( _sources.size() )
00677 + " sources in listener list." ) ;
00678
00679 #endif // OSDL_DEBUG_WIDGET
00680
00681
00682
00683 const Surface * container = dynamic_cast<Surface *>( _sources.back() ) ;
00684
00685 if ( container == 0 )
00686 Ceylan::emergencyShutdown( "Widget::getConstContainer: "
00687 "listener source was not a surface container." ) ;
00688
00689 return * container ;
00690
00691 }
00692
00693
00694
00695 void Widget::drawFundamentals( Surface & targetSurface )
00696 {
00697
00698 clean() ;
00699
00700
00701 targetSurface.drawEdges( _EdgeColor ) ;
00702
00703
00704
00705
00706 }
00707
00708
00709
00710 bool Widget::isDecorated() const
00711 {
00712
00713 return _decorated ;
00714
00715 }
00716
00717
00718
00719 void Widget::drawDecorations( Surface & targetSurface )
00720 {
00721
00722
00723
00724 if ( _title.empty() )
00725 _title = _DefaultTitle ;
00726
00727 Coordinate startingAbscissa ;
00728 Coordinate startingOrdinate ;
00729
00730
00731 switch( _TitleHorizontalAlignment )
00732 {
00733
00734
00735
00736 case Text::Left:
00737 startingAbscissa = targetSurface.getUpperLeftAbscissa()
00738 + _TitleOffsetAbscissa ;
00739 break ;
00740
00741 case Text::WidthCentered:
00742 case Text::Right:
00743 default:
00744
00745 startingAbscissa = targetSurface.getUpperLeftAbscissa()
00746 + ( targetSurface.getWidth() -
00747 static_cast<Coordinate>( _title.size() )
00748 * Text::BasicFontCharacterWidth ) / 2 ;
00749 break ;
00750
00751 }
00752
00753
00754 switch ( _TitleVerticalAlignment )
00755 {
00756
00757
00758
00759 case Text::Top:
00760 startingOrdinate = targetSurface.getUpperLeftOrdinate()
00761 + _TitleOffsetOrdinate ;
00762 break ;
00763
00764 case Text::HeightCentered:
00765 case Text::Bottom:
00766 default:
00767
00768 startingOrdinate = targetSurface.getUpperLeftOrdinate()
00769 + 1
00770 + ( _TitleBarOffsetOrdinate - Text::BasicFontCharacterHeight )
00771 / 2 ;
00772 break ;
00773
00774 }
00775
00776 targetSurface.printText( _title, startingAbscissa,
00777 startingOrdinate, _TitleColor ) ;
00778
00779 targetSurface.drawHorizontalLine( targetSurface.getUpperLeftAbscissa(),
00780 targetSurface.getWidth(),
00781 targetSurface.getUpperLeftOrdinate() + _TitleBarOffsetOrdinate,
00782 _EdgeColor ) ;
00783
00784
00785 }