feat(publicItem):添加themeIcon获取图标

This commit is contained in:
qiqi 2023-09-19 15:25:32 +08:00
parent e4ae7bfc8f
commit cf0cf89193
12 changed files with 339 additions and 141 deletions

View File

@ -15,8 +15,8 @@ find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Qml Quick REQUIRED)
set (PLUGIN_SRCS set (PLUGIN_SRCS
panel-framework-public-plugin.cpp panel-framework-public-plugin.cpp
panel-framework-public-plugin.h panel-framework-public-plugin.h
../config/ini-config.cpp items/theme-icon.cpp
../config/ini-config.h items/theme-icon.h
) )
add_library(${PROJECT_NAME} SHARED ${PLUGIN_SRCS}) add_library(${PROJECT_NAME} SHARED ${PLUGIN_SRCS})
set(PLUGIN_IMPORT_URI "org.ukui.panel.publicItems") set(PLUGIN_IMPORT_URI "org.ukui.panel.publicItems")

View File

@ -0,0 +1,292 @@
/*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* 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 3 of the License, 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Authors: hxf <hewenfei@kylinos.cn>
*
*/
#include "theme-icon.h"
#include <QUrl>
#include <QPainter>
#include <QFile>
#include <QImageReader>
#include <QDebug>
#include <QGuiApplication>
#include <QPalette>
#include <QImage>
#include <QtMath>
#include <QPainterPath>
#define COLOR_DIFFERENCE 10
QColor ThemeIcon::symbolicColor = QColor(31, 32, 34, 192);
ThemeIcon::ThemeIcon(QQuickItem *parent) : QQuickPaintedItem(parent)
{
}
void ThemeIcon::paint(QPainter *painter)
{
//默认居中绘制
QRect rect(0, 0, static_cast<int>(width()), static_cast<int>(height()));
QPixmap target = m_rawIcon.pixmap({128, 128});
painter->save();
//抗锯齿,平滑过渡
painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
if (m_disabled) {
QPainter p(&target);
p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
p.setCompositionMode(QPainter::CompositionMode_SourceIn);
p.fillRect(target.rect(), QGuiApplication::palette().color(QPalette::Disabled, QPalette::ButtonText));
} else if (m_highLight) {
bool isPureColor = true;
if(!m_forceHighlight) {
isPureColor = isPixmapPureColor(target);
}
if (isPureColor) {
QPainter p(&target);
p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
p.setCompositionMode(QPainter::CompositionMode_SourceIn);
p.fillRect(target.rect(), QGuiApplication::palette().color(QPalette::HighlightedText));
}
}
if (m_radius > 0) {
int radius = qMin(m_radius, qMin((rect.height() / 2), (rect.width() / 2)));
QPainterPath path;
path.addRoundedRect(rect, radius, radius);
painter->setClipPath(path);
}
painter->drawPixmap(rect, target, target.rect());
painter->restore();
}
QVariant ThemeIcon::getSource()
{
return m_source;
}
void ThemeIcon::setSource(const QVariant &source)
{
if (m_source == source) {
return;
}
m_source = source;
updateRawIcon(source);
}
QString ThemeIcon::getFallBack()
{
return m_fallback;
}
void ThemeIcon::setFallBack(const QString &fallback)
{
if (fallback.isEmpty()) {
qWarning() << "ThemeIcon: fallback is empty!";
return;
}
if (m_rawIcon.isNull()) {
setSource(fallback);
}
}
void ThemeIcon::readImage(const QString &path)
{
QFile file(path);
if (!file.exists()) {
qDebug() << "Error: ThemeIcon: " << QString("File not found: %1").arg(path);
return;
}
if (!file.open(QFileDevice::ReadOnly)) {
qWarning() << "Error: ThemeIcon: " << QString("Cannot open: %1").arg(path);
return;
}
QImageReader imageReader(&file);
QImage image;
QPixmap pixmap;
if (!imageReader.read(&image)) {
qWarning() << "Error: ThemeIcon: " << QString("Error decoding: %1").arg(path);
return;
}
pixmap = QPixmap::fromImage(image);
m_source = path;
file.close();
}
bool ThemeIcon::isHighLight() const
{
return m_highLight;
}
void ThemeIcon::setHighLight(bool highLight)
{
m_highLight = highLight;
update();
}
bool ThemeIcon::isForceHighlight() const
{
return m_forceHighlight;
}
void ThemeIcon::setForceHighLight(bool force)
{
m_forceHighlight = force;
}
bool ThemeIcon::disable() const
{
return m_disabled;
}
void ThemeIcon::setDisable(bool disable)
{
m_disabled = disable;
update();
}
//copy from ukui-platform-theme
bool ThemeIcon::isPixmapPureColor(const QPixmap &pixmap)
{
if (pixmap.isNull()) {
qWarning("pixmap is null!");
return false;
}
QImage image = pixmap.toImage();
QVector<QColor> vector;
int total_red = 0;
int total_green = 0;
int total_blue = 0;
bool pure = true;
for (int y = 0; y < image.height(); ++y) {
for (int x = 0; x < image.width(); ++x) {
if (image.pixelColor(x, y).alphaF() > 0.3) {
QColor color = image.pixelColor(x, y);
vector << color;
total_red += color.red();
total_green += color.green();
total_blue += color.blue();
int dr = qAbs(color.red() - symbolicColor.red());
int dg = qAbs(color.green() - symbolicColor.green());
int db = qAbs(color.blue() - symbolicColor.blue());
if (dr > COLOR_DIFFERENCE || dg > COLOR_DIFFERENCE || db > COLOR_DIFFERENCE)
pure = false;
}
}
}
if (pure)
return true;
qreal squareRoot_red = 0;
qreal squareRoot_green = 0;
qreal squareRoot_blue = 0;
qreal average_red = total_red / vector.count();
qreal average_green = total_green / vector.count();
qreal average_blue = total_blue / vector.count();
for (QColor color : vector) {
squareRoot_red += (color.red() - average_red) * (color.red() - average_red);
squareRoot_green += (color.green() - average_green) * (color.green() - average_green);
squareRoot_blue += (color.blue() - average_blue) * (color.blue() - average_blue);
}
qreal arithmeticSquareRoot_red = qSqrt(squareRoot_red / vector.count());
qreal arithmeticSquareRoot_green = qSqrt(squareRoot_green / vector.count());
qreal arithmeticSquareRoot_blue = qSqrt(squareRoot_blue / vector.count());
return arithmeticSquareRoot_red < 2.0 && arithmeticSquareRoot_green < 2.0 && arithmeticSquareRoot_blue < 2.0;
}
void ThemeIcon::updateRawIcon(const QVariant &icon)
{
switch (m_source.userType()) {
case QMetaType::QPixmap:
m_rawIcon = QIcon(m_source.value<QPixmap>());
break;
case QMetaType::QImage:
m_rawIcon = QIcon(QPixmap::fromImage(m_source.value<QImage>()));
break;
case QMetaType::QIcon:
m_rawIcon = m_source.value<QIcon>();
break;
case QMetaType::QString:
m_rawIcon = findIcon(m_source.toString());
break;
default:
break;
}
if (m_rawIcon.isNull()) {
QImage image = QImage(QSize(width(), height()), QImage::Format_Alpha8);
image.fill(Qt::transparent);
m_rawIcon = QIcon(QPixmap::fromImage(image));
}
}
QIcon ThemeIcon::findIcon(const QString &source)
{
QIcon icon;
QUrl url(source);
QString schema = url.scheme();
if (!schema.isEmpty()) {
QString path = url.path();
if (!path.isEmpty()) {
if (schema == QLatin1String("qrc")) {
path.prepend(QLatin1String(":"));
}
readImage(path);
icon = QIcon(m_source.toString());
} else {
qWarning() << "Error: ThemeIcon: source is invalid! schema:" << schema;
}
} else {
//qrc path: :/xxx/xxx.png
if (source.startsWith(QLatin1String("/")) || source.startsWith(QLatin1String(":/"))) {
readImage(source);
icon = QIcon(m_source.toString());
} else {
if (!QIcon::hasThemeIcon(source)) {
qWarning() << "Error: ThemeIcon: icon dose not exists. name:" << source;
}
QIcon icon = QIcon::fromTheme(source);
}
}
return icon;
}
int ThemeIcon::radius()
{
return m_radius;
}
void ThemeIcon::setRadius(int radius)
{
m_radius = radius < 0 ? 0 : radius;
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2023, KylinSoft Co., Ltd. * Copyright (C) 2022, KylinSoft Co., Ltd.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -18,43 +18,61 @@
* *
*/ */
#ifndef UKUI_MENU_THEME_ICON_H #ifndef UKUI_PANEL_THEME_ICON_H
#define UKUI_MENU_THEME_ICON_H #define UKUI_PANEL_THEME_ICON_H
#include <QQuickPaintedItem> #include <QQuickPaintedItem>
#include <QIcon> #include <QIcon>
namespace TaskManager {
class ThemeIcon : public QQuickPaintedItem class ThemeIcon : public QQuickPaintedItem
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QVariant source READ getSource WRITE setSource)
Q_PROPERTY(QString fallback READ getFallBack WRITE setFallBack)
Q_PROPERTY(bool disable READ disable WRITE setDisable) Q_PROPERTY(bool disable READ disable WRITE setDisable)
Q_PROPERTY(int radius READ radius WRITE setRadius) Q_PROPERTY(int radius READ radius WRITE setRadius)
Q_PROPERTY(QIcon icon READ getIcon WRITE setIcon) Q_PROPERTY(bool highLight READ isHighLight WRITE setHighLight)
Q_PROPERTY(bool forceHighlight READ isForceHighlight WRITE setForceHighLight)
public: public:
explicit ThemeIcon(QQuickItem *parent = nullptr); explicit ThemeIcon(QQuickItem *parent = nullptr);
void paint(QPainter *painter) override; void paint(QPainter *painter) override;
QVariant getSource();
void setSource(const QVariant& source);
QString getFallBack();
void setFallBack(const QString &fallback);
bool isHighLight() const;
void setHighLight(bool highLight);
bool isForceHighlight() const;
void setForceHighLight(bool force);
bool disable() const; bool disable() const;
void setDisable(bool disable); void setDisable(bool disable);
int radius(); int radius();
void setRadius(int radius); void setRadius(int radius);
QIcon getIcon(); private:
void setIcon(const QIcon &icon); void readImage(const QString &path);
bool isPixmapPureColor(const QPixmap &pixmap);
void updateRawIcon(const QVariant &icon);
QIcon findIcon(const QString &source);
private: private:
bool m_disabled = false; bool m_disabled = false;
int m_radius = 0; int m_radius = 0;
QIcon m_icon; bool m_highLight = false;
bool m_forceHighlight = false;
QIcon m_rawIcon;
QVariant m_source;
QString m_fallback;
static QColor symbolicColor; static QColor symbolicColor;
}; };
} #endif //UKUI_PANEL_THEME_ICON_H
#endif // UKUI_MENU_THEME_ICON_H

View File

@ -18,6 +18,8 @@
* *
*/ */
#include "panel-framework-public-plugin.h" #include "panel-framework-public-plugin.h"
#include "items/theme-icon.h"
#include <QQmlContext> #include <QQmlContext>
#include <QQmlEngine> #include <QQmlEngine>
@ -25,4 +27,6 @@ void PanelFrameworkPublicPlugin::registerTypes(const char *uri)
{ {
Q_ASSERT(QLatin1String(uri) == QLatin1String(PLUGIN_IMPORT_URI)); Q_ASSERT(QLatin1String(uri) == QLatin1String(PLUGIN_IMPORT_URI));
qmlRegisterModule(uri, 1, 0); qmlRegisterModule(uri, 1, 0);
qmlRegisterType<ThemeIcon>(uri, 1, 0, "ThemeIcon");
} }

View File

@ -15,6 +15,6 @@ target_link_libraries(${PROJECT_NAME}
PRIVATE PRIVATE
Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Quick Qt${QT_VERSION_MAJOR}::Quick
framework-ui framework-widget-ui
framework-widget framework-widget
) )

View File

@ -4,8 +4,6 @@ set(ukuiTaskManagerTest_SRCS
window-thumbnail-view.cpp window-thumbnail-view.cpp
task-manager-view.h task-manager-view.h
task-manager-view.cpp task-manager-view.cpp
theme-icon.h
theme-icon.cpp
) )
include_directories(../) include_directories(../)

View File

@ -1,7 +1,7 @@
import QtQuick 2.12 import QtQuick 2.12
import QtQuick.Layouts 1.12 import QtQuick.Layouts 1.12
import org.ukui.windowThumbnail 1.0 import org.ukui.windowThumbnail 1.0
import org.ukui.taskManager.core 1.0 import org.ukui.panel.publicItems 1.0
MouseArea { MouseArea {
width: childrenRect.width width: childrenRect.width
@ -52,7 +52,7 @@ MouseArea {
ThemeIcon { ThemeIcon {
Layout.preferredHeight: 32 Layout.preferredHeight: 32
Layout.preferredWidth: 32 Layout.preferredWidth: 32
icon: taskModel.windowIcon(modelData) source: taskModel.windowIcon(modelData)
} }
Text { Text {
Layout.fillHeight: true Layout.fillHeight: true

View File

@ -2,7 +2,7 @@ import QtQuick 2.15
import QtQml.Models 2.12 import QtQml.Models 2.12
import QtQuick.Layouts 1.12 import QtQuick.Layouts 1.12
import QtQuick.Controls 2.12 import QtQuick.Controls 2.12
import org.ukui.taskManager.core 1.0 import org.ukui.panel.publicItems 1.0
Item { Item {
id: root id: root
@ -88,7 +88,7 @@ Item {
id: icon id: icon
width: 96 width: 96
height: 96 height: 96
icon: model.Icon source: model.Icon
anchors.centerIn: parent anchors.centerIn: parent
} }

View File

@ -7,7 +7,6 @@
#include <KWindowSystem> #include <KWindowSystem>
#include "actions.h" #include "actions.h"
#include "theme-icon.h"
#include "task-manager-view.h" #include "task-manager-view.h"
#include "ukui-task-manager.h" #include "ukui-task-manager.h"
#include "window-thumbnail/x-window-thumbnail.h" #include "window-thumbnail/x-window-thumbnail.h"
@ -65,8 +64,6 @@ void TaskManagerView::initWindow()
engine()->rootContext()->setContextProperty("proxyModel", m_model); engine()->rootContext()->setContextProperty("proxyModel", m_model);
engine()->rootContext()->setContextProperty("thumbnailView", m_windowThumbnailView); engine()->rootContext()->setContextProperty("thumbnailView", m_windowThumbnailView);
qmlRegisterType<TaskManager::ThemeIcon>("org.ukui.taskManager.core", 1, 0, "ThemeIcon");
setSource(QUrl("qrc:/main.qml")); setSource(QUrl("qrc:/main.qml"));
kdk::WindowManager::setSkipTaskBar(this, true); kdk::WindowManager::setSkipTaskBar(this, true);

View File

@ -1,108 +0,0 @@
/*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* 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 3 of the License, 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 General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Authors: hxf <hewenfei@kylinos.cn>
*
*/
#include "theme-icon.h"
#include <QUrl>
#include <QPainter>
#include <QImageReader>
#include <QDebug>
#include <QGuiApplication>
#include <QPalette>
#include <QImage>
#include <QtMath>
#include <QPainterPath>
#define COLOR_DIFFERENCE 10
using namespace TaskManager;
QColor ThemeIcon::symbolicColor = QColor(31, 32, 34, 192);
ThemeIcon::ThemeIcon(QQuickItem *parent) : QQuickPaintedItem(parent)
{
update();
}
void ThemeIcon::paint(QPainter *painter)
{
//默认居中绘制
QRect rect(0, 0, static_cast<int>(width()), static_cast<int>(height()));
QPixmap pixmap = m_icon.pixmap({128,128});
painter->save();
//抗锯齿,平滑过渡
painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
if (m_disabled) {
QPainter p(&pixmap);
p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
p.setCompositionMode(QPainter::CompositionMode_SourceIn);
p.fillRect(pixmap.rect(), QGuiApplication::palette().color(QPalette::Disabled, QPalette::ButtonText));
}
if (m_radius > 0) {
int radius = qMin(m_radius, qMin((rect.height() / 2), (rect.width() / 2)));
QPainterPath path;
path.addRoundedRect(rect, radius, radius);
painter->setClipPath(path);
}
painter->drawPixmap(rect, pixmap, pixmap.rect());
painter->restore();
}
bool ThemeIcon::disable() const
{
return m_disabled;
}
void ThemeIcon::setDisable(bool disable)
{
m_disabled = disable;
update();
}
int ThemeIcon::radius()
{
return m_radius;
}
void ThemeIcon::setRadius(int radius)
{
m_radius = radius < 0 ? 0 : radius;
}
QIcon ThemeIcon::getIcon()
{
return m_icon;
}
void ThemeIcon::setIcon(const QIcon &icon)
{
if (icon.isNull()) {
// qWarning() << "ThemeIcon: icon is empty!";
return;
}
m_icon = icon;
update();
}

View File

@ -8,7 +8,6 @@
#include "window-thumbnail-view.h" #include "window-thumbnail-view.h"
#include "ukui-task-manager.h" #include "ukui-task-manager.h"
#include "window-thumbnail/x-window-thumbnail.h" #include "window-thumbnail/x-window-thumbnail.h"
#include "theme-icon.h"
#include "actions.h" #include "actions.h"
#include <windowmanager/windowmanager.h> #include <windowmanager/windowmanager.h>
@ -53,7 +52,6 @@ WindowThumbnailView::WindowThumbnailView(QWindow *parent)
setColor("transparent"); setColor("transparent");
// qmlRegisterType<XWindowThumbnail>("org.ukui.taskManager.core", 1, 0, "XWindowThumbnail"); // qmlRegisterType<XWindowThumbnail>("org.ukui.taskManager.core", 1, 0, "XWindowThumbnail");
qmlRegisterType<TaskManager::ThemeIcon>("org.ukui.taskManager.core", 1, 0, "ThemeIcon");
engine()->rootContext()->setContextProperty("thumbnailView", this); engine()->rootContext()->setContextProperty("thumbnailView", this);
engine()->rootContext()->setContextProperty("taskModel", &TaskManager::UkuiTaskManager::self()); engine()->rootContext()->setContextProperty("taskModel", &TaskManager::UkuiTaskManager::self());
setSource(QUrl("qrc:/ThumbnailView.qml")); setSource(QUrl("qrc:/ThumbnailView.qml"));

View File

@ -2,7 +2,6 @@ import QtQuick 2.12
import QtQuick.Layouts 1.12 import QtQuick.Layouts 1.12
import QtQuick.Controls 2.12 import QtQuick.Controls 2.12
import org.ukui.panel.publicItems 1.0 import org.ukui.panel.publicItems 1.0
import org.ukui.sidebar.items 1.0
import org.ukui.windowThumbnail 1.0 import org.ukui.windowThumbnail 1.0
ListView { ListView {
@ -33,7 +32,7 @@ ListView {
RowLayout { RowLayout {
height: parent.height height: parent.height
width: height * 3 width: height * 3
Image { ThemeIcon {
id: artUrlImage id: artUrlImage
Layout.fillHeight: true Layout.fillHeight: true
Layout.preferredWidth: artUrlImage.height Layout.preferredWidth: artUrlImage.height
@ -131,7 +130,7 @@ ListView {
mprisModel.operation(mprisView.model.index(index, 0), MprisProperties.Previous, []) mprisModel.operation(mprisView.model.index(index, 0), MprisProperties.Previous, [])
} }
Image { ThemeIcon {
height: 16 height: 16
width: 16 width: 16
anchors.centerIn: parent anchors.centerIn: parent
@ -145,7 +144,7 @@ ListView {
onClicked: { onClicked: {
mprisModel.operation(mprisView.model.index(index, 0), MprisProperties.PlayPause, []) mprisModel.operation(mprisView.model.index(index, 0), MprisProperties.PlayPause, [])
} }
Image { ThemeIcon {
height: 16 height: 16
width: 16 width: 16
anchors.centerIn: parent anchors.centerIn: parent
@ -169,7 +168,7 @@ ListView {
onClicked: { onClicked: {
mprisModel.operation(mprisView.model.index(index, 0), MprisProperties.Next, []) mprisModel.operation(mprisView.model.index(index, 0), MprisProperties.Next, [])
} }
Image { ThemeIcon {
height: 16 height: 16
width: 16 width: 16
anchors.centerIn: parent anchors.centerIn: parent