feat: 添加容器qml组件,添加方向指示属性,插件适配容器方向

This commit is contained in:
hewenfei 2023-09-28 17:47:59 +08:00
parent 153307d33d
commit b6c7ce4a5e
17 changed files with 311 additions and 131 deletions

View File

@ -23,6 +23,7 @@ set(PROJECT_SOURCES
widget/widget-metadata.cpp widget/widget-metadata.h
widget/widget-content.cpp widget/widget-content.h
widget/widget-container.cpp widget/widget-container.h
widget/widget-property.h
widget-ui/widget-item.cpp widget-ui/widget-item.h
widget-ui/widget-item-engine.cpp widget-ui/widget-item-engine.h
widget-ui/widget-item-context.cpp widget-ui/widget-item-context.h

View File

@ -20,6 +20,7 @@ public:
// ====== WidgetContainerItem ====== //
void WidgetContainerItem::registerTypes()
{
WidgetItem::registerTypes();
const char *uri = "org.ukui.panel.container";
qmlRegisterType<WidgetContainerItem>(uri, 1, 0, "WidgetContainerItem");
qmlRegisterUncreatableType<WidgetContainerItemAttached>(uri, 1, 0, "WidgetContainer", "For WidgetContainer attached prop.");

View File

@ -35,6 +35,8 @@ void WidgetItem::registerTypes()
qmlRegisterType<WidgetItem>(uri, 1, 0, "WidgetItem");
// Attached Prop.
qmlRegisterUncreatableType<WidgetItemAttached>(uri, 1, 0, "Widget", "For widgetItem attached prop.");
// enum
qmlRegisterUncreatableType<ContainerProperty>(uri, 1, 0, "ContainerProperty", "For ContainerProperty.");
}
WidgetItem *WidgetItem::itemForWidget(Widget *widget)

View File

@ -16,7 +16,7 @@ public:
QRect geometry;
QMargins margins {0, 0, 0, 0};
WidgetContainer::Orientation orientation {WidgetContainer::LeftToRight};
ContainerProperty::Orientation orientation {ContainerProperty::Horizontal};
// widgets
QVector<Widget *> widgets;
@ -26,7 +26,7 @@ WidgetContainer::WidgetContainer(const QString &appid, const QString &containerI
{
d->appid = appid;
d->containerId = containerId;
qRegisterMetaType<WidgetContainer::Orientation>();
qRegisterMetaType<ContainerProperty::Orientation>("ContainerProperty::Orientation");
qRegisterMetaType<WidgetContainer*>("WidgetContainer*");
}
@ -95,12 +95,12 @@ void WidgetContainer::removeWidget(int index)
Q_EMIT widgetRemoved(widget);
}
WidgetContainer::Orientation WidgetContainer::orientation() const
ContainerProperty::Orientation WidgetContainer::orientation() const
{
return d->orientation;
}
void WidgetContainer::setOrientation(WidgetContainer::Orientation o)
void WidgetContainer::setOrientation(ContainerProperty::Orientation o)
{
if (d->orientation == o) {
return;

View File

@ -6,6 +6,8 @@
#include <QRect>
#include <QMargins>
#include "widget-property.h"
namespace UkuiPanel {
class Widget;
@ -19,14 +21,8 @@ class WidgetContainer : public QObject
Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged FINAL)
Q_PROPERTY(QRect geometry READ geometry NOTIFY geometryChanged FINAL)
Q_PROPERTY(QMargins margins READ margins NOTIFY marginsChanged FINAL)
Q_PROPERTY(WidgetContainer::Orientation orientation READ orientation NOTIFY orientationChanged FINAL)
Q_PROPERTY(ContainerProperty::Orientation orientation READ orientation NOTIFY orientationChanged FINAL)
public:
enum Orientation {
LeftToRight,
TopToBottom
};
Q_ENUM(Orientation)
explicit WidgetContainer(const QString &appid, const QString &containerId, QObject *parent = nullptr);
// prop
@ -42,8 +38,8 @@ public:
QMargins margins() const;
void setMargins(QMargins margins);
WidgetContainer::Orientation orientation() const;
void setOrientation(WidgetContainer::Orientation o);
ContainerProperty::Orientation orientation() const;
void setOrientation(ContainerProperty::Orientation o);
// widgets
void addWidget(Widget *widget);
@ -53,8 +49,8 @@ public:
void removeWidget(Widget *widget);
Q_SIGNALS:
void widgetAdded(Widget *widget);
void widgetRemoved(Widget *widget);
void widgetAdded(UkuiPanel::Widget *widget);
void widgetRemoved(UkuiPanel::Widget *widget);
void visibleChanged();
void geometryChanged();
void marginsChanged();
@ -66,6 +62,4 @@ private:
} // UkuiPanel
Q_DECLARE_METATYPE(UkuiPanel::WidgetContainer::Orientation)
#endif //UKUI_PANEL_WIDGET_CONTAINER_H

View File

@ -0,0 +1,23 @@
#ifndef UKUI_PANEL_WIDGET_PROPERTY_H
#define UKUI_PANEL_WIDGET_PROPERTY_H
#include <QObject>
namespace UkuiPanel {
class ContainerProperty
{
Q_GADGET
public:
enum Orientation {
Vertical,
Horizontal
};
Q_ENUM(Orientation)
};
}
Q_DECLARE_METATYPE(UkuiPanel::ContainerProperty::Orientation)
#endif //UKUI_PANEL_WIDGET_PROPERTY_H

View File

@ -52,6 +52,7 @@ Widget::Widget(const WidgetMetadata& metaData, QObject *parent) : QObject(parent
{
// qDebug() << "load widget, id:" << metaData.id() << "name:" << metaData.name()
// << "authors:" << metaData.authors() << "description:" << metaData.description();
qRegisterMetaType<Widget *>("Widget*");
qRegisterMetaType<WidgetConfig *>("WidgetConfig*");
}
@ -182,5 +183,23 @@ void Widget::setContainer(WidgetContainer *container)
WidgetContainer *old = d->container;
d->container = container;
if (old) {
old->disconnect(this, nullptr);
}
if (d->container) {
connect(d->container, &WidgetContainer::orientationChanged, this, &Widget::orientationChanged);
Q_EMIT orientationChanged();
}
Q_EMIT containerChanged(old ? old->containerId() : "", d->container ? d->container->containerId() : "");
}
ContainerProperty::Orientation Widget::orientation() const
{
if (d->container) {
return d->container->orientation();
}
return ContainerProperty::Horizontal;
}

View File

@ -5,6 +5,7 @@
#include <QObject>
#include "widget-metadata.h"
#include "widget-content.h"
#include "widget-property.h"
namespace UkuiPanel {
@ -30,6 +31,7 @@ class Widget : public QObject
Q_PROPERTY(QString description READ description CONSTANT FINAL)
Q_PROPERTY(QVariantList authors READ authors CONSTANT FINAL)
Q_PROPERTY(WidgetConfig *config READ config CONSTANT FINAL)
Q_PROPERTY(ContainerProperty::Orientation orientation READ orientation NOTIFY orientationChanged FINAL)
public:
explicit Widget(const WidgetMetadata& metaData, QObject *parent=nullptr);
~Widget() override;
@ -48,6 +50,8 @@ public:
QString version() const;
void setVersion(const QString &version);
ContainerProperty::Orientation orientation() const;
QString website() const;
QString bugReport() const;
QString description() const;
@ -71,6 +75,7 @@ Q_SIGNALS:
void nameChanged();
void tooltipChanged();
void versionChanged();
void orientationChanged();
// widget生命周期信号
void widgetDeleted(Widget *widget);

81
panel/qml/Container.qml Normal file
View File

@ -0,0 +1,81 @@
import QtQuick 2.15
import QtQml.Models 2.15
import QtQuick.Layouts 1.15
import org.ukui.panel.widgets 1.0
import org.ukui.panel.container 1.0
WidgetContainerItem {
id: containerItem
property int orientation: WidgetContainer.orientation
onParentChanged: {
anchors.fill = parent
}
WidgetContainer.onWidgetAdded: (widget) => {
let widgetItem = containerItem.widgetItemForWidget(widget);
if (widgetItem == null) {
return;
}
let data = {
widgetItem: widgetItem
};
widgetModel.append(data);
}
ListModel {
id: widgetModel
}
GridLayout {
id: mainLayout
anchors.fill: parent
rows: (containerItem.orientation === ContainerProperty.Horizontal) ? 1 : widgetModel.count
columns: (containerItem.orientation === ContainerProperty.Horizontal) ? widgetModel.count : 1
rowSpacing: 0
columnSpacing: 0
Repeater {
id: repeater
model: widgetModel
delegate: widgetLoaderComponent
}
}
Component {
id: widgetLoaderComponent
Rectangle {
id: widgetParent
color: "#DAE3E6CC"
property int index: model.index
property Item widgetItem: model.widgetItem
Layout.fillWidth: widgetItem && ((containerItem.orientation === ContainerProperty.Horizontal) ? widgetItem.Layout.fillWidth : widgetItem.Layout.fillHeight)
Layout.fillHeight: widgetItem && ((containerItem.orientation === ContainerProperty.Horizontal) ? widgetItem.Layout.fillHeight : widgetItem.Layout.fillWidth)
Layout.minimumWidth: widgetItem ? ((containerItem.orientation === ContainerProperty.Horizontal) ? widgetItem.Layout.minimumWidth : widgetItem.Layout.minimumHeight) : -1
Layout.minimumHeight: widgetItem ? ((containerItem.orientation === ContainerProperty.Horizontal) ? widgetItem.Layout.minimumHeight : widgetItem.Layout.minimumWidth) : -1
Layout.maximumWidth: widgetItem ? ((containerItem.orientation === ContainerProperty.Horizontal) ? widgetItem.Layout.maximumWidth : widgetItem.Layout.maximumHeight) : -1
Layout.maximumHeight: widgetItem ? ((containerItem.orientation === ContainerProperty.Horizontal) ? widgetItem.Layout.maximumHeight : widgetItem.Layout.maximumWidth) : -1
Layout.preferredWidth: widgetItem ?
((containerItem.orientation === ContainerProperty.Horizontal) ? widgetItem.Layout.preferredWidth : widgetItem.Layout.preferredHeight) :
(containerItem.orientation === ContainerProperty.Horizontal) ? mainLayout.height : mainLayout.width
Layout.preferredHeight: widgetItem ?
((containerItem.orientation === ContainerProperty.Horizontal) ? widgetItem.Layout.preferredHeight : widgetItem.Layout.preferredWidth) :
(containerItem.orientation === ContainerProperty.Horizontal) ? mainLayout.height : mainLayout.width
onWidgetItemChanged: {
if (widgetItem) {
widgetItem.parent = widgetParent
widgetItem.anchors.fill = widgetParent
}
}
}
}
}

View File

@ -1,6 +1,4 @@
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Layouts 1.15
RowLayout {
Item {
}

View File

@ -1,5 +1,6 @@
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>Container.qml</file>
</qresource>
</RCC>

View File

@ -4,11 +4,13 @@
#include <QUrl>
#include <windowmanager/windowmanager.h>
#include <KWindowSystem>
#include <QPushButton>
#include "widget.h"
#include "widget-loader.h"
#include "widget-item.h"
#include "widget-config-loader.h"
#include "widget-container-item.h"
#define DEFAULT_PANEL_SIZE 48
static const QString PANEL_SIZE_KEY = QStringLiteral("panelSize");
@ -22,100 +24,34 @@ Panel::Panel(QScreen *screen, const QString &id, QWindow *parent) : SharedEngine
m_id = id;
m_config = ConfigLoader::loadConfig(m_id, "ukui-panel");
connect(m_screen, &QScreen::geometryChanged, this, &Panel::onScreenGeometryChanged);
setColor(Qt::transparent);
setResizeMode(SharedEngineView::SizeRootObjectToView);
setFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
KWindowSystem::setType(this->winId(), NET::Dock);
KWindowSystem::setType(this->winId(), NET::Dock);
kdk::WindowManager::setOnAllDesktops(this->winId());
initGeomtry();
updateGeometry();
const QUrl url(QStringLiteral("qrc:/main.qml"));
setSource(url);
initContainer();
initWidgets();
QPushButton *button = new QPushButton();
button->resize(200, 100);
connect(button, &QPushButton::clicked, this, [this] {
if (m_position == Panel::Bottom) {
setPosition(Panel::Left);
} else {
setPosition(Panel::Bottom);
}
});
button->show();
}
QRect Panel::refreshRect()
{
QRect screenGeometry = m_screen->geometry();
switch (m_position) {
case Bottom:
KWindowSystem::setExtendedStrut(winId(),
/* Left */ 0, 0, 0,
/* Right */ 0, 0, 0,
/* Top */ 0, 0, 0,
/* Bottom */ this->height(), geometry().left(), geometry().right()
);
return screenGeometry.adjusted(0, screenGeometry.height() - this->height(), 0, 0);
case Left:
KWindowSystem::setExtendedStrut(winId(),
/* Left */ this->width(), geometry().top(), geometry().bottom(),
/* Right */ 0, 0, 0,
/* Top */ 0, 0, 0,
/* Bottom */ 0, 0, 0
);
return screenGeometry.adjusted(0, 0, this->width() - screenGeometry.width(), 0);
case Top:
KWindowSystem::setExtendedStrut(winId(),
/* Left */ 0, 0, 0,
/* Right */ 0, 0, 0,
/* Top */ this->height(), geometry().left(), geometry().right(),
/* Bottom */ 0, 0, 0
);
return screenGeometry.adjusted(0, 0, 0, this->height() - screenGeometry.height());
case Right:
KWindowSystem::setExtendedStrut(winId(),
/* Left */ 0, 0, 0,
/* Right */ this->width(), geometry().top(), geometry().bottom(),
/* Top */ 0, 0, 0,
/* Bottom */ 0, 0, 0
);
return screenGeometry.adjusted(screenGeometry.width() - this->width(), 0, 0, 0);
};
}
void Panel::onScreenGeometryChanged(const QRect &geometry)
{
Q_UNUSED(geometry)
kdk::WindowManager::setGeometry(this, refreshRect());
}
void Panel::initWidgets()
{
QStringList loadingWidgets = DEFAULT_LOADING_WIDGETS;
QVariant widgets = m_config->getValue(WIDGETS_KEY);
if(widgets.isNull()) {
m_config->setValue(WIDGETS_KEY, DEFAULT_LOADING_WIDGETS);
} else {
loadingWidgets = widgets.toStringList();
}
if(!m_container) {
m_container = new WidgetContainer("ukui-panel", m_id, this);
}
UkuiPanel::WidgetLoader loader;
for (const auto &id : loadingWidgets) {
UkuiPanel::Widget *widget = loader.loadWidget(id);
if (!widget) {
continue;
}
m_container->addWidget(widget);
UkuiPanel::WidgetItem *widgetItem = UkuiPanel::WidgetItem::itemForWidget(widget);
if (!widgetItem) {
continue;
}
widgetItem->setParentItem(rootObject());
}
}
void Panel::changeScreen(QScreen *screen)
{
disconnect(m_screen, &QScreen::geometryChanged, this, &Panel::onScreenGeometryChanged);
m_screen = screen;
connect(m_screen, &QScreen::geometryChanged, this, &Panel::onScreenGeometryChanged);
initGeomtry();
}
void Panel::initGeomtry()
{
QVariant size = m_config->getValue(PANEL_SIZE_KEY);
int panelSize = DEFAULT_PANEL_SIZE;
@ -125,7 +61,117 @@ void Panel::initGeomtry()
panelSize = size.toInt();
}
resize(m_screen->geometry().width(), panelSize);
kdk::WindowManager::setGeometry(this, refreshRect());
QRect screenGeometry = m_screen->geometry(), panelRect;
switch (m_position) {
case Bottom:
panelRect = screenGeometry.adjusted(0, screenGeometry.height() - panelSize, 0, 0);
KWindowSystem::setExtendedStrut(winId(),
/* Left */ 0, 0, 0,
/* Right */ 0, 0, 0,
/* Top */ 0, 0, 0,
/* Bottom */ panelRect.height(), panelRect.left(), panelRect.right()
);
return panelRect;
case Left:
panelRect = screenGeometry.adjusted(0, 0, panelSize - screenGeometry.width(), 0);
KWindowSystem::setExtendedStrut(winId(),
/* Left */ panelRect.width(), panelRect.top(), panelRect.bottom(),
/* Right */ 0, 0, 0,
/* Top */ 0, 0, 0,
/* Bottom */ 0, 0, 0
);
return panelRect;
case Top:
panelRect = screenGeometry.adjusted(0, 0, 0, panelSize - screenGeometry.height());
KWindowSystem::setExtendedStrut(winId(),
/* Left */ 0, 0, 0,
/* Right */ 0, 0, 0,
/* Top */ panelRect.height(), panelRect.left(), panelRect.right(),
/* Bottom */ 0, 0, 0
);
return panelRect;
case Right:
panelRect = screenGeometry.adjusted(screenGeometry.width() - panelSize, 0, 0, 0);
KWindowSystem::setExtendedStrut(winId(),
/* Left */ 0, 0, 0,
/* Right */ panelRect.width(), panelRect.top(), panelRect.bottom(),
/* Top */ 0, 0, 0,
/* Bottom */ 0, 0, 0
);
return panelRect;
}
}
void Panel::onScreenGeometryChanged(const QRect &geometry)
{
Q_UNUSED(geometry)
updateGeometry();
}
void Panel::initWidgets()
{
if (!m_container) {
return;
}
QStringList loadingWidgets = DEFAULT_LOADING_WIDGETS;
QVariant widgets = m_config->getValue(WIDGETS_KEY);
if(widgets.isNull()) {
m_config->setValue(WIDGETS_KEY, DEFAULT_LOADING_WIDGETS);
} else {
loadingWidgets = widgets.toStringList();
}
WidgetLoader loader;
for (const auto &id : loadingWidgets) {
auto widget = loader.loadWidget(id);
if (widget) {
m_container->addWidget(widget);
}
}
}
void Panel::changeScreen(QScreen *screen)
{
disconnect(m_screen, &QScreen::geometryChanged, this, &Panel::onScreenGeometryChanged);
m_screen = screen;
connect(m_screen, &QScreen::geometryChanged, this, &Panel::onScreenGeometryChanged);
updateGeometry();
}
void Panel::updateGeometry()
{
QRect rect = refreshRect();
setGeometry(rect);
kdk::WindowManager::setGeometry(this, rect);
}
void Panel::initContainer()
{
m_container = new WidgetContainer("ukui-panel", m_id, this);
m_container->setOrientation(ContainerProperty::Horizontal);
auto item = UkuiPanel::WidgetContainerItem::loadContainerItem(QUrl("qrc:///Container.qml"), m_container);
item->setParent(rootObject());
item->setParentItem(rootObject());
}
void Panel::setPosition(Panel::Position position)
{
if (position == m_position) {
return;
}
m_position = position;
updateGeometry();
if (m_container) {
if (m_position == Left || m_position == Right) {
m_container->setOrientation(ContainerProperty::Vertical);
} else {
m_container->setOrientation(ContainerProperty::Horizontal);
}
}
}
} // UkuiPanel

View File

@ -27,10 +27,13 @@ public:
private Q_SLOTS:
void onScreenGeometryChanged(const QRect &geometry);
void setPosition(Panel::Position position);
private:
QRect refreshRect();
void initContainer();
void initWidgets();
void initGeomtry();
void updateGeometry();
QScreen *m_screen = nullptr;
Position m_position = Bottom;

View File

@ -5,19 +5,19 @@ import org.ukui.panel.widgets 1.0
import org.ukui.menu.starter 1.0
WidgetItem {
width: 50
height: 50
id: root
Layout.objectName: "layout"
Layout.fillHeight: true
Layout.minimumHeight: height
Layout.preferredHeight: height
Layout.preferredWidth: width
Layout.preferredWidth: height
Rectangle {
anchors.fill: parent
radius: height / 2
color: "lightblue"
Image {
anchors.centerIn: parent
width: parent.height - 8
height: parent.height - 8
smooth: true
source: "file:///usr/share/icons/ukui-icon-theme-default/scalable/apps/kylin-startmenu.svg"
}
MouseArea {

View File

@ -5,16 +5,23 @@ import org.ukui.panel.widgets 1.0
import org.ukui.menu.starter 1.0
WidgetItem {
width: 600
height: 600
Layout.objectName: "layout"
Layout.fillHeight: true
Layout.minimumHeight: height
Layout.preferredHeight: height
Layout.preferredWidth: width
Layout.preferredWidth: 200
BlurImageTest {
// BlurImageTest {
// anchors.fill: parent
// }
Rectangle {
anchors.fill: parent
color: "#407D52BF"
DropArea {
anchors.fill: parent
onDropped: (drop) => {
console.log("drop:", drop.urls, drop.text);
}
}
}
}

View File

@ -32,8 +32,7 @@ ListView {
property int dragStartIndex: 0
property bool isBusy: false
property bool dragIsContain: true
property int itemSize: 32
height: itemSize
property int itemSize: (orientation == ListView.Horizontal) ? height : width
spacing: 16
interactive: false
@ -108,10 +107,10 @@ ListView {
ThemeIcon {
id: icon
width: baseView.itemSize
height: baseView.itemSize
source: model.Icon
width: baseView.itemSize - 8
height: baseView.itemSize - 8
anchors.centerIn: parent
source: model.Icon
}
MouseArea {

View File

@ -29,11 +29,11 @@ WidgetItem {
Layout.objectName: "layout"
Layout.fillHeight: true
Layout.minimumHeight: height
Layout.preferredHeight: height
Layout.preferredWidth: width
Layout.fillWidth: true
TaskManagerView {
width: childrenRect.width
orientation: (Widget.orientation == ContainerProperty.Horizontal) ? ListView.Horizontal : ListView.Vertical
height: (Widget.orientation == ContainerProperty.Horizontal) ? parent.height : childrenRect.height
width: (Widget.orientation == ContainerProperty.Horizontal) ? childrenRect.width : parent.width
}
}