Merge branch 'davidedmundson/framesvg_native'
Use FrameSVG as 9 tiles instead of uploading a big texture of the finished frame each time. This also saves the cache being populated with full created frames in different sizes; which end up taking up space in the disk and shared memory cache as well as the GPU memory. A code path falls back to the original uploading the entire texture if obscure settings are used, i.e overlay. Benchmarks: apitrace when resizing a frame goes from an average of 7.6ms per frame of CPU time just for the swizzling and uploading to 1.4ms GPU time also drops from 40us to 10us Themes will need to remove stretch-borders (when we gain nothing from stretching; i.e Breeze) to get the most out of it. REVIEW: 119330
This commit is contained in:
commit
ab93d83890
@ -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();
|
||||
|
@ -69,7 +69,7 @@ Page {
|
||||
text: title
|
||||
}
|
||||
}
|
||||
onClicked: pageStack.push(Qt.createComponent(plasmoid.file("ui", page)))
|
||||
onClicked: pageStack.push(Qt.createComponent(page))
|
||||
}
|
||||
}
|
||||
ScrollBar {
|
||||
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2011 by Daker Fernandes Pinheiro <dakerfp@gmail.com>
|
||||
*
|
||||
* 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")
|
||||
}
|
||||
}
|
@ -22,7 +22,13 @@
|
||||
|
||||
#include <QQuickWindow>
|
||||
#include <QSGTexture>
|
||||
#include <QSGGeometry>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QPainter>
|
||||
|
||||
#include <plasma/private/framesvg_p.h>
|
||||
#include <plasma/private/framesvg_helpers.h>
|
||||
|
||||
#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<QSGTextureMaterial*>(material())->setHorizontalWrapMode(QSGTexture::Repeat);
|
||||
static_cast<QSGOpaqueTextureMaterial*>(opaqueMaterial())->setHorizontalWrapMode(QSGTexture::Repeat);
|
||||
}
|
||||
if (m_border == FrameSvg::LeftBorder || m_border == FrameSvg::RightBorder || m_border == FrameSvg::NoBorder) {
|
||||
static_cast<QSGTextureMaterial*>(material())->setVerticalWrapMode(QSGTexture::Repeat);
|
||||
static_cast<QSGOpaqueTextureMaterial*>(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<SVGTextureNode *>(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; i<oldNode->childCount(); ++i) {
|
||||
FrameItemNode* it = static_cast<FrameItemNode*>(oldNode->childAtIndex(i));
|
||||
it->reposition(geometry, frameSize);
|
||||
}
|
||||
|
||||
m_sizeChanged = false;
|
||||
}
|
||||
} else {
|
||||
SVGTextureNode *textureNode = dynamic_cast<SVGTextureNode *>(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()
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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<SVGTextureNode *>(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);
|
||||
}
|
||||
|
@ -24,8 +24,6 @@
|
||||
#include <QDebug>
|
||||
#include <QPropertyAnimation>
|
||||
|
||||
#include "framesvgitem.h"
|
||||
|
||||
#include <kdeclarative/qmlobject.h>
|
||||
|
||||
ToolTipDialog::ToolTipDialog(QQuickItem *parent)
|
||||
|
@ -32,8 +32,9 @@
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <theme.h>
|
||||
#include <private/svg_p.h>
|
||||
#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<QString, FrameData *>::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"
|
||||
|
@ -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;
|
||||
|
100
src/plasma/private/framesvg_helpers.h
Normal file
100
src/plasma/private/framesvg_helpers.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2014 by Aleix Pol Gonzalez <aleixpol@blue-systems.com>
|
||||
*
|
||||
* 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
|
@ -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;
|
||||
|
39
tests/dialog.qml
Normal file
39
tests/dialog.qml
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2014 David Edmundson <davidedmundson@kde.org>
|
||||
*
|
||||
* 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()
|
||||
}
|
||||
}
|
||||
}
|
106
tests/testborders.qml
Normal file
106
tests/testborders.qml
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2014 by Aleix Pol Gonzalez <aleixpol@blue-systems.com>
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user