file mode +x
parent
d3cec8bd26
commit
146f9e3a14
@ -0,0 +1,404 @@
|
||||
/*
|
||||
* Copyright 2012 Marco Martin <mart@kde.org>
|
||||
* Copyright 2014 David Edmundson <davidedmudnson@kde.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include "iconitem.h"
|
||||
#include "../liblattedock/extras.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QPainter>
|
||||
#include <QPaintEngine>
|
||||
#include <QQuickWindow>
|
||||
#include <QPixmap>
|
||||
#include <QSGSimpleTextureNode>
|
||||
#include <QuickAddons/ManagedTextureNode>
|
||||
|
||||
#include <KIconTheme>
|
||||
#include <KIconThemes/KIconLoader>
|
||||
#include <KIconThemes/KIconEffect>
|
||||
|
||||
namespace Latte {
|
||||
|
||||
IconItem::IconItem(QQuickItem *parent)
|
||||
: QQuickItem(parent),
|
||||
m_smooth(false),
|
||||
m_active(false),
|
||||
m_textureChanged(false),
|
||||
m_sizeChanged(false)
|
||||
{
|
||||
setFlag(ItemHasContents, true);
|
||||
|
||||
connect(KIconLoader::global(), SIGNAL(iconLoaderSettingsChanged()),
|
||||
this, SIGNAL(implicitWidthChanged()));
|
||||
|
||||
connect(KIconLoader::global(), SIGNAL(iconLoaderSettingsChanged()),
|
||||
this, SIGNAL(implicitHeightChanged()));
|
||||
|
||||
connect(this, &QQuickItem::enabledChanged,
|
||||
this, &IconItem::enabledChanged);
|
||||
|
||||
connect(this, &QQuickItem::windowChanged,
|
||||
this, &IconItem::schedulePixmapUpdate);
|
||||
|
||||
connect(this, SIGNAL(overlaysChanged()),
|
||||
this, SLOT(schedulePixmapUpdate()));
|
||||
|
||||
//initialize implicit size to the Dialog size
|
||||
setImplicitWidth(KIconLoader::global()->currentSize(KIconLoader::Dialog));
|
||||
setImplicitHeight(KIconLoader::global()->currentSize(KIconLoader::Dialog));
|
||||
}
|
||||
|
||||
IconItem::~IconItem()
|
||||
{
|
||||
}
|
||||
|
||||
void IconItem::setSource(const QVariant &source)
|
||||
{
|
||||
if (source == m_source) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_source = source;
|
||||
QString sourceString = source.toString();
|
||||
|
||||
// If the QIcon was created with QIcon::fromTheme(), try to load it as svg
|
||||
if (source.canConvert<QIcon>() && !source.value<QIcon>().name().isEmpty()) {
|
||||
sourceString = source.value<QIcon>().name();
|
||||
}
|
||||
|
||||
if (!sourceString.isEmpty()) {
|
||||
//If a url in the form file:// is passed, take the image pointed by that from disk
|
||||
QUrl url(sourceString);
|
||||
|
||||
if (url.isLocalFile()) {
|
||||
m_icon = QIcon();
|
||||
m_imageIcon = QImage(url.path());
|
||||
m_svgIconName.clear();
|
||||
m_svgIcon.reset();
|
||||
} else {
|
||||
if (!m_svgIcon) {
|
||||
m_svgIcon = std::make_unique<Plasma::Svg>(this);
|
||||
m_svgIcon->setColorGroup(Plasma::Theme::NormalColorGroup);
|
||||
m_svgIcon->setStatus(Plasma::Svg::Normal);
|
||||
m_svgIcon->setDevicePixelRatio((window() ? window()->devicePixelRatio() : qApp->devicePixelRatio()));
|
||||
connect(m_svgIcon.get(), &Plasma::Svg::repaintNeeded, this, &IconItem::schedulePixmapUpdate);
|
||||
}
|
||||
|
||||
//success?
|
||||
if (m_svgIcon->isValid() && m_svgIcon->hasElement(sourceString)) {
|
||||
m_icon = QIcon();
|
||||
m_svgIconName = sourceString;
|
||||
|
||||
//ok, svg not available from the plasma theme
|
||||
} else {
|
||||
//try to load from iconloader an svg with Plasma::Svg
|
||||
const auto *iconTheme = KIconLoader::global()->theme();
|
||||
QString iconPath;
|
||||
|
||||
if (iconTheme) {
|
||||
iconPath = iconTheme->iconPath(sourceString + QLatin1String(".svg")
|
||||
, static_cast<int>(qMin(width(), height()))
|
||||
, KIconLoader::MatchBest);
|
||||
|
||||
if (iconPath.isEmpty()) {
|
||||
iconPath = iconTheme->iconPath(sourceString + QLatin1String(".svgz")
|
||||
, static_cast<int>(qMin(width(), height()))
|
||||
, KIconLoader::MatchBest);
|
||||
}
|
||||
} else {
|
||||
qWarning() << "KIconLoader has no theme set";
|
||||
}
|
||||
|
||||
if (!iconPath.isEmpty()) {
|
||||
m_svgIcon->setImagePath(iconPath);
|
||||
m_svgIconName = sourceString;
|
||||
//fail, use QIcon
|
||||
} else {
|
||||
//if we started with a QIcon use that.
|
||||
m_icon = source.value<QIcon>();
|
||||
|
||||
if (m_icon.isNull()) {
|
||||
m_icon = QIcon::fromTheme(sourceString);
|
||||
}
|
||||
|
||||
m_svgIconName.clear();
|
||||
m_svgIcon.reset();
|
||||
m_imageIcon = QImage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if (source.canConvert<QIcon>()) {
|
||||
m_icon = source.value<QIcon>();
|
||||
m_imageIcon = QImage();
|
||||
m_svgIconName.clear();
|
||||
m_svgIcon.reset();
|
||||
} else if (source.canConvert<QImage>()) {
|
||||
m_icon = QIcon();
|
||||
m_imageIcon = source.value<QImage>();
|
||||
m_svgIconName.clear();
|
||||
m_svgIcon.reset();
|
||||
} else {
|
||||
m_icon = QIcon();
|
||||
m_imageIcon = QImage();
|
||||
m_svgIconName.clear();
|
||||
m_svgIcon.reset();
|
||||
}
|
||||
|
||||
if (width() > 0 && height() > 0) {
|
||||
schedulePixmapUpdate();
|
||||
}
|
||||
|
||||
emit sourceChanged();
|
||||
emit validChanged();
|
||||
}
|
||||
|
||||
QVariant IconItem::source() const
|
||||
{
|
||||
return m_source;
|
||||
}
|
||||
|
||||
void IconItem::setOverlays(const QStringList &overlays)
|
||||
{
|
||||
if (overlays == m_overlays) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_overlays = overlays;
|
||||
emit overlaysChanged();
|
||||
}
|
||||
|
||||
QStringList IconItem::overlays() const
|
||||
{
|
||||
return m_overlays;
|
||||
}
|
||||
|
||||
|
||||
bool IconItem::isActive() const
|
||||
{
|
||||
return m_active;
|
||||
}
|
||||
|
||||
void IconItem::setActive(bool active)
|
||||
{
|
||||
if (m_active == active) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_active = active;
|
||||
|
||||
if (isComponentComplete()) {
|
||||
schedulePixmapUpdate();
|
||||
}
|
||||
|
||||
emit activeChanged();
|
||||
}
|
||||
|
||||
void IconItem::setSmooth(const bool smooth)
|
||||
{
|
||||
if (smooth == m_smooth) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_smooth = smooth;
|
||||
update();
|
||||
}
|
||||
|
||||
bool IconItem::smooth() const
|
||||
{
|
||||
return m_smooth;
|
||||
}
|
||||
|
||||
bool IconItem::isValid() const
|
||||
{
|
||||
return !m_icon.isNull() || m_svgIcon || !m_imageIcon.isNull();
|
||||
}
|
||||
|
||||
int IconItem::paintedWidth() const
|
||||
{
|
||||
return boundingRect().size().toSize().width();
|
||||
}
|
||||
|
||||
int IconItem::paintedHeight() const
|
||||
{
|
||||
return boundingRect().size().toSize().height();
|
||||
}
|
||||
|
||||
void IconItem::updatePolish()
|
||||
{
|
||||
QQuickItem::updatePolish();
|
||||
loadPixmap();
|
||||
}
|
||||
|
||||
QSGNode *IconItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData)
|
||||
{
|
||||
Q_UNUSED(updatePaintNodeData)
|
||||
|
||||
if (m_iconPixmap.isNull() || width() < 1.0 || height() < 1.0) {
|
||||
delete oldNode;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ManagedTextureNode *textureNode = dynamic_cast<ManagedTextureNode *>(oldNode);
|
||||
|
||||
if (!textureNode || m_textureChanged) {
|
||||
if (oldNode)
|
||||
delete oldNode;
|
||||
|
||||
textureNode = new ManagedTextureNode;
|
||||
textureNode->setTexture(QSharedPointer<QSGTexture>(window()->createTextureFromImage(m_iconPixmap.toImage())));
|
||||
m_sizeChanged = true;
|
||||
m_textureChanged = false;
|
||||
}
|
||||
|
||||
if (m_sizeChanged) {
|
||||
const auto iconSize = qMin(boundingRect().size().width(), boundingRect().size().height());
|
||||
const QRectF destRect(QPointF(boundingRect().center() - QPointF(iconSize / 2, iconSize / 2)), QSizeF(iconSize, iconSize));
|
||||
|
||||
textureNode->setRect(destRect);
|
||||
m_sizeChanged = false;
|
||||
}
|
||||
|
||||
return textureNode;
|
||||
}
|
||||
|
||||
void IconItem::schedulePixmapUpdate()
|
||||
{
|
||||
polish();
|
||||
}
|
||||
|
||||
void IconItem::enabledChanged()
|
||||
{
|
||||
schedulePixmapUpdate();
|
||||
}
|
||||
|
||||
void IconItem::loadPixmap()
|
||||
{
|
||||
if (!isComponentComplete()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto size = static_cast<int>(qMin(width(), height()));
|
||||
|
||||
//final pixmap to paint
|
||||
QPixmap result;
|
||||
|
||||
if (size <= 0) {
|
||||
m_iconPixmap = QPixmap();
|
||||
update();
|
||||
return;
|
||||
} else if (m_svgIcon) {
|
||||
m_svgIcon->resize(size, size);
|
||||
|
||||
if (m_svgIcon->hasElement(m_svgIconName)) {
|
||||
result = m_svgIcon->pixmap(m_svgIconName);
|
||||
} else if (!m_svgIconName.isEmpty()) {
|
||||
const auto *iconTheme = KIconLoader::global()->theme();
|
||||
QString iconPath;
|
||||
|
||||
if (iconTheme) {
|
||||
iconPath = iconTheme->iconPath(m_svgIconName + QLatin1String(".svg")
|
||||
, static_cast<int>(qMin(width(), height()))
|
||||
, KIconLoader::MatchBest);
|
||||
|
||||
if (iconPath.isEmpty()) {
|
||||
iconPath = iconTheme->iconPath(m_svgIconName + QLatin1String(".svgz"),
|
||||
static_cast<int>(qMin(width(), height()))
|
||||
, KIconLoader::MatchBest);
|
||||
}
|
||||
} else {
|
||||
qWarning() << "KIconLoader has no theme set";
|
||||
}
|
||||
|
||||
if (!iconPath.isEmpty()) {
|
||||
m_svgIcon->setImagePath(iconPath);
|
||||
}
|
||||
|
||||
result = m_svgIcon->pixmap();
|
||||
}
|
||||
} else if (!m_icon.isNull()) {
|
||||
result = m_icon.pixmap(QSize(size, size) * (window() ? window()->devicePixelRatio() : qApp->devicePixelRatio()));
|
||||
} else if (!m_imageIcon.isNull()) {
|
||||
result = QPixmap::fromImage(m_imageIcon);
|
||||
} else {
|
||||
m_iconPixmap = QPixmap();
|
||||
update();
|
||||
return;
|
||||
}
|
||||
|
||||
// Strangely KFileItem::overlays() returns empty string-values, so
|
||||
// we need to check first whether an overlay must be drawn at all.
|
||||
// It is more efficient to do it here, as KIconLoader::drawOverlays()
|
||||
// assumes that an overlay will be drawn and has some additional
|
||||
// setup time.
|
||||
foreach (const QString &overlay, m_overlays) {
|
||||
if (!overlay.isEmpty()) {
|
||||
// There is at least one overlay, draw all overlays above m_pixmap
|
||||
// and cancel the check
|
||||
KIconLoader::global()->drawOverlays(m_overlays, result, KIconLoader::Desktop);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isEnabled()) {
|
||||
result = KIconLoader::global()->iconEffect()->apply(result, KIconLoader::Desktop, KIconLoader::DisabledState);
|
||||
} else if (m_active) {
|
||||
result = KIconLoader::global()->iconEffect()->apply(result, KIconLoader::Desktop, KIconLoader::ActiveState);
|
||||
}
|
||||
|
||||
m_iconPixmap = result;
|
||||
m_textureChanged = true;
|
||||
|
||||
//don't animate initial setting
|
||||
update();
|
||||
}
|
||||
|
||||
void IconItem::itemChange(ItemChange change, const ItemChangeData &value)
|
||||
{
|
||||
QQuickItem::itemChange(change, value);
|
||||
}
|
||||
|
||||
void IconItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
|
||||
{
|
||||
if (newGeometry.size() != oldGeometry.size()) {
|
||||
m_sizeChanged = true;
|
||||
|
||||
if (newGeometry.width() > 1 && newGeometry.height() > 1) {
|
||||
schedulePixmapUpdate();
|
||||
} else {
|
||||
update();
|
||||
}
|
||||
|
||||
const auto oldSize = qMin(oldGeometry.size().width(), oldGeometry.size().height());
|
||||
const auto newSize = qMin(newGeometry.size().width(), newGeometry.size().height());
|
||||
|
||||
if (!almost_equal(oldSize, newSize, 2)) {
|
||||
emit paintedSizeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QQuickItem::geometryChanged(newGeometry, oldGeometry);
|
||||
}
|
||||
|
||||
void IconItem::componentComplete()
|
||||
{
|
||||
QQuickItem::componentComplete();
|
||||
schedulePixmapUpdate();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright 2012 Marco Martin <mart@kde.org>
|
||||
* Copyright 2014 David Edmundson <davidedmudnson@kde.org>
|
||||
*
|
||||
* 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 ICONITEM_H
|
||||
#define ICONITEM_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QQuickItem>
|
||||
#include <QIcon>
|
||||
#include <QImage>
|
||||
#include <QPixmap>
|
||||
|
||||
#include <Plasma/Svg>
|
||||
|
||||
// this file is based on PlasmaCore::IconItem class, thanks to KDE
|
||||
namespace Latte {
|
||||
class IconItem : public QQuickItem {
|
||||
Q_OBJECT
|
||||
|
||||
/**
|
||||
* Sets the icon to be displayed. Source can be one of:
|
||||
* - iconName (as a string)
|
||||
* - URL
|
||||
* - QImage
|
||||
* - QPixmap
|
||||
* - QIcon
|
||||
*
|
||||
* When passing an icon name (or a QIcon with an icon name set) it will:
|
||||
* - load the plasma variant if usesPlasmaTheme is set and exists
|
||||
* - otherwise try to load the icon as an SVG so colorscopes apply
|
||||
* - load the icon as normal
|
||||
*/
|
||||
Q_PROPERTY(QVariant source READ source WRITE setSource NOTIFY sourceChanged)
|
||||
|
||||
/**
|
||||
* Specifies the overlay(s) for this icon
|
||||
*/
|
||||
Q_PROPERTY(QStringList overlays READ overlays WRITE setOverlays NOTIFY overlaysChanged)
|
||||
|
||||
/**
|
||||
* See QQuickItem::smooth
|
||||
*/
|
||||
Q_PROPERTY(bool smooth READ smooth WRITE setSmooth NOTIFY smoothChanged)
|
||||
|
||||
/**
|
||||
* Apply a visual indication that this icon is active.
|
||||
* Typically used to indicate that it is hovered
|
||||
*/
|
||||
Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged)
|
||||
|
||||
/**
|
||||
* True if a valid icon is set. False otherwise.
|
||||
*/
|
||||
Q_PROPERTY(bool valid READ isValid NOTIFY validChanged)
|
||||
|
||||
/**
|
||||
* The width of the icon that is actually painted
|
||||
*/
|
||||
Q_PROPERTY(int paintedWidth READ paintedWidth NOTIFY paintedSizeChanged)
|
||||
|
||||
/**
|
||||
* The height of the icon actually being drawn.
|
||||
*/
|
||||
Q_PROPERTY(int paintedHeight READ paintedHeight NOTIFY paintedSizeChanged)
|
||||
|
||||
public:
|
||||
IconItem(QQuickItem *parent = nullptr);
|
||||
virtual ~IconItem();
|
||||
|
||||
void setSource(const QVariant &source);
|
||||
QVariant source() const;
|
||||
|
||||
void setOverlays(const QStringList &overlays);
|
||||
QStringList overlays() const;
|
||||
|
||||
bool isActive() const;
|
||||
void setActive(bool active);
|
||||
|
||||
void setSmooth(const bool smooth);
|
||||
bool smooth() const;
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
int paintedWidth() const;
|
||||
int paintedHeight() const;
|
||||
|
||||
void updatePolish() Q_DECL_OVERRIDE;
|
||||
QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) override;
|
||||
|
||||
void itemChange(ItemChange change, const ItemChangeData &value) override;
|
||||
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
|
||||
|
||||
void componentComplete() Q_DECL_OVERRIDE;
|
||||
|
||||
signals:
|
||||
void overlaysChanged();
|
||||
void activeChanged();
|
||||
void sourceChanged();
|
||||
void smoothChanged();
|
||||
void validChanged();
|
||||
void paintedSizeChanged();
|
||||
|
||||
private slots:
|
||||
void schedulePixmapUpdate();
|
||||
void enabledChanged();
|
||||
|
||||
private:
|
||||
void loadPixmap();
|
||||
|
||||
QIcon m_icon;
|
||||
QPixmap m_iconPixmap;
|
||||
QImage m_imageIcon;
|
||||
std::unique_ptr<Plasma::Svg> m_svgIcon;
|
||||
QString m_svgIconName;
|
||||
QStringList m_overlays;
|
||||
//this contains the raw variant it was passed
|
||||
QVariant m_source;
|
||||
|
||||
QSizeF m_implicitSize;
|
||||
|
||||
bool m_smooth;
|
||||
bool m_active;
|
||||
|
||||
bool m_textureChanged;
|
||||
bool m_sizeChanged;
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
#endif // ICONITEM_H
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2016 Smith AR <audoban@openmailbox.org>
|
||||
*
|
||||
* This file is part of Candil-Dock
|
||||
*
|
||||
* Candil-Dock 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 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* Candil-Dock 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 General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NOWDOCKCONFIGVIEW_H
|
||||
#define NOWDOCKCONFIGVIEW_H
|
||||
|
||||
#include "plasmaquick/configview.h"
|
||||
#include <plasma/package.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QWindow>
|
||||
#include <QPointer>
|
||||
#include <QTimer>
|
||||
|
||||
namespace Plasma {
|
||||
class Applet;
|
||||
class Containment;
|
||||
class Types;
|
||||
}
|
||||
|
||||
namespace Latte {
|
||||
|
||||
class NowDockView;
|
||||
|
||||
class DockConfigView : public PlasmaQuick::ConfigView {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DockConfigView(Plasma::Containment *containment, NowDockView *dockView, QWindow *parent = nullptr);
|
||||
~DockConfigView() override;
|
||||
|
||||
void init() override;
|
||||
Qt::WindowFlags wFlags() const;
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *ev) override;
|
||||
void hideEvent(QHideEvent *ev) override;
|
||||
void focusOutEvent(QFocusEvent *ev) override;
|
||||
|
||||
void syncGeometry();
|
||||
void syncSlideEffect();
|
||||
|
||||
private Q_SLOTS:
|
||||
void immutabilityChanged(Plasma::Types::ImmutabilityType type);
|
||||
void configurationShown(PlasmaQuick::ConfigView *configView);
|
||||
|
||||
private:
|
||||
Plasma::Containment *m_containment{nullptr};
|
||||
QPointer<NowDockView> m_dockView;
|
||||
QTimer m_deleterTimer;
|
||||
QTimer m_screenSyncTimer;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
#endif //DOCKCONFIGVIEW_H
|
||||
// kate: indent-mode cstyle; indent-width 4; replace-tabs on;
|
@ -0,0 +1,572 @@
|
||||
/*
|
||||
* Copyright 2014 Bhushan Shah <bhush94@gmail.com>
|
||||
* Copyright 2014 Marco Martin <notmart@gmail.com>
|
||||
*
|
||||
* 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) version 3 or any later version
|
||||
* accepted by the membership of KDE e.V. (or its successor approved
|
||||
* by the membership of KDE e.V.), which shall act as a proxy
|
||||
* defined in Section 14 of version 3 of the license.
|
||||
*
|
||||
* 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 General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "nowdockview.h"
|
||||
#include "nowdockconfigview.h"
|
||||
#include "visibilitymanager.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QQmlContext>
|
||||
#include <QQmlEngine>
|
||||
#include <QQmlProperty>
|
||||
#include <QQuickItem>
|
||||
#include <QMetaEnum>
|
||||
//#include <QtX11Extras/QX11Info>
|
||||
|
||||
#include <NETWM>
|
||||
#include <KWindowSystem>
|
||||
#include <Plasma/Containment>
|
||||
#include <KActionCollection>
|
||||
#include <KLocalizedContext>
|
||||
|
||||
#include "nowdockcorona.h"
|
||||
|
||||
namespace Latte {
|
||||
|
||||
NowDockView::NowDockView(Plasma::Corona *corona, QScreen *targetScreen)
|
||||
: PlasmaQuick::ContainmentView(corona),
|
||||
m_corona(corona)
|
||||
{
|
||||
KWindowSystem::setType(winId(), NET::Dock);
|
||||
KWindowSystem::setState(winId(), NET::SkipTaskbar | NET::SkipPager);
|
||||
|
||||
setVisible(false);
|
||||
setTitle(corona->kPackage().metadata().name());
|
||||
setIcon(QIcon::fromTheme(corona->kPackage().metadata().iconName()));
|
||||
|
||||
setResizeMode(QuickViewSharedEngine::SizeRootObjectToView);
|
||||
setClearBeforeRendering(true);
|
||||
/* setFlags(Qt::FramelessWindowHint
|
||||
| Qt::WindowStaysOnTopHint
|
||||
| Qt::NoDropShadowWindowHint
|
||||
| Qt::WindowDoesNotAcceptFocus);*/
|
||||
|
||||
// NETWinInfo winfo(QX11Info::connection(), winId(), winId(), 0, 0);
|
||||
// winfo.setAllowedActions(NET::ActionChangeDesktop);
|
||||
|
||||
if (targetScreen)
|
||||
adaptToScreen(targetScreen);
|
||||
else
|
||||
adaptToScreen(qGuiApp->primaryScreen());
|
||||
|
||||
m_timerGeometry.setSingleShot(true);
|
||||
m_timerGeometry.setInterval(400);
|
||||
|
||||
m_lockGeometry.setSingleShot(true);
|
||||
m_lockGeometry.setInterval(700);
|
||||
|
||||
connect(this, &NowDockView::containmentChanged
|
||||
, this, [&]() {
|
||||
if (!containment())
|
||||
return;
|
||||
|
||||
if (!m_visibility) {
|
||||
m_visibility = new VisibilityManager(this);
|
||||
}
|
||||
|
||||
}, Qt::DirectConnection);
|
||||
}
|
||||
|
||||
NowDockView::~NowDockView()
|
||||
{
|
||||
}
|
||||
|
||||
void NowDockView::init()
|
||||
{
|
||||
connect(this, &NowDockView::screenChanged
|
||||
, this, &NowDockView::adaptToScreen
|
||||
, Qt::QueuedConnection);
|
||||
|
||||
|
||||
connect(&m_timerGeometry, &QTimer::timeout, [&]() {
|
||||
initWindow();
|
||||
});
|
||||
|
||||
connect(this, &NowDockView::locationChanged, [&]() {
|
||||
//! avoid glitches
|
||||
m_timerGeometry.start();
|
||||
});
|
||||
|
||||
connect(KWindowSystem::self(), &KWindowSystem::compositingChanged
|
||||
, this, [&]() {
|
||||
emit compositingChanged();
|
||||
} , Qt::QueuedConnection);
|
||||
|
||||
connect(this, &NowDockView::screenGeometryChanged
|
||||
, this, &NowDockView::updateDockPosition
|
||||
, Qt::QueuedConnection);
|
||||
|
||||
connect(this, SIGNAL(widthChanged(int)), this, SIGNAL(widthChanged()));
|
||||
connect(this, SIGNAL(heightChanged(int)), this, SIGNAL(heightChanged()));
|
||||
|
||||
rootContext()->setContextProperty(QStringLiteral("dock"), this);
|
||||
engine()->rootContext()->setContextObject(new KLocalizedContext(this));
|
||||
|
||||
// engine()->rootContext()->setContextProperty(QStringLiteral("dock"), this);
|
||||
setSource(corona()->kPackage().filePath("nowdockui"));
|
||||
|
||||
|
||||
connect(this, SIGNAL(xChanged(int)), this, SLOT(updateDockPositionSlot()));
|
||||
connect(this, SIGNAL(yChanged(int)), this, SLOT(updateDockPositionSlot()));
|
||||
|
||||
connect(&m_lockGeometry, &QTimer::timeout, [&]() {
|
||||
updateDockPosition();
|
||||
});
|
||||
|
||||
qDebug() << "SOURCE:" << source();
|
||||
|
||||
initialize();
|
||||
}
|
||||
|
||||
|
||||
void NowDockView::initialize()
|
||||
{
|
||||
m_secondInitPass = true;
|
||||
m_timerGeometry.start();
|
||||
}
|
||||
|
||||
void NowDockView::initWindow()
|
||||
{
|
||||
// m_visibility->updateVisibilityFlags();
|
||||
|
||||
updateDockPosition();
|
||||
resizeWindow();
|
||||
|
||||
// The initialization phase makes two passes because
|
||||
// changing the window style and type wants a small delay
|
||||
// and afterwards the second pass positions them correctly
|
||||
if (m_secondInitPass) {
|
||||
m_timerGeometry.start();
|
||||
m_secondInitPass = false;
|
||||
setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
void NowDockView::updateDockPositionSlot()
|
||||
{
|
||||
if (!m_lockGeometry.isActive()) {
|
||||
m_lockGeometry.start();
|
||||
}
|
||||
}
|
||||
|
||||
//!BEGIN SLOTS
|
||||
void NowDockView::adaptToScreen(QScreen *screen)
|
||||
{
|
||||
setScreen(screen);
|
||||
|
||||
if (formFactor() == Plasma::Types::Vertical)
|
||||
m_maxLength = screen->size().height();
|
||||
else
|
||||
m_maxLength = screen->size().width();
|
||||
|
||||
// KWindowSystem::setOnAllDesktops(winId(), true);
|
||||
// KWindowSystem::setType(winId(), NET::Dock);
|
||||
|
||||
if (containment())
|
||||
containment()->reactToScreenChange();
|
||||
|
||||
m_timerGeometry.start();
|
||||
}
|
||||
|
||||
void NowDockView::addNewDock()
|
||||
{
|
||||
NowDockCorona *corona = dynamic_cast<NowDockCorona *>(m_corona);
|
||||
|
||||
if (corona) {
|
||||
corona->loadDefaultLayout();
|
||||
}
|
||||
}
|
||||
|
||||
void NowDockView::removeDock()
|
||||
{
|
||||
NowDockCorona *corona = dynamic_cast<NowDockCorona *>(m_corona);
|
||||
|
||||
if (corona->containments().count() > 1) {
|
||||
QAction *removeAct = containment()->actions()->action(QStringLiteral("remove"));
|
||||
|
||||
if (removeAct) {
|
||||
removeAct->trigger();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QQmlListProperty<QScreen> NowDockView::screens()
|
||||
{
|
||||
return QQmlListProperty<QScreen>(this, nullptr, &countScreens, &atScreens);
|
||||
}
|
||||
|
||||
int NowDockView::countScreens(QQmlListProperty<QScreen> *property)
|
||||
{
|
||||
Q_UNUSED(property)
|
||||
return qGuiApp->screens().count();
|
||||
}
|
||||
|
||||
QScreen *NowDockView::atScreens(QQmlListProperty<QScreen> *property, int index)
|
||||
{
|
||||
Q_UNUSED(property)
|
||||
return qGuiApp->screens().at(index);
|
||||
}
|
||||
|
||||
void NowDockView::showConfigurationInterface(Plasma::Applet *applet)
|
||||
{
|
||||
if (!applet || !applet->containment())
|
||||
return;
|
||||
|
||||
Plasma::Containment *c = qobject_cast<Plasma::Containment *>(applet);
|
||||
|
||||
if (m_configView && c && c->isContainment() && c == containment()) {
|
||||
if (m_configView->isVisible()) {
|
||||
m_configView->hide();
|
||||
} else {
|
||||
m_configView->show();
|
||||
m_configView->requestActivate();
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (m_configView) {
|
||||
if (m_configView->applet() == applet) {
|
||||
m_configView->show();
|
||||
m_configView->requestActivate();
|
||||
return;
|
||||
} else {
|
||||
m_configView->hide();
|
||||
m_configView->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
if (c && containment() && c->isContainment() && c->id() == containment()->id()) {
|
||||
m_configView = new DockConfigView(c, this);
|
||||
} else {
|
||||
m_configView = new PlasmaQuick::ConfigView(applet);
|
||||
}
|
||||
|
||||
m_configView->init();
|
||||
m_configView->show();
|
||||
m_configView->requestActivate();
|
||||
}
|
||||
|
||||
void NowDockView::resizeWindow()
|
||||
{
|
||||
setVisible(true);
|
||||
|
||||
QSize screenSize = screen()->size();
|
||||
|
||||
if (formFactor() == Plasma::Types::Vertical) {
|
||||
const QSize size{maxThickness(), screenSize.height()};
|
||||
setMinimumSize(size);
|
||||
setMaximumSize(size);
|
||||
resize(size);
|
||||
|
||||
qDebug() << "dock size:" << size;
|
||||
} else {
|
||||
const QSize size{screenSize.width(), maxThickness()};
|
||||
setMinimumSize(size);
|
||||
setMaximumSize(size);
|
||||
resize(size);
|
||||
|
||||
qDebug() << "dock size:" << size;
|
||||
}
|
||||
}
|
||||
|
||||
inline void NowDockView::updateDockPosition()
|
||||
{
|
||||
if (!containment())
|
||||
return;
|
||||
|
||||
const QRect screenGeometry = screen()->geometry();
|
||||
QPoint position;
|
||||
|
||||
qDebug() << "current dock geometry: " << geometry();
|
||||
|
||||
// containment()->setFormFactor(Plasma::Types::Horizontal);
|
||||
position = {0, 0};
|
||||
m_maxLength = screenGeometry.width();
|
||||
|
||||
switch (location()) {
|
||||
case Plasma::Types::TopEdge:
|
||||
containment()->setFormFactor(Plasma::Types::Horizontal);
|
||||
position = {screenGeometry.x(), screenGeometry.y()};
|
||||
m_maxLength = screenGeometry.width();
|
||||
break;
|
||||
|
||||
case Plasma::Types::BottomEdge:
|
||||
containment()->setFormFactor(Plasma::Types::Horizontal);
|
||||
position = {screenGeometry.x(), screenGeometry.y() + screenGeometry.height() - height()};
|
||||
m_maxLength = screenGeometry.width();
|
||||
break;
|
||||
|
||||
case Plasma::Types::RightEdge:
|
||||
containment()->setFormFactor(Plasma::Types::Vertical);
|
||||
position = {screenGeometry.x() + screenGeometry.width() - width(), screenGeometry.y()};
|
||||
m_maxLength = screenGeometry.height();
|
||||
break;
|
||||
|
||||
case Plasma::Types::LeftEdge:
|
||||
containment()->setFormFactor(Plasma::Types::Vertical);
|
||||
position = {screenGeometry.x(), screenGeometry.y()};
|
||||
m_maxLength = screenGeometry.height();
|
||||
break;
|
||||
|
||||
default:
|
||||
qWarning() << "wrong location, couldn't update the panel position"
|
||||
<< location();
|
||||
}
|
||||
|
||||
emit maxLengthChanged();
|
||||
setX(position.x());
|
||||
setY(position.y());
|
||||
//setPosition(position);
|
||||
qDebug() << "dock position:" << position;
|
||||
}
|
||||
|
||||
int NowDockView::currentThickness() const
|
||||
{
|
||||
if (containment()->formFactor() == Plasma::Types::Vertical) {
|
||||
return m_maskArea.isNull() ? width() : m_maskArea.width();
|
||||
} else {
|
||||
return m_maskArea.isNull() ? height() : m_maskArea.height();
|
||||
}
|
||||
}
|
||||
|
||||
bool NowDockView::compositing() const
|
||||
{
|
||||
return KWindowSystem::compositingActive();
|
||||
}
|
||||
|
||||
/*Candil::VisibilityManager *NowDockView::visibility()
|
||||
{
|
||||
return m_visibility.data();
|
||||
}*/
|
||||
|
||||
int NowDockView::maxThickness() const
|
||||
{
|
||||
return m_maxThickness;
|
||||
}
|
||||
|
||||
void NowDockView::setMaxThickness(int thickness)
|
||||
{
|
||||
if (m_maxThickness == thickness)
|
||||
return;
|
||||
|
||||
m_maxThickness = thickness;
|
||||
m_timerGeometry.start();
|
||||
emit maxThicknessChanged();
|
||||
}
|
||||
|
||||
int NowDockView::length() const
|
||||
{
|
||||
return m_length;
|
||||
}
|
||||
|
||||
void NowDockView::setLength(int length)
|
||||
{
|
||||
if (m_length == length)
|
||||
return;
|
||||
|
||||
if (length > m_maxLength)
|
||||
m_length = m_maxLength;
|
||||
else
|
||||
m_length = length;
|
||||
|
||||
m_timerGeometry.start();
|
||||
emit lengthChanged();
|
||||
}
|
||||
|
||||
int NowDockView::maxLength() const
|
||||
{
|
||||
return m_maxLength;
|
||||
}
|
||||
|
||||
void NowDockView::setMaxLength(int maxLength)
|
||||
{
|
||||
if (m_maxLength == maxLength)
|
||||
return;
|
||||
|
||||
m_maxLength = maxLength;
|
||||
emit maxLengthChanged();
|
||||
}
|
||||
|
||||
|
||||
QRect NowDockView::maskArea() const
|
||||
{
|
||||
return m_maskArea;
|
||||
}
|
||||
|
||||
void NowDockView::setMaskArea(QRect area)
|
||||
{
|
||||
if (m_maskArea == area) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_maskArea = area;
|
||||
|
||||
setMask(m_maskArea);
|
||||
|
||||
//qDebug() << "dock mask set:" << m_maskArea;
|
||||
emit maskAreaChanged();
|
||||
}
|
||||
|
||||
/*Dock::Alignment NowDockView::alignment() const
|
||||
{
|
||||
return m_alignment;
|
||||
}
|
||||
|
||||
void NowDockView::setAlignment(Dock::Alignment align)
|
||||
{
|
||||
if (m_alignment == align)
|
||||
return;
|
||||
|
||||
m_alignment = align;
|
||||
emit alignmentChanged();
|
||||
}
|
||||
*/
|
||||
int NowDockView::offset() const
|
||||
{
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
void NowDockView::setOffset(int offset)
|
||||
{
|
||||
if (m_offset == offset)
|
||||
return;
|
||||
|
||||
m_offset = offset;
|
||||
m_timerGeometry.start();
|
||||
emit offsetChanged();
|
||||
}
|
||||
|
||||
void NowDockView::updateOffset()
|
||||
{
|
||||
if (!containment())
|
||||
return;
|
||||
|
||||
const float offsetPercent = containment()->config().readEntry("offset").toFloat();
|
||||
const int offset = offsetPercent * (m_maxLength - m_length) / 2;
|
||||
|
||||
if (offset == m_offset)
|
||||
return;
|
||||
|
||||
m_offset = offset;
|
||||
emit offsetChanged();
|
||||
}
|
||||
|
||||
VisibilityManager *NowDockView::visibility()
|
||||
{
|
||||
return m_visibility;
|
||||
}
|
||||
|
||||
bool NowDockView::event(QEvent *e)
|
||||
{
|
||||
emit eventTriggered(e);
|
||||
|
||||
return ContainmentView::event(e);
|
||||
}
|
||||
|
||||
/*void NowDockView::showEvent(QShowEvent *ev)
|
||||
{
|
||||
KWindowSystem::setType(winId(), NET::Dock);
|
||||
KWindowSystem::setOnAllDesktops(winId(), true);
|
||||
|
||||
//QQuickWindow::showEvent(ev);
|
||||
ContainmentView::showEvent(ev);
|
||||
}*/
|
||||
|
||||
bool NowDockView::containmentContainsPosition(const QPointF &point) const
|
||||
{
|
||||
QQuickItem *containmentItem = containment()->property("_plasma_graphicObject").value<QQuickItem *>();
|
||||
|
||||
if (!containmentItem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return QRectF(containmentItem->mapToScene(QPoint(0, 0)), QSizeF(containmentItem->width(), containmentItem->height())).contains(point);
|
||||
}
|
||||
|
||||
QPointF NowDockView::positionAdjustedForContainment(const QPointF &point) const
|
||||
{
|
||||
QQuickItem *containmentItem = containment()->property("_plasma_graphicObject").value<QQuickItem *>();
|
||||
|
||||
if (!containmentItem) {
|
||||
return point;
|
||||
}
|
||||
|
||||
QRectF containmentRect(containmentItem->mapToScene(QPoint(0, 0)), QSizeF(containmentItem->width(), containmentItem->height()));
|
||||
|
||||
return QPointF(qBound(containmentRect.left() + 2, point.x(), containmentRect.right() - 2),
|
||||
qBound(containmentRect.top() + 2, point.y(), containmentRect.bottom() - 2));
|
||||
}
|
||||
|
||||
QList<int> NowDockView::freeEdges() const
|
||||
{
|
||||
QList<Plasma::Types::Location> edges = m_corona->freeEdges(containment()->screen());
|
||||
|
||||
QList<int> edgesInt;
|
||||
|
||||
foreach (Plasma::Types::Location edge, edges) {
|
||||
edgesInt.append((int)edge);
|
||||
}
|
||||
|
||||
return edgesInt;
|
||||
}
|
||||
|
||||
void NowDockView::saveConfig()
|
||||
{
|
||||
if (!containment())
|
||||
return;
|
||||
|
||||
const auto writeEntry = [&](const char *entry, const QVariant & value) {
|
||||
containment()->config().writeEntry(entry, value);
|
||||
};
|
||||
|
||||
//! convert offset to percent, range [-1,1] 0 is Centered
|
||||
//! offsetPercent = offset * 2 / (maxLength - length)
|
||||
// const float offsetPercent = m_offset * 2.0f / (m_maxLength - m_length);
|
||||
// writeEntry("offset", offsetPercent);
|
||||
// writeEntry("iconSize", m_iconSize);
|
||||
// writeEntry("zoomFactor", m_zoomFactor);
|
||||
// writeEntry("alignment", static_cast<int>(m_alignment));
|
||||
}
|
||||
|
||||
void NowDockView::restoreConfig()
|
||||
{
|
||||
if (!containment())
|
||||
return;
|
||||
|
||||
const auto readEntry = [&](const char *entry, QVariant defaultValue) -> QVariant {
|
||||
return containment()->config().readEntry(entry, defaultValue);
|
||||
};
|
||||
//! convert offset-percent to pixels
|
||||
//! offset = offsetPercent * (maxLength - length) / 2
|
||||
// const float offsetPercent {readEntry("offset", 0).toFloat()};
|
||||
// const int offset {static_cast<int>(offsetPercent * (m_maxLength - m_length) / 2)};
|
||||
// setOffset(offset);
|
||||
|
||||
// setIconSize(readEntry("iconSize", 32).toInt());
|
||||
// setZoomFactor(readEntry("zoomFactor", 1.0).toFloat());
|
||||
// setAlignment(static_cast<Dock::Alignment>(readEntry("alignment", Dock::Center).toInt()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//!END SLOTS
|
||||
|
||||
|
||||
//!END namespace
|
Loading…
Reference in New Issue