diff --git a/src/declarativeimports/core/framesvgitem.cpp b/src/declarativeimports/core/framesvgitem.cpp index 1826d8854..5d4b1452e 100644 --- a/src/declarativeimports/core/framesvgitem.cpp +++ b/src/declarativeimports/core/framesvgitem.cpp @@ -29,7 +29,8 @@ namespace Plasma FrameSvgItemMargins::FrameSvgItemMargins(Plasma::FrameSvg *frameSvg, QObject *parent) : QObject(parent), - m_frameSvg(frameSvg) + m_frameSvg(frameSvg), + m_fixed(false) { //qDebug() << "margins at: " << left() << top() << right() << bottom(); connect(m_frameSvg, SIGNAL(repaintNeeded()), this, SLOT(update())); @@ -37,22 +38,38 @@ FrameSvgItemMargins::FrameSvgItemMargins(Plasma::FrameSvg *frameSvg, QObject *pa qreal FrameSvgItemMargins::left() const { - return m_frameSvg->marginSize(Types::LeftMargin); + if (m_fixed) { + return m_frameSvg->fixedMarginSize(Types::LeftMargin); + } else { + return m_frameSvg->marginSize(Types::LeftMargin); + } } qreal FrameSvgItemMargins::top() const { - return m_frameSvg->marginSize(Types::TopMargin); + if (m_fixed) { + return m_frameSvg->fixedMarginSize(Types::TopMargin); + } else { + return m_frameSvg->marginSize(Types::TopMargin); + } } qreal FrameSvgItemMargins::right() const { - return m_frameSvg->marginSize(Types::RightMargin); + if (m_fixed) { + return m_frameSvg->fixedMarginSize(Types::RightMargin); + } else { + return m_frameSvg->marginSize(Types::RightMargin); + } } qreal FrameSvgItemMargins::bottom() const { - return m_frameSvg->marginSize(Types::BottomMargin); + if (m_fixed) { + return m_frameSvg->fixedMarginSize(Types::BottomMargin); + } else { + return m_frameSvg->marginSize(Types::BottomMargin); + } } void FrameSvgItemMargins::update() @@ -60,13 +77,31 @@ void FrameSvgItemMargins::update() emit marginsChanged(); } +void FrameSvgItemMargins::setFixed(bool fixed) +{ + if (fixed == m_fixed) { + return; + } + + m_fixed = fixed; + emit marginsChanged(); +} + +bool FrameSvgItemMargins::isFixed() const +{ + return m_fixed; +} + FrameSvgItem::FrameSvgItem(QQuickItem *parent) : QQuickPaintedItem(parent) { m_frameSvg = new Plasma::FrameSvg(this); m_margins = new FrameSvgItemMargins(m_frameSvg, this); + m_fixedMargins = new FrameSvgItemMargins(m_frameSvg, this); + m_fixedMargins->setFixed(true); setFlag(ItemHasContents, true); connect(m_frameSvg, SIGNAL(repaintNeeded()), this, SLOT(doUpdate())); + connect(&m_units, &Units::devicePixelRatioChanged, this, &FrameSvgItem::updateDevicePixelRatio); } @@ -82,6 +117,7 @@ void FrameSvgItem::setImagePath(const QString &path) m_frameSvg->setImagePath(path); m_frameSvg->setElementPrefix(m_prefix); + updateDevicePixelRatio(); if (implicitWidth() <= 0) { setImplicitWidth(m_frameSvg->marginSize(Plasma::Types::LeftMargin) + m_frameSvg->marginSize(Plasma::Types::RightMargin)); @@ -142,6 +178,11 @@ FrameSvgItemMargins *FrameSvgItem::margins() const return m_margins; } +FrameSvgItemMargins *FrameSvgItem::fixedMargins() const +{ + return m_fixedMargins; +} + void FrameSvgItem::setEnabledBorders(const Plasma::FrameSvg::EnabledBorders borders) { if (m_frameSvg->enabledBorders() == borders) @@ -228,6 +269,13 @@ void FrameSvgItem::componentComplete() } +void FrameSvgItem::updateDevicePixelRatio() +{ + //devicepixelratio is always set integer in the svg, so needs at least 192dpi to double up. + //(it needs to be integer to have lines contained inside a svg piece to keep being pixel aligned) + m_frameSvg->setDevicePixelRatio(qMax((qreal)1.0, floor(m_units.devicePixelRatio()))); +} + } // Plasma namespace #include "framesvgitem.moc" diff --git a/src/declarativeimports/core/framesvgitem.h b/src/declarativeimports/core/framesvgitem.h index e348c4c78..a54ae726f 100644 --- a/src/declarativeimports/core/framesvgitem.h +++ b/src/declarativeimports/core/framesvgitem.h @@ -23,6 +23,8 @@ #include +#include "units.h" + namespace Plasma { class FrameSvg; @@ -59,6 +61,9 @@ public: qreal right() const; qreal bottom() const; + void setFixed(bool fixed); + bool isFixed() const; + public Q_SLOTS: void update(); @@ -67,6 +72,7 @@ Q_SIGNALS: private: FrameSvg *m_frameSvg; + bool m_fixed; }; class FrameSvgItem : public QQuickPaintedItem @@ -91,6 +97,13 @@ class FrameSvgItem : public QQuickPaintedItem */ Q_PROPERTY(QObject *margins READ margins CONSTANT) + /** + * The margins of the frame, regardless if they are enabled or not + * read only + * @see FrameSvgItemMargins + */ + Q_PROPERTY(QObject *fixedMargins READ fixedMargins CONSTANT) + Q_FLAGS(Plasma::FrameSvg::EnabledBorders) /** * The borders that will be rendered, it's a flag combination of: @@ -126,6 +139,7 @@ public: Plasma::FrameSvg::EnabledBorders enabledBorders() const; FrameSvgItemMargins *margins() const; + FrameSvgItemMargins *fixedMargins() const; void paint(QPainter *painter); @@ -155,11 +169,14 @@ Q_SIGNALS: private Q_SLOTS: void doUpdate(); + void updateDevicePixelRatio(); private: Plasma::FrameSvg *m_frameSvg; FrameSvgItemMargins *m_margins; + FrameSvgItemMargins *m_fixedMargins; QString m_prefix; + Units m_units; }; } diff --git a/src/declarativeimports/core/svgitem.cpp b/src/declarativeimports/core/svgitem.cpp index e90751a02..1db6523db 100644 --- a/src/declarativeimports/core/svgitem.cpp +++ b/src/declarativeimports/core/svgitem.cpp @@ -19,6 +19,8 @@ #include "svgitem.h" +#include +#include #include #include "QDebug" @@ -32,6 +34,7 @@ SvgItem::SvgItem(QQuickItem *parent) m_smooth(false) { setFlag(QQuickItem::ItemHasContents, true); + connect(&m_units, &Units::devicePixelRatioChanged, this, &SvgItem::updateDevicePixelRatio); } @@ -81,6 +84,8 @@ void SvgItem::setSvg(Plasma::Svg *svg) disconnect(m_svg.data(), 0, this, 0); } m_svg = svg; + updateDevicePixelRatio(); + if (svg) { connect(svg, SIGNAL(repaintNeeded()), this, SLOT(updateNeeded())); connect(svg, SIGNAL(repaintNeeded()), this, SIGNAL(naturalSizeChanged())); @@ -179,6 +184,15 @@ qreal SvgItem::implicitHeight() const return QQuickItem::implicitHeight(); } +void SvgItem::updateDevicePixelRatio() +{ + if (m_svg) { + //devicepixelratio is always set integer in the svg, so needs at least 192dpi to double up. + //(it needs to be integer to have lines contained inside a svg piece to keep being pixel aligned) + m_svg.data()->setDevicePixelRatio(qMax((qreal)1.0, floor(m_units.devicePixelRatio()))); + } +} + } // Plasma namespace #include "svgitem.moc" diff --git a/src/declarativeimports/core/svgitem.h b/src/declarativeimports/core/svgitem.h index c8be7ccd5..05072eb99 100644 --- a/src/declarativeimports/core/svgitem.h +++ b/src/declarativeimports/core/svgitem.h @@ -21,6 +21,8 @@ #include +#include "units.h" + namespace Plasma { class Svg; @@ -99,11 +101,13 @@ Q_SIGNALS: protected Q_SLOTS: void updateNeeded(); + void updateDevicePixelRatio(); private: QWeakPointer m_svg; QString m_elementID; bool m_smooth; + Units m_units; }; } diff --git a/src/declarativeimports/plasmacomponents/qml/ToolButton.qml b/src/declarativeimports/plasmacomponents/qml/ToolButton.qml index 2319879d3..7ff4f011c 100644 --- a/src/declarativeimports/plasmacomponents/qml/ToolButton.qml +++ b/src/declarativeimports/plasmacomponents/qml/ToolButton.qml @@ -177,7 +177,7 @@ Item { Item { parent: delegate anchors.fill: parent - property alias margins: surface.margins + property alias margins: surface.fixedMargins property alias hasOverState: shadow.hasOverState Private.ButtonShadow { id: shadow diff --git a/src/plasma/framesvg.cpp b/src/plasma/framesvg.cpp index 9e1a53ea9..d581c5d9f 100644 --- a/src/plasma/framesvg.cpp +++ b/src/plasma/framesvg.cpp @@ -412,6 +412,32 @@ qreal FrameSvg::marginSize(const Plasma::Types::MarginEdge edge) const } } +qreal FrameSvg::fixedMarginSize(const Plasma::Types::MarginEdge edge) const +{ + if (d->frames[d->prefix]->noBorderPadding) { + return .0; + } + + switch (edge) { + case Plasma::Types::TopMargin: + return d->frames[d->prefix]->fixedTopMargin; + break; + + case Plasma::Types::LeftMargin: + return d->frames[d->prefix]->fixedLeftMargin; + break; + + case Plasma::Types::RightMargin: + return d->frames[d->prefix]->fixedRightMargin; + break; + + //Plasma::BottomMargin + default: + return d->frames[d->prefix]->fixedBottomMargin; + break; + } +} + void FrameSvg::getMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const { FrameData *frame = d->frames[d->prefix]; @@ -427,6 +453,21 @@ void FrameSvg::getMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) bottom = frame->bottomMargin; } +void FrameSvg::getFixedMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const +{ + FrameData *frame = d->frames[d->prefix]; + + if (frame->noBorderPadding) { + left = top = right = bottom = 0; + return; + } + + top = frame->fixedTopMargin; + left = frame->fixedLeftMargin; + right = frame->fixedRightMargin; + bottom = frame->fixedBottomMargin; +} + QRectF FrameSvg::contentsRect() const { QSizeF size(frameSize()); @@ -975,6 +1016,17 @@ void FrameSvgPrivate::updateSizes() const q->resize(); frame->cachedBackground = QPixmap(); + //This has the same size regardless the border is enabled or not + frame->fixedTopHeight = q->elementSize(prefix % "top").height(); + + if (q->hasElement(prefix % "hint-top-margin")) { + frame->fixedTopMargin = q->elementSize(prefix % "hint-top-margin").height(); + } else { + frame->fixedTopMargin = frame->fixedTopHeight; + } + + + //The same, but its size depends from the margin being enabled if (frame->enabledBorders & FrameSvg::TopBorder) { frame->topHeight = q->elementSize(prefix % "top").height(); @@ -987,6 +1039,14 @@ void FrameSvgPrivate::updateSizes() const frame->topMargin = frame->topHeight = 0; } + frame->fixedLeftWidth = q->elementSize(prefix % "left").width(); + + if (q->hasElement(prefix % "hint-left-margin")) { + frame->fixedLeftMargin = q->elementSize(prefix % "hint-left-margin").width(); + } else { + frame->fixedLeftMargin = frame->fixedLeftWidth; + } + if (frame->enabledBorders & FrameSvg::LeftBorder) { frame->leftWidth = q->elementSize(prefix % "left").width(); @@ -999,6 +1059,14 @@ void FrameSvgPrivate::updateSizes() const frame->leftMargin = frame->leftWidth = 0; } + frame->fixedRightWidth = q->elementSize(prefix % "right").width(); + + if (q->hasElement(prefix % "hint-right-margin")) { + frame->fixedRightMargin = q->elementSize(prefix % "hint-right-margin").width(); + } else { + frame->fixedRightMargin = frame->fixedRightWidth; + } + if (frame->enabledBorders & FrameSvg::RightBorder) { frame->rightWidth = q->elementSize(prefix % "right").width(); @@ -1011,6 +1079,14 @@ void FrameSvgPrivate::updateSizes() const frame->rightMargin = frame->rightWidth = 0; } + frame->fixedBottomHeight = q->elementSize(prefix % "bottom").height(); + + if (q->hasElement(prefix % "hint-bottom-margin")) { + frame->fixedBottomMargin = q->elementSize(prefix % "hint-bottom-margin").height(); + } else { + frame->fixedBottomMargin = frame->fixedBottomHeight; + } + if (frame->enabledBorders & FrameSvg::BottomBorder) { frame->bottomHeight = q->elementSize(prefix % "bottom").height(); diff --git a/src/plasma/framesvg.h b/src/plasma/framesvg.h index 482956de1..f4b166980 100644 --- a/src/plasma/framesvg.h +++ b/src/plasma/framesvg.h @@ -137,6 +137,8 @@ class PLASMA_EXPORT FrameSvg : public Svg /** * Returns the margin size given the margin edge we want + * If the given margin is disabled, it will return 0. + * If you don't care about the margin being on or off, use fixedMarginSize() * @param edge the margin edge we want, top, bottom, left or right * @return the margin size */ @@ -145,6 +147,8 @@ class PLASMA_EXPORT FrameSvg : public Svg /** * Convenience method that extracts the size of the four margins * in the four output parameters + * The disabled margins will be 0. + * If you don't care about the margins being on or off, use getFixedMargins() * @param left left margin size * @param top top margin size * @param right right margin size @@ -152,6 +156,25 @@ class PLASMA_EXPORT FrameSvg : public Svg */ Q_INVOKABLE void getMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const; + /** + * Returns the margin size given the margin edge we want. + * Compared to marginSize(), this doesn't depend whether the margin is enabled or not + * @param edge the margin edge we want, top, bottom, left or right + * @return the margin size + */ + Q_INVOKABLE qreal fixedMarginSize(const Plasma::Types::MarginEdge edge) const; + + /** + * Convenience method that extracts the size of the four margins + * in the four output parameters + * Compared to getMargins(), this doesn't depend whether the margins are enabled or not + * @param left left margin size + * @param top top margin size + * @param right right margin size + * @param bottom bottom margin size + */ + Q_INVOKABLE void getFixedMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const; + /** * @return the rectangle of the center element, taking the margins into account. */ diff --git a/src/plasma/private/framesvg_p.h b/src/plasma/private/framesvg_p.h index 1bbc7448d..055fcf343 100644 --- a/src/plasma/private/framesvg_p.h +++ b/src/plasma/private/framesvg_p.h @@ -100,6 +100,18 @@ public: int rightMargin; int bottomMargin; + //measures + int fixedTopHeight; + int fixedLeftWidth; + int fixedRightWidth; + int fixedBottomHeight; + + //margins, are equal to the measures by default + int fixedTopMargin; + int fixedLeftMargin; + int fixedRightMargin; + int fixedBottomMargin; + //size of the svg where the size of the "center" //element is contentWidth x contentHeight bool noBorderPadding : 1; diff --git a/src/plasma/private/svg_p.h b/src/plasma/private/svg_p.h index 332efda6f..9614500dc 100644 --- a/src/plasma/private/svg_p.h +++ b/src/plasma/private/svg_p.h @@ -107,6 +107,7 @@ public: QSizeF naturalSize; QChar styleCrc; unsigned int lastModified; + qreal devicePixelRatio; bool multipleImages : 1; bool themed : 1; bool applyColors : 1; diff --git a/src/plasma/svg.cpp b/src/plasma/svg.cpp index 9ec2aa5dc..097413e35 100644 --- a/src/plasma/svg.cpp +++ b/src/plasma/svg.cpp @@ -129,14 +129,15 @@ bool SharedSvgRenderer::load( } #define QLSEP QLatin1Char('_') -#define CACHE_ID_WITH_SIZE(size, id) QString::number(int(size.width())) % QLSEP % QString::number(int(size.height())) % QLSEP % id -#define CACHE_ID_NATURAL_SIZE(id) QLatin1Literal("Natural") % QLSEP % id +#define CACHE_ID_WITH_SIZE(size, id, devicePixelRatio) QString::number(int(size.width())) % QLSEP % QString::number(int(size.height())) % QLSEP % id % QLSEP % QString::number(int(devicePixelRatio)) +#define CACHE_ID_NATURAL_SIZE(id, devicePixelRatio) QLatin1Literal("Natural") % QLSEP % id % QLSEP % QString::number(int(devicePixelRatio)) SvgPrivate::SvgPrivate(Svg *svg) : q(svg), renderer(0), styleCrc(0), lastModified(0), + devicePixelRatio(1.0), multipleImages(false), themed(false), applyColors(false), @@ -155,16 +156,16 @@ SvgPrivate::~SvgPrivate() QString SvgPrivate::cacheId(const QString &elementId) { if (size.isValid() && size != naturalSize) { - return CACHE_ID_WITH_SIZE(size, elementId); + return CACHE_ID_WITH_SIZE(size, elementId, devicePixelRatio); } else { - return CACHE_ID_NATURAL_SIZE(elementId); + return CACHE_ID_NATURAL_SIZE(elementId, devicePixelRatio); } } //This function is meant for the pixmap cache QString SvgPrivate::cachePath(const QString &path, const QSize &size) { - return CACHE_ID_WITH_SIZE(size, path); + return CACHE_ID_WITH_SIZE(size, path, devicePixelRatio); } bool SvgPrivate::setImagePath(const QString &imagePath) @@ -221,7 +222,7 @@ bool SvgPrivate::setImagePath(const QString &imagePath) naturalSize = rect.size(); } else { createRenderer(); - naturalSize = renderer->defaultSize(); + naturalSize = renderer->defaultSize() * devicePixelRatio; //qDebug() << "natural size for" << path << "from renderer is" << naturalSize; cacheAndColorsTheme()->insertIntoRectsCache(path, "_Natural", QRectF(QPointF(0,0), naturalSize)); //qDebug() << "natural size for" << path << "from cache is" << naturalSize; @@ -271,7 +272,7 @@ QPixmap SvgPrivate::findInCache(const QString &elementId, const QSizeF &s) if (elementsWithSizeHints.isEmpty()) { // Fetch all size hinted element ids from the theme's rect cache // and store them locally. - QRegExp sizeHintedKeyExpr(CACHE_ID_NATURAL_SIZE("(\\d+)-(\\d+)-(.+)")); + QRegExp sizeHintedKeyExpr(CACHE_ID_NATURAL_SIZE("(\\d+)-(\\d+)-(.+)", devicePixelRatio)); foreach (const QString &key, cacheAndColorsTheme()->listCachedRectKeys(path)) { if (sizeHintedKeyExpr.exactMatch(key)) { @@ -438,7 +439,7 @@ void SvgPrivate::createRenderer() const QString &elementId = i.key(); const QRectF &elementRect = i.value(); - const QString cacheId = CACHE_ID_NATURAL_SIZE(elementId); + const QString cacheId = CACHE_ID_NATURAL_SIZE(elementId, devicePixelRatio); localRectCache.insert(cacheId, elementRect); cacheAndColorsTheme()->insertIntoRectsCache(path, cacheId, elementRect); } @@ -518,7 +519,7 @@ QRectF SvgPrivate::findAndCacheElementRect(const QString &elementId) qreal dy = size.height() / naturalSize.height(); elementRect = QRectF(elementRect.x() * dx, elementRect.y() * dy, - elementRect.width() * dx, elementRect.height() * dy); + elementRect.width() * dx * devicePixelRatio, elementRect.height() * dy * devicePixelRatio); cacheAndColorsTheme()->insertIntoRectsCache(path, id, elementRect); return elementRect; @@ -659,6 +660,25 @@ Svg::~Svg() delete d; } +void Svg::setDevicePixelRatio(qreal ratio) +{ + //be completely integer for now + //devicepixelratio is always set integer in the svg, so needs at least 192dpi to double up. + //(it needs to be integer to have lines contained inside a svg piece to keep being pixel aligned) + if (floor(d->devicePixelRatio) == floor(ratio)) { + return; + } + + d->devicePixelRatio = floor(ratio); + emit repaintNeeded(); + emit sizeChanged(); +} + +qreal Svg::devicePixelRatio() +{ + return d->devicePixelRatio; +} + QPixmap Svg::pixmap(const QString &elementID) { if (elementID.isNull() || d->multipleImages) { diff --git a/src/plasma/svg.h b/src/plasma/svg.h index 01d98f8f1..4e13009f4 100644 --- a/src/plasma/svg.h +++ b/src/plasma/svg.h @@ -80,6 +80,19 @@ class PLASMA_EXPORT Svg : public QObject explicit Svg(QObject *parent = 0); ~Svg(); + /** + * Set the device pixel ratio for the Svg. This is the ratio between + * image pixels and device-independent pixels. + * The default value is 1.0. + * Setting it to something more, will make all the elements of this svg appear bigger. + */ + void setDevicePixelRatio(qreal ratio); + + /** + * @return the device pixel ratio for this Svg. + */ + qreal devicePixelRatio(); + /** * Returns a pixmap of the SVG represented by this object. *