[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: KDE/kdebase/workspace
From: Oswald Buddenhagen <ossi () kde ! org>
Date: 2010-03-20 21:25:24
Message-ID: 20100320212524.80C26AC870 () svn ! kde ! org
[Download RAW message or body]
SVN commit 1105670 by ossi:
add wallpaper attribute to <pixmap> elements
this includes support for plasma wallpaper packages and fuzzy matching
of image sizes.
M +16 -4 doc/kdm/theme-ref.docbook
M +107 -16 kdm/kfrontend/themer/kdmpixmap.cpp
M +5 -1 kdm/kfrontend/themer/kdmpixmap.h
--- trunk/KDE/kdebase/workspace/doc/kdm/theme-ref.docbook #1105669:1105670
@@ -932,15 +932,27 @@
</para>
<para>
+ <literal>wallpaper</literal> can be used instead of
+ <literal>file</literal> to have &kdm; look for images in the
+ usual locations for &kde; wallpapers. Plasma wallpaper packages
+ are supported.
+ </para>
+
+ <para>
<literal>element</literal> specifies the element id of a SVG file.
If empty, the whole SVG image will be rendered.
</para>
<para>
- For <literal>pixmap</literal> nodes, &kdm; first tries to open
- a file that matches \
<replaceable>basename</replaceable><literal>-</literal><replaceable>width</replaceable \
><literal>x</literal><replaceable>height</replaceable><literal>.</literal><replaceable>extension</replaceable>
>
- based on the specified file name, so the best-quality image
- for a given resolution can be used.
+ For <literal>pixmap</literal> nodes, it is possible to provide
+ multiple images, so the best-quality image for a given resolution
+ can be used. Size-tagged file names have the format
+ <replaceable>basename</replaceable><literal>-</literal><replaceable>wid \
th</replaceable><literal>x</literal><replaceable>height</replaceable><literal>.</literal><replaceable>extension</replaceable>.
+ If the not size-tagged file exists and it is no Plasma
+ wallpaper package, &kdm; will accept only a perfect match
+ for a given size and otherwise fall back to the original file.
+ Otherwise it will try to find an image whose dimensions come
+ closest to the required size if no perfect match is found.
</para>
<!--
--- trunk/KDE/kdebase/workspace/kdm/kfrontend/themer/kdmpixmap.cpp #1105669:1105670
@@ -22,11 +22,15 @@
#include "kdmpixmap.h"
#include "kdmthemer.h"
+#include <kstandarddirs.h>
#include <ksvgrenderer.h>
+#include <QDirIterator>
#include <QPainter>
#include <QSignalMapper>
+#include <math.h>
+
KdmPixmap::KdmPixmap( QObject *parent, const QDomNode &node )
: KdmItem( parent, node )
, qsm( 0 )
@@ -65,8 +69,26 @@
KdmPixmap::definePixmap( const QDomElement &el, PixmapStruct::PixmapClass &pClass )
{
QString fileName = el.attribute( "file" );
- if (fileName.isEmpty())
- return;
+ if (!fileName.isEmpty()) {
+ if (fileName.at( 0 ) != '/')
+ fileName.prepend( themer()->baseDir() + '/' );
+ pClass.fullpath = fileName;
+ } else {
+ fileName = el.attribute( "wallpaper" );
+ if (fileName.isEmpty())
+ return;
+ QString xf = KStandardDirs::locate( "wallpaper", fileName + "/contents/images/" );
+ if (!xf.isEmpty()) {
+ pClass.package = true;
+ } else {
+ xf = KStandardDirs::locate( "wallpaper", fileName );
+ if (xf.isEmpty()) {
+ kWarning() << "Cannot find wallpaper" << fileName;
+ return;
+ }
+ }
+ pClass.fullpath = xf;
+ }
QString aspect = el.attribute( "scalemode", "free" );
pClass.aspectMode =
@@ -74,15 +96,61 @@
(aspect == "crop") ? Qt::KeepAspectRatioByExpanding :
Qt::IgnoreAspectRatio;
- pClass.fullpath = fileName;
- if (fileName.at( 0 ) != '/')
- pClass.fullpath = themer()->baseDir() + '/' + fileName;
-
pClass.svgImage = fileName.endsWith( ".svg" ) || fileName.endsWith( ".svgz" );
if (pClass.svgImage)
pClass.svgElement = el.attribute( "element" );
}
+QString
+KdmPixmap::findBestPixmap( const QString &dir, const QString &pat,
+ const QRect &area, Qt::AspectRatioMode aspectMode )
+{
+ int tw = area.width(), th = area.height();
+ float tar = 1.0 * tw / th;
+ float tpn = tw * th;
+ QString best;
+ float bestPenalty = 0;
+ QRegExp rx( QRegExp::escape( dir ) + pat );
+ QDirIterator dit( dir );
+ while (dit.hasNext()) {
+ QString fn = dit.next();
+ if (rx.exactMatch( fn )) {
+ int w = rx.cap( 1 ).toInt(), h = rx.cap( 2 ).toInt();
+ // This algorithm considers need for zooming and distortion of
+ // aspect ratio / discarded pixels / pixels left free. The weighting
+ // gives good results in the tested cases, but is pretty arbitrary
+ // by all practical means.
+ float ar = 1.0 * w / h;
+ float pn = w * h;
+ float rawAspect = ((tar > ar) ? tar / ar : ar / tar);
+ float penalty = rawAspect - 1;
+ if (aspectMode != Qt::IgnoreAspectRatio) {
+ bool exp = (aspectMode == Qt::KeepAspectRatioByExpanding);
+ // Give an advantage to non-zooming cases.
+ if ((w == tw && (h > th) == exp) || (h == th && (w > tw) == exp))
+ goto skipSize;
+ else
+ penalty *= 5;
+ // Dropped pixels don't contribute to the input area.
+ if (exp)
+ pn /= rawAspect;
+ } else {
+ // This mode does not preserve aspect ratio, so give an
+ // advantage to pics with a better ratio to start with.
+ penalty *= 10;
+ }
+ // Too small is worse than too big - within limits.
+ penalty += sqrt( (tpn > pn) ? (tpn / pn - 1) * 2 : pn / tpn - 1 );
+ skipSize:
+ if (best.isEmpty() || penalty < bestPenalty) {
+ best = fn;
+ bestPenalty = penalty;
+ }
+ }
+ }
+ return best;
+}
+
bool
KdmPixmap::loadPixmap( PixmapStruct::PixmapClass &pClass )
{
@@ -90,20 +158,43 @@
return true;
if (pClass.fullpath.isEmpty())
return false;
- if (area.isValid()) {
- int dot = pClass.fullpath.lastIndexOf( '.' );
- if (pClass.image.load( pClass.fullpath.left( dot )
- .append( QString( "-%1x%2" )
- .arg( area.width() ).arg( area.height() ) )
- .append( pClass.fullpath.mid( dot ) ) ))
- goto gotit;
+ QString fn;
+ if (pClass.package) {
+ // Always find best fit from package.
+ fn = findBestPixmap( pClass.fullpath, "(\\d+)x(\\d+)\\.[^.]+",
+ area.isValid() ? area : QRect( 0, 0, 1600, 1200 ),
+ pClass.aspectMode );
+ } else {
+ if (area.isValid()) {
+ if (QFile::exists( pClass.fullpath )) {
+ // If base file exists, use only a perfect match.
+ int dot = pClass.fullpath.lastIndexOf( '.' );
+ fn = pClass.fullpath.left( dot );
+ fn += QString( "-%1x%2" ).arg( area.width() ).arg( area.height() );
+ fn += pClass.fullpath.mid( dot );
+ if (!QFile::exists( fn ))
+ fn = pClass.fullpath;
+ } else {
+ // Otherwise find best match.
+ int sep = pClass.fullpath.lastIndexOf( '/' );
+ int dot = pClass.fullpath.lastIndexOf( '.' );
+ if (dot < sep)
+ dot = pClass.fullpath.length();
+ QString f = QRegExp::escape( pClass.fullpath.mid( sep + 1, dot - sep - 1 ) );
+ f += "-(\\d+)x(\\d+)";
+ f += QRegExp::escape( pClass.fullpath.mid( dot ) );
+ fn = findBestPixmap( pClass.fullpath.left( sep + 1 ), f, area,
+ pClass.aspectMode );
+ }
+ } else {
+ fn = pClass.fullpath;
+ }
}
- if (!pClass.image.load( pClass.fullpath )) {
- kWarning() << "failed to load " << pClass.fullpath ;
+ if (!pClass.image.load( fn )) {
+ kWarning() << "failed to load" << fn;
pClass.fullpath.clear();
return false;
}
- gotit:
if (pClass.image.format() != QImage::Format_ARGB32)
pClass.image = pClass.image.convertToFormat( QImage::Format_ARGB32 );
applyTint( pClass, pClass.image );
--- trunk/KDE/kdebase/workspace/kdm/kfrontend/themer/kdmpixmap.h #1105669:1105670
@@ -55,7 +55,8 @@
struct PixmapStruct {
struct PixmapClass {
PixmapClass()
- : svgRenderer(0), present(false), svgImage(false), \
aspectMode(Qt::IgnoreAspectRatio) {} + : svgRenderer(0), present(false), \
svgImage(false), package(false), + aspectMode(Qt::IgnoreAspectRatio) {}
QString fullpath;
QImage image;
KSvgRenderer *svgRenderer;
@@ -64,6 +65,7 @@
QColor tint;
bool present;
bool svgImage;
+ bool package;
QString svgElement;
QSize svgSizeHint;
Qt::AspectRatioMode aspectMode;
@@ -75,6 +77,8 @@
private:
// Method to load the image given by the theme
void definePixmap( const QDomElement &el, PixmapStruct::PixmapClass &pc );
+ QString findBestPixmap( const QString &dir, const QString &pat,
+ const QRect &area, Qt::AspectRatioMode aspectMode );
bool loadPixmap( PixmapStruct::PixmapClass &pc );
bool loadSvg( PixmapStruct::PixmapClass &pc );
bool calcTargetArea( PixmapStruct::PixmapClass &pClass, const QSize &sh );
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic