/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * osd.cpp: Shows some text in a pretty way independent to the WM * begin: Fre Sep 26 2003 * copyright: (C) 2004 Christian Muehlhaeuser * (C) 2004-2006 Seb Ruiz * (C) 2004, 2005 Max Howell * (C) 2005 Gábor Lehel */ #include "amarok.h" #include "amarokconfig.h" #include "collectiondb.h" //for albumCover location #include "debug.h" #include "enginecontroller.h" #include "osd.h" #include "playlist.h" //if osdUsePlaylistColumns() #include "playlistitem.h" //ditto #include "podcastbundle.h" #include "qstringx.h" #include "starmanager.h" #include #include #include #include //locate #include #include #include #include #include #include #include #include namespace ShadowEngine { TQImage makeShadow( const TQPixmap &textPixmap, const TQColor &bgColor ); } #define MOODBAR_HEIGHT 20 OSDWidget::OSDWidget( TQWidget *parent, const char *name ) : TQWidget( parent, name, WType_TopLevel | WNoAutoErase | WStyle_Customize | WX11BypassWM | WStyle_StaysOnTop ) , m_duration( 2000 ) , m_timer( new TQTimer( this ) ) , m_tqalignment( Middle ) , m_screen( 0 ) , m_y( MARGIN ) , m_drawShadow( false ) , m_translucency( false ) , m_rating( 0 ) , m_volume( false ) { setFocusPolicy( TQ_NoFocus ); setBackgroundMode( NoBackground ); unsetColors(); connect( m_timer, TQT_SIGNAL(timeout()), TQT_SLOT(hide()) ); connect( CollectionDB::instance(), TQT_SIGNAL( ratingChanged( const TQString&, int ) ), this, TQT_SLOT( ratingChanged( const TQString&, int ) ) ); //or crashes, KWin bug I think, crashes in TQWidget::icon() kapp->setTopWidget( this ); } void OSDWidget::show( const TQString &text, TQImage newImage ) { #ifdef TQ_WS_X11 m_text = text; if ( !newImage.isNull() ) { m_cover = newImage; int w = m_scaledCover.width(); int h = m_scaledCover.height(); m_scaledCover = m_cover.smoothScale(w, h); } show(); #else Q_UNUSED( text ); Q_UNUSED( newImage ); #endif } void OSDWidget::ratingChanged( const short rating ) { //m_text = '\n' + i18n( "Rating changed" ); setRating( rating ); //Checks isEnabled() before doing anything if( useMoodbar() ) OSDWidget::setMoodbar( EngineController::instance()->bundle() ); if( isShown() ) show(); } void OSDWidget::ratingChanged( const TQString& path, int rating ) { const MetaBundle ¤tTrack = EngineController::instance()->bundle(); if( currentTrack.isFile() && currentTrack.url().path() == path ) ratingChanged( rating ); } void OSDWidget::volChanged( unsigned char volume ) { if ( isEnabled() ) { m_volume = true; m_newvolume = volume; m_text = m_newvolume ? i18n("Volume: %1%").tqarg( m_newvolume ) : i18n("Mute"); show(); } } void OSDWidget::show() //virtual { #ifdef TQ_WS_X11 if ( !isEnabled() || m_text.isEmpty() ) return; const uint M = fontMetrics().width( 'x' ); const TQRect oldGeometry = TQRect( pos(), size() ); const TQRect newGeometry = determineMetrics( M ); if( m_translucency && !isShown() || !newGeometry.intersects( oldGeometry ) ) m_screenshot = TQPixmap(TQPixmap::grabWindow( qt_xrootwin(), newGeometry.x(), newGeometry.y(), newGeometry.width(), newGeometry.height() )); else if (( m_translucency ) && (!kapp->isX11CompositionAvailable())) { const TQRect unite = oldGeometry.unite( newGeometry ); KPixmap pix = TQPixmap(TQPixmap::grabWindow( qt_xrootwin(), unite.x(), unite.y(), unite.width(), unite.height() )); TQPoint p = oldGeometry.topLeft() - unite.topLeft(); bitBlt( &pix, p, &m_screenshot ); m_screenshot.resize( newGeometry.size() ); p = newGeometry.topLeft() - unite.topLeft(); bitBlt( &m_screenshot, 0, 0, &pix, p.x(), p.y() ); } if( newGeometry.width() > 0 && newGeometry.height() > 0 ) { render( M, newGeometry.size() ); setGeometry( newGeometry ); TQWidget::show(); paintMe(); if( m_duration ) //duration 0 -> stay forever m_timer->start( m_duration, true ); //calls hide() } else warning() << "Attempted to make an invalid sized OSD\n"; #endif } TQRect OSDWidget::determineMetrics( const uint M ) { // sometimes we only have a tiddly cover const TQSize minImageSize = m_cover.size().boundedTo( TQSize(100,100) ); // determine a sensible maximum size, don't cover the whole desktop or cross the screen const TQSize margin( (M + MARGIN) * 2, (M + MARGIN) * 2 ); //margins const TQSize image = m_cover.isNull() ? TQSize( 0, 0 ) : minImageSize; const TQSize max = TQApplication::desktop()->screen( m_screen )->size() - margin; // If we don't do that, the boundingRect() might not be suitable for drawText() (TQt issue N67674) m_text.replace( TQRegExp(" +\n"), "\n" ); // remove consecutive line breaks m_text.replace( TQRegExp("\n+"), "\n" ); // The osd cannot be larger than the screen TQRect rect = fontMetrics().boundingRect( 0, 0, max.width() - image.width(), max.height(), AlignCenter | WordBreak, m_text ); if( m_volume ) { static const TQString tmp = TQString ("******").insert( 3, ( i18n("Volume: 100%").length() >= i18n("Mute").length() )? i18n("Volume: 100%") : i18n("Mute") ); TQRect tmpRect = fontMetrics().boundingRect( 0, 0, max.width() - image.width(), max.height() - fontMetrics().height(), AlignCenter | WordBreak, tmp ); tmpRect.setHeight( tmpRect.height() + fontMetrics().height() / 2 ); rect = tmpRect; } if( m_rating ) { TQPixmap* star = StarManager::instance()->getStar( 1, true ); if( rect.width() < star->width() * 5 ) rect.setWidth( star->width() * 5 ); //changes right edge position rect.setHeight( rect.height() + star->height() + M ); //changes bottom edge pos } if( useMoodbar() ) rect.setHeight( rect.height() + MOODBAR_HEIGHT + M ); if( !m_cover.isNull() ) { const int availableWidth = max.width() - rect.width() - M; //WILL be >= (minImageSize.width() - M) m_scaledCover = m_cover.smoothScale( TQMIN( availableWidth, m_cover.width() ), TQMIN( rect.height(), m_cover.height() ), TQ_ScaleMin ); //this will force us to be with our bounds int shadowWidth = 0; if( m_drawShadow && !m_scaledCover.hasAlpha() && ( m_scaledCover.width() > 22 || m_scaledCover.height() > 22 ) ) shadowWidth = static_cast( m_scaledCover.width() / 100.0 * 6.0 ); const int widthIncludingImage = rect.width() + m_scaledCover.width() + shadowWidth + M; //margin between text + image rect.setWidth( widthIncludingImage ); } // expand in all directions by M rect.addCoords( -M, -M, M, M ); const TQSize newSize = rect.size(); const TQRect screen = TQApplication::desktop()->screenGeometry( m_screen ); TQPoint newPos( MARGIN, m_y ); switch( m_tqalignment ) { case Left: break; case Right: newPos.rx() = screen.width() - MARGIN - newSize.width(); break; case Center: newPos.ry() = (screen.height() - newSize.height()) / 2; //FALL THROUGH case Middle: newPos.rx() = (screen.width() - newSize.width()) / 2; break; } //ensure we don't dip below the screen if ( newPos.y() + newSize.height() > screen.height() - MARGIN ) newPos.ry() = screen.height() - MARGIN - newSize.height(); // correct for screen position newPos += screen.topLeft(); return TQRect( newPos, rect.size() ); } void OSDWidget::render( const uint M, const TQSize &size ) { /// render with margin/spacing @param M and @param size TQPoint point; TQRect rect( point, size ); // From qt sources const uint xround = (M * 200) / size.width(); const uint yround = (M * 200) / size.height(); { /// apply the mask static TQBitmap mask; mask.resize( size ); mask.fill( TQt::black ); TQPainter p( &mask ); p.setBrush( TQt::white ); p.drawRoundRect( rect, xround, yround ); setMask( mask ); } TQColor shadowColor; { int h,s,v; foregroundColor().getHsv( &h, &s, &v ); shadowColor = v > 128 ? TQt::black : TQt::white; } int align = TQt::AlignCenter | WordBreak; m_buffer.resize( rect.size() ); TQPainter p( &m_buffer ); if (( m_translucency ) && (!kapp->isX11CompositionAvailable())) { KPixmap background( m_screenshot ); KPixmapEffect::fade( background, 0.80, backgroundColor() ); p.drawPixmap( 0, 0, background ); } else if (( m_translucency ) && (kapp->isX11CompositionAvailable())) { // Make the background semi-transparent TQPixmap background( m_screenshot.width(), m_screenshot.height(), 32 ); TQRgb blend_color = tqRgba(backgroundColor().red(), backgroundColor().green(), backgroundColor().blue(), 204); // RGBA float alpha = tqAlpha(blend_color) / 255.0; int pixel = tqAlpha(blend_color) << 24 | int(tqRed(blend_color) * alpha) << 16 | int(tqGreen(blend_color) * alpha) << 8 | int(tqBlue(blend_color) * alpha); background.fill(TQColor(blend_color, pixel)); bitBlt( &m_buffer, 0, 0, &background ); } else p.fillRect( rect, backgroundColor() ); p.setPen( backgroundColor().dark() ); p.drawRoundRect( rect, xround, yround ); rect.addCoords( M, M, -M, -M ); if( !m_cover.isNull() ) { TQRect r( rect ); r.setTop( (size.height() - m_scaledCover.height()) / 2 ); r.setSize( m_scaledCover.size() ); if( !m_scaledCover.hasAlpha() && m_drawShadow && ( m_scaledCover.width() > 22 || m_scaledCover.height() > 22 ) ) { // don't draw a shadow for eg, the Amarok icon TQImage shadow; const uint shadowSize = static_cast( m_scaledCover.width() / 100.0 * 6.0 ); const TQString folder = Amarok::saveLocation( "covershadow-cache/" ); const TQString file = TQString( "shadow_albumcover%1x%2.png" ).tqarg( m_scaledCover.width() + shadowSize ) .tqarg( m_scaledCover.height() + shadowSize ); if ( TQFile::exists( folder + file ) ) shadow.load( folder + file ); else { shadow.load( locate( "data", "amarok/images/shadow_albumcover.png" ) ); shadow = shadow.smoothScale( m_scaledCover.width() + shadowSize, m_scaledCover.height() + shadowSize ); shadow.save( folder + file, "PNG" ); } TQPixmap target; target.convertFromImage( shadow ); //FIXME slow copyBlt( &target, 0, 0, &m_scaledCover ); m_scaledCover = target; r.setTop( (size.height() - m_scaledCover.height()) / 2 ); r.setSize( m_scaledCover.size() ); } p.drawPixmap( r.topLeft(), m_scaledCover ); rect.rLeft() += m_scaledCover.width() + M; } if( m_volume ) { TQPixmap vol; vol = TQPixmap( rect.width(), rect.height() + fontMetrics().height() / 4 ); TQPixmap buf( vol.size() ); TQRect r( rect ); r.setLeft( rect.left() + rect.width() / 2 - vol.width() / 2 ); r.setTop( size.height() / 2 - vol.height() / 2); KPixmap pixmapGradient; { // gradient TQBitmap mask; mask.resize( vol.size() ); mask.fill( TQt::black ); TQPainter p( &mask ); p.setBrush( TQt::white ); p.drawRoundRect ( 3, 3, vol.width() - 6, vol.height() - 6, M * 300 / vol.width(), 99 ); p.end(); pixmapGradient = TQPixmap( vol.size() ); KPixmapEffect::gradient( pixmapGradient, tqcolorGroup().background(), tqcolorGroup().highlight(), KPixmapEffect::EllipticGradient ); pixmapGradient.setMask( mask ); } if (( m_translucency ) && (!kapp->isX11CompositionAvailable())) { KPixmap background( m_screenshot ); KPixmapEffect::fade( background, 0.80, backgroundColor() ); bitBlt( &vol, -r.left(), -r.top(), &background ); } else if (( m_translucency ) && (kapp->isX11CompositionAvailable())) { // Make the background semi-transparent TQPixmap background( m_screenshot.width(), m_screenshot.height(), 32 ); TQRgb blend_color = tqRgba(backgroundColor().red(), backgroundColor().green(), backgroundColor().blue(), 204); // RGBA float alpha = tqAlpha(blend_color) / 255.0; int pixel = tqAlpha(blend_color) << 24 | int(tqRed(blend_color) * alpha) << 16 | int(tqGreen(blend_color) * alpha) << 8 | int(tqBlue(blend_color) * alpha); background.fill(TQColor(blend_color, pixel)); bitBlt( &vol, -r.left(), -r.top(), &background ); } else vol.fill( backgroundColor() ); { // vol ( bg-alpha ) static TQBitmap mask; mask.resize( vol.size() ); mask.fill( TQt::white ); TQPainter p( &mask ); p.setBrush( TQt::black ); p.drawRoundRect ( 1, 1, rect.width()-2, rect.height() + fontMetrics().height() / 4 - 2, M * 300 / vol.width(), 99 ); p.setBrush( TQt::white ); p.drawRoundRect ( 3, 3, vol.width() - 6, vol.height() - 6, M * 300 / vol.width(), 99 ); p.end(); vol.setMask( mask ); } buf.fill( backgroundColor().dark() ); const int offset = int( double( vol.width() * m_newvolume ) / 100 ); bitBlt( &buf, 0, 0, &vol ); // bg bitBlt( &buf, 0, 0, &pixmapGradient, 0, 0, offset ); p.drawPixmap( r.left(), r.top(), buf ); m_volume = false; } TQPixmap* star = StarManager::instance()->getStar( m_rating/2, true ); int graphicsHeight = 0; if( useMoodbar() ) { TQPixmap moodbar = m_moodbarBundle.moodbar().draw( rect.width(), MOODBAR_HEIGHT ); TQRect r( rect ); r.setTop( rect.bottom() - moodbar.height() - (m_rating ? star->height() + M : 0) ); graphicsHeight += moodbar.height() + M; p.drawPixmap( r.left(), r.top(), moodbar ); m_moodbarBundle = MetaBundle(); } if( m_rating > 0 ) { TQRect r( rect ); //Align to center... r.setLeft(( rect.left() + rect.width() / 2 ) - star->width() * m_rating / 4 ); r.setTop( rect.bottom() - star->height() ); graphicsHeight += star->height() + M; bool half = m_rating%2; if( half ) { TQPixmap* halfStar = StarManager::instance()->getHalfStar( m_rating/2 + 1, true ); p.drawPixmap( r.left() + star->width() * ( m_rating / 2 ), r.top(), *halfStar ); star = StarManager::instance()->getStar( m_rating/2 + 1, true ); } for( int i = 0; i < m_rating/2; i++ ) { p.drawPixmap( r.left() + i * star->width(), r.top(), *star ); } m_rating = 0; } rect.setBottom( rect.bottom() - graphicsHeight ); if( m_drawShadow ) { TQPixmap pixmap( rect.size() + TQSize(10,10) ); pixmap.fill( TQt::black ); pixmap.setMask( pixmap.createHeuristicMask( true ) ); TQPainter p2( &pixmap ); p2.setFont( font() ); p2.setPen( TQt::white ); p2.setBrush( TQt::white ); p2.drawText( TQRect(TQPoint(5,5), rect.size()), align , m_text ); p2.end(); p.drawImage( rect.topLeft() - TQPoint(5,5), ShadowEngine::makeShadow( pixmap, shadowColor ) ); } p.setPen( foregroundColor() ); p.setFont( font() ); p.drawText( rect, align, m_text ); p.end(); } void OSDWidget::paintMe() { if ((m_translucency) && (kapp->isX11CompositionAvailable())) { // We have true composition support, so make the OSD truly transparent TQImage blendedImage = m_buffer.convertToImage(); blendedImage = blendedImage.convertDepth(32); blendedImage.setAlphaBuffer(true); // Convert the ARGB pixmap to an ARGB image // NOTE 1: TQPixmap::convertToImage() always converts an ARGB pixmap into an RGB image // NOTE 2: This should eventually make its way into kdelibs or Qt itself, // as it would also be useful in applications other than Amarok int w = blendedImage.width(); int h = blendedImage.height(); Pixmap rawpixmap = m_buffer.handle(); XImage *image; image = XGetImage (qt_xdisplay(), rawpixmap, 0, 0, w, h, AllPlanes, XYPixmap); for (int y = 0; y < h; ++y) { TQRgb *ls = (TQRgb *)blendedImage.scanLine( y ); for (int x = 0; x < w; ++x) { unsigned int rawpixel = XGetPixel(image, x, y); int r = int( (rawpixel & 0x00ff0000) >> 16 ); int g = int( (rawpixel & 0x0000ff00) >> 8 ); int b = int( (rawpixel & 0x000000ff) ); int a = int( (rawpixel & 0xff000000) >> 24 ); ls[x] = tqRgba( r, g, b, a ); } } XFree (image); // Finally, paint it TQPainter p1; p1.begin( this ); blendedImage.setAlphaBuffer(false); p1.drawImage( 0, 0, blendedImage ); p1.end(); } else { bitBlt( this, 0, 0, &m_buffer ); } } bool OSDWidget::event( TQEvent *e ) { switch( e->type() ) { case TQEvent::ApplicationPaletteChange: if( !AmarokConfig::osdUseCustomColors() ) unsetColors(); //use new palette's colours return true; case TQEvent::Paint: paintMe(); return true; default: return TQWidget::event( e ); } } void OSDWidget::mousePressEvent( TQMouseEvent* ) { hide(); } void OSDWidget::unsetColors() { const TQColorGroup c = TQApplication::tqpalette().active(); setPaletteForegroundColor( c.highlightedText() ); setPaletteBackgroundColor( c.highlight() ); } void OSDWidget::setScreen( int screen ) { const int n = TQApplication::desktop()->numScreens(); m_screen = (screen >= n) ? n-1 : screen; } bool OSDWidget::useMoodbar( void ) { return (m_moodbarBundle.moodbar().state() == Moodbar::Loaded && AmarokConfig::showMoodbar() ); } ////// OSDPreviewWidget below ///////////////////// #include #include #include namespace Amarok { TQImage icon() { return TQImage( KIconLoader().iconPath( "amarok", -KIcon::SizeHuge ) ); } } OSDPreviewWidget::OSDPreviewWidget( TQWidget *parent ) : OSDWidget( parent, "osdpreview" ) , m_dragging( false ) { m_text = i18n( "OSD Preview - drag to reposition" ); m_duration = 0; m_cover = Amarok::icon(); } void OSDPreviewWidget::mousePressEvent( TQMouseEvent *event ) { m_dragOffset = event->pos(); if( event->button() == Qt::LeftButton && !m_dragging ) { grabMouse( KCursor::sizeAllCursor() ); m_dragging = true; } } void OSDPreviewWidget::mouseReleaseEvent( TQMouseEvent * /*event*/ ) { if( m_dragging ) { m_dragging = false; releaseMouse(); // compute current Position && offset TQDesktopWidget *desktop = TQApplication::desktop(); int currentScreen = desktop->screenNumber( pos() ); if( currentScreen != -1 ) { // set new data m_screen = currentScreen; m_y = TQWidget::y(); emit positionChanged(); } } } void OSDPreviewWidget::mouseMoveEvent( TQMouseEvent *e ) { if( m_dragging && this == mouseGrabber() ) { // Here we implement a "snap-to-grid" like positioning system for the preview widget const TQRect screen = TQApplication::desktop()->screenGeometry( m_screen ); const uint hcenter = screen.width() / 2; const uint eGlobalPosX = e->globalPos().x() - screen.left(); const uint snapZone = screen.width() / 24; TQPoint destination = e->globalPos() - m_dragOffset - screen.topLeft(); int maxY = screen.height() - height() - MARGIN; if( destination.y() < MARGIN ) destination.ry() = MARGIN; if( destination.y() > maxY ) destination.ry() = maxY; if( eGlobalPosX < (hcenter-snapZone) ) { m_tqalignment = Left; destination.rx() = MARGIN; } else if( eGlobalPosX > (hcenter+snapZone) ) { m_tqalignment = Right; destination.rx() = screen.width() - MARGIN - width(); } else { const uint eGlobalPosY = e->globalPos().y() - screen.top(); const uint vcenter = screen.height()/2; destination.rx() = hcenter - width()/2; if( eGlobalPosY >= (vcenter-snapZone) && eGlobalPosY <= (vcenter+snapZone) ) { m_tqalignment = Center; destination.ry() = vcenter - height()/2; } else m_tqalignment = Middle; } destination += screen.topLeft(); move( destination ); } } ////// Amarok::OSD below ///////////////////// #include "enginecontroller.h" #include "metabundle.h" #include Amarok::OSD::OSD(): OSDWidget( 0 ) { connect( CollectionDB::instance(), TQT_SIGNAL( coverChanged( const TQString&, const TQString& ) ), this, TQT_SLOT( slotCoverChanged( const TQString&, const TQString& ) ) ); connect( CollectionDB::instance(), TQT_SIGNAL( imageFetched( const TQString& ) ), this, TQT_SLOT( slotImageChanged( const TQString& ) ) ); } void Amarok::OSD::show( const MetaBundle &bundle ) //slot { #ifdef TQ_WS_X11 TQString text = ""; if( bundle.url().isEmpty() ) text = i18n( "No track playing" ); else { TQValueVector tags; tags.append(bundle.prettyTitle()); for( int i = 0; i < PlaylistItem::NUM_COLUMNS; ++i ) tags.append(bundle.prettyText( i )); if( bundle.length() <= 0 ) tags[PlaylistItem::Length+1] = TQString(); if( AmarokConfig::osdUsePlaylistColumns() ) { TQString tag; TQValueVector availableTags; //eg, ones that aren't empty static const TQValueList parens = //display these in parentheses TQValueList() << PlaylistItem::PlayCount << PlaylistItem::Year << PlaylistItem::Comment << PlaylistItem::Genre << PlaylistItem::Length << PlaylistItem::Bitrate << PlaylistItem::LastPlayed << PlaylistItem::Score << PlaylistItem::Filesize; OSDWidget::setMoodbar(); OSDWidget::setRating( 0 ); for( int i = 0, n = Playlist::instance()->numVisibleColumns(); i < n; ++i ) { const int column = Playlist::instance()->mapToLogicalColumn( i ); if( !tags.at( column + 1 ).isEmpty() && column != PlaylistItem::Rating ) availableTags.append(column); if( column == PlaylistItem::Rating ) OSDWidget::setRating( bundle.rating() ); else if( column == PlaylistItem::Mood ) OSDWidget::setMoodbar( bundle ); } for( int n = availableTags.count(), i = 0; i < n; ++i ) { const int column = availableTags.at( i ); TQString append = ( i == 0 ) ? "" : ( n > 1 && i == n / 2 ) ? "\n" : ( parens.contains( column ) || parens.contains( availableTags.at( i - 1 ) ) ) ? " " : i18n(" - "); append += ( parens.contains( column ) ? "(%1)" : "%1" ); text += append.tqarg( tags.at( column + 1 ) ); } } else { TQMap args; args["prettytitle"] = bundle.prettyTitle(); for( int i = 0; i < PlaylistItem::NUM_COLUMNS; ++i ) args[bundle.exactColumnName( i ).lower()] = bundle.prettyText( i ); if( bundle.length() <= 0 ) args["length"] = TQString(); uint time=EngineController::instance()->engine()->position(); uint sec=(time/1000)%60; //is there a better way to calculate the time? time /= 1000; uint min=(time/60)%60; time /= 60; uint hour=(time/60)%60; TQString timeformat=""; if(hour!=0) { timeformat += TQString::number(hour); timeformat +=":"; } timeformat +=TQString::number(min); timeformat +=":"; if(sec<10) timeformat +="0"; timeformat +=TQString::number(sec); args["elapsed"]=timeformat; QStringx osd = AmarokConfig::osdText(); // hacky, but works... if( osd.contains( "%rating" ) ) OSDWidget::setRating( AmarokConfig::useRatings() ? bundle.rating() : 0 ); else OSDWidget::setRating( 0 ); osd.replace( "%rating", "" ); if( osd.contains( "%moodbar" ) && AmarokConfig::showMoodbar() ) OSDWidget::setMoodbar( bundle ); osd.replace( "%moodbar", "" ); text = osd.namedOptArgs( args ); // KDE 3.3 rejects \n in the .kcfg file, and KConfig turns \n into \\n, so... text.replace( "\\n", "\n" ); } if ( AmarokConfig::osdCover() ) { //avoid showing the generic cover. we can overwrite this by passing an arg. //get large cover for scaling if big cover needed TQString location = TQString(); if( bundle.podcastBundle() ) location = CollectionDB::instance()->podcastImage( bundle, false, 0 ); else location = CollectionDB::instance()->albumImage( bundle, false, 0 ); if ( location.find( "nocover" ) != -1 ) setImage( Amarok::icon() ); else setImage( location ); } text = text.stripWhiteSpace(); } if( text.isEmpty() ) text = MetaBundle::prettyTitle( bundle.url().fileName() ).stripWhiteSpace(); if( text.startsWith( "- " ) ) //When we only have a title tag, _something_ prepends a fucking hyphen. Remove that. text = text.mid( 2 ); if( text.isEmpty() ) //still text = i18n("No information available for this track"); OSDWidget::show( text ); #else Q_UNUSED( bundle ); #endif } void Amarok::OSD::applySettings() { tqsetAlignment( static_cast( AmarokConfig::osdAlignment() ) ); setDuration( AmarokConfig::osdDuration() ); #ifdef TQ_WS_X11 setEnabled( AmarokConfig::osdEnabled() ); #else setEnabled( false ); #endif setOffset( AmarokConfig::osdYOffset() ); setScreen( AmarokConfig::osdScreen() ); setFont( AmarokConfig::osdFont() ); setDrawShadow( AmarokConfig::osdDrawShadow() ); setTranslucency( AmarokConfig::osdUseFakeTranslucency() ); if( AmarokConfig::osdUseCustomColors() ) { setTextColor( AmarokConfig::osdTextColor() ); setBackgroundColor( AmarokConfig::osdBackgroundColor() ); } else unsetColors(); } void Amarok::OSD::forceToggleOSD() { #ifdef TQ_WS_X11 if ( !isShown() ) { const bool b = isEnabled(); setEnabled( true ); show( EngineController::instance()->bundle() ); setEnabled( b ); } else hide(); #endif } void Amarok::OSD::slotCoverChanged( const TQString &artist, const TQString &album ) { if( AmarokConfig::osdCover() && artist == EngineController::instance()->bundle().artist() && album == EngineController::instance()->bundle().album() ) { TQString location = CollectionDB::instance()->albumImage( artist, album, false, 0 ); if( location.find( "nocover" ) != -1 ) setImage( Amarok::icon() ); else setImage( location ); } } void Amarok::OSD::slotImageChanged( const TQString &remoteURL ) { TQString url = EngineController::instance()->bundle().url().url(); PodcastEpisodeBundle peb; if( CollectionDB::instance()->getPodcastEpisodeBundle( url, &peb ) ) { PodcastChannelBundle pcb; if( CollectionDB::instance()->getPodcastChannelBundle( peb.parent().url(), &pcb ) ) { if( pcb.imageURL().url() == remoteURL ) { TQString location = CollectionDB::instance()->podcastImage( remoteURL, false, 0 ); if( location == CollectionDB::instance()->notAvailCover( false, 0 ) ) setImage( Amarok::icon() ); else setImage( location ); } } } } /* Code copied from kshadowengine.cpp * * Copyright (C) 2003 Laur Ivan * * Many thanks to: * - Bernardo Hung for the enhanced shadow * algorithm (currently used) * - Tim Jansen for the API updates and fixes. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License version 2 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, * Boston, MA 02110-1301, USA. */ namespace ShadowEngine { // Not sure, doesn't work above 10 static const int MULTIPLICATION_FACTOR = 3; // Multiplication factor for pixels directly above, under, or next to the text static const double AXIS_FACTOR = 2.0; // Multiplication factor for pixels diagonal to the text static const double DIAGONAL_FACTOR = 0.1; // Self explanatory static const int MAX_OPACITY = 200; double decay( TQImage&, int, int ); TQImage makeShadow( const TQPixmap& textPixmap, const TQColor &bgColor ) { TQImage result; const int w = textPixmap.width(); const int h = textPixmap.height(); const int bgr = bgColor.red(); const int bgg = bgColor.green(); const int bgb = bgColor.blue(); int alphaShadow; // This is the source pixmap TQImage img = textPixmap.convertToImage().convertDepth( 32 ); result.create( w, h, 32 ); result.fill( 0 ); // fill with black result.setAlphaBuffer( true ); static const int M = 5; for( int i = M; i < w - M; i++) { for( int j = M; j < h - M; j++ ) { alphaShadow = (int) decay( img, i, j ); result.setPixel( i,j, tqRgba( bgr, bgg , bgb, TQMIN( MAX_OPACITY, alphaShadow ) ) ); } } return result; } double decay( TQImage& source, int i, int j ) { //if ((i < 1) || (j < 1) || (i > source.width() - 2) || (j > source.height() - 2)) // return 0; double alphaShadow; alphaShadow =(tqGray(source.pixel(i-1,j-1)) * DIAGONAL_FACTOR + tqGray(source.pixel(i-1,j )) * AXIS_FACTOR + tqGray(source.pixel(i-1,j+1)) * DIAGONAL_FACTOR + tqGray(source.pixel(i ,j-1)) * AXIS_FACTOR + 0 + tqGray(source.pixel(i ,j+1)) * AXIS_FACTOR + tqGray(source.pixel(i+1,j-1)) * DIAGONAL_FACTOR + tqGray(source.pixel(i+1,j )) * AXIS_FACTOR + tqGray(source.pixel(i+1,j+1)) * DIAGONAL_FACTOR) / MULTIPLICATION_FACTOR; return alphaShadow; } } #include "osd.moc"