diff --git a/examples/applets/widgetgallery/contents/ui/Buttons.qml b/examples/applets/widgetgallery/contents/ui/Buttons.qml index 379585fea..9134df9cc 100644 --- a/examples/applets/widgetgallery/contents/ui/Buttons.qml +++ b/examples/applets/widgetgallery/contents/ui/Buttons.qml @@ -64,7 +64,7 @@ PlasmaComponents.Page { onClicked: { console.log("Clicked"); - pageStack.push(Qt.createComponent(plasmoid.file("ui", "Scrollers.qml"))) + pageStack.push(Qt.createComponent("Scrollers.qml")) } Keys.onTabPressed: bt2.forceActiveFocus(); diff --git a/examples/applets/widgetgallery/contents/ui/Menu.qml b/examples/applets/widgetgallery/contents/ui/Menu.qml index 1336c42e3..be97ff8d0 100644 --- a/examples/applets/widgetgallery/contents/ui/Menu.qml +++ b/examples/applets/widgetgallery/contents/ui/Menu.qml @@ -69,7 +69,7 @@ Page { text: title } } - onClicked: pageStack.push(Qt.createComponent(plasmoid.file("ui", page))) + onClicked: pageStack.push(Qt.createComponent(page)) } } ScrollBar { diff --git a/examples/applets/widgetgallery/contents/ui/standalonemain.qml b/examples/applets/widgetgallery/contents/ui/standalonemain.qml new file mode 100644 index 000000000..3db74090d --- /dev/null +++ b/examples/applets/widgetgallery/contents/ui/standalonemain.qml @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2011 by Daker Fernandes Pinheiro + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program 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 General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.0 +import QtQuick.Layouts 1.1 +import org.kde.plasma.core 2.0 +import org.kde.plasma.components 2.0 + +FrameSvgItem { + width: 300 + height: 400 + imagePath: "widgets/background" + + + ToolBar { + id: toolBar + z: 10 + + anchors { + top: parent.top + left: parent.left + right: parent.right + margins: 10 + } + } + + PageStack { + id: pageStack + toolBar: toolBar + clip: true + anchors { + top: toolBar.bottom + left: parent.left + right: parent.right + bottom: parent.bottom + margins: 10 + } + initialPage: Qt.createComponent("Menu.qml") + } +} diff --git a/src/declarativeimports/core/framesvgitem.cpp b/src/declarativeimports/core/framesvgitem.cpp index 832021228..8cd8edb91 100644 --- a/src/declarativeimports/core/framesvgitem.cpp +++ b/src/declarativeimports/core/framesvgitem.cpp @@ -22,7 +22,13 @@ #include #include +#include + #include +#include + +#include +#include #include "svgtexturenode.h" @@ -31,6 +37,109 @@ namespace Plasma { +class FrameItemNode : public SVGTextureNode +{ +public: + enum FitMode { + //render SVG at native resolution then stretch it in openGL + FastStretch, + //on resize re-render the part of the frame from the SVG + Stretch, + Tile + }; + + FrameItemNode(FrameSvgItem* frameSvg, FrameSvg::EnabledBorders borders, FitMode fitMode, QSGNode* parent) + : SVGTextureNode() + , m_frameSvg(frameSvg) + , m_border(borders) + , m_lastParent(parent) + , m_fitMode(fitMode) + { + m_lastParent->appendChildNode(this); + + if (m_fitMode == Tile) { + if (m_border == FrameSvg::TopBorder || m_border == FrameSvg::BottomBorder || m_border == FrameSvg::NoBorder) { + static_cast(material())->setHorizontalWrapMode(QSGTexture::Repeat); + static_cast(opaqueMaterial())->setHorizontalWrapMode(QSGTexture::Repeat); + } + if (m_border == FrameSvg::LeftBorder || m_border == FrameSvg::RightBorder || m_border == FrameSvg::NoBorder) { + static_cast(material())->setVerticalWrapMode(QSGTexture::Repeat); + static_cast(opaqueMaterial())->setVerticalWrapMode(QSGTexture::Repeat); + } + } + + if (m_fitMode == Tile || m_fitMode == FastStretch) { + QString elementId = m_frameSvg->frameSvg()->actualPrefix() + FrameSvgHelpers::borderToElementId(m_border); + m_elementNativeSize = m_frameSvg->frameSvg()->elementSize(elementId); + + updateTexture(m_elementNativeSize, elementId, false); + } + } + + void updateTexture(const QSize &size, const QString &elementId, bool composeOverBorder) + { + QImage image = m_frameSvg->frameSvg()->image(size, elementId); + + QString prefix = m_frameSvg->frameSvg()->actualPrefix(); + + //in compose over border we paint the center over the full size + //then blend in an alpha mask generated from the corners to + //remove the garbage left in the corners + if (m_border == FrameSvg::NoBorder && m_fitMode == Stretch && composeOverBorder) { + QPixmap pixmap = QPixmap::fromImage(image); + QPainter p(&pixmap); + p.setCompositionMode(QPainter::CompositionMode_DestinationIn); + p.drawPixmap(QRect(QPoint(0, 0), size), m_frameSvg->frameSvg()->alphaMask()); + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + image = pixmap.toImage(); + } + QSGTexture *texture = m_frameSvg->window()->createTextureFromImage(image); + setTexture(texture); + } + + void reposition(const QRect& frameGeometry, QSize& fullSize) + { + QRect nodeRect = FrameSvgHelpers::sectionRect(m_border, frameGeometry, fullSize); + + //ensure we're not passing a weird rectangle to updateTexturedRectGeometry + if(!nodeRect.isValid() || nodeRect.isEmpty()) + nodeRect = QRect(); + + QRectF textureRect = QRectF(0,0,1,1); + if (m_fitMode == Tile) { + if (m_border == FrameSvg::TopBorder || m_border == FrameSvg::BottomBorder || m_border == FrameSvg::NoBorder) { + textureRect.setWidth(nodeRect.width() / m_elementNativeSize.width()); + } + if (m_border == FrameSvg::LeftBorder || m_border == FrameSvg::RightBorder || m_border == FrameSvg::NoBorder) { + textureRect.setHeight(nodeRect.height() / m_elementNativeSize.height()); + } + } else if (m_fitMode == Stretch) { + QString prefix = m_frameSvg->frameSvg()->actualPrefix(); + bool composeOverBorder = (m_border == FrameSvg::NoBorder) && (m_frameSvg->frameSvg()->hasElement(prefix % "hint-compose-over-border") && + m_frameSvg->frameSvg()->hasElement("mask-" % prefix % "center")); + + QString elementId = prefix + FrameSvgHelpers::borderToElementId(m_border); + + if (composeOverBorder) { + nodeRect = QRect(QPoint(0,0), fullSize); + } + + //re-render the SVG at new size + updateTexture(nodeRect.size(), elementId, composeOverBorder); + } // for fast stretch, we don't have to do anything + + QSGGeometry::updateTexturedRectGeometry(geometry(), nodeRect, textureRect); + markDirty(QSGNode::DirtyGeometry); + } + +private: + FrameSvgItem* m_frameSvg; + FrameSvg::EnabledBorders m_border; + QSGNode *m_lastParent; + QSize m_elementNativeSize; + FitMode m_fitMode; +}; + FrameSvgItemMargins::FrameSvgItemMargins(Plasma::FrameSvg *frameSvg, QObject *parent) : QObject(parent), m_frameSvg(frameSvg), @@ -98,7 +207,9 @@ bool FrameSvgItemMargins::isFixed() const FrameSvgItem::FrameSvgItem(QQuickItem *parent) : QQuickItem(parent), - m_textureChanged(false) + m_textureChanged(false), + m_sizeChanged(false), + m_fastPath(true) { m_frameSvg = new Plasma::FrameSvg(this); m_margins = new FrameSvgItemMargins(m_frameSvg, this); @@ -215,7 +326,7 @@ void FrameSvgItem::geometryChanged(const QRectF &newGeometry, { if (isComponentComplete()) { m_frameSvg->resizeFrame(newGeometry.size()); - m_textureChanged = true; + m_sizeChanged = true; } QQuickItem::geometryChanged(newGeometry, oldGeometry); } @@ -230,6 +341,9 @@ void FrameSvgItem::doUpdate() setImplicitHeight(m_frameSvg->marginSize(Plasma::Types::TopMargin) + m_frameSvg->marginSize(Plasma::Types::BottomMargin)); } + QString prefix = m_frameSvg->actualPrefix(); + bool hasOverlay = !prefix.startsWith(QStringLiteral("mask-")) && m_frameSvg->hasElement(prefix % "overlay"); + m_fastPath = !hasOverlay; m_textureChanged = true; update(); } @@ -278,23 +392,68 @@ QSGNode *FrameSvgItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaint return Q_NULLPTR; } - SVGTextureNode *textureNode = static_cast(oldNode); - if (!textureNode) { - textureNode = new SVGTextureNode; - textureNode->setFiltering(QSGTexture::Nearest); - m_textureChanged = true; //force updating the texture on our newly created node + if (m_fastPath) { + if (m_textureChanged) { + delete oldNode; + oldNode = 0; + } + + if (!oldNode) { + oldNode = new QSGNode; + + QString prefix = m_frameSvg->actualPrefix(); + bool tileCenter = (m_frameSvg->hasElement("hint-tile-center") || m_frameSvg->hasElement(prefix % "hint-tile-center")); + bool stretchBorders = (m_frameSvg->hasElement("hint-stretch-borders") || m_frameSvg->hasElement(prefix % "hint-stretch-borders")); + FrameItemNode::FitMode borderFitMode = stretchBorders ? FrameItemNode::Stretch : FrameItemNode::Tile; + FrameItemNode::FitMode centerFitMode = tileCenter ? FrameItemNode::Tile: FrameItemNode::Stretch; + + new FrameItemNode(this, FrameSvg::NoBorder, centerFitMode, oldNode); //needs to be de first, in case of composeOverBorder + new FrameItemNode(this, FrameSvg::TopBorder | FrameSvg::LeftBorder, FrameItemNode::FastStretch, oldNode); + new FrameItemNode(this, FrameSvg::TopBorder | FrameSvg::RightBorder, FrameItemNode::FastStretch, oldNode); + new FrameItemNode(this, FrameSvg::TopBorder, borderFitMode, oldNode); + new FrameItemNode(this, FrameSvg::BottomBorder, borderFitMode, oldNode); + new FrameItemNode(this, FrameSvg::BottomBorder | FrameSvg::LeftBorder, FrameItemNode::FastStretch, oldNode); + new FrameItemNode(this, FrameSvg::BottomBorder | FrameSvg::RightBorder, FrameItemNode::FastStretch, oldNode); + new FrameItemNode(this, FrameSvg::LeftBorder, borderFitMode, oldNode); + new FrameItemNode(this, FrameSvg::RightBorder, borderFitMode, oldNode); + + m_sizeChanged = true; + m_textureChanged = false; + } + + if (m_sizeChanged) { + QSize frameSize(width(), height()); + QRect geometry = m_frameSvg->contentsRect().toRect(); + for(int i = 0; ichildCount(); ++i) { + FrameItemNode* it = static_cast(oldNode->childAtIndex(i)); + it->reposition(geometry, frameSize); + } + + m_sizeChanged = false; + } + } else { + SVGTextureNode *textureNode = dynamic_cast(oldNode); + if (!textureNode) { + delete oldNode; + textureNode = new SVGTextureNode; + textureNode->setFiltering(QSGTexture::Nearest); + m_textureChanged = true; //force updating the texture on our newly created node + oldNode = textureNode; + } + + if ((m_textureChanged || m_sizeChanged) || textureNode->texture()->textureSize() != m_frameSvg->size()) { + QImage image = m_frameSvg->framePixmap().toImage(); + QSGTexture *texture = window()->createTextureFromImage(image); + texture->setFiltering(QSGTexture::Nearest); + textureNode->setTexture(texture); + textureNode->setRect(0, 0, width(), height()); + + m_textureChanged = false; + m_sizeChanged = false; + } } - if (m_textureChanged || textureNode->texture()->textureSize() != m_frameSvg->size()) { - const QImage image = m_frameSvg->framePixmap().toImage(); - QSGTexture *texture = window()->createTextureFromImage(image); - texture->setFiltering(QSGTexture::Nearest); - textureNode->setTexture(texture); - m_textureChanged = false; - textureNode->setRect(0, 0, width(), height()); - } - - return textureNode; + return oldNode; } void FrameSvgItem::componentComplete() diff --git a/src/declarativeimports/core/framesvgitem.h b/src/declarativeimports/core/framesvgitem.h index e155f6a33..0b39c7052 100644 --- a/src/declarativeimports/core/framesvgitem.h +++ b/src/declarativeimports/core/framesvgitem.h @@ -31,6 +31,7 @@ namespace Plasma { class FrameSvg; +class SVGTextureNode; class FrameSvgItemMargins : public QObject { @@ -188,6 +189,8 @@ private: QString m_prefix; Units m_units; bool m_textureChanged; + bool m_sizeChanged; + bool m_fastPath; }; } diff --git a/src/declarativeimports/core/svgitem.cpp b/src/declarativeimports/core/svgitem.cpp index 1ed0631af..eccff55a4 100644 --- a/src/declarativeimports/core/svgitem.cpp +++ b/src/declarativeimports/core/svgitem.cpp @@ -137,6 +137,12 @@ QSGNode *SvgItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updateP return Q_NULLPTR; } + //this is more than just an optimisation, uploading a null image to QSGAtlasTexture causes a crash + if (width() == 0 || height() == 0) { + delete oldNode; + return Q_NULLPTR; + } + SVGTextureNode *textureNode = static_cast(oldNode); if (!textureNode) { textureNode = new SVGTextureNode; @@ -152,7 +158,8 @@ QSGNode *SvgItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updateP //setContainsMultipleImages has to be done there since m_frameSvg can be shared with somebody else m_svg.data()->setContainsMultipleImages(!m_elementID.isEmpty()); const QImage image = m_svg.data()->image(QSize(width(), height()), m_elementID); - QSGTexture *texture = window()->createTextureFromImage(image); + + QSGTexture *texture = window()->createTextureFromImage(image, QQuickWindow::TextureCanUseAtlas); if (m_smooth) { texture->setFiltering(QSGTexture::Linear); } diff --git a/src/declarativeimports/core/tooltipdialog.cpp b/src/declarativeimports/core/tooltipdialog.cpp index e62ed6e7f..872f9692f 100644 --- a/src/declarativeimports/core/tooltipdialog.cpp +++ b/src/declarativeimports/core/tooltipdialog.cpp @@ -24,8 +24,6 @@ #include #include -#include "framesvgitem.h" - #include ToolTipDialog::ToolTipDialog(QQuickItem *parent) diff --git a/src/plasma/framesvg.cpp b/src/plasma/framesvg.cpp index fcc680923..3e1b9373d 100644 --- a/src/plasma/framesvg.cpp +++ b/src/plasma/framesvg.cpp @@ -32,8 +32,9 @@ #include -#include -#include +#include "theme.h" +#include "private/svg_p.h" +#include "private/framesvg_helpers.h" namespace Plasma { @@ -474,14 +475,9 @@ void FrameSvg::getFixedMargins(qreal &left, qreal &top, qreal &right, qreal &bot QRectF FrameSvg::contentsRect() const { - QSizeF size(frameSize()); - - if (size.isValid()) { - QRectF rect(QPointF(0, 0), size); - FrameData *frame = d->frames[d->prefix]; - - return rect.adjusted(frame->leftMargin, frame->topMargin, - -frame->rightMargin, -frame->bottomMargin); + QHash::const_iterator it = d->frames.constFind(d->prefix); + if (it != d->frames.constEnd()) { + return d->contentGeometry(*it, (*it)->frameSize); } else { return QRectF(); } @@ -814,21 +810,21 @@ void FrameSvgPrivate::generateFrameBackground(FrameData *frame) p.setRenderHint(QPainter::SmoothPixmapTransform); QRect contentRect = contentGeometry(frame, size); - paintCenter(p, frame, contentRect.size(), size); + paintCenter(p, frame, contentRect, size); - paintCorner(p, frame, FrameSvg::LeftBorder|FrameSvg::TopBorder, QRect(QPoint(0, 0), QSize(frame->leftWidth, frame->topHeight))); - paintCorner(p, frame, FrameSvg::RightBorder|FrameSvg::TopBorder, QRect(QPoint(contentRect.right(), 0), QSize(frame->rightWidth, frame->topHeight))); - paintCorner(p, frame, FrameSvg::LeftBorder|FrameSvg::BottomBorder, QRect(QPoint(0, contentRect.bottom()), QSize(frame->leftWidth, frame->bottomHeight))); - paintCorner(p, frame, FrameSvg::RightBorder|FrameSvg::BottomBorder, QRect(contentRect.bottomRight(), QSize(frame->rightWidth, frame->bottomHeight))); + paintCorner(p, frame, FrameSvg::LeftBorder|FrameSvg::TopBorder, contentRect); + paintCorner(p, frame, FrameSvg::RightBorder|FrameSvg::TopBorder, contentRect); + paintCorner(p, frame, FrameSvg::LeftBorder|FrameSvg::BottomBorder, contentRect); + paintCorner(p, frame, FrameSvg::RightBorder|FrameSvg::BottomBorder, contentRect); // Sides const int leftHeight = q->elementSize(prefix % "left").height(); - paintBorder(p, frame, FrameSvg::LeftBorder, QSize(frame->leftWidth, leftHeight), QRect(QPoint(0, contentRect.top()), QSize(frame->leftWidth, contentRect.height()))); - paintBorder(p, frame, FrameSvg::RightBorder, QSize(frame->rightWidth, leftHeight), QRect(contentRect.topRight(), QSize(frame->rightWidth, contentRect.height()))); + paintBorder(p, frame, FrameSvg::LeftBorder, QSize(frame->leftWidth, leftHeight), contentRect); + paintBorder(p, frame, FrameSvg::RightBorder, QSize(frame->rightWidth, leftHeight), contentRect); const int topWidth = q->elementSize(prefix % "top").width(); - paintBorder(p, frame, FrameSvg::TopBorder, QSize(topWidth, frame->topHeight), QRect(QPoint(contentRect.left(), 0), QSize(contentRect.width(), frame->topHeight))); - paintBorder(p, frame, FrameSvg::BottomBorder, QSize(topWidth, frame->bottomHeight), QRect(contentRect.bottomLeft(), QSize(contentRect.width(), frame->bottomHeight))); + paintBorder(p, frame, FrameSvg::TopBorder, QSize(topWidth, frame->topHeight), contentRect); + paintBorder(p, frame, FrameSvg::BottomBorder, QSize(topWidth, frame->bottomHeight), contentRect); } QRect FrameSvgPrivate::contentGeometry(FrameData* frame, const QSize& size) const @@ -846,9 +842,9 @@ QRect FrameSvgPrivate::contentGeometry(FrameData* frame, const QSize& size) cons return contentRect; } -void FrameSvgPrivate::paintCenter(QPainter& p, FrameData* frame, const QSize& contentSize, const QSize& fullSize) +void FrameSvgPrivate::paintCenter(QPainter& p, FrameData* frame, const QRect& contentRect, const QSize& fullSize) { - if (!contentSize.isEmpty()) { + if (!contentRect.isEmpty()) { const QString centerElementId = prefix % "center"; if (frame->tileCenter) { QSize centerTileSize = q->elementSize(centerElementId); @@ -862,15 +858,14 @@ void FrameSvgPrivate::paintCenter(QPainter& p, FrameData* frame, const QSize& co if (frame->composeOverBorder) { p.drawTiledPixmap(QRect(QPoint(0, 0), fullSize), center); } else { - p.drawTiledPixmap(QRect(QPoint(frame->leftWidth, frame->topHeight), contentSize), center); + p.drawTiledPixmap(FrameSvgHelpers::sectionRect(FrameSvg::NoBorder, contentRect, fullSize), center); } } else { if (frame->composeOverBorder) { q->paint(&p, QRect(QPoint(0, 0), fullSize), centerElementId); } else { - q->paint(&p, QRect(QPoint(frame->leftWidth, frame->topHeight), contentSize), - centerElementId); + q->paint(&p, FrameSvgHelpers::sectionRect(FrameSvg::NoBorder, contentRect, fullSize), centerElementId); } } } @@ -882,12 +877,12 @@ void FrameSvgPrivate::paintCenter(QPainter& p, FrameData* frame, const QSize& co } } -void FrameSvgPrivate::paintBorder(QPainter& p, FrameData* frame, const FrameSvg::EnabledBorders borders, const QSize& size, const QRect& output) const +void FrameSvgPrivate::paintBorder(QPainter& p, FrameData* frame, const FrameSvg::EnabledBorders borders, const QSize& size, const QRect& contentRect) const { - QString side = prefix % borderToElementId(borders); + QString side = prefix % FrameSvgHelpers::borderToElementId(borders); if (frame->enabledBorders & borders && q->hasElement(side) && !size.isEmpty()) { if (frame->stretchBorders) { - q->paint(&p, output, side); + q->paint(&p, FrameSvgHelpers::sectionRect(borders, contentRect, frame->frameSize), side); } else { QPixmap px(size); px.fill(Qt::transparent); @@ -896,46 +891,19 @@ void FrameSvgPrivate::paintBorder(QPainter& p, FrameData* frame, const FrameSvg: sidePainter.setCompositionMode(QPainter::CompositionMode_Source); q->paint(&sidePainter, QRect(QPoint(0, 0), size), side); - p.drawTiledPixmap(output, px); + p.drawTiledPixmap(FrameSvgHelpers::sectionRect(borders, contentRect, frame->frameSize), px); } } } -void FrameSvgPrivate::paintCorner(QPainter& p, FrameData* frame, Plasma::FrameSvg::EnabledBorders border, const QRect& output) const +void FrameSvgPrivate::paintCorner(QPainter& p, FrameData* frame, Plasma::FrameSvg::EnabledBorders border, const QRect& contentRect) const { - QString corner = prefix % borderToElementId(border); + QString corner = prefix % FrameSvgHelpers::borderToElementId(border); if (frame->enabledBorders & border && q->hasElement(corner)) { - q->paint(&p, output, corner); + q->paint(&p, FrameSvgHelpers::sectionRect(border, contentRect, frame->frameSize), corner); } } -QString FrameSvgPrivate::borderToElementId(FrameSvg::EnabledBorders borders) -{ - switch(borders) { - case FrameSvg::NoBorder: - return QString(); - case FrameSvg::TopBorder: - return QStringLiteral("top"); - case FrameSvg::BottomBorder: - return QStringLiteral("bottom"); - case FrameSvg::LeftBorder: - return QStringLiteral("left"); - case FrameSvg::RightBorder: - return QStringLiteral("right"); - case FrameSvg::TopBorder | FrameSvg::LeftBorder: - return QStringLiteral("topleft"); - case FrameSvg::TopBorder | FrameSvg::RightBorder: - return QStringLiteral("topright"); - case FrameSvg::BottomBorder | FrameSvg::LeftBorder: - return QStringLiteral("bottomleft"); - case FrameSvg::BottomBorder | FrameSvg::RightBorder: - return QStringLiteral("bottomright"); - default: - qWarning() << "unrecognized border" << borders; - } - return QString(); -} - QString FrameSvgPrivate::cacheId(FrameData *frame, const QString &prefixToSave) const { const QSize size = frameSize(frame).toSize(); @@ -1127,6 +1095,11 @@ int FrameData::refcount() const return references.count(); } +QString FrameSvg::actualPrefix() const +{ + return d->prefix; +} + } // Plasma namespace #include "moc_framesvg.cpp" diff --git a/src/plasma/framesvg.h b/src/plasma/framesvg.h index dd6d8da07..9aaf5440c 100644 --- a/src/plasma/framesvg.h +++ b/src/plasma/framesvg.h @@ -287,6 +287,11 @@ public: */ Q_INVOKABLE void paintFrame(QPainter *painter, const QPointF &pos = QPointF(0, 0)); + /** + * @returns the prefix that is actually used + */ + QString actualPrefix() const; + private: FrameSvgPrivate *const d; friend class FrameData; diff --git a/src/plasma/private/framesvg_helpers.h b/src/plasma/private/framesvg_helpers.h new file mode 100644 index 000000000..5b96cd589 --- /dev/null +++ b/src/plasma/private/framesvg_helpers.h @@ -0,0 +1,100 @@ +/* + * Copyright 2014 by Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program 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 General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef FRAMESVG_HELPERS_H +#define FRAMESVG_HELPERS_H + +#include "framesvg.h" + +namespace Plasma +{ + +namespace FrameSvgHelpers +{ + +/** + * @returns the element id name for said @p borders + */ +QString borderToElementId(FrameSvg::EnabledBorders borders) +{ + switch(borders) { + case FrameSvg::NoBorder: + return QStringLiteral("center"); + case FrameSvg::TopBorder: + return QStringLiteral("top"); + case FrameSvg::BottomBorder: + return QStringLiteral("bottom"); + case FrameSvg::LeftBorder: + return QStringLiteral("left"); + case FrameSvg::RightBorder: + return QStringLiteral("right"); + case FrameSvg::TopBorder | FrameSvg::LeftBorder: + return QStringLiteral("topleft"); + case FrameSvg::TopBorder | FrameSvg::RightBorder: + return QStringLiteral("topright"); + case FrameSvg::BottomBorder | FrameSvg::LeftBorder: + return QStringLiteral("bottomleft"); + case FrameSvg::BottomBorder | FrameSvg::RightBorder: + return QStringLiteral("bottomright"); + default: + qWarning() << "unrecognized border" << borders; + } + return QString(); +} + +/** + * @returns the suggested geometry for the @p borders given a @p fullSize frame size and a @p contentRect + */ +QRect sectionRect(Plasma::FrameSvg::EnabledBorders borders, const QRect& contentRect, const QSize& fullSize) +{ + //don't use QRect corner methods here, they have semantics that might come as unexpected. + //prefer constructing the points explicitly. e.g. from QRect::topRight docs: + //Note that for historical reasons this function returns QPoint(left() + width() -1, top()). + + switch(borders) { + case FrameSvg::NoBorder: + return contentRect; + case FrameSvg::TopBorder: + return QRect(QPoint(contentRect.left(), 0), QSize(contentRect.width(), contentRect.top())); + case FrameSvg::BottomBorder: + return QRect(QPoint(contentRect.left(), contentRect.bottom()+1), QSize(contentRect.width(), fullSize.height()-contentRect.bottom()-1)); + case FrameSvg::LeftBorder: + return QRect(QPoint(0, contentRect.top()), QSize(contentRect.left(), contentRect.height())); + case FrameSvg::RightBorder: + return QRect(QPoint(contentRect.right()+1, contentRect.top()), QSize(fullSize.width()-contentRect.right()-1, contentRect.height())); + case FrameSvg::TopBorder | FrameSvg::LeftBorder: + return QRect(QPoint(0, 0), QSize(contentRect.left(), contentRect.top())); + case FrameSvg::TopBorder | FrameSvg::RightBorder: + return QRect(QPoint(contentRect.right()+1, 0), QSize(fullSize.width()-contentRect.right()-1, contentRect.top())); + case FrameSvg::BottomBorder | FrameSvg::LeftBorder: + return QRect(QPoint(0, contentRect.bottom()+1), QSize(contentRect.left(), fullSize.height()-contentRect.bottom()-1)); + case FrameSvg::BottomBorder | FrameSvg::RightBorder: + return QRect(QPoint(contentRect.right()+1, contentRect.bottom()+1), QSize(fullSize.width()-contentRect.right()-1, fullSize.height()-contentRect.bottom()-1)); + default: + qWarning() << "unrecognized border" << borders; + return QRect(); + } + return QRect(); +} + +} + +} + +#endif diff --git a/src/plasma/private/framesvg_p.h b/src/plasma/private/framesvg_p.h index 8aceef234..560e1b21c 100644 --- a/src/plasma/private/framesvg_p.h +++ b/src/plasma/private/framesvg_p.h @@ -150,8 +150,7 @@ public: QSizeF frameSize(FrameData *frame) const; void paintBorder(QPainter& p, FrameData* frame, Plasma::FrameSvg::EnabledBorders border, const QSize& originalSize, const QRect& output) const; void paintCorner(QPainter& p, FrameData* frame, Plasma::FrameSvg::EnabledBorders border, const QRect& output) const; - void paintCenter(QPainter& p, FrameData* frame, const QSize& contentSize, const QSize& fullSize); - static QString borderToElementId(Plasma::FrameSvg::EnabledBorders borders); + void paintCenter(QPainter& p, FrameData* frame, const QRect& contentRect, const QSize& fullSize); QRect contentGeometry(FrameData* frame, const QSize& size) const; Types::Location location; diff --git a/tests/dialog.qml b/tests/dialog.qml new file mode 100644 index 000000000..e857d8c39 --- /dev/null +++ b/tests/dialog.qml @@ -0,0 +1,39 @@ +/* + * Copyright 2014 David Edmundson + * + * 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, + * or (at your option) any later version. + * + * This program 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 General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.0 + +import QtQuick.Controls 1.1 as Controls +import QtQuick.Layouts 1.1 + +import org.kde.plasma.core 2.0 as PlasmaCore + +PlasmaCore.Dialog { + visible: true + + mainItem: Item { + width: 200 + height: 200 + + MouseArea { + anchors.fill: parent + onClicked: Qt.quit() + } + } +} diff --git a/tests/testborders.qml b/tests/testborders.qml new file mode 100644 index 000000000..32605a47a --- /dev/null +++ b/tests/testborders.qml @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2014 by Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2, or + * (at your option) any later version. + * + * This program 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 program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. + */ + + +import QtQuick 2.0 +import QtQuick.Layouts 1.1 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +Item +{ + width: 500 + height: 500 + + PlasmaCore.FrameSvgItem { + id: theItem + + imagePath: "widgets/background" + anchors { + fill: parent + margins: 10 + } + + PlasmaComponents.Button { + text: "left" + checkable: true + checked: true + anchors { + horizontalCenterOffset: -50 + centerIn: parent + } + onClicked: { + if (checked) + theItem.enabledBorders |= PlasmaCore.FrameSvg.LeftBorder; + else + theItem.enabledBorders &=~PlasmaCore.FrameSvg.LeftBorder; + } + } + PlasmaComponents.Button { + text: "right" + checkable: true + checked: true + + anchors { + horizontalCenterOffset: 50 + centerIn: parent + } + onClicked: { + if (checked) + theItem.enabledBorders |= PlasmaCore.FrameSvg.RightBorder; + else + theItem.enabledBorders &=~PlasmaCore.FrameSvg.RightBorder; + } + } + PlasmaComponents.Button { + text: "top" + checkable: true + checked: true + + anchors { + verticalCenterOffset: -50 + centerIn: parent + } + onClicked: { + if (checked) + theItem.enabledBorders |= PlasmaCore.FrameSvg.TopBorder; + else + theItem.enabledBorders &=~PlasmaCore.FrameSvg.TopBorder; + } + } + PlasmaComponents.Button { + text: "bottom" + checkable: true + checked: true + + anchors { + verticalCenterOffset: 50 + centerIn: parent + } + onClicked: { + if (checked) + theItem.enabledBorders |= PlasmaCore.FrameSvg.BottomBorder; + else + theItem.enabledBorders &=~PlasmaCore.FrameSvg.BottomBorder; + } + } + } +} +