feat: 快捷设置面板功能
完成快捷设置面板加载插件,显示插件,完成快捷设置的插件的接口 Log: 完成快捷设置面板的基本功能 Influence: v23任务栏快捷设置面板 Task: https://pms.uniontech.com/task-view-110309.html Change-Id: Idaf5c50f8f447d684646afd3ed0fa3e42a94f83c
@ -64,6 +64,7 @@ include_directories(
|
||||
frame/item
|
||||
frame/item/components
|
||||
frame/item/resources
|
||||
frame/model
|
||||
frame/util
|
||||
frame/window
|
||||
frame/window/components
|
||||
@ -77,6 +78,7 @@ aux_source_directory(frame/dbus DBUS)
|
||||
aux_source_directory(frame/dbus/sni SNI)
|
||||
aux_source_directory(frame/display DISPLAY)
|
||||
aux_source_directory(frame/item ITEM)
|
||||
aux_source_directory(frame/model MODEL)
|
||||
aux_source_directory(frame/item/components ITEMCOMPONENTS)
|
||||
aux_source_directory(frame/item/resources RESOURCES)
|
||||
aux_source_directory(frame/util UTIL)
|
||||
@ -91,6 +93,7 @@ file(GLOB SRC_PATH
|
||||
${SNI}
|
||||
${DISPLAY}
|
||||
${ITEM}
|
||||
${MODEL}
|
||||
${ITEMCOMPONENTS}
|
||||
${UTIL}
|
||||
${WINDOW}
|
||||
|
@ -51,6 +51,7 @@ target_include_directories(${BIN_NAME} PUBLIC
|
||||
display
|
||||
item
|
||||
item/components
|
||||
model
|
||||
util
|
||||
window
|
||||
window/components
|
||||
|
72
frame/controller/quicksettingcontroller.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
#include "quicksettingcontroller.h"
|
||||
#include "quicksettingitem.h"
|
||||
|
||||
QuickSettingController::QuickSettingController(QObject *parent)
|
||||
: AbstractPluginsController(parent)
|
||||
{
|
||||
// 异步加载本地插件
|
||||
QMetaObject::invokeMethod(this, &QuickSettingController::startLoader, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
QuickSettingController::~QuickSettingController()
|
||||
{
|
||||
}
|
||||
|
||||
void QuickSettingController::itemAdded(PluginsItemInterface * const itemInter, const QString &itemKey)
|
||||
{
|
||||
QList<QuickSettingItem *>::iterator findItemIterator = std::find_if(m_quickSettingItems.begin(), m_quickSettingItems.end(),
|
||||
[ = ](QuickSettingItem *item) {
|
||||
return item->itemKey() == itemKey;
|
||||
});
|
||||
|
||||
if (findItemIterator != m_quickSettingItems.end())
|
||||
return;
|
||||
|
||||
QuickSettingItem *quickItem = new QuickSettingItem(itemInter, itemKey);
|
||||
|
||||
m_quickSettingItems << quickItem;
|
||||
|
||||
emit pluginInsert(quickItem);
|
||||
}
|
||||
|
||||
void QuickSettingController::itemUpdate(PluginsItemInterface * const itemInter, const QString &)
|
||||
{
|
||||
auto findItemIterator = std::find_if(m_quickSettingItems.begin(), m_quickSettingItems.end(),
|
||||
[ = ](QuickSettingItem *item) {
|
||||
return item->pluginItem() == itemInter;
|
||||
});
|
||||
if (findItemIterator != m_quickSettingItems.end()) {
|
||||
QuickSettingItem *settingItem = *findItemIterator;
|
||||
settingItem->update();
|
||||
}
|
||||
}
|
||||
|
||||
void QuickSettingController::itemRemoved(PluginsItemInterface * const itemInter, const QString &)
|
||||
{
|
||||
// 删除本地记录的插件列表
|
||||
QList<QuickSettingItem *>::iterator findItemIterator = std::find_if(m_quickSettingItems.begin(), m_quickSettingItems.end(),
|
||||
[ = ](QuickSettingItem *item) {
|
||||
return (item->pluginItem() == itemInter);
|
||||
});
|
||||
if (findItemIterator != m_quickSettingItems.end()) {
|
||||
QuickSettingItem *quickItem = *findItemIterator;
|
||||
m_quickSettingItems.removeOne(quickItem);
|
||||
Q_EMIT pluginRemove(quickItem);
|
||||
quickItem->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
QuickSettingController *QuickSettingController::instance()
|
||||
{
|
||||
static QuickSettingController instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
void QuickSettingController::startLoader()
|
||||
{
|
||||
QString pluginsDir("../plugins/quick-trays");
|
||||
if (!QDir(pluginsDir).exists())
|
||||
pluginsDir = "/usr/lib/dde-dock/plugins/quick-trays";
|
||||
|
||||
AbstractPluginsController::startLoader(new PluginLoader(pluginsDir, this));
|
||||
}
|
37
frame/controller/quicksettingcontroller.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef QUICKSETTINGCONTROLLER_H
|
||||
#define QUICKSETTINGCONTROLLER_H
|
||||
|
||||
#include "abstractpluginscontroller.h"
|
||||
|
||||
class QuickSettingItem;
|
||||
|
||||
class QuickSettingController : public AbstractPluginsController
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static QuickSettingController *instance();
|
||||
const QList<QuickSettingItem *> &settingItems() const { return m_quickSettingItems; }
|
||||
|
||||
Q_SIGNALS:
|
||||
void pluginInsert(QuickSettingItem *);
|
||||
void pluginRemove(QuickSettingItem *);
|
||||
|
||||
protected:
|
||||
void startLoader();
|
||||
QuickSettingController(QObject *parent = Q_NULLPTR);
|
||||
~QuickSettingController() override;
|
||||
|
||||
protected:
|
||||
void itemAdded(PluginsItemInterface * const itemInter, const QString &itemKey) override;
|
||||
void itemUpdate(PluginsItemInterface * const itemInter, const QString &) override;
|
||||
void itemRemoved(PluginsItemInterface * const itemInter, const QString &) override;
|
||||
void requestWindowAutoHide(PluginsItemInterface * const, const QString &, const bool) override {}
|
||||
void requestRefreshWindowVisible(PluginsItemInterface * const, const QString &) override {}
|
||||
void requestSetAppletVisible(PluginsItemInterface * const, const QString &, const bool) override {}
|
||||
|
||||
private:
|
||||
QList<QuickSettingItem *> m_quickSettingItems;
|
||||
};
|
||||
|
||||
#endif // CONTAINERPLUGINSCONTROLLER_H
|
@ -27,10 +27,13 @@
|
||||
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
|
||||
AppDrag::AppDrag(QObject *dragSource)
|
||||
AppDrag::AppDrag(QObject *dragSource, AppDragWidget *dragWidget)
|
||||
: QDrag(dragSource)
|
||||
, m_appDragWidget(new AppDragWidget)
|
||||
, m_appDragWidget(dragWidget)
|
||||
{
|
||||
if (!m_appDragWidget)
|
||||
m_appDragWidget = new AppDragWidget;
|
||||
|
||||
// delete by itself
|
||||
m_appDragWidget->setVisible(false);
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
class AppDrag : public QDrag
|
||||
{
|
||||
public:
|
||||
explicit AppDrag(QObject *dragSource);
|
||||
explicit AppDrag(QObject *dragSource, AppDragWidget *dragWidget = Q_NULLPTR);
|
||||
virtual ~AppDrag();
|
||||
|
||||
void setPixmap(const QPixmap &);
|
||||
|
@ -431,3 +431,43 @@ void AppDragWidget::moveEvent(QMoveEvent *event)
|
||||
Q_UNUSED(event);
|
||||
showRemoveTips();
|
||||
}
|
||||
|
||||
QuickDragWidget::QuickDragWidget(QWidget *parent)
|
||||
: AppDragWidget(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QuickDragWidget::~QuickDragWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void QuickDragWidget::dropEvent(QDropEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
m_followMouseTimer->stop();
|
||||
m_bDragDrop = false;
|
||||
|
||||
if (isRemoveAble(QCursor::pos())) {
|
||||
if (DWindowManagerHelper::instance()->hasComposite())
|
||||
showRemoveAnimation();
|
||||
else
|
||||
hide();
|
||||
|
||||
m_popupWindow->setVisible(false);
|
||||
} else {
|
||||
if (DWindowManagerHelper::instance()->hasComposite())
|
||||
showGoBackAnimation();
|
||||
else
|
||||
hide();
|
||||
|
||||
Q_EMIT requestDropItem();
|
||||
}
|
||||
}
|
||||
|
||||
void QuickDragWidget::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
AppDragWidget::dragMoveEvent(event);
|
||||
requestDragMove(event);
|
||||
}
|
||||
|
@ -81,6 +81,7 @@ private:
|
||||
class AppDragWidget : public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AppDragWidget(QWidget *parent = Q_NULLPTR);
|
||||
|
||||
@ -118,7 +119,7 @@ private:
|
||||
private Q_SLOTS:
|
||||
void onFollowMouse();
|
||||
|
||||
private:
|
||||
protected:
|
||||
QScopedPointer<AppGraphicsObject> m_object;
|
||||
QGraphicsScene *m_scene;
|
||||
QTimer *m_followMouseTimer;
|
||||
@ -144,4 +145,21 @@ private:
|
||||
DockItem *m_item;
|
||||
};
|
||||
|
||||
class QuickDragWidget : public AppDragWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_SIGNALS:
|
||||
void requestDropItem();
|
||||
void requestDragMove(QDragMoveEvent *event);
|
||||
|
||||
public:
|
||||
explicit QuickDragWidget(QWidget *parent = Q_NULLPTR);
|
||||
~QuickDragWidget() override;
|
||||
|
||||
protected:
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
void dragMoveEvent(QDragMoveEvent *event) override;
|
||||
};
|
||||
|
||||
#endif /* APPDRAGWIDGET_H */
|
||||
|
@ -46,6 +46,7 @@ public:
|
||||
FixedPlugin,
|
||||
Placeholder,
|
||||
TrayPlugin,
|
||||
QuickSettingPlugin
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -67,5 +67,23 @@
|
||||
<file>resources/week5.svg</file>
|
||||
<file>resources/week6.svg</file>
|
||||
<file>resources/week7.svg</file>
|
||||
<file>resources/brightnesshigh.svg</file>
|
||||
<file>resources/brightnesslow.svg</file>
|
||||
<file>resources/audio-volume-high-dark.svg</file>
|
||||
<file>resources/audio-volume-high.svg</file>
|
||||
<file>resources/audio-volume-low-dark.svg</file>
|
||||
<file>resources/audio-volume-low.svg</file>
|
||||
<file>resources/audio-volume-medium.svg</file>
|
||||
<file>resources/audio-volume-muted-dark.svg</file>
|
||||
<file>resources/audio-volume-muted.svg</file>
|
||||
<file>resources/audio-volume-medium-dark.svg</file>
|
||||
<file>resources/brightness.svg</file>
|
||||
<file>resources/laptop.svg</file>
|
||||
<file>resources/volume.svg</file>
|
||||
<file>resources/broadcast.svg</file>
|
||||
<file>resources/ICON_Device_Headphone_dark.svg</file>
|
||||
<file>resources/ICON_Device_Headphone.svg</file>
|
||||
<file>resources/ICON_Device_Laptop_dark.svg</file>
|
||||
<file>resources/ICON_Device_Laptop.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@ -318,3 +318,29 @@ void PluginsItem::setDraging(bool bDrag)
|
||||
|
||||
m_centralWidget->setVisible(!bDrag);
|
||||
}
|
||||
|
||||
PluginsItemInterface *PluginsItem::pluginItem() const
|
||||
{
|
||||
return m_pluginInter;
|
||||
}
|
||||
|
||||
StretchPluginsItem::StretchPluginsItem(PluginsItemInterface * const pluginInter, const QString &itemKey, const QString &plginApi, QWidget *parent)
|
||||
: PluginsItem (pluginInter, itemKey, plginApi, parent)
|
||||
, m_nameLabel(new QLabel(this))
|
||||
{
|
||||
m_nameLabel->setText(pluginInter->pluginDisplayName());
|
||||
m_nameLabel->setAlignment(Qt::AlignCenter);
|
||||
QBoxLayout *mainLayout = static_cast<QHBoxLayout *>(layout());
|
||||
mainLayout->setDirection(QBoxLayout::Direction::TopToBottom);
|
||||
mainLayout->addWidget(m_nameLabel);
|
||||
}
|
||||
|
||||
StretchPluginsItem::~StretchPluginsItem()
|
||||
{
|
||||
}
|
||||
|
||||
void StretchPluginsItem::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
m_nameLabel->setVisible(height() >= 30);
|
||||
PluginsItem::resizeEvent(event);
|
||||
}
|
||||
|
@ -51,6 +51,8 @@ public:
|
||||
|
||||
virtual void setDraging(bool bDrag) override;
|
||||
|
||||
PluginsItemInterface *pluginItem() const;
|
||||
|
||||
public slots:
|
||||
void refreshIcon() override;
|
||||
|
||||
@ -89,4 +91,19 @@ private:
|
||||
const QGSettings *m_gsettings;
|
||||
};
|
||||
|
||||
class StretchPluginsItem : public PluginsItem
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
StretchPluginsItem(PluginsItemInterface *const pluginInter, const QString &itemKey, const QString &plginApi, QWidget *parent = nullptr);
|
||||
~StretchPluginsItem() override;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
QLabel *m_nameLabel;
|
||||
};
|
||||
|
||||
#endif // PLUGINSITEM_H
|
||||
|
215
frame/item/quicksettingitem.cpp
Normal file
@ -0,0 +1,215 @@
|
||||
#include "quicksettingitem.h"
|
||||
#include "pluginsiteminterface.h"
|
||||
|
||||
#include <DGuiApplicationHelper>
|
||||
#include <DFontSizeManager>
|
||||
|
||||
#include <QIcon>
|
||||
#include <QPainterPath>
|
||||
|
||||
#define ICONWIDTH 24
|
||||
#define ICONHEIGHT 24
|
||||
#define ICONSPACE 10
|
||||
#define RADIUS 8
|
||||
#define FONTSIZE 10
|
||||
|
||||
#define BGWIDTH 128
|
||||
#define BGSIZE 36
|
||||
#define OPENICONSIZE 12
|
||||
static QSize expandSize = QSize(6, 10);
|
||||
|
||||
QuickSettingItem::QuickSettingItem(PluginsItemInterface *const pluginInter, const QString &itemKey, QWidget *parent)
|
||||
: DockItem(parent)
|
||||
, m_pluginInter(pluginInter)
|
||||
, m_itemKey(itemKey)
|
||||
{
|
||||
setAcceptDrops(true);
|
||||
this->installEventFilter(this);
|
||||
}
|
||||
|
||||
QuickSettingItem::~QuickSettingItem()
|
||||
{
|
||||
}
|
||||
|
||||
PluginsItemInterface *QuickSettingItem::pluginItem() const
|
||||
{
|
||||
return m_pluginInter;
|
||||
}
|
||||
|
||||
DockItem::ItemType QuickSettingItem::itemType() const
|
||||
{
|
||||
return DockItem::QuickSettingPlugin;
|
||||
}
|
||||
|
||||
const QPixmap QuickSettingItem::dragPixmap()
|
||||
{
|
||||
QPixmap pm = m_pluginInter->icon()->pixmap(ICONWIDTH, ICONHEIGHT);
|
||||
|
||||
QPainter pa(&pm);
|
||||
pa.setPen(foregroundColor());
|
||||
pa.setCompositionMode(QPainter::CompositionMode_SourceIn);
|
||||
pa.fillRect(pm.rect(), foregroundColor());
|
||||
|
||||
QPixmap pmRet(ICONWIDTH + ICONSPACE + FONTSIZE * 2, ICONHEIGHT + ICONSPACE + FONTSIZE * 2);
|
||||
pmRet.fill(Qt::transparent);
|
||||
QPainter paRet(&pmRet);
|
||||
paRet.drawPixmap(QPoint((ICONSPACE + FONTSIZE * 2) / 2, 0), pm);
|
||||
paRet.setPen(pa.pen());
|
||||
|
||||
QFont ft;
|
||||
ft.setPixelSize(FONTSIZE);
|
||||
paRet.setFont(ft);
|
||||
QTextOption option;
|
||||
option.setAlignment(Qt::AlignTop | Qt::AlignHCenter);
|
||||
paRet.drawText(QRect(QPoint(0, ICONHEIGHT + ICONSPACE),
|
||||
QPoint(pmRet.width(), pmRet.height())), m_pluginInter->pluginDisplayName(), option);
|
||||
return pmRet;
|
||||
}
|
||||
|
||||
const QString QuickSettingItem::itemKey() const
|
||||
{
|
||||
return m_itemKey;
|
||||
}
|
||||
|
||||
void QuickSettingItem::paintEvent(QPaintEvent *e)
|
||||
{
|
||||
QWidget::paintEvent(e);
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::RenderHint::Antialiasing);
|
||||
painter.setPen(foregroundColor());
|
||||
QPainterPath path;
|
||||
path.addRoundedRect(rect(), RADIUS, RADIUS);
|
||||
painter.setClipPath(path);
|
||||
|
||||
// 绘制背景色
|
||||
painter.fillRect(rect(), backgroundColor());
|
||||
// 让图标填上前景色
|
||||
QPixmap pm = m_pluginInter->icon()->pixmap(ICONWIDTH, ICONHEIGHT);
|
||||
QPainter pa(&pm);
|
||||
pa.setCompositionMode(QPainter::CompositionMode_SourceIn);
|
||||
pa.fillRect(pm.rect(), painter.pen().brush());
|
||||
if (m_pluginInter->isPrimary()) {
|
||||
// 如果是主图标,则显示阴影背景
|
||||
int marginXSpace = xMarginSpace();
|
||||
int marginYSpace = yMarginSpace();
|
||||
QRect iconBg(marginXSpace, marginYSpace, BGSIZE, BGSIZE);
|
||||
painter.save();
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.setBrush(shadowColor());
|
||||
painter.drawEllipse(iconBg);
|
||||
painter.restore();
|
||||
QRect rctIcon(iconBg.x() + (iconBg.width() - ICONWIDTH) / 2,
|
||||
iconBg.y() + (iconBg.height() - ICONHEIGHT) / 2,
|
||||
ICONWIDTH, ICONHEIGHT);
|
||||
painter.drawPixmap(rctIcon, pm);
|
||||
// 绘制文字
|
||||
painter.setPen(QColor(0, 0, 0));
|
||||
|
||||
QRect rctPluginName(iconBg.right() + 10, iconBg.top(), BGWIDTH - BGSIZE - OPENICONSIZE - 10 * 2, BGSIZE / 2);
|
||||
QFont font = DFontSizeManager::instance()->t6();
|
||||
font.setBold(true);
|
||||
painter.setFont(font);
|
||||
QTextOption textOption;
|
||||
textOption.setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||||
QString displayName = QFontMetrics(font).elidedText(m_pluginInter->pluginDisplayName(), Qt::TextElideMode::ElideRight, rctPluginName.width());
|
||||
QFontMetrics fm(font);
|
||||
painter.drawText(rctPluginName, displayName, textOption);
|
||||
// 绘制下方啊的状态文字
|
||||
QRect rctPluginStatus(rctPluginName.x(), rctPluginName.bottom() + 1,
|
||||
rctPluginName.width(), BGSIZE / 2);
|
||||
font = DFontSizeManager::instance()->t10();
|
||||
painter.setFont(font);
|
||||
QString description = QFontMetrics(font).elidedText(m_pluginInter->description(), Qt::TextElideMode::ElideRight, rctPluginStatus.width());
|
||||
painter.drawText(rctPluginStatus, description, textOption);
|
||||
// 绘制右侧的展开按钮
|
||||
QPen pen;
|
||||
pen.setColor(QColor(0, 0, 0));
|
||||
pen.setWidth(2);
|
||||
painter.setPen(pen);
|
||||
int iconLeft = rect().width() - marginXSpace - expandSize.width();
|
||||
int iconRight = rect().width() - marginXSpace;
|
||||
painter.drawLine(QPoint(iconLeft, (rctIcon.y() + (rctIcon.height() - expandSize.height()) / 2)),
|
||||
QPoint(iconRight, (rctIcon.y() + rctIcon.height() / 2)));
|
||||
painter.drawLine(QPoint(iconRight, (rctIcon.y() + rctIcon.height() / 2)),
|
||||
QPoint(iconLeft, (rctIcon.y() + (rctIcon.height() + expandSize.height()) / 2)));
|
||||
} else {
|
||||
// 绘制图标
|
||||
QRect rctIcon = iconRect();
|
||||
painter.drawPixmap(rctIcon, pm);
|
||||
// 绘制文字
|
||||
QFont ft;
|
||||
ft.setPixelSize(FONTSIZE);
|
||||
painter.setFont(ft);
|
||||
QTextOption option;
|
||||
option.setAlignment(Qt::AlignTop | Qt::AlignHCenter);
|
||||
painter.drawText(QRect(QPoint(0, rctIcon.top() + ICONHEIGHT + ICONSPACE),
|
||||
QPoint(width(), height())), m_pluginInter->pluginDisplayName(), option);
|
||||
}
|
||||
}
|
||||
|
||||
QRect QuickSettingItem::iconRect()
|
||||
{
|
||||
int left = (width() - ICONWIDTH) / 2;
|
||||
int top = (height() - ICONHEIGHT - ICONSPACE - 10) / 2;
|
||||
return QRect(left, top, ICONWIDTH, ICONHEIGHT);
|
||||
}
|
||||
|
||||
QColor QuickSettingItem::foregroundColor() const
|
||||
{
|
||||
// 此处的颜色是临时获取的,后期需要和设计师确认,改成正规的颜色
|
||||
if (m_pluginInter->status() == PluginsItemInterface::PluginStatus::Active)
|
||||
return QColor(0, 129, 255);
|
||||
|
||||
if (m_pluginInter->status() == PluginsItemInterface::PluginStatus::Deactive)
|
||||
return QColor(51, 51, 51);
|
||||
|
||||
return QColor(181, 181, 181);
|
||||
}
|
||||
|
||||
QColor QuickSettingItem::backgroundColor() const
|
||||
{
|
||||
// 此处的颜色是临时获取的,后期需要和设计师确认,改成正规的颜色
|
||||
if (m_pluginInter->status() == PluginsItemInterface::PluginStatus::Active)
|
||||
return QColor(250, 250, 252);
|
||||
|
||||
return QColor(241, 241, 246);
|
||||
}
|
||||
|
||||
QColor QuickSettingItem::shadowColor() const
|
||||
{
|
||||
// 此处的颜色是临时获取的,后期需要和设计师确认,改成正规的颜色
|
||||
if (m_pluginInter->status() == PluginsItemInterface::PluginStatus::Active)
|
||||
return QColor(217, 219, 226);
|
||||
|
||||
return QColor(199, 203, 222);
|
||||
}
|
||||
|
||||
void QuickSettingItem::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
// 如果是鼠标的按下事件
|
||||
if (m_pluginInter->isPrimary()) {
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
QRect rctExpand(rect().width() - xMarginSpace() - expandSize.width(),
|
||||
(rect().height() - expandSize.height()) / 2,
|
||||
expandSize.width(), expandSize.height());
|
||||
if (rctExpand.contains(mapFromGlobal(mouseEvent->globalPos())))
|
||||
Q_EMIT detailClicked(m_pluginInter);
|
||||
} else {
|
||||
const QString command = m_pluginInter->itemCommand(m_itemKey);
|
||||
if (!command.isEmpty())
|
||||
QProcess::startDetached(command);
|
||||
|
||||
if (QWidget *w = m_pluginInter->itemPopupApplet(m_itemKey))
|
||||
showPopupApplet(w);
|
||||
}
|
||||
}
|
||||
|
||||
int QuickSettingItem::xMarginSpace()
|
||||
{
|
||||
return (rect().width() - BGWIDTH) / 2;
|
||||
}
|
||||
|
||||
int QuickSettingItem::yMarginSpace()
|
||||
{
|
||||
return (rect().height() - BGSIZE) / 2;
|
||||
}
|
44
frame/item/quicksettingitem.h
Normal file
@ -0,0 +1,44 @@
|
||||
#ifndef QUICKSETTINGITEM_H
|
||||
#define QUICKSETTINGITEM_H
|
||||
|
||||
#include "dockitem.h"
|
||||
|
||||
class PluginsItemInterface;
|
||||
|
||||
class QuickSettingItem : public DockItem
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class QuickSettingController;
|
||||
|
||||
Q_SIGNALS:
|
||||
void detailClicked(PluginsItemInterface *);
|
||||
|
||||
public:
|
||||
PluginsItemInterface *pluginItem() const;
|
||||
ItemType itemType() const override;
|
||||
const QPixmap dragPixmap();
|
||||
const QString itemKey() const;
|
||||
|
||||
protected:
|
||||
QuickSettingItem(PluginsItemInterface *const pluginInter, const QString &itemKey, QWidget *parent = nullptr);
|
||||
~QuickSettingItem() override;
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
QRect iconRect();
|
||||
QColor foregroundColor() const;
|
||||
QColor backgroundColor() const;
|
||||
QColor shadowColor() const;
|
||||
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
|
||||
private:
|
||||
int xMarginSpace();
|
||||
int yMarginSpace();
|
||||
|
||||
private:
|
||||
PluginsItemInterface *m_pluginInter;
|
||||
QString m_itemKey;
|
||||
};
|
||||
|
||||
#endif // QUICKSETTINGITEM_H
|
17
frame/item/resources/ICON_Device_Headphone.svg
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>-mockplus-</title>
|
||||
<g id="任务栏" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="任务栏-其他插件" transform="translate(-43.000000, -222.000000)" fill="#FFFFFF" fill-rule="nonzero">
|
||||
<g id="声音" transform="translate(23.000000, 50.000000)">
|
||||
<g id="-mockplus-" transform="translate(10.000000, 162.000000)">
|
||||
<g id="-mockplus-" transform="translate(10.000000, 10.000000)">
|
||||
<g id="ICON" transform="translate(1.000000, 1.500000)">
|
||||
<path d="M7,0 C10.7854517,0 13.8690987,3.00478338 13.995941,6.75935025 L14,7 L14,9.5 C14,9.77614237 13.7761424,10 13.5,10 C13.2545401,10 13.0503916,9.82312484 13.0080557,9.58987563 L13,9.5 L13,7 C13,3.6862915 10.3137085,1 7,1 C3.76160306,1 1.12242824,3.56557489 1.00413847,6.77506174 L1,7 L1,9.5 C1,9.77614237 0.776142375,10 0.5,10 C0.254540111,10 0.0503916296,9.82312484 0.00805566941,9.58987563 L0,9.5 L0,7 C0,3.13400675 3.13400675,0 7,0 Z M3.5,7 C4.32842712,7 5,7.67157288 5,8.5 L5,11.5 C5,12.3284271 4.32842712,13 3.5,13 C2.67157288,13 2,12.3284271 2,11.5 L2,8.5 C2,7.67157288 2.67157288,7 3.5,7 Z M10.5,7 C11.3284271,7 12,7.67157288 12,8.5 L12,11.5 C12,12.3284271 11.3284271,13 10.5,13 C9.67157288,13 9,12.3284271 9,11.5 L9,8.5 C9,7.67157288 9.67157288,7 10.5,7 Z" id="形状结合"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
17
frame/item/resources/ICON_Device_Headphone_dark.svg
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>-mockplus-</title>
|
||||
<g id="任务栏" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="任务栏-其他插件" transform="translate(-34.000000, -680.000000)" fill="#000000" fill-rule="nonzero">
|
||||
<g id="蓝牙" transform="translate(14.000000, 580.000000)">
|
||||
<g id="-mockplus-" transform="translate(10.000000, 90.000000)">
|
||||
<g id="-mockplus-" transform="translate(10.000000, 10.000000)">
|
||||
<g id="ICON" transform="translate(1.000000, 1.500000)">
|
||||
<path d="M7,0 C10.7854517,0 13.8690987,3.00478338 13.995941,6.75935025 L14,7 L14,9.5 C14,9.77614237 13.7761424,10 13.5,10 C13.2545401,10 13.0503916,9.82312484 13.0080557,9.58987563 L13,9.5 L13,7 C13,3.6862915 10.3137085,1 7,1 C3.76160306,1 1.12242824,3.56557489 1.00413847,6.77506174 L1,7 L1,9.5 C1,9.77614237 0.776142375,10 0.5,10 C0.254540111,10 0.0503916296,9.82312484 0.00805566941,9.58987563 L0,9.5 L0,7 C0,3.13400675 3.13400675,0 7,0 Z M3.5,7 C4.32842712,7 5,7.67157288 5,8.5 L5,11.5 C5,12.3284271 4.32842712,13 3.5,13 C2.67157288,13 2,12.3284271 2,11.5 L2,8.5 C2,7.67157288 2.67157288,7 3.5,7 Z M10.5,7 C11.3284271,7 12,7.67157288 12,8.5 L12,11.5 C12,12.3284271 11.3284271,13 10.5,13 C9.67157288,13 9,12.3284271 9,11.5 L9,8.5 C9,7.67157288 9.67157288,7 10.5,7 Z" id="形状结合"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
17
frame/item/resources/ICON_Device_Laptop.svg
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>-mockplus-</title>
|
||||
<g id="任务栏" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="任务栏-其他插件" transform="translate(-393.000000, -176.000000)" fill="#000000" fill-rule="nonzero">
|
||||
<g id="声音" transform="translate(373.000000, 50.000000)">
|
||||
<g id="-mockplus-" transform="translate(10.000000, 116.000000)">
|
||||
<g id="-mockplus-" transform="translate(10.000000, 10.000000)">
|
||||
<g id="ICON" transform="translate(0.000000, 2.000000)">
|
||||
<path d="M13,0 C14.1045695,-2.02906125e-16 15,0.8954305 15,2 L15,10 L15.5,10 C15.7761424,10 16,10.2238576 16,10.5 C16,10.7761424 15.7761424,11 15.5,11 L0.5,11 C0.223857625,11 3.38176876e-17,10.7761424 0,10.5 C-3.38176876e-17,10.2238576 0.223857625,10 0.5,10 L1,10 L1,2 C1,0.8954305 1.8954305,2.02906125e-16 3,0 L13,0 Z M13,0.999999998 L3,0.999999998 C2.44771525,0.999999998 2,1.44771525 2,2 L2,2 L2,8 C2,8.55228475 2.44771525,9 3,9 L3,9 L13,9 C13.5522847,9 14,8.55228475 14,8 L14,8 L14,2 C14,1.44771525 13.5522847,0.999999998 13,0.999999998 L13,0.999999998 Z" id="形状结合"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
17
frame/item/resources/ICON_Device_Laptop_dark.svg
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>-mockplus-</title>
|
||||
<g id="任务栏" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="任务栏-其他插件" transform="translate(-43.000000, -176.000000)" fill="#000000" fill-rule="nonzero">
|
||||
<g id="声音" transform="translate(23.000000, 50.000000)">
|
||||
<g id="-mockplus-" transform="translate(10.000000, 116.000000)">
|
||||
<g id="-mockplus-" transform="translate(10.000000, 10.000000)">
|
||||
<g id="ICON" transform="translate(0.000000, 2.000000)">
|
||||
<path d="M13,0 C14.1045695,-2.02906125e-16 15,0.8954305 15,2 L15,10 L15.5,10 C15.7761424,10 16,10.2238576 16,10.5 C16,10.7761424 15.7761424,11 15.5,11 L0.5,11 C0.223857625,11 3.38176876e-17,10.7761424 0,10.5 C-3.38176876e-17,10.2238576 0.223857625,10 0.5,10 L1,10 L1,2 C1,0.8954305 1.8954305,2.02906125e-16 3,0 L13,0 Z M13,0.999999998 L3,0.999999998 C2.44771525,0.999999998 2,1.44771525 2,2 L2,2 L2,8 C2,8.55228475 2.44771525,9 3,9 L3,9 L13,9 C13.5522847,9 14,8.55228475 14,8 L14,8 L14,2 C14,1.44771525 13.5522847,0.999999998 13,0.999999998 L13,0.999999998 Z" id="形状结合"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
3
frame/item/resources/audio-volume-high-dark.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M17.5,0.455002377 C17.7761424,0.455002377 18,0.678860002 18,0.955002377 L18,15.0900024 C18,15.3661448 17.7761424,15.5900024 17.5,15.5900024 C17.2238576,15.5900024 17,15.3661448 17,15.0900024 L17,0.955002377 C17,0.678860002 17.2238576,0.455002377 17.5,0.455002377 Z M9,2.50100238 L9,13.5010024 C9,13.9464548 8.46142904,14.1695382 8.14644661,13.8545558 L6.17157288,11.879682 C5.60896374,11.3170729 4.845902,11.0010024 4.05025253,11.0010024 L2,11.0010024 C0.8954305,11.0010024 9.96112538e-14,10.1055719 0,9.00100238 L0,7.00100238 C-3.09994708e-14,5.89643288 0.8954305,5.00100238 2,5.00100238 L4.05025253,5.00100238 C4.845902,5.00100238 5.60896374,4.68493186 6.17157288,4.12232272 L8.14644661,2.14744899 C8.46142904,1.83246656 9,2.05554995 9,2.50100238 Z M14.5,2.29800238 C14.7761424,2.29800238 15,2.52186 15,2.79800238 L15,13.2470024 C15,13.5231448 14.7761424,13.7470024 14.5,13.7470024 C14.2238576,13.7470024 14,13.5231448 14,13.2470024 L14,2.79800238 C14,2.52186 14.2238576,2.29800238 14.5,2.29800238 Z M11.514,4.11900238 C11.7901424,4.11900238 12.014,4.34286 12.014,4.61900238 L12.014,11.3830024 C12.014,11.6591448 11.7901424,11.8830024 11.514,11.8830024 C11.2378576,11.8830024 11.014,11.6591448 11.014,11.3830024 L11.014,4.61900238 C11.014,4.34286 11.2378576,4.11900238 11.514,4.11900238 Z" transform="translate(1 2)"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
3
frame/item/resources/audio-volume-high.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<path fill="#FFF" fill-opacity=".8" fill-rule="evenodd" d="M17.5,0.455002377 C17.7761424,0.455002377 18,0.678860002 18,0.955002377 L18,15.0900024 C18,15.3661448 17.7761424,15.5900024 17.5,15.5900024 C17.2238576,15.5900024 17,15.3661448 17,15.0900024 L17,0.955002377 C17,0.678860002 17.2238576,0.455002377 17.5,0.455002377 Z M9,2.50100238 L9,13.5010024 C9,13.9464548 8.46142904,14.1695382 8.14644661,13.8545558 L6.17157288,11.879682 C5.60896374,11.3170729 4.845902,11.0010024 4.05025253,11.0010024 L2,11.0010024 C0.8954305,11.0010024 9.96112538e-14,10.1055719 0,9.00100238 L0,7.00100238 C-3.09994708e-14,5.89643288 0.8954305,5.00100238 2,5.00100238 L4.05025253,5.00100238 C4.845902,5.00100238 5.60896374,4.68493186 6.17157288,4.12232272 L8.14644661,2.14744899 C8.46142904,1.83246656 9,2.05554995 9,2.50100238 Z M14.5,2.29800238 C14.7761424,2.29800238 15,2.52186 15,2.79800238 L15,13.2470024 C15,13.5231448 14.7761424,13.7470024 14.5,13.7470024 C14.2238576,13.7470024 14,13.5231448 14,13.2470024 L14,2.79800238 C14,2.52186 14.2238576,2.29800238 14.5,2.29800238 Z M11.514,4.11900238 C11.7901424,4.11900238 12.014,4.34286 12.014,4.61900238 L12.014,11.3830024 C12.014,11.6591448 11.7901424,11.8830024 11.514,11.8830024 C11.2378576,11.8830024 11.014,11.6591448 11.014,11.3830024 L11.014,4.61900238 C11.014,4.34286 11.2378576,4.11900238 11.514,4.11900238 Z" transform="translate(1 2)"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
3
frame/item/resources/audio-volume-low-dark.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M10,4.50100238 L10,15.5010024 C10,15.9464548 9.46142904,16.1695382 9.14644661,15.8545558 L7.17157288,13.879682 C6.60896374,13.3170729 5.845902,13.0010024 5.05025253,13.0010024 L3,13.0010024 C1.8954305,13.0010024 1,12.1055719 1,11.0010024 L1,9.00100238 C1,7.89643288 1.8954305,7.00100238 3,7.00100238 L5.05025253,7.00100238 C5.845902,7.00100238 6.60896374,6.68493186 7.17157288,6.12232272 L9.14644661,4.14744899 C9.46142904,3.83246656 10,4.05554995 10,4.50100238 Z M12.514,6.11900238 C12.7901424,6.11900238 13.014,6.34286 13.014,6.61900238 L13.014,13.3830024 C13.014,13.6591448 12.7901424,13.8830024 12.514,13.8830024 C12.2378576,13.8830024 12.014,13.6591448 12.014,13.3830024 L12.014,6.61900238 C12.014,6.34286 12.2378576,6.11900238 12.514,6.11900238 Z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 878 B |
3
frame/item/resources/audio-volume-low.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<path fill="#FFF" fill-opacity=".8" fill-rule="evenodd" d="M10,4.50100238 L10,15.5010024 C10,15.9464548 9.46142904,16.1695382 9.14644661,15.8545558 L7.17157288,13.879682 C6.60896374,13.3170729 5.845902,13.0010024 5.05025253,13.0010024 L3,13.0010024 C1.8954305,13.0010024 1,12.1055719 1,11.0010024 L1,9.00100238 C1,7.89643288 1.8954305,7.00100238 3,7.00100238 L5.05025253,7.00100238 C5.845902,7.00100238 6.60896374,6.68493186 7.17157288,6.12232272 L9.14644661,4.14744899 C9.46142904,3.83246656 10,4.05554995 10,4.50100238 Z M12.514,6.11900238 C12.7901424,6.11900238 13.014,6.34286 13.014,6.61900238 L13.014,13.3830024 C13.014,13.6591448 12.7901424,13.8830024 12.514,13.8830024 C12.2378576,13.8830024 12.014,13.6591448 12.014,13.3830024 L12.014,6.61900238 C12.014,6.34286 12.2378576,6.11900238 12.514,6.11900238 Z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 908 B |
3
frame/item/resources/audio-volume-medium-dark.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M9,0.501002377 L9,11.5010024 C9,11.9464548 8.46142904,12.1695382 8.14644661,11.8545558 L6.17157288,9.87968203 C5.60896374,9.3170729 4.845902,9.00100238 4.05025253,9.00100238 L2,9.00100238 C0.8954305,9.00100238 9.96112538e-14,8.10557188 0,7.00100238 L0,5.00100238 C-3.09994708e-14,3.89643288 0.8954305,3.00100238 2,3.00100238 L4.05025253,3.00100238 C4.845902,3.00100238 5.60896374,2.68493186 6.17157288,2.12232272 L8.14644661,0.147448987 C8.46142904,-0.167533444 9,0.055549952 9,0.501002377 Z M14.5,0.298002377 C14.7761424,0.298002377 15,0.521860002 15,0.798002377 L15,11.2470024 C15,11.5231448 14.7761424,11.7470024 14.5,11.7470024 C14.2238576,11.7470024 14,11.5231448 14,11.2470024 L14,0.798002377 C14,0.521860002 14.2238576,0.298002377 14.5,0.298002377 Z M11.514,2.11900238 C11.7901424,2.11900238 12.014,2.34286 12.014,2.61900238 L12.014,9.38300238 C12.014,9.65914475 11.7901424,9.88300238 11.514,9.88300238 C11.2378576,9.88300238 11.014,9.65914475 11.014,9.38300238 L11.014,2.61900238 C11.014,2.34286 11.2378576,2.11900238 11.514,2.11900238 Z" transform="translate(1 4)"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
3
frame/item/resources/audio-volume-medium.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<path fill="#FFF" fill-opacity=".8" fill-rule="evenodd" d="M9,0.501002377 L9,11.5010024 C9,11.9464548 8.46142904,12.1695382 8.14644661,11.8545558 L6.17157288,9.87968203 C5.60896374,9.3170729 4.845902,9.00100238 4.05025253,9.00100238 L2,9.00100238 C0.8954305,9.00100238 9.96112538e-14,8.10557188 0,7.00100238 L0,5.00100238 C-3.09994708e-14,3.89643288 0.8954305,3.00100238 2,3.00100238 L4.05025253,3.00100238 C4.845902,3.00100238 5.60896374,2.68493186 6.17157288,2.12232272 L8.14644661,0.147448987 C8.46142904,-0.167533444 9,0.055549952 9,0.501002377 Z M14.5,0.298002377 C14.7761424,0.298002377 15,0.521860002 15,0.798002377 L15,11.2470024 C15,11.5231448 14.7761424,11.7470024 14.5,11.7470024 C14.2238576,11.7470024 14,11.5231448 14,11.2470024 L14,0.798002377 C14,0.521860002 14.2238576,0.298002377 14.5,0.298002377 Z M11.514,2.11900238 C11.7901424,2.11900238 12.014,2.34286 12.014,2.61900238 L12.014,9.38300238 C12.014,9.65914475 11.7901424,9.88300238 11.514,9.88300238 C11.2378576,9.88300238 11.014,9.65914475 11.014,9.38300238 L11.014,2.61900238 C11.014,2.34286 11.2378576,2.11900238 11.514,2.11900238 Z" transform="translate(1 4)"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
3
frame/item/resources/audio-volume-muted-dark.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M9,1.046 L9,12.046 C9,12.4914524 8.46142904,12.7145358 8.14644661,12.3995534 L6.17157288,10.4246797 C5.60896374,9.86207052 4.845902,9.546 4.05025253,9.546 L2,9.546 C0.8954305,9.546 9.96112538e-14,8.6505695 0,7.546 L0,5.546 C-3.09994708e-14,4.4414305 0.8954305,3.546 2,3.546 L4.05025253,3.546 C4.845902,3.546 5.60896374,3.22992948 6.17157288,2.66732034 L8.14644661,0.692446609 C8.46142904,0.377464179 9,0.600547575 9,1.046 Z M14.8412133,5.16189438 C15.0442449,5.36492592 15.060441,5.67790899 14.8773883,5.86096165 L13.738,6.99999762 L14.8773883,8.13903835 C15.060441,8.32209101 15.0442449,8.63507408 14.8412133,8.83810562 C14.6381818,9.04113717 14.3251987,9.05733326 14.1421461,8.8742806 L13.003,7.73499762 L11.8640694,8.8742806 C11.6810167,9.05733326 11.3680336,9.04113717 11.1650021,8.83810562 C10.9619706,8.63507408 10.9457745,8.32209101 11.1288271,8.13903835 L12.268,6.99999762 L11.1288271,5.86096165 C10.9457745,5.67790899 10.9619706,5.36492592 11.1650021,5.16189438 C11.3680336,4.95886283 11.6810167,4.94266674 11.8640694,5.1257194 L13.003,6.26399762 L14.1421461,5.1257194 C14.3251987,4.94266674 14.6381818,4.95886283 14.8412133,5.16189438 Z" transform="translate(1 3)"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
3
frame/item/resources/audio-volume-muted.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<path fill="#FFF" fill-opacity=".8" fill-rule="evenodd" d="M9,0.501002377 L9,11.5010024 C9,11.9464548 8.46142904,12.1695382 8.14644661,11.8545558 L6.17157288,9.87968203 C5.60896374,9.3170729 4.845902,9.00100238 4.05025253,9.00100238 L2,9.00100238 C0.8954305,9.00100238 9.96112538e-14,8.10557188 0,7.00100238 L0,5.00100238 C-3.09994708e-14,3.89643288 0.8954305,3.00100238 2,3.00100238 L4.05025253,3.00100238 C4.845902,3.00100238 5.60896374,2.68493186 6.17157288,2.12232272 L8.14644661,0.147448987 C8.46142904,-0.167533444 9,0.055549952 9,0.501002377 Z M14.8412133,4.61689675 C15.0442449,4.81992829 15.060441,5.13291137 14.8773883,5.31596402 L13.738,6.455 L14.8773883,7.59404073 C15.060441,7.77709338 15.0442449,8.09007646 14.8412133,8.293108 C14.6381818,8.49613954 14.3251987,8.51233563 14.1421461,8.32928298 L13.003,7.19 L11.8640694,8.32928298 C11.6810167,8.51233563 11.3680336,8.49613954 11.1650021,8.293108 C10.9619706,8.09007646 10.9457745,7.77709338 11.1288271,7.59404073 L12.268,6.455 L11.1288271,5.31596402 C10.9457745,5.13291137 10.9619706,4.81992829 11.1650021,4.61689675 C11.3680336,4.41386521 11.6810167,4.39766912 11.8640694,4.58072177 L13.003,5.719 L14.1421461,4.58072177 C14.3251987,4.39766912 14.6381818,4.41386521 14.8412133,4.61689675 Z" transform="translate(1 4)"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
15
frame/item/resources/brightness.svg
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>ICON / MenuItem / Brightness+</title>
|
||||
<g id="任务栏" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="任务栏-时尚" transform="translate(-738.000000, -914.000000)" fill="#000000" fill-rule="nonzero">
|
||||
<g id="UDE-/-ControlPanel" transform="translate(712.000000, 534.000000)">
|
||||
<g id="编组-5" transform="translate(10.000000, 360.000000)">
|
||||
<g id="ICON-/-MenuItem-/-Brightness+" transform="translate(16.000000, 20.000000)">
|
||||
<path d="M10.125,15.625 C10.4011424,15.625 10.625,15.8488576 10.625,16.125 L10.625,18.875 C10.625,19.1511424 10.4011424,19.375 10.125,19.375 L9.875,19.375 C9.59885763,19.375 9.375,19.1511424 9.375,18.875 L9.375,16.125 C9.375,15.8488576 9.59885763,15.625 9.875,15.625 L10.125,15.625 Z M14.7729708,13.8890873 L16.7175144,15.8336309 C16.9127766,16.0288931 16.9127766,16.3454756 16.7175144,16.5407377 L16.5407377,16.7175144 C16.3454756,16.9127766 16.0288931,16.9127766 15.8336309,16.7175144 L13.8890873,14.7729708 C13.6938252,14.5777086 13.6938252,14.2611261 13.8890873,14.065864 L14.065864,13.8890873 C14.2611261,13.6938252 14.5777086,13.6938252 14.7729708,13.8890873 Z M5.93413601,13.8890873 L6.1109127,14.065864 C6.30617485,14.2611261 6.30617485,14.5777086 6.1109127,14.7729708 L4.16636906,16.7175144 C3.97110691,16.9127766 3.65452442,16.9127766 3.45926227,16.7175144 L3.28248558,16.5407377 C3.08722343,16.3454756 3.08722343,16.0288931 3.28248558,15.8336309 L5.22702923,13.8890873 C5.42229137,13.6938252 5.73887386,13.6938252 5.93413601,13.8890873 Z M10,5.625 C12.4162458,5.625 14.375,7.58375422 14.375,10 C14.375,12.4162458 12.4162458,14.375 10,14.375 C7.58375422,14.375 5.625,12.4162458 5.625,10 C5.625,7.58375422 7.58375422,5.625 10,5.625 Z M18.875,9.375 C19.1511424,9.375 19.375,9.59885763 19.375,9.875 L19.375,10.125 C19.375,10.4011424 19.1511424,10.625 18.875,10.625 L16.125,10.625 C15.8488576,10.625 15.625,10.4011424 15.625,10.125 L15.625,9.875 C15.625,9.59885763 15.8488576,9.375 16.125,9.375 L18.875,9.375 Z M3.875,9.375 C4.15114237,9.375 4.375,9.59885763 4.375,9.875 L4.375,10.125 C4.375,10.4011424 4.15114237,10.625 3.875,10.625 L1.125,10.625 C0.848857625,10.625 0.625,10.4011424 0.625,10.125 L0.625,9.875 C0.625,9.59885763 0.848857625,9.375 1.125,9.375 L3.875,9.375 Z M16.5407377,3.28248558 L16.7175144,3.45926227 C16.9127766,3.65452442 16.9127766,3.97110691 16.7175144,4.16636906 L14.7729708,6.1109127 C14.5777086,6.30617485 14.2611261,6.30617485 14.065864,6.1109127 L13.8890873,5.93413601 C13.6938252,5.73887386 13.6938252,5.42229137 13.8890873,5.22702923 L15.8336309,3.28248558 C16.0288931,3.08722343 16.3454756,3.08722343 16.5407377,3.28248558 Z M4.16636906,3.28248558 L6.1109127,5.22702923 C6.30617485,5.42229137 6.30617485,5.73887386 6.1109127,5.93413601 L5.93413601,6.1109127 C5.73887386,6.30617485 5.42229137,6.30617485 5.22702923,6.1109127 L3.28248558,4.16636906 C3.08722343,3.97110691 3.08722343,3.65452442 3.28248558,3.45926227 L3.45926227,3.28248558 C3.65452442,3.08722343 3.97110691,3.08722343 4.16636906,3.28248558 Z M10.125,0.625 C10.4011424,0.625 10.625,0.848857625 10.625,1.125 L10.625,3.875 C10.625,4.15114237 10.4011424,4.375 10.125,4.375 L9.875,4.375 C9.59885763,4.375 9.375,4.15114237 9.375,3.875 L9.375,1.125 C9.375,0.848857625 9.59885763,0.625 9.875,0.625 L10.125,0.625 Z" id="形状结合"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.6 KiB |
3
frame/item/resources/brightnesshigh.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill="#536076" fill-rule="evenodd" d="M11.5,18 C11.7761424,18 12,18.2238576 12,18.5 L12,20.5 C12,20.7761424 11.7761424,21 11.5,21 C11.2238576,21 11,20.7761424 11,20.5 L11,18.5 C11,18.2238576 11.2238576,18 11.5,18 Z M17.8121778,14.5669873 L19.5442286,15.5669873 C19.7833749,15.7050585 19.8653125,16.0108537 19.7272413,16.25 C19.5891701,16.4891463 19.2833749,16.5710839 19.0442286,16.4330127 L17.3121778,15.4330127 C17.0730315,15.2949415 16.9910939,14.9891463 17.1291651,14.75 C17.2672363,14.5108537 17.5730315,14.4289161 17.8121778,14.5669873 Z M5.87083488,14.75 C6.00890606,14.9891463 5.92696849,15.2949415 5.68782217,15.4330127 L3.95577137,16.4330127 C3.71662505,16.5710839 3.41082985,16.4891463 3.27275866,16.25 C3.13468748,16.0108537 3.21662505,15.7050585 3.45577137,15.5669873 L5.18782217,14.5669873 C5.42696849,14.4289161 5.73276369,14.5108537 5.87083488,14.75 Z M11.5,7 C13.9852814,7 16,9.01471863 16,11.5 C16,13.9852814 13.9852814,16 11.5,16 C9.01471863,16 7,13.9852814 7,11.5 C7,9.01471863 9.01471863,7 11.5,7 Z M19.7272413,6.75 C19.8653125,6.98914631 19.7833749,7.29494151 19.5442286,7.4330127 L17.8121778,8.4330127 C17.5730315,8.57108389 17.2672363,8.48914631 17.1291651,8.25 C16.9910939,8.01085369 17.0730315,7.70505849 17.3121778,7.5669873 L19.0442286,6.5669873 C19.2833749,6.42891611 19.5891701,6.51085369 19.7272413,6.75 Z M3.95577137,6.5669873 L5.68782217,7.5669873 C5.92696849,7.70505849 6.00890606,8.01085369 5.87083488,8.25 C5.73276369,8.48914631 5.42696849,8.57108389 5.18782217,8.4330127 L3.45577137,7.4330127 C3.21662505,7.29494151 3.13468748,6.98914631 3.27275866,6.75 C3.41082985,6.51085369 3.71662505,6.42891611 3.95577137,6.5669873 Z M11.5,2 C11.7761424,2 12,2.22385763 12,2.5 L12,4.5 C12,4.77614237 11.7761424,5 11.5,5 C11.2238576,5 11,4.77614237 11,4.5 L11,2.5 C11,2.22385763 11.2238576,2 11.5,2 Z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
3
frame/item/resources/brightnesslow.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="25" height="24" viewBox="0 0 25 24">
|
||||
<path fill="#536076" fill-rule="evenodd" d="M11.5,17 C11.7761424,17 12,17.2238576 12,17.5 L12,18.5 C12,18.7761424 11.7761424,19 11.5,19 C11.2238576,19 11,18.7761424 11,18.5 L11,17.5 C11,17.2238576 11.2238576,17 11.5,17 Z M16.9461524,14.0669873 L17.8121778,14.5669873 C18.0513241,14.7050585 18.1332617,15.0108537 17.9951905,15.25 C17.8571193,15.4891463 17.5513241,15.5710839 17.3121778,15.4330127 L16.4461524,14.9330127 C16.2070061,14.7949415 16.1250685,14.4891463 16.2631397,14.25 C16.4012109,14.0108537 16.7070061,13.9289161 16.9461524,14.0669873 Z M6.73686028,14.25 C6.87493147,14.4891463 6.79299389,14.7949415 6.55384758,14.9330127 L5.68782217,15.4330127 C5.44867586,15.5710839 5.14288066,15.4891463 5.00480947,15.25 C4.86673828,15.0108537 4.94867586,14.7050585 5.18782217,14.5669873 L6.05384758,14.0669873 C6.29299389,13.9289161 6.59878909,14.0108537 6.73686028,14.25 Z M11.5,8 C13.4329966,8 15,9.56700338 15,11.5 C15,13.4329966 13.4329966,15 11.5,15 C9.56700338,15 8,13.4329966 8,11.5 C8,9.56700338 9.56700338,8 11.5,8 Z M17.9951905,7.75 C18.1332617,7.98914631 18.0513241,8.29494151 17.8121778,8.4330127 L16.9461524,8.9330127 C16.7070061,9.07108389 16.4012109,8.98914631 16.2631397,8.75 C16.1250685,8.51085369 16.2070061,8.20505849 16.4461524,8.0669873 L17.3121778,7.5669873 C17.5513241,7.42891611 17.8571193,7.51085369 17.9951905,7.75 Z M5.68782217,7.5669873 L6.55384758,8.0669873 C6.79299389,8.20505849 6.87493147,8.51085369 6.73686028,8.75 C6.59878909,8.98914631 6.29299389,9.07108389 6.05384758,8.9330127 L5.18782217,8.4330127 C4.94867586,8.29494151 4.86673828,7.98914631 5.00480947,7.75 C5.14288066,7.51085369 5.44867586,7.42891611 5.68782217,7.5669873 Z M11.5,4 C11.7761424,4 12,4.22385763 12,4.5 L12,5.5 C12,5.77614237 11.7761424,6 11.5,6 C11.2238576,6 11,5.77614237 11,5.5 L11,4.5 C11,4.22385763 11.2238576,4 11.5,4 Z" transform="translate(1)"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
15
frame/item/resources/broadcast.svg
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="18px" height="20px" viewBox="0 0 18 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>ICON / MenuItem / Broadcast</title>
|
||||
<g id="任务栏" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="任务栏-时尚" transform="translate(-993.000000, -844.000000)" fill="#000000" fill-rule="nonzero">
|
||||
<g id="UDE-/-ControlPanel" transform="translate(712.000000, 534.000000)">
|
||||
<g id="编组-4" transform="translate(10.000000, 290.000000)">
|
||||
<g id="形状结合" transform="translate(268.000000, 18.000000)">
|
||||
<path d="M12,14 L20,22 L4,22 L12,14 Z M12,2 C16.9705627,2 21,6.02943725 21,11 C21,13.8342485 19.6898859,16.3625035 17.642214,18.0122085 L16.8031599,17.146139 C18.6274776,15.7184347 19.8,13.496146 19.8,11 C19.8,6.69217895 16.307821,3.2 12,3.2 C7.69217895,3.2 4.2,6.69217895 4.2,11 C4.2,13.4965987 5.37294772,15.7192407 7.19783267,17.1469157 L6.35879863,18.0130242 C4.31054605,16.3633369 3,13.8347157 3,11 C3,6.02943725 7.02943725,2 12,2 Z M12,5 C15.3137085,5 18,7.6862915 18,11 C18,12.9892946 17.0318944,14.752476 15.541118,15.8441093 L14.6955445,14.9722251 C15.9657118,14.1086147 16.8,12.6517366 16.8,11 C16.8,8.3490332 14.6509668,6.2 12,6.2 C9.3490332,6.2 7.2,8.3490332 7.2,11 C7.2,12.652163 8.03471909,14.109367 9.30543941,14.9728939 L8.4598839,15.8448429 C6.96853942,14.753266 6,12.9897402 6,11 C6,7.6862915 8.6862915,5 12,5 Z M12,8 C13.6568542,8 15,9.34314575 15,11 C15,12.1468362 14.356487,13.1433719 13.4108513,13.6482168 L12,12.1937608 L10.5901445,13.6487482 C9.6439648,13.1440714 9,12.1472387 9,11 C9,9.34314575 10.3431458,8 12,8 Z"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
15
frame/item/resources/laptop.svg
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24px" height="16px" viewBox="0 0 24 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>ICON / Device / Laptop</title>
|
||||
<g id="任务栏" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="任务栏-时尚" transform="translate(-990.000000, -916.000000)" fill="#000000" fill-rule="nonzero">
|
||||
<g id="UDE-/-ControlPanel" transform="translate(712.000000, 534.000000)">
|
||||
<g id="编组-5" transform="translate(10.000000, 360.000000)">
|
||||
<g id="ICON-/-Device-/-Laptop" transform="translate(268.000000, 18.000000)">
|
||||
<path d="M20,4 C21.1045695,4 22,4.8954305 22,6 L22,18 L23.3125,18 C23.6921958,18 24,18.3078042 24,18.6875 L24,19.3125 C24,19.6921958 23.6921958,20 23.3125,20 L0.6875,20 C0.307804234,20 4.64993204e-17,19.6921958 0,19.3125 L0,18.6875 C-4.64993204e-17,18.3078042 0.307804234,18 0.6875,18 L2,18 L2,6 C2,4.8954305 2.8954305,4 4,4 L20,4 Z M20,5 L4,5 C3.48716416,5 3.06449284,5.35634479 3.00672773,5.81542665 L3,5.92307692 L3,17 L21,17 L21,5.92307692 C21,5.44968999 20.6139598,5.05953185 20.1166211,5.00621021 L20,5 Z" id="形状结合"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
15
frame/item/resources/volume.svg
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>ICON / MenuItem / Volume+</title>
|
||||
<g id="任务栏" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="任务栏-时尚" transform="translate(-739.000000, -845.000000)" fill="#000000" fill-rule="nonzero">
|
||||
<g id="UDE-/-ControlPanel" transform="translate(712.000000, 534.000000)">
|
||||
<g id="编组-4" transform="translate(10.000000, 290.000000)">
|
||||
<g id="ICON-/-MenuItem-/-Volume+" transform="translate(16.000000, 20.000000)">
|
||||
<path d="M7.42511349,5.62852582 L10.4450149,3.30395027 C10.6638368,3.13551163 10.9777735,3.17635535 11.1462121,3.39517727 C11.213509,3.48260398 11.25,3.58983426 11.25,3.70016242 L11.25,16.6041118 C11.25,16.8802542 11.0261424,17.1041118 10.75,17.1041118 C10.6314788,17.1041118 10.5168113,17.0620095 10.4264501,16.9853145 L7.45591022,14.4640369 C6.91374298,14.0038666 6.2257383,13.751253 5.51461104,13.751253 L2.75,13.751253 C1.92157288,13.751253 1.25,13.0796801 1.25,12.251253 L1.25,7.75125297 C1.25,6.92282585 1.92157288,6.25125297 2.75,6.25125297 L5.59520262,6.25125297 C6.25717158,6.25125297 6.90055321,6.03230722 7.42511349,5.62852582 Z M17.5,2.44375297 C17.5,2.098575 17.779822,1.81875297 18.125,1.81875297 C18.470178,1.81875297 18.75,2.098575 18.75,2.44375297 L18.75,17.612503 C18.75,17.9576809 18.470178,18.237503 18.125,18.237503 C17.779822,18.237503 17.5,17.9576809 17.5,17.612503 L17.5,2.44375297 Z M15,4.74750297 C15,4.402325 15.279822,4.12250297 15.625,4.12250297 C15.970178,4.12250297 16.25,4.402325 16.25,4.74750297 L16.25,15.308753 C16.25,15.6539309 15.970178,15.933753 15.625,15.933753 C15.279822,15.933753 15,15.6539309 15,15.308753 L15,4.74750297 Z M12.5175,7.02375297 C12.5175,6.678575 12.797322,6.39875297 13.1425,6.39875297 C13.487678,6.39875297 13.7675,6.678575 13.7675,7.02375297 L13.7675,12.978753 C13.7675,13.3239309 13.487678,13.603753 13.1425,13.603753 C12.797322,13.603753 12.5175,13.3239309 12.5175,12.978753 L12.5175,7.02375297 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
179
frame/model/brightnessmodel.cpp
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
*
|
||||
* Author: sbw <sbw@sbw.so>
|
||||
* kirigaya <kirigaya@mkacg.com>
|
||||
* Hualet <mr.asianwang@gmail.com>
|
||||
*
|
||||
* Maintainer: sbw <sbw@sbw.so>
|
||||
* kirigaya <kirigaya@mkacg.com>
|
||||
* Hualet <mr.asianwang@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 3 of the License, or
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "brightnessmodel.h"
|
||||
|
||||
#include <QDBusArgument>
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusPendingCall>
|
||||
#include <QDebug>
|
||||
#include <QApplication>
|
||||
#include <QScreen>
|
||||
|
||||
static const QString serviceName("com.deepin.daemon.Display");
|
||||
static const QString servicePath("/com/deepin/daemon/Display");
|
||||
static const QString serviceInterface("com.deepin.daemon.Display");
|
||||
static const QString propertiesInterface("org.freedesktop.DBus.Properties");
|
||||
|
||||
BrightnessModel::BrightnessModel(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
QDBusInterface dbusInter(serviceName, servicePath, serviceInterface, QDBusConnection::sessionBus());
|
||||
if (dbusInter.isValid()) {
|
||||
// 读取所有的屏幕的信息
|
||||
QString primaryScreenName = qApp->primaryScreen() ? qApp->primaryScreen()->name() : QString();
|
||||
QList<QDBusObjectPath> paths = dbusInter.property("Monitors").value<QList<QDBusObjectPath>>();
|
||||
for (QDBusObjectPath path : paths) {
|
||||
BrightMonitor *monitor = new BrightMonitor(path.path(), this);
|
||||
m_monitor << monitor;
|
||||
connect(monitor, &BrightMonitor::brightnessChanged, this, [ = ] {
|
||||
Q_EMIT brightnessChanged(monitor);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
QDBusConnection::sessionBus().connect(serviceName, servicePath, propertiesInterface,
|
||||
"PropertiesChanged", "sa{sv}as", this, SLOT(onPropertyChanged(const QDBusMessage &)));
|
||||
}
|
||||
|
||||
BrightnessModel::~BrightnessModel()
|
||||
{
|
||||
}
|
||||
|
||||
QList<BrightMonitor *> BrightnessModel::monitors()
|
||||
{
|
||||
return m_monitor;
|
||||
}
|
||||
|
||||
void BrightnessModel::setBrightness(BrightMonitor *monitor, int brightness)
|
||||
{
|
||||
setBrightness(monitor->name(), brightness);
|
||||
}
|
||||
|
||||
void BrightnessModel::setBrightness(QString name, int brightness)
|
||||
{
|
||||
callMethod("SetBrightness", { name, static_cast<double>(brightness *0.01) });
|
||||
}
|
||||
|
||||
QDBusMessage BrightnessModel::callMethod(const QString &methodName, const QList<QVariant> &argument)
|
||||
{
|
||||
QDBusInterface dbusInter(serviceName, servicePath, serviceInterface, QDBusConnection::sessionBus());
|
||||
if (dbusInter.isValid()) {
|
||||
QDBusPendingCall reply = dbusInter.asyncCallWithArgumentList(methodName, argument);
|
||||
reply.waitForFinished();
|
||||
return reply.reply();
|
||||
}
|
||||
return QDBusMessage();
|
||||
}
|
||||
|
||||
void BrightnessModel::onPropertyChanged(const QDBusMessage &msg)
|
||||
{
|
||||
QList<QVariant> arguments = msg.arguments();
|
||||
if (3 != arguments.count())
|
||||
return;
|
||||
|
||||
QString interfaceName = msg.arguments().at(0).toString();
|
||||
if (interfaceName != serviceInterface)
|
||||
return;
|
||||
|
||||
QVariantMap changedProps = qdbus_cast<QVariantMap>(arguments.at(1).value<QDBusArgument>());
|
||||
if (changedProps.contains("Brightness")) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief monitor
|
||||
*/
|
||||
BrightMonitor::BrightMonitor(QString path, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_path(path)
|
||||
, m_brightness(100)
|
||||
, m_enabled(false)
|
||||
{
|
||||
QDBusInterface dbusInter(serviceName, path, serviceInterface + QString(".Monitor"), QDBusConnection::sessionBus());
|
||||
if (dbusInter.isValid()) {
|
||||
// 读取所有的屏幕的信息
|
||||
m_name = dbusInter.property("Name").toString();
|
||||
m_brightness = static_cast<int>(dbusInter.property("Brightness").toDouble() * 100);
|
||||
m_enabled = dbusInter.property("Enabled").toBool();
|
||||
}
|
||||
|
||||
QDBusConnection::sessionBus().connect(serviceName, path, propertiesInterface,
|
||||
"PropertiesChanged", "sa{sv}as", this, SLOT(onPropertyChanged(const QDBusMessage &)));
|
||||
}
|
||||
|
||||
BrightMonitor::~BrightMonitor()
|
||||
{
|
||||
}
|
||||
|
||||
int BrightMonitor::brihtness()
|
||||
{
|
||||
return m_brightness;
|
||||
}
|
||||
|
||||
bool BrightMonitor::enabled()
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
QString BrightMonitor::name()
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void BrightMonitor::onPropertyChanged(const QDBusMessage &msg)
|
||||
{
|
||||
QList<QVariant> arguments = msg.arguments();
|
||||
if (3 != arguments.count())
|
||||
return;
|
||||
|
||||
QString interfaceName = msg.arguments().at(0).toString();
|
||||
if (interfaceName != QString("%1.Monitor").arg(serviceInterface))
|
||||
return;
|
||||
|
||||
QVariantMap changedProps = qdbus_cast<QVariantMap>(arguments.at(1).value<QDBusArgument>());
|
||||
if (changedProps.contains("Brightness")) {
|
||||
int brightness = static_cast<int>(changedProps.value("Brightness").value<double>() * 100);
|
||||
if (brightness != m_brightness) {
|
||||
m_brightness = brightness;
|
||||
Q_EMIT brightnessChanged(brightness);
|
||||
}
|
||||
}
|
||||
if (changedProps.contains("Name")) {
|
||||
QString name = changedProps.value("Name").value<QString>();
|
||||
if (name != m_name) {
|
||||
m_name = name;
|
||||
Q_EMIT nameChanged(name);
|
||||
}
|
||||
}
|
||||
if (changedProps.contains("Enabled")) {
|
||||
bool enabled = changedProps.value("Enabled").value<bool>();
|
||||
if (enabled != m_enabled) {
|
||||
m_enabled = enabled;
|
||||
Q_EMIT enabledChanged(enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
86
frame/model/brightnessmodel.h
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2011 ~ 2022 Deepin Technology Co., Ltd.
|
||||
*
|
||||
* Author: donghualin <donghualin@uniontech.com>
|
||||
*
|
||||
* Maintainer: donghualin <donghualin@uniontech.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 3 of the License, or
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BRIGHTNESSMODEL_H
|
||||
#define BRIGHTNESSMODEL_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class BrightMonitor;
|
||||
class QDBusMessage;
|
||||
|
||||
class BrightnessModel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_SIGNALS:
|
||||
void brightnessChanged(BrightMonitor *);
|
||||
|
||||
public:
|
||||
explicit BrightnessModel(QObject *parent = nullptr);
|
||||
~BrightnessModel();
|
||||
|
||||
QList<BrightMonitor *> monitors();
|
||||
void setBrightness(BrightMonitor *monitor, int brightness);
|
||||
void setBrightness(QString name, int brightness);
|
||||
|
||||
protected:
|
||||
QDBusMessage callMethod(const QString &methodName, const QList<QVariant> &argument);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onPropertyChanged(const QDBusMessage &msg);
|
||||
|
||||
private:
|
||||
QList<BrightMonitor *> m_monitor;
|
||||
};
|
||||
|
||||
class BrightMonitor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class BrightnessModel;
|
||||
|
||||
Q_SIGNALS:
|
||||
void brightnessChanged(int);
|
||||
void nameChanged(QString);
|
||||
void enabledChanged(bool);
|
||||
|
||||
public:
|
||||
int brihtness();
|
||||
bool enabled();
|
||||
QString name();
|
||||
//bool isDefault();
|
||||
|
||||
protected:
|
||||
explicit BrightMonitor(QString path, QObject *parent);
|
||||
~BrightMonitor();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onPropertyChanged(const QDBusMessage &msg);
|
||||
|
||||
private:
|
||||
QString m_path;
|
||||
QString m_name;
|
||||
int m_brightness;
|
||||
bool m_enabled;
|
||||
};
|
||||
|
||||
#endif // DISPLAYMODEL_H
|
259
frame/model/mediaplayermodel.cpp
Normal file
@ -0,0 +1,259 @@
|
||||
#include "mediaplayermodel.h"
|
||||
|
||||
#include <QDBusConnectionInterface>
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusPendingCall>
|
||||
#include <QDBusReply>
|
||||
#include <QDebug>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QMetaMethod>
|
||||
#include <QDBusAbstractInterface>
|
||||
|
||||
MediaPlayerModel::MediaPlayerModel(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_isActived(false)
|
||||
, m_mediaInter(nullptr)
|
||||
{
|
||||
initMediaPlayer();
|
||||
}
|
||||
|
||||
MediaPlayerModel::~MediaPlayerModel()
|
||||
{
|
||||
}
|
||||
|
||||
MediaPlayerModel *MediaPlayerModel::instance()
|
||||
{
|
||||
static MediaPlayerModel instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
bool MediaPlayerModel::isActived()
|
||||
{
|
||||
return m_isActived;
|
||||
}
|
||||
|
||||
bool MediaPlayerModel::canGoNext()
|
||||
{
|
||||
return m_mediaInter ? m_mediaInter->canGoNext() : false;
|
||||
}
|
||||
|
||||
bool MediaPlayerModel::canGoPrevious()
|
||||
{
|
||||
return m_mediaInter ? m_mediaInter->canGoPrevious() : false;
|
||||
}
|
||||
|
||||
bool MediaPlayerModel::canPause()
|
||||
{
|
||||
|
||||
return m_mediaInter ? m_mediaInter->canPause() : false;
|
||||
}
|
||||
|
||||
MediaPlayerModel::PlayStatus MediaPlayerModel::status()
|
||||
{
|
||||
if (!m_isActived || !m_mediaInter)
|
||||
return PlayStatus::Stop;
|
||||
|
||||
return convertStatus(m_mediaInter->playbackStatus());
|
||||
}
|
||||
|
||||
const QString MediaPlayerModel::name()
|
||||
{
|
||||
if (m_mediaInter) {
|
||||
Dict data = m_mediaInter->metadata();
|
||||
return data["xesam:title"].toString();
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
const QString MediaPlayerModel::iconUrl()
|
||||
{
|
||||
if (m_mediaInter) {
|
||||
Dict data = m_mediaInter->metadata();
|
||||
return data["mpris:artUrl"].toString();
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
const QString MediaPlayerModel::album()
|
||||
{
|
||||
if (m_mediaInter) {
|
||||
Dict data = m_mediaInter->metadata();
|
||||
return data["xesam:album"].toString();
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
const QString MediaPlayerModel::artist()
|
||||
{
|
||||
if (m_mediaInter) {
|
||||
Dict data = m_mediaInter->metadata();
|
||||
return data["xesam:artist"].toString();
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
void MediaPlayerModel::setStatus(const MediaPlayerModel::PlayStatus &stat)
|
||||
{
|
||||
if (!m_mediaInter)
|
||||
return;
|
||||
|
||||
switch (stat) {
|
||||
case MediaPlayerModel::PlayStatus::Play: {
|
||||
m_mediaInter->Play();
|
||||
break;
|
||||
}
|
||||
case MediaPlayerModel::PlayStatus::Stop: {
|
||||
m_mediaInter->Stop();
|
||||
break;
|
||||
}
|
||||
case MediaPlayerModel::PlayStatus::Pause: {
|
||||
m_mediaInter->Pause();
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPlayerModel::playNext()
|
||||
{
|
||||
if (m_mediaInter)
|
||||
m_mediaInter->Next();
|
||||
}
|
||||
|
||||
void MediaPlayerModel::initMediaPlayer()
|
||||
{
|
||||
QDBusInterface dbusInter("org.freedesktop.DBus", "/", "org.freedesktop.DBus", QDBusConnection::sessionBus(), this);
|
||||
QDBusPendingCall call = dbusInter.asyncCall("ListNames");
|
||||
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished, [ = ] {
|
||||
m_serviceName.clear();
|
||||
if (call.isError())
|
||||
return;
|
||||
|
||||
QDBusReply<QStringList> reply = call.reply();
|
||||
const QStringList &serviceList = reply.value();
|
||||
|
||||
for (const QString &serv : serviceList) {
|
||||
if (!serv.startsWith("org.mpris.MediaPlayer2"))
|
||||
continue;
|
||||
|
||||
QDBusInterface serviceInterface(serv, "/org/mpris/MediaPlayer2",
|
||||
"org.mpris.MediaPlayer2.Player", QDBusConnection::sessionBus(), this);
|
||||
// 如果开启了谷歌浏览器的后台服务(org.mpris.MediaPlayer2.chromium.instance17352)
|
||||
// 也符合名称要求,但是它不是音乐服务,此时需要判断是否存在这个属性
|
||||
QVariant v = serviceInterface.property("CanPlay");
|
||||
if (!v.isValid() || !v.value<bool>())
|
||||
continue;
|
||||
|
||||
m_serviceName = serv;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!m_serviceName.isEmpty()) {
|
||||
m_isActived = true;
|
||||
|
||||
m_mediaInter = new MediaPlayerInterface(m_serviceName, "/org/mpris/MediaPlayer2", QDBusConnection::sessionBus(), this);
|
||||
connect(m_mediaInter, &MediaPlayerInterface::PlaybackStatusChanged, this, [ this ] {
|
||||
Q_EMIT statusChanged(convertStatus(m_mediaInter->playbackStatus()));
|
||||
});
|
||||
connect(m_mediaInter, &MediaPlayerInterface::MetadataChanged, this, &MediaPlayerModel::metadataChanged);
|
||||
Dict v = m_mediaInter->metadata();
|
||||
m_name = v.value("xesam:title").toString();
|
||||
m_icon = v.value("mpris:artUrl").toString();
|
||||
m_album = v.value("xesam:album").toString();
|
||||
m_artist = v.value("xesam:artist").toString();
|
||||
Q_EMIT startStop(true);
|
||||
return;
|
||||
}
|
||||
|
||||
QDBusConnectionInterface *dbusInterface = QDBusConnection::sessionBus().interface();
|
||||
connect(dbusInterface, &QDBusConnectionInterface::serviceOwnerChanged, this,
|
||||
[ = ](const QString &name, const QString &, const QString &newOwner) {
|
||||
if (name.startsWith("org.mpris.MediaPlayer2")) {
|
||||
// 启动了音乐播放
|
||||
m_isActived = !newOwner.isEmpty();
|
||||
if (m_isActived) {
|
||||
m_serviceName = name;
|
||||
m_mediaInter = new MediaPlayerInterface(m_serviceName, "/org/mpris/MediaPlayer2", QDBusConnection::sessionBus(), this);
|
||||
connect(m_mediaInter, &MediaPlayerInterface::PlaybackStatusChanged, this, [ this ] {
|
||||
Q_EMIT statusChanged(convertStatus(m_mediaInter->playbackStatus()));
|
||||
});
|
||||
connect(m_mediaInter, &MediaPlayerInterface::MetadataChanged, this, &MediaPlayerModel::metadataChanged);
|
||||
Dict v = m_mediaInter->metadata();
|
||||
m_name = v.value("xesam:title").toString();
|
||||
m_icon = v.value("mpris:artUrl").toString();
|
||||
m_album = v.value("xesam:album").toString();
|
||||
m_artist = v.value("xesam:artist").toString();
|
||||
} else {
|
||||
if (!m_serviceName.isEmpty()) {
|
||||
delete m_mediaInter;
|
||||
m_mediaInter = nullptr;
|
||||
}
|
||||
m_serviceName.clear();
|
||||
}
|
||||
Q_EMIT startStop(m_isActived);
|
||||
}
|
||||
});
|
||||
connect(dbusInterface, &QDBusConnectionInterface::serviceUnregistered, this,
|
||||
[ = ](const QString &service) {
|
||||
if (service.startsWith("org.mpris.MediaPlayer2")) {
|
||||
// 启动了音乐播放
|
||||
m_serviceName.clear();
|
||||
m_isActived = false;
|
||||
Q_EMIT startStop(m_isActived);
|
||||
}
|
||||
});
|
||||
});
|
||||
connect(watcher, &QDBusPendingCallWatcher::finished, watcher, &QDBusPendingCallWatcher::deleteLater);
|
||||
}
|
||||
|
||||
MediaPlayerModel::PlayStatus MediaPlayerModel::convertStatus(const QString &stat)
|
||||
{
|
||||
if (stat == "Paused")
|
||||
return PlayStatus::Pause;
|
||||
if (stat == "Playing")
|
||||
return PlayStatus::Play;
|
||||
if (stat == "Stopped")
|
||||
return PlayStatus::Stop;
|
||||
|
||||
return PlayStatus::Unknow;
|
||||
}
|
||||
|
||||
MediaPlayerInterface::MediaPlayerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
|
||||
: QDBusAbstractInterface(service, path, "org.mpris.MediaPlayer2.Player", connection, parent)
|
||||
{
|
||||
QDBusConnection::sessionBus().connect(this->service(), this->path(), "org.freedesktop.DBus.Properties", "PropertiesChanged","sa{sv}as", this, SLOT(onPropertyChanged(QDBusMessage)));
|
||||
}
|
||||
|
||||
MediaPlayerInterface::~MediaPlayerInterface()
|
||||
{
|
||||
QDBusConnection::sessionBus().disconnect(this->service(), this->path(), "org.freedesktop.DBus.Properties", "PropertiesChanged","sa{sv}as", this, SLOT(__propertyChanged__(QDBusMessage)));
|
||||
}
|
||||
|
||||
void MediaPlayerInterface::onPropertyChanged(const QDBusMessage& msg)
|
||||
{
|
||||
QList<QVariant> arguments = msg.arguments();
|
||||
if (3 != arguments.count())
|
||||
return;
|
||||
|
||||
QString interfaceName = msg.arguments().at(0).toString();
|
||||
if (interfaceName !="org.mpris.MediaPlayer2.Player")
|
||||
return;
|
||||
|
||||
QVariantMap changedProps = qdbus_cast<QVariantMap>(arguments.at(1).value<QDBusArgument>());
|
||||
QStringList keys = changedProps.keys();
|
||||
foreach(const QString &prop, keys) {
|
||||
const QMetaObject* self = metaObject();
|
||||
for (int i=self->propertyOffset(); i < self->propertyCount(); ++i) {
|
||||
QMetaProperty p = self->property(i);
|
||||
if (p.name() == prop) {
|
||||
Q_EMIT p.notifySignal().invoke(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
126
frame/model/mediaplayermodel.h
Normal file
@ -0,0 +1,126 @@
|
||||
#ifndef MEDIAPLAYERMODEL_H
|
||||
#define MEDIAPLAYERMODEL_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDBusAbstractInterface>
|
||||
#include <QDBusPendingReply>
|
||||
|
||||
typedef QMap<QString, QVariant> Dict;
|
||||
Q_DECLARE_METATYPE(Dict)
|
||||
|
||||
class QDBusMessage;
|
||||
class QDBusConnection;
|
||||
class MediaPlayerInterface;
|
||||
|
||||
class MediaPlayerModel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum PlayStatus {
|
||||
Unknow = 0,
|
||||
Play,
|
||||
Pause,
|
||||
Stop
|
||||
};
|
||||
|
||||
Q_SIGNALS:
|
||||
void startStop(bool);
|
||||
void statusChanged(const PlayStatus &);
|
||||
void metadataChanged();
|
||||
|
||||
public:
|
||||
static MediaPlayerModel *instance();
|
||||
bool isActived();
|
||||
bool canGoNext();
|
||||
bool canGoPrevious();
|
||||
bool canPause();
|
||||
|
||||
PlayStatus status();
|
||||
const QString name();
|
||||
const QString iconUrl();
|
||||
const QString album();
|
||||
const QString artist();
|
||||
|
||||
void setStatus(const PlayStatus &stat);
|
||||
void playNext();
|
||||
|
||||
protected:
|
||||
explicit MediaPlayerModel(QObject *parent = nullptr);
|
||||
~MediaPlayerModel();
|
||||
|
||||
private:
|
||||
void initMediaPlayer();
|
||||
PlayStatus convertStatus(const QString &stat);
|
||||
|
||||
private:
|
||||
bool m_isActived;
|
||||
QString m_serviceName;
|
||||
QString m_name;
|
||||
QString m_icon;
|
||||
QString m_album;
|
||||
QString m_artist;
|
||||
MediaPlayerInterface *m_mediaInter;
|
||||
};
|
||||
|
||||
class MediaPlayerInterface : public QDBusAbstractInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_SIGNALS:
|
||||
void MetadataChanged();
|
||||
void CanGoNextChanged();
|
||||
void CanGoPreviousChanged();
|
||||
void CanPauseChanged();
|
||||
void PlaybackStatusChanged();
|
||||
|
||||
public:
|
||||
MediaPlayerInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
|
||||
~MediaPlayerInterface();
|
||||
|
||||
public:
|
||||
inline QDBusPendingReply<> Play() {
|
||||
QList<QVariant> argumentList;
|
||||
return asyncCallWithArgumentList(QStringLiteral("Play"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<> Stop() {
|
||||
QList<QVariant> argumentList;
|
||||
return asyncCallWithArgumentList(QStringLiteral("Stop"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<> Pause() {
|
||||
QList<QVariant> argumentList;
|
||||
return asyncCallWithArgumentList(QStringLiteral("Pause"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<> Next() {
|
||||
QList<QVariant> argumentList;
|
||||
return asyncCallWithArgumentList(QStringLiteral("Next"), argumentList);
|
||||
}
|
||||
|
||||
Q_PROPERTY(Dict Metadata READ metadata NOTIFY MetadataChanged)
|
||||
inline Dict metadata() const
|
||||
{ return qvariant_cast<Dict>(property("Metadata")); }
|
||||
|
||||
Q_PROPERTY(bool CanGoNext READ canGoNext NOTIFY CanGoNextChanged)
|
||||
inline bool canGoNext() const
|
||||
{ return qvariant_cast< bool >(property("CanGoNext")); }
|
||||
|
||||
Q_PROPERTY(bool CanGoPrevious READ canGoPrevious NOTIFY CanGoPreviousChanged)
|
||||
inline bool canGoPrevious() const
|
||||
{ return qvariant_cast< bool >(property("CanGoPrevious")); }
|
||||
|
||||
Q_PROPERTY(bool CanPause READ canPause NOTIFY CanPauseChanged)
|
||||
inline bool canPause() const
|
||||
{ return qvariant_cast< bool >(property("CanPause")); }
|
||||
|
||||
Q_PROPERTY(QString PlaybackStatus READ playbackStatus NOTIFY PlaybackStatusChanged)
|
||||
inline QString playbackStatus() const
|
||||
{ return qvariant_cast< QString >(property("PlaybackStatus")); }
|
||||
|
||||
private Q_SLOTS:
|
||||
void onPropertyChanged(const QDBusMessage& msg);
|
||||
};
|
||||
|
||||
#endif // MEDIAPLAYERLISTENER_H
|
589
frame/model/volumemodel.cpp
Normal file
@ -0,0 +1,589 @@
|
||||
#include "volumemodel.h"
|
||||
|
||||
#include <QDBusArgument>
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusConnectionInterface>
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusMessage>
|
||||
#include <QDBusObjectPath>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QVariantMap>
|
||||
#include <QDebug>
|
||||
#include <QDBusMetaType>
|
||||
|
||||
/**
|
||||
* @brief 声音控制的类
|
||||
* @param parent
|
||||
*/
|
||||
|
||||
static const QString serviceName = QString("com.deepin.daemon.Audio");
|
||||
static const QString servicePath = QString("/com/deepin/daemon/Audio");
|
||||
static const QString interfaceName = QString("com.deepin.daemon.Audio");
|
||||
static const QString propertiesInterface = QString("org.freedesktop.DBus.Properties");
|
||||
|
||||
VolumeModel::VolumeModel(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
initService();
|
||||
}
|
||||
|
||||
VolumeModel::~VolumeModel()
|
||||
{
|
||||
clearPorts();
|
||||
clearSinks();
|
||||
}
|
||||
|
||||
void VolumeModel::setActivePort(AudioPorts *port)
|
||||
{
|
||||
callMethod("SetPort", { port->cardId(), port->name(), port->direction() });
|
||||
}
|
||||
|
||||
QList<AudioSink *> VolumeModel::sinks() const
|
||||
{
|
||||
return m_sinks;
|
||||
}
|
||||
|
||||
QList<AudioPorts *> VolumeModel::ports() const
|
||||
{
|
||||
return m_ports;
|
||||
}
|
||||
|
||||
AudioSink *VolumeModel::defaultSink() const
|
||||
{
|
||||
for (AudioSink *sink : m_sinks) {
|
||||
if (sink->isDefault())
|
||||
return sink;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void VolumeModel::setVolume(int volumn)
|
||||
{
|
||||
for (AudioSink *audiosink : m_sinks) {
|
||||
if (audiosink->isDefault()) {
|
||||
audiosink->setVolume(volumn, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VolumeModel::setMute(bool value)
|
||||
{
|
||||
for (AudioSink *audiosink : m_sinks) {
|
||||
if (audiosink->isDefault()) {
|
||||
audiosink->setMute(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int VolumeModel::volume()
|
||||
{
|
||||
for (AudioSink *audiosink : m_sinks) {
|
||||
if (audiosink->isDefault())
|
||||
return audiosink->volume();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool VolumeModel::isMute()
|
||||
{
|
||||
for (AudioSink *audiosink : m_sinks) {
|
||||
if (audiosink->isDefault())
|
||||
return audiosink->isMute();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VolumeModel::existActiveOutputDevice()
|
||||
{
|
||||
for (AudioPorts *port : m_ports) {
|
||||
if (port->direction() == 1)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void VolumeModel::onPropertyChanged(const QDBusMessage &msg)
|
||||
{
|
||||
QList<QVariant> arguments = msg.arguments();
|
||||
if (3 != arguments.count())
|
||||
return;
|
||||
|
||||
QString interName = msg.arguments().at(0).toString();
|
||||
if (interName != interfaceName)
|
||||
return;
|
||||
|
||||
QVariantMap changedProps = qdbus_cast<QVariantMap>(arguments.at(1).value<QDBusArgument>());
|
||||
if (changedProps.contains("DefaultSink")) {
|
||||
QVariant defaultSink = changedProps.value("DefaultSink");
|
||||
QString defaultSinkPath = defaultSink.value<QDBusObjectPath>().path();
|
||||
for (AudioSink *audioSink : m_sinks) {
|
||||
if (audioSink->m_devicePath == defaultSinkPath) {
|
||||
updateDefaultSink(audioSink);
|
||||
Q_EMIT defaultSinkChanged(audioSink);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VolumeModel::initService()
|
||||
{
|
||||
QDBusConnection::sessionBus().connect(serviceName, servicePath, propertiesInterface,
|
||||
"PropertiesChanged", "sa{sv}as", this, SLOT(onPropertyChanged(const QDBusMessage &)));
|
||||
|
||||
reloadSinks();
|
||||
reloadPorts();
|
||||
|
||||
QDBusConnectionInterface *dbusInterface = QDBusConnection::sessionBus().interface();
|
||||
connect(dbusInterface, &QDBusConnectionInterface::serviceOwnerChanged, this,
|
||||
[ = ](const QString &name, const QString &, const QString &newOwner) {
|
||||
if (name == serviceName) {
|
||||
if (newOwner.isEmpty()) {
|
||||
QDBusConnection::sessionBus().disconnect(serviceName, servicePath, propertiesInterface,
|
||||
"PropertiesChanged", "sa{sv}as", this, SLOT(onPropertyChanged(const QDBusMessage &)));
|
||||
clearSinks();
|
||||
} else {
|
||||
QDBusConnection::sessionBus().connect(serviceName, servicePath, propertiesInterface,
|
||||
"PropertiesChanged", "sa{sv}as", this, SLOT(onPropertyChanged(const QDBusMessage &)));
|
||||
reloadSinks();
|
||||
reloadPorts();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void VolumeModel::reloadSinks()
|
||||
{
|
||||
clearSinks();
|
||||
QList<QDBusObjectPath> sinkPaths = properties<QList<QDBusObjectPath>>("Sinks");
|
||||
for (const QDBusObjectPath &sinkPath : sinkPaths) {
|
||||
AudioSink *sink = new AudioSink(sinkPath.path(), this);
|
||||
connect(sink, &AudioSink::volumeChanged, this, [ = ](int volume) {
|
||||
if (sink->isDefault())
|
||||
Q_EMIT volumeChanged(volume);
|
||||
});
|
||||
connect(sink, &AudioSink::muteChanged, this, [ = ](bool isMute) {
|
||||
if (sink->isDefault())
|
||||
Q_EMIT muteChanged(isMute);
|
||||
});
|
||||
|
||||
m_sinks << sink;
|
||||
}
|
||||
}
|
||||
|
||||
void VolumeModel::reloadPorts()
|
||||
{
|
||||
clearPorts();
|
||||
QString cards = properties<QString>("CardsWithoutUnavailable");
|
||||
QJsonParseError error;
|
||||
QJsonDocument json = QJsonDocument::fromJson(cards.toLocal8Bit(), &error);
|
||||
if (error.error != QJsonParseError::NoError)
|
||||
return;
|
||||
|
||||
int sinkCardId = -1;
|
||||
QString sinkCardName;
|
||||
AudioSink *sink = defaultSink();
|
||||
if (sink) {
|
||||
sinkCardId = sink->cardId();
|
||||
sinkCardName = sink->name();
|
||||
}
|
||||
|
||||
QJsonArray array = json.array();
|
||||
for (const QJsonValue value : array) {
|
||||
QJsonObject cardObject = value.toObject();
|
||||
int cardId = cardObject.value("Id").toInt();
|
||||
QString cardName = cardObject.value("Name").toString();
|
||||
QJsonArray jPorts = cardObject.value("Ports").toArray();
|
||||
for (const QJsonValue jPortValue : jPorts) {
|
||||
QJsonObject jPort = jPortValue.toObject();
|
||||
if (!jPort.value("Enabled").toBool())
|
||||
continue;
|
||||
|
||||
int direction = jPort.value("Direction").toInt();
|
||||
if (direction != 1)
|
||||
continue;
|
||||
|
||||
AudioPorts *port = new AudioPorts(cardId, cardName);
|
||||
port->setName(jPort.value("Name").toString());
|
||||
port->setDescription(jPort.value("Description").toString());
|
||||
port->setDirection(direction);
|
||||
if (port->cardId() == sinkCardId && port->name() == sinkCardName)
|
||||
port->setIsChecked(true);
|
||||
|
||||
m_ports << port;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VolumeModel::updateDefaultSink(AudioSink *audioSink)
|
||||
{
|
||||
bool checkChanged = false;
|
||||
for (AudioPorts *port : m_ports) {
|
||||
bool oldChecked = port->isChecked();
|
||||
port->setIsChecked(port->cardId() == audioSink->cardId()
|
||||
&& port->name() == audioSink->name());
|
||||
|
||||
if (oldChecked != port->isChecked() && port->isChecked())
|
||||
checkChanged = true;
|
||||
}
|
||||
|
||||
if (checkChanged)
|
||||
Q_EMIT checkPortChanged();
|
||||
}
|
||||
|
||||
void VolumeModel::clearSinks()
|
||||
{
|
||||
for (AudioSink *sink : m_sinks)
|
||||
delete sink;
|
||||
|
||||
m_sinks.clear();
|
||||
}
|
||||
|
||||
void VolumeModel::clearPorts()
|
||||
{
|
||||
for (AudioPorts *port : m_ports)
|
||||
delete port;
|
||||
|
||||
m_ports.clear();
|
||||
}
|
||||
|
||||
QDBusMessage VolumeModel::callMethod(const QString &methodName, const QList<QVariant> &argument)
|
||||
{
|
||||
QDBusInterface dbusInter(serviceName, servicePath, interfaceName, QDBusConnection::sessionBus());
|
||||
if (dbusInter.isValid()) {
|
||||
QDBusPendingCall reply = dbusInter.asyncCallWithArgumentList(methodName, argument);
|
||||
reply.waitForFinished();
|
||||
return reply.reply();
|
||||
}
|
||||
return QDBusMessage();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T VolumeModel::properties(const QString &propName)
|
||||
{
|
||||
QDBusInterface dbusInter(serviceName, servicePath, interfaceName, QDBusConnection::sessionBus());
|
||||
if (dbusInter.isValid()) {
|
||||
QByteArray ba = propName.toLatin1();
|
||||
const char *prop = ba.data();
|
||||
return dbusInter.property(prop).value<T>();
|
||||
}
|
||||
|
||||
return T();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 具体的声音设备
|
||||
* @param parent
|
||||
*/
|
||||
|
||||
AudioSink::AudioSink(QString path, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_devicePath(path)
|
||||
{
|
||||
QDBusConnection::sessionBus().connect(serviceName, path, propertiesInterface,
|
||||
"PropertiesChanged", "sa{sv}as", this, SLOT(onPropertyChanged(const QDBusMessage&)));
|
||||
}
|
||||
|
||||
AudioSink::~AudioSink()
|
||||
{
|
||||
}
|
||||
|
||||
bool AudioSink::isDefault()
|
||||
{
|
||||
QDBusInterface dbusInter(serviceName, servicePath, interfaceName, QDBusConnection::sessionBus());
|
||||
if (dbusInter.isValid()) {
|
||||
QString defaultSink = dbusInter.property("DefaultSink").value<QDBusObjectPath>().path();
|
||||
return defaultSink == m_devicePath;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AudioSink::isHeadPhone()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void AudioSink::setBalance(double value, bool isPlay)
|
||||
{
|
||||
callMethod("SetBalance", { value, isPlay });
|
||||
}
|
||||
|
||||
void AudioSink::setFade(double value)
|
||||
{
|
||||
callMethod("SetFade", { value });
|
||||
}
|
||||
|
||||
void AudioSink::setMute(bool mute)
|
||||
{
|
||||
callMethod("SetMute", { mute });
|
||||
}
|
||||
|
||||
void AudioSink::setPort(QString name)
|
||||
{
|
||||
callMethod("SetPort", { name });
|
||||
}
|
||||
|
||||
void AudioSink::setVolume(double value, bool isPlay)
|
||||
{
|
||||
callMethod("SetVolume", { value * 0.01, isPlay });
|
||||
}
|
||||
|
||||
bool AudioSink::isMute()
|
||||
{
|
||||
return getProperties<bool>("Mute");
|
||||
}
|
||||
|
||||
bool AudioSink::supportBalance()
|
||||
{
|
||||
return getProperties<bool>("SupportBalance");
|
||||
}
|
||||
|
||||
bool AudioSink::suoportFade()
|
||||
{
|
||||
return getProperties<bool>("SupportFade");
|
||||
}
|
||||
|
||||
double AudioSink::balance()
|
||||
{
|
||||
return getProperties<double>("Balance");
|
||||
}
|
||||
|
||||
double AudioSink::baseVolume()
|
||||
{
|
||||
return getProperties<double>("BaseVolume");
|
||||
}
|
||||
|
||||
double AudioSink::fade()
|
||||
{
|
||||
return getProperties<double>("Fade");
|
||||
}
|
||||
|
||||
int AudioSink::volume()
|
||||
{
|
||||
return static_cast<int>(getProperties<double>("Volume") * 100);
|
||||
}
|
||||
|
||||
QString AudioSink::description()
|
||||
{
|
||||
QVariantList value = getPropertiesByFreeDesktop("ActivePort");
|
||||
if (value.size() >= 2)
|
||||
return value[1].toString();
|
||||
|
||||
return getProperties<QString>("Description");
|
||||
}
|
||||
|
||||
QString AudioSink::name()
|
||||
{
|
||||
QVariantList value = getPropertiesByFreeDesktop("ActivePort");
|
||||
if (value.size() >= 2)
|
||||
return value[0].toString();
|
||||
|
||||
return getProperties<QString>("Name");
|
||||
}
|
||||
|
||||
int AudioSink::cardId()
|
||||
{
|
||||
return getProperties<int>("Card");
|
||||
}
|
||||
|
||||
void AudioSink::onPropertyChanged(const QDBusMessage &msg)
|
||||
{
|
||||
QList<QVariant> arguments = msg.arguments();
|
||||
if (3 != arguments.count())
|
||||
return;
|
||||
|
||||
QString interfaceName = msg.arguments().at(0).toString();
|
||||
if (interfaceName != propertiesInterface)
|
||||
return;
|
||||
|
||||
QVariantMap changedProps = qdbus_cast<QVariantMap>(arguments.at(1).value<QDBusArgument>());
|
||||
if (changedProps.contains("Volume"))
|
||||
Q_EMIT volumeChanged(static_cast<int>(changedProps.value("Volume").toDouble() * 100));
|
||||
|
||||
if (changedProps.contains("Mute"))
|
||||
Q_EMIT muteChanged(changedProps.value("Mute").toBool());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T AudioSink::getProperties(const QString &propName)
|
||||
{
|
||||
QDBusInterface dbusInter(serviceName, m_devicePath, interfaceName + QString(".Sink"), QDBusConnection::sessionBus());
|
||||
if (dbusInter.isValid()) {
|
||||
QByteArray ba = propName.toLatin1();
|
||||
const char *prop = ba.data();
|
||||
return dbusInter.property(prop).value<T>();
|
||||
}
|
||||
|
||||
return T();
|
||||
}
|
||||
|
||||
QDBusMessage AudioSink::callMethod(const QString &methodName, const QList<QVariant> &argument)
|
||||
{
|
||||
QDBusInterface dbusInter(serviceName, m_devicePath, interfaceName + QString(".Sink"), QDBusConnection::sessionBus());
|
||||
if (dbusInter.isValid()) {
|
||||
QDBusPendingCall reply = dbusInter.asyncCallWithArgumentList(methodName, argument);
|
||||
reply.waitForFinished();
|
||||
return reply.reply();
|
||||
}
|
||||
|
||||
return QDBusMessage();
|
||||
}
|
||||
|
||||
static QVariantList argToString(const QDBusArgument &busArg)
|
||||
{
|
||||
QVariantList out;
|
||||
QString busSig = busArg.currentSignature();
|
||||
bool doIterate = false;
|
||||
QDBusArgument::ElementType elementType = busArg.currentType();
|
||||
|
||||
switch (elementType) {
|
||||
case QDBusArgument::BasicType:
|
||||
case QDBusArgument::VariantType: {
|
||||
QVariant value = busArg.asVariant();
|
||||
switch (value.type()) {
|
||||
case QVariant::Bool:
|
||||
out << value.toBool();
|
||||
break;
|
||||
case QVariant::Int:
|
||||
out << value.toInt();
|
||||
break;
|
||||
case QVariant::String:
|
||||
out << value.toString();
|
||||
break;
|
||||
case QVariant::UInt:
|
||||
out << value.toUInt();
|
||||
break;
|
||||
case QVariant::ULongLong:
|
||||
out << value.toULongLong();
|
||||
break;
|
||||
case QMetaType::UChar:
|
||||
out << value.toUInt();
|
||||
break;
|
||||
default:
|
||||
out << QVariant();
|
||||
break;
|
||||
}
|
||||
out += busArg.asVariant().toString();
|
||||
break;
|
||||
}
|
||||
case QDBusArgument::StructureType:
|
||||
busArg.beginStructure();
|
||||
doIterate = true;
|
||||
break;
|
||||
case QDBusArgument::ArrayType:
|
||||
busArg.beginArray();
|
||||
doIterate = true;
|
||||
break;
|
||||
case QDBusArgument::MapType:
|
||||
busArg.beginMap();
|
||||
doIterate = true;
|
||||
break;
|
||||
case QDBusArgument::UnknownType:
|
||||
default:
|
||||
out << QVariant();
|
||||
return out;
|
||||
}
|
||||
|
||||
if (doIterate && !busArg.atEnd()) {
|
||||
while (!busArg.atEnd()) {
|
||||
out << argToString(busArg);
|
||||
if (out.isEmpty())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
QVariantList AudioSink::getPropertiesByFreeDesktop(const QString &propName)
|
||||
{
|
||||
QDBusInterface dbusInter(serviceName, m_devicePath, "org.freedesktop.DBus.Properties", QDBusConnection::sessionBus());
|
||||
if (dbusInter.isValid()) {
|
||||
QDBusPendingCall reply = dbusInter.asyncCallWithArgumentList("Get", { interfaceName + ".Sink", propName });
|
||||
reply.waitForFinished();
|
||||
QVariantList lists = reply.reply().arguments();
|
||||
for (QVariantList::ConstIterator it = lists.begin(); it != lists.end(); ++it) {
|
||||
QVariant arg = (*it);
|
||||
const QVariant v = qvariant_cast<QDBusVariant>(arg).variant();
|
||||
return argToString(v.value<QDBusArgument>());
|
||||
}
|
||||
}
|
||||
|
||||
return QVariantList();
|
||||
}
|
||||
|
||||
AudioPorts::AudioPorts(int cardId, QString cardName)
|
||||
: m_cardId(cardId)
|
||||
, m_cardName(cardName)
|
||||
, m_isCheck(false)
|
||||
, m_isHeadPhone(false)
|
||||
{
|
||||
}
|
||||
|
||||
AudioPorts::~AudioPorts()
|
||||
{
|
||||
}
|
||||
|
||||
int AudioPorts::cardId() const
|
||||
{
|
||||
return m_cardId;
|
||||
}
|
||||
|
||||
QString AudioPorts::cardName() const
|
||||
{
|
||||
return m_cardName;
|
||||
}
|
||||
|
||||
void AudioPorts::setName(const QString &name)
|
||||
{
|
||||
m_portName = name;
|
||||
}
|
||||
|
||||
QString AudioPorts::name() const
|
||||
{
|
||||
return m_portName;
|
||||
}
|
||||
|
||||
void AudioPorts::setDescription(const QString &desc)
|
||||
{
|
||||
m_description = desc;
|
||||
}
|
||||
|
||||
QString AudioPorts::description() const
|
||||
{
|
||||
return m_description;
|
||||
}
|
||||
|
||||
void AudioPorts::setDirection(int dir)
|
||||
{
|
||||
m_direction = dir;
|
||||
}
|
||||
|
||||
void AudioPorts::setIsChecked(bool isChecked)
|
||||
{
|
||||
m_isCheck = isChecked;
|
||||
}
|
||||
|
||||
int AudioPorts::direction() const
|
||||
{
|
||||
return m_direction;
|
||||
}
|
||||
|
||||
bool AudioPorts::isChecked() const
|
||||
{
|
||||
return m_isCheck;
|
||||
}
|
||||
|
||||
bool AudioPorts::isHeadPhone() const
|
||||
{
|
||||
return m_isHeadPhone;
|
||||
}
|
141
frame/model/volumemodel.h
Normal file
@ -0,0 +1,141 @@
|
||||
#ifndef VOLUMNMODEL_H
|
||||
#define VOLUMNMODEL_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class QDBusMessage;
|
||||
class AudioSink;
|
||||
class AudioPorts;
|
||||
|
||||
class VolumeModel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_SIGNALS:
|
||||
void defaultSinkChanged(AudioSink *);
|
||||
void volumeChanged(int);
|
||||
void muteChanged(bool);
|
||||
void checkPortChanged();
|
||||
|
||||
public:
|
||||
explicit VolumeModel(QObject *parent);
|
||||
~VolumeModel();
|
||||
|
||||
void setActivePort(AudioPorts *port);
|
||||
|
||||
QList<AudioSink *> sinks() const;
|
||||
QList<AudioPorts *> ports() const;
|
||||
|
||||
AudioSink *defaultSink() const;
|
||||
|
||||
void setVolume(int volume);
|
||||
void setMute(bool value);
|
||||
|
||||
int volume();
|
||||
bool isMute();
|
||||
bool existActiveOutputDevice();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onPropertyChanged(const QDBusMessage& msg);
|
||||
|
||||
private:
|
||||
void initService();
|
||||
void reloadSinks();
|
||||
void reloadPorts();
|
||||
void clearSinks();
|
||||
void clearPorts();
|
||||
void updateDefaultSink(AudioSink *audioSink);
|
||||
|
||||
private:
|
||||
QDBusMessage callMethod(const QString &methodName, const QList<QVariant> &argument);
|
||||
template<typename T>
|
||||
T properties(const QString &propName);
|
||||
|
||||
private:
|
||||
QList<AudioSink *> m_sinks;
|
||||
QList<AudioPorts *> m_ports;
|
||||
};
|
||||
|
||||
class AudioSink : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class VolumeModel;
|
||||
|
||||
Q_SIGNALS:
|
||||
void volumeChanged(int);
|
||||
void muteChanged(bool);
|
||||
|
||||
public:
|
||||
bool isDefault();
|
||||
bool isHeadPhone();
|
||||
|
||||
void setBalance(double value, bool isPlay);
|
||||
void setFade(double value);
|
||||
void setMute(bool mute);
|
||||
void setPort(QString name);
|
||||
void setVolume(double value, bool isPlay);
|
||||
|
||||
bool isMute();
|
||||
bool supportBalance();
|
||||
bool suoportFade();
|
||||
double balance();
|
||||
double baseVolume();
|
||||
double fade();
|
||||
int volume();
|
||||
QString description();
|
||||
QString name();
|
||||
int cardId();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onPropertyChanged(const QDBusMessage& msg);
|
||||
|
||||
protected:
|
||||
explicit AudioSink(QString path, QObject *parent = nullptr);
|
||||
~AudioSink();
|
||||
|
||||
private:
|
||||
QDBusMessage callMethod(const QString &methodName, const QList<QVariant> &argument);
|
||||
template<typename T>
|
||||
T getProperties(const QString &propName);
|
||||
|
||||
QList<QVariant> getPropertiesByFreeDesktop(const QString &propName);
|
||||
|
||||
private:
|
||||
QString m_devicePath;
|
||||
};
|
||||
|
||||
class AudioPorts : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class VolumeModel;
|
||||
|
||||
public:
|
||||
int cardId() const;
|
||||
QString cardName() const;
|
||||
QString name() const;
|
||||
QString description() const;
|
||||
int direction() const;
|
||||
bool isChecked() const;
|
||||
bool isHeadPhone() const;
|
||||
|
||||
protected:
|
||||
AudioPorts(int cardId, QString cardName);
|
||||
~AudioPorts();
|
||||
void setName(const QString &name);
|
||||
void setDescription(const QString &desc);
|
||||
void setDirection(int dir);
|
||||
void setIsChecked(bool isChecked);
|
||||
|
||||
private:
|
||||
int m_cardId;
|
||||
QString m_cardName;
|
||||
QString m_portName;
|
||||
QString m_description;
|
||||
int m_direction;
|
||||
bool m_isCheck;
|
||||
bool m_isHeadPhone;
|
||||
};
|
||||
|
||||
#endif // VOLUMNMODEL_H
|
171
frame/window/components/brightnessmonitorwidget.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
#include "brightnessmonitorwidget.h"
|
||||
#include "brightnessmodel.h"
|
||||
#include "customslider.h"
|
||||
#include "settingdelegate.h"
|
||||
|
||||
#include <DListView>
|
||||
|
||||
#include <QScrollBar>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
#include <QEvent>
|
||||
#include <QProcess>
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusConnection>
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
|
||||
#define ITEMSPACE 16
|
||||
|
||||
BrightnessMonitorWidget::BrightnessMonitorWidget(BrightnessModel *model, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_sliderWidget(new QWidget(this))
|
||||
, m_sliderLayout(new QVBoxLayout(m_sliderWidget))
|
||||
, m_descriptionLabel(new QLabel(tr("Output Device"), this))
|
||||
, m_deviceList(new DListView(this))
|
||||
, m_brightModel(model)
|
||||
, m_model(new QStandardItemModel(this))
|
||||
, m_delegate(new SettingDelegate(m_deviceList))
|
||||
{
|
||||
initUi();
|
||||
initConnection();
|
||||
reloadMonitor();
|
||||
|
||||
QMetaObject::invokeMethod(this, [ this ]{
|
||||
resetHeight();
|
||||
}, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
BrightnessMonitorWidget::~BrightnessMonitorWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void BrightnessMonitorWidget::initUi()
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(10, 12, 10, 12);
|
||||
layout->setSpacing(6);
|
||||
|
||||
m_sliderLayout->setContentsMargins(0, 0, 0, 0);
|
||||
m_sliderLayout->setSpacing(5);
|
||||
|
||||
QList<BrightMonitor *> monitors = m_brightModel->monitors();
|
||||
for (BrightMonitor *monitor : monitors) {
|
||||
SliderContainer *container = new SliderContainer(CustomSlider::Normal, m_sliderWidget);
|
||||
container->setTitle(monitor->name());
|
||||
container->slider()->setIconSize(QSize(20, 20));
|
||||
container->slider()->setLeftIcon(QIcon(":/icons/resources/brightnesslow"));
|
||||
container->slider()->setRightIcon(QIcon(":/icons/resources/brightnesshigh"));
|
||||
container->setFixedHeight(50);
|
||||
m_sliderLayout->addWidget(container);
|
||||
|
||||
m_sliderContainers << qMakePair(monitor, container);
|
||||
}
|
||||
|
||||
layout->addSpacing(ITEMSPACE - layout->spacing());
|
||||
layout->addWidget(m_sliderWidget);
|
||||
layout->addSpacing(4);
|
||||
layout->addWidget(m_descriptionLabel);
|
||||
|
||||
m_deviceList->setContentsMargins(0, 0, 0, 0);
|
||||
m_deviceList->setModel(m_model);
|
||||
m_deviceList->setViewMode(QListView::ListMode);
|
||||
m_deviceList->setMovement(QListView::Free);
|
||||
m_deviceList->setItemRadius(12);
|
||||
m_deviceList->setWordWrap(false);
|
||||
m_deviceList->verticalScrollBar()->setVisible(false);
|
||||
m_deviceList->horizontalScrollBar()->setVisible(false);
|
||||
m_deviceList->setOrientation(QListView::Flow::TopToBottom, false);
|
||||
layout->addWidget(m_deviceList);
|
||||
layout->addStretch();
|
||||
m_deviceList->setSpacing(10);
|
||||
|
||||
m_deviceList->setItemDelegate(m_delegate);
|
||||
}
|
||||
|
||||
void BrightnessMonitorWidget::initConnection()
|
||||
{
|
||||
connect(m_delegate, &SettingDelegate::selectIndexChanged, this, [ this ](const QModelIndex &index) {
|
||||
BrightMonitor *monitor = index.data(itemDataRole).value<BrightMonitor *>();
|
||||
if (monitor) {
|
||||
m_deviceList->update();
|
||||
// 更新滚动条的内容
|
||||
onBrightChanged(monitor);
|
||||
} else {
|
||||
QDBusInterface controlcenter("com.deepin.dde.ControlCenter", "/com/deepin/dde/ControlCenter",
|
||||
"com.deepin.dde.ControlCenter", QDBusConnection::sessionBus());
|
||||
controlcenter.call("ShowModule", "display");
|
||||
hide();
|
||||
}
|
||||
});
|
||||
|
||||
for (QPair<BrightMonitor *, SliderContainer *> container : m_sliderContainers) {
|
||||
SliderContainer *slider = container.second;
|
||||
connect(slider->slider(), &CustomSlider::valueChanged, this, [ = ](int value) {
|
||||
m_brightModel->setBrightness(container.first, value);
|
||||
});
|
||||
}
|
||||
|
||||
connect(m_brightModel, &BrightnessModel::brightnessChanged, this, &BrightnessMonitorWidget::onBrightChanged);
|
||||
}
|
||||
|
||||
void BrightnessMonitorWidget::reloadMonitor()
|
||||
{
|
||||
m_model->clear();
|
||||
QList<BrightMonitor *> monitots = m_brightModel->monitors();
|
||||
for (BrightMonitor *monitor : monitots) {
|
||||
DStandardItem *item = new DStandardItem;
|
||||
item->setIcon(QIcon(":/icons/resources/laptop.svg"));
|
||||
item->setText(monitor->name());
|
||||
item->setFlags(Qt::NoItemFlags);
|
||||
item->setData(QVariant::fromValue(monitor), itemDataRole);
|
||||
m_model->appendRow(item);
|
||||
onBrightChanged(monitor);
|
||||
}
|
||||
// 显示设置
|
||||
DStandardItem *settingItem = new DStandardItem;
|
||||
settingItem->setIcon(QIcon(""));
|
||||
settingItem->setText(tr("Display settings"));
|
||||
settingItem->setFlags(Qt::NoItemFlags);
|
||||
settingItem->setData(false, itemCheckRole);
|
||||
m_model->appendRow(settingItem);
|
||||
}
|
||||
|
||||
void BrightnessMonitorWidget::onBrightChanged(BrightMonitor *monitor)
|
||||
{
|
||||
for (QPair<BrightMonitor *, SliderContainer *> container : m_sliderContainers) {
|
||||
SliderContainer *slider = container.second;
|
||||
if (container.first == monitor) {
|
||||
slider->slider()->blockSignals(true);
|
||||
slider->slider()->setValue(monitor->brihtness());
|
||||
slider->slider()->blockSignals(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BrightnessMonitorWidget::resetHeight()
|
||||
{
|
||||
int viewHeight = 0;
|
||||
for (int i = 0; i < m_model->rowCount(); i++) {
|
||||
QRect indexRect = m_deviceList->visualRect(m_model->index(i, 0));
|
||||
viewHeight += indexRect.height();
|
||||
// 上下间距
|
||||
viewHeight += m_deviceList->spacing() * 2;
|
||||
}
|
||||
// 设置列表的高度
|
||||
m_deviceList->setFixedHeight(viewHeight);
|
||||
QMargins sliderMargin = m_sliderLayout->contentsMargins();
|
||||
int sliderHeight = sliderMargin.top() + sliderMargin.bottom();
|
||||
for (QPair<BrightMonitor *, SliderContainer *> container : m_sliderContainers) {
|
||||
SliderContainer *slider = container.second;
|
||||
sliderHeight += slider->height();
|
||||
}
|
||||
|
||||
m_sliderWidget->setFixedHeight(sliderHeight);
|
||||
QMargins m = layout()->contentsMargins();
|
||||
int space1 = ITEMSPACE - layout()->spacing();
|
||||
int space2 = 4;
|
||||
int height = m.top() + m.bottom() + sliderHeight + space1
|
||||
+ m_descriptionLabel->height() + space2 + m_deviceList->height();
|
||||
setFixedHeight(height);
|
||||
}
|
49
frame/window/components/brightnessmonitorwidget.h
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef BRIGHTNESSMONITORWIDGET_H
|
||||
#define BRIGHTNESSMONITORWIDGET_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QWidget>
|
||||
|
||||
class QLabel;
|
||||
class CustomSlider;
|
||||
class BrightnessModel;
|
||||
class QStandardItemModel;
|
||||
class QVBoxLayout;
|
||||
class SliderContainer;
|
||||
class BrightMonitor;
|
||||
class SettingDelegate;
|
||||
|
||||
namespace Dtk { namespace Widget { class DListView; } }
|
||||
|
||||
using namespace Dtk::Widget;
|
||||
|
||||
class BrightnessMonitorWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BrightnessMonitorWidget(BrightnessModel *model, QWidget *parent = nullptr);
|
||||
~BrightnessMonitorWidget() override;
|
||||
|
||||
private:
|
||||
void initUi();
|
||||
void initConnection();
|
||||
void reloadMonitor();
|
||||
|
||||
void resetHeight();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onBrightChanged(BrightMonitor *monitor);
|
||||
|
||||
private:
|
||||
QWidget *m_sliderWidget;
|
||||
QVBoxLayout *m_sliderLayout;
|
||||
QList<QPair<BrightMonitor *, SliderContainer *>> m_sliderContainers;
|
||||
QLabel *m_descriptionLabel;
|
||||
DListView *m_deviceList;
|
||||
BrightnessModel *m_brightModel;
|
||||
QStandardItemModel *m_model;
|
||||
SettingDelegate *m_delegate;
|
||||
};
|
||||
|
||||
#endif // BRIGHTNESSMONITORWIDGET_H
|
70
frame/window/components/brightnesswidget.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#include "brightnesswidget.h"
|
||||
#include "customslider.h"
|
||||
#include "brightnessmodel.h"
|
||||
#include "brightnessmonitorwidget.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QDebug>
|
||||
|
||||
BrightnessWidget::BrightnessWidget(QWidget *parent)
|
||||
: DBlurEffectWidget(parent)
|
||||
, m_slider(new CustomSlider(CustomSlider::SliderType::Normal, this))
|
||||
, m_model(new BrightnessModel(this))
|
||||
{
|
||||
initUi();
|
||||
initConenction();
|
||||
onUpdateBright();
|
||||
}
|
||||
|
||||
BrightnessWidget::~BrightnessWidget()
|
||||
{
|
||||
}
|
||||
|
||||
BrightnessModel *BrightnessWidget::model()
|
||||
{
|
||||
return m_model;
|
||||
}
|
||||
|
||||
void BrightnessWidget::showEvent(QShowEvent *event)
|
||||
{
|
||||
DBlurEffectWidget::showEvent(event);
|
||||
Q_EMIT visibleChanged(true);
|
||||
}
|
||||
|
||||
void BrightnessWidget::hideEvent(QHideEvent *event)
|
||||
{
|
||||
DBlurEffectWidget::hideEvent(event);
|
||||
Q_EMIT visibleChanged(true);
|
||||
}
|
||||
|
||||
void BrightnessWidget::initUi()
|
||||
{
|
||||
QHBoxLayout *layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(20, 0, 20, 0);
|
||||
layout->addWidget(m_slider);
|
||||
|
||||
m_slider->setPageStep(1);
|
||||
m_slider->setIconSize(QSize(24, 24));
|
||||
|
||||
m_slider->setLeftIcon(QIcon(":/icons/resources/brightness.svg"));
|
||||
m_slider->setRightIcon(QIcon::fromTheme(":/icons/resources/ICON_Device_Laptop.svg"));
|
||||
m_slider->setTickPosition(QSlider::TicksBelow);
|
||||
}
|
||||
|
||||
void BrightnessWidget::initConenction()
|
||||
{
|
||||
connect(m_slider, &CustomSlider::iconClicked, this, [ this ](DSlider::SliderIcons icon, bool) {
|
||||
if (icon == DSlider::SliderIcons::RightIcon)
|
||||
Q_EMIT rightIconClicked();
|
||||
});
|
||||
connect(m_slider, &CustomSlider::valueChanged, this, [ this ](int value) {
|
||||
|
||||
});
|
||||
|
||||
connect(m_model, &BrightnessModel::brightnessChanged, this, &BrightnessWidget::onUpdateBright);
|
||||
}
|
||||
|
||||
void BrightnessWidget::onUpdateBright()
|
||||
{
|
||||
|
||||
}
|
41
frame/window/components/brightnesswidget.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef BRIGHTNESSWIDGET_H
|
||||
#define BRIGHTNESSWIDGET_H
|
||||
|
||||
#include <DBlurEffectWidget>
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
|
||||
class CustomSlider;
|
||||
class BrightnessModel;
|
||||
class BrightMonitor;
|
||||
|
||||
class BrightnessWidget : public DBlurEffectWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BrightnessWidget(QWidget *parent = nullptr);
|
||||
~BrightnessWidget() override;
|
||||
BrightnessModel *model();
|
||||
|
||||
Q_SIGNALS:
|
||||
void visibleChanged(bool);
|
||||
void rightIconClicked();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void onUpdateBright();
|
||||
|
||||
private:
|
||||
void initUi();
|
||||
void initConenction();
|
||||
|
||||
private:
|
||||
CustomSlider *m_slider;
|
||||
BrightnessModel *m_model;
|
||||
};
|
||||
|
||||
#endif // LIGHTSETTINGWIDGET_H
|
214
frame/window/components/customslider.cpp
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
*
|
||||
* Author: sbw <sbw@sbw.so>
|
||||
*
|
||||
* Maintainer: sbw <sbw@sbw.so>
|
||||
*
|
||||
* 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
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "customslider.h"
|
||||
|
||||
#include <DStyle>
|
||||
#include <DApplicationHelper>
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
|
||||
CustomSlider::CustomSlider(CustomSlider::SliderType type, QWidget *parent)
|
||||
: DSlider(Qt::Horizontal, parent)
|
||||
, m_separateValue(0)
|
||||
{
|
||||
setType(type);
|
||||
DSlider::slider()->setTracking(false);
|
||||
}
|
||||
|
||||
CustomSlider::CustomSlider(Qt::Orientation orientation, QWidget *parent)
|
||||
: DSlider(orientation, parent)
|
||||
{
|
||||
DSlider::slider()->setTracking(false);
|
||||
}
|
||||
|
||||
void CustomSlider::setType(CustomSlider::SliderType type)
|
||||
{
|
||||
switch (type) {
|
||||
case Vernier: setProperty("handleType", "Vernier"); break;
|
||||
case Progress: setProperty("handleType", "None"); break;
|
||||
default: setProperty("handleType", "Normal"); break;
|
||||
}
|
||||
}
|
||||
|
||||
QSlider *CustomSlider::qtSlider()
|
||||
{
|
||||
return DSlider::slider();
|
||||
}
|
||||
|
||||
void CustomSlider::setRange(int min, int max)
|
||||
{
|
||||
setMinimum(min);
|
||||
setMaximum(max);
|
||||
}
|
||||
|
||||
void CustomSlider::setTickPosition(QSlider::TickPosition tick)
|
||||
{
|
||||
m_tickPosition = tick;
|
||||
}
|
||||
|
||||
void CustomSlider::setTickInterval(int ti)
|
||||
{
|
||||
DSlider::slider()->setTickInterval(ti);
|
||||
}
|
||||
|
||||
void CustomSlider::setSliderPosition(int Position)
|
||||
{
|
||||
DSlider::slider()->setSliderPosition(Position);
|
||||
}
|
||||
|
||||
void CustomSlider::setAnnotations(const QStringList &annotations)
|
||||
{
|
||||
switch (m_tickPosition) {
|
||||
case QSlider::TicksLeft:
|
||||
setLeftTicks(annotations);
|
||||
break;
|
||||
case QSlider::TicksRight:
|
||||
setRightTicks(annotations);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CustomSlider::setOrientation(Qt::Orientation orientation)
|
||||
{
|
||||
Q_UNUSED(orientation)
|
||||
}
|
||||
|
||||
void CustomSlider::setSeparateValue(int value)
|
||||
{
|
||||
m_separateValue = value;
|
||||
}
|
||||
|
||||
void CustomSlider::wheelEvent(QWheelEvent *e)
|
||||
{
|
||||
e->ignore();
|
||||
}
|
||||
|
||||
void CustomSlider::paintEvent(QPaintEvent *e)
|
||||
{
|
||||
Q_UNUSED(e)
|
||||
|
||||
if (m_separateValue <= 0)
|
||||
return;
|
||||
|
||||
QPainter pa(this);
|
||||
auto dpa = DApplicationHelper::instance()->palette(this);
|
||||
QPen penLine = QPen(dpa.color(DPalette::ObviousBackground), 2);
|
||||
|
||||
//超过间隔线后需要更换间隔线颜色为活动色
|
||||
if (qtSlider()->value() >= m_separateValue ) {
|
||||
QPalette pe = this->palette();
|
||||
QColor brushColor(pe.color(QPalette::Highlight));
|
||||
penLine.setColor(brushColor);
|
||||
}
|
||||
|
||||
int margin = DStyle::pixelMetric(style(), DStyle::PM_FocusBorderSpacing) + DStyle::pixelMetric(style(), DStyle::PM_FocusBorderSpacing);
|
||||
int offsetSize = style()->pixelMetric(QStyle::PM_SliderLength, nullptr, this) / 2;
|
||||
int width = this->qtSlider()->width();
|
||||
|
||||
width -= 2 * offsetSize + margin * 2;
|
||||
Qt::Orientation orient = this->orientation();
|
||||
QSlider::TickPosition tick = m_tickPosition;
|
||||
QSlider* slider = DSlider::slider();
|
||||
qreal percentage = (m_separateValue - slider->minimum()) * 1.0 / (slider->maximum() - slider->minimum());
|
||||
|
||||
pa.setPen(penLine);
|
||||
int leftIconwidth = 0;
|
||||
//获取左边声音图标宽度
|
||||
QGridLayout *gridLayout = dynamic_cast<QGridLayout *>(this->layout());
|
||||
if (!gridLayout)
|
||||
return;
|
||||
QLayoutItem* item = gridLayout->itemAtPosition(1, 0);
|
||||
if (item) {
|
||||
leftIconwidth = item->geometry().size().width();
|
||||
}
|
||||
|
||||
qreal startX = offsetSize + margin + leftIconwidth + this->contentsMargins().left();
|
||||
qreal startY = slider->y() + 10;
|
||||
//分别绘制滑动条上方矩形和下方矩形,避免与滑动条重叠,
|
||||
//画笔宽为2个像素,设置绘制时矩形高设为3,可达到高度为5的效果
|
||||
if (orient == Qt::Horizontal) {
|
||||
qreal sliderX = percentage * width;
|
||||
if (slider->value() >= m_separateValue) {
|
||||
int num = (sliderX + 2) / 3;
|
||||
qAbs(3 * num + 1 - sliderX) - qAbs(sliderX - (3 * num - 2)) >= 0 ? num : num++;
|
||||
sliderX = 3 * num - 2;
|
||||
} else {
|
||||
//将分割线左、右的滚动条进行比较获取距离最相近的位置,绘制分割线
|
||||
sliderX = (slider->maximum() - m_separateValue) * 1.0 * width / slider->maximum();
|
||||
int num = (sliderX + 1) / 3;
|
||||
qAbs(3 * num - sliderX) - qAbs(sliderX - 3 * (num - 1)) >= 0 ? num : num++;
|
||||
sliderX = width - (3 * num - 1);
|
||||
}
|
||||
if (tick == QSlider::TicksAbove || tick == QSlider::TicksBelow || tick == QSlider::NoTicks) {
|
||||
pa.drawLine(QPointF(startX + sliderX, startY), QPointF(startX + sliderX, startY + 3));
|
||||
pa.drawLine(QPointF(startX + sliderX, startY + 9), QPointF(startX + sliderX, startY + 12));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SliderContainer::SliderContainer(CustomSlider::SliderType type, QWidget *parent)
|
||||
: QWidget (parent)
|
||||
, m_slider(new CustomSlider(type, this))
|
||||
, m_titleLabel(new QLabel(this))
|
||||
{
|
||||
QVBoxLayout *mainlayout = new QVBoxLayout(this);
|
||||
mainlayout->setContentsMargins(0, 0, 0, 0);
|
||||
mainlayout->setSpacing(5);
|
||||
mainlayout->addWidget(m_titleLabel);
|
||||
mainlayout->addWidget(m_slider);
|
||||
}
|
||||
|
||||
SliderContainer::SliderContainer(Qt::Orientation orientation, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_slider(new CustomSlider(orientation, this))
|
||||
, m_titleLabel(new QLabel(this))
|
||||
{
|
||||
QVBoxLayout *mainlayout = new QVBoxLayout(this);
|
||||
mainlayout->setContentsMargins(0, 1, 0, 0);
|
||||
mainlayout->setSpacing(1);
|
||||
|
||||
m_titleLabel->setFixedHeight(8);
|
||||
mainlayout->addWidget(m_titleLabel);
|
||||
mainlayout->addWidget(m_slider);
|
||||
}
|
||||
|
||||
SliderContainer::~SliderContainer()
|
||||
{
|
||||
}
|
||||
|
||||
void SliderContainer::setTitle(const QString &title)
|
||||
{
|
||||
m_titleLabel->setText(title);
|
||||
}
|
||||
|
||||
CustomSlider *SliderContainer::slider()
|
||||
{
|
||||
return m_slider;
|
||||
}
|
82
frame/window/components/customslider.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
*
|
||||
* Author: sbw <sbw@sbw.so>
|
||||
*
|
||||
* Maintainer: sbw <sbw@sbw.so>
|
||||
*
|
||||
* 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
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CUSTOMCTRL_H
|
||||
#define CUSTOMCTRL_H
|
||||
|
||||
#include <DSlider>
|
||||
#include <QTimer>
|
||||
|
||||
class QLabel;
|
||||
|
||||
class CustomSlider : public DTK_WIDGET_NAMESPACE::DSlider
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum SliderType {
|
||||
Normal,
|
||||
Vernier,
|
||||
Progress
|
||||
};
|
||||
|
||||
public:
|
||||
explicit CustomSlider(SliderType type = Normal, QWidget *parent = nullptr);
|
||||
explicit CustomSlider(Qt::Orientation orientation, QWidget *parent = nullptr);
|
||||
|
||||
inline CustomSlider *slider() const { return const_cast<CustomSlider *>(this); }
|
||||
QSlider *qtSlider();
|
||||
|
||||
void setType(SliderType type);
|
||||
void setRange(int min, int max);
|
||||
void setTickPosition(QSlider::TickPosition tick);
|
||||
void setTickInterval(int ti);
|
||||
void setSliderPosition(int Position);
|
||||
void setAnnotations(const QStringList &annotations);
|
||||
void setOrientation(Qt::Orientation orientation);
|
||||
//当value大于0时,在slider中插入一条分隔线
|
||||
void setSeparateValue(int value = 0);
|
||||
|
||||
protected:
|
||||
void wheelEvent(QWheelEvent *e);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
private:
|
||||
QSlider::TickPosition m_tickPosition = QSlider::TicksBelow;
|
||||
int m_separateValue;
|
||||
};
|
||||
|
||||
class SliderContainer : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SliderContainer(CustomSlider::SliderType type = CustomSlider::Normal, QWidget *parent = nullptr);
|
||||
explicit SliderContainer(Qt::Orientation orientation, QWidget *parent);
|
||||
~SliderContainer();
|
||||
void setTitle(const QString &title);
|
||||
CustomSlider *slider();
|
||||
|
||||
private:
|
||||
CustomSlider *m_slider;
|
||||
QLabel *m_titleLabel;
|
||||
};
|
||||
|
||||
#endif // VOLUMESLIDER_H
|
178
frame/window/components/mediawidget.cpp
Normal file
@ -0,0 +1,178 @@
|
||||
#include "mediawidget.h"
|
||||
|
||||
#include <DFontSizeManager>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QEvent>
|
||||
#include <QPainter>
|
||||
#include <QDebug>
|
||||
#include <QPainterPath>
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
|
||||
MediaWidget::MediaWidget(QWidget *parent)
|
||||
: DBlurEffectWidget(parent)
|
||||
, m_musicIcon(new QLabel(this))
|
||||
, m_musicName(new QLabel(this))
|
||||
, m_musicSinger(new QLabel(this))
|
||||
, m_pausePlayButton(new MusicButton(this))
|
||||
, m_nextButton(new MusicButton(this))
|
||||
{
|
||||
initUi();
|
||||
initConnection();
|
||||
}
|
||||
|
||||
MediaWidget::~MediaWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void MediaWidget::showEvent(QShowEvent *event)
|
||||
{
|
||||
DBlurEffectWidget::showEvent(event);
|
||||
Q_EMIT visibleChanged(true);
|
||||
}
|
||||
|
||||
void MediaWidget::hideEvent(QHideEvent *event)
|
||||
{
|
||||
DBlurEffectWidget::hideEvent(event);
|
||||
Q_EMIT visibleChanged(false);
|
||||
}
|
||||
|
||||
void MediaWidget::statusChanged(const MediaPlayerModel::PlayStatus &newStatus)
|
||||
{
|
||||
switch (newStatus) {
|
||||
case MediaPlayerModel::PlayStatus::Play: {
|
||||
m_pausePlayButton->setButtonType(MusicButton::ButtonType::Pause);
|
||||
break;
|
||||
}
|
||||
case MediaPlayerModel::PlayStatus::Stop:
|
||||
case MediaPlayerModel::PlayStatus::Pause: {
|
||||
m_pausePlayButton->setButtonType(MusicButton::ButtonType::Playing);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void MediaWidget::onPlayClicked()
|
||||
{
|
||||
// 设置当前的播放状态
|
||||
MediaPlayerModel *player = MediaPlayerModel::instance();
|
||||
if (player->status() == MediaPlayerModel::PlayStatus::Play)
|
||||
player->setStatus(MediaPlayerModel::PlayStatus::Pause);
|
||||
else
|
||||
player->setStatus(MediaPlayerModel::PlayStatus::Play);
|
||||
}
|
||||
|
||||
void MediaWidget::onNext()
|
||||
{
|
||||
// 播放下一曲
|
||||
MediaPlayerModel *player = MediaPlayerModel::instance();
|
||||
player->playNext();
|
||||
}
|
||||
|
||||
void MediaWidget::initUi()
|
||||
{
|
||||
m_pausePlayButton->setFixedWidth(20);
|
||||
m_nextButton->setFixedWidth(20);
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout(this);
|
||||
mainLayout->setContentsMargins(20, 0, 20, 0);
|
||||
mainLayout->addWidget(m_musicIcon);
|
||||
|
||||
QWidget *infoWidget = new QWidget(this);
|
||||
QVBoxLayout *infoLayout = new QVBoxLayout(infoWidget);
|
||||
infoLayout->addWidget(m_musicName);
|
||||
infoLayout->addWidget(m_musicSinger);
|
||||
mainLayout->addWidget(infoWidget);
|
||||
mainLayout->addWidget(m_pausePlayButton);
|
||||
mainLayout->addSpacing(25);
|
||||
mainLayout->addWidget(m_nextButton);
|
||||
|
||||
m_musicIcon->setFixedSize(32, 32);
|
||||
m_musicName->setFont(DFontSizeManager::instance()->t8());
|
||||
m_musicSinger->setFont(DFontSizeManager::instance()->t10());
|
||||
setVisible(MediaPlayerModel::instance()->isActived());
|
||||
}
|
||||
|
||||
void MediaWidget::initConnection()
|
||||
{
|
||||
MediaPlayerModel *mediaPlayer = MediaPlayerModel::instance();
|
||||
connect(mediaPlayer, &MediaPlayerModel::startStop, this, [ this, mediaPlayer ](bool startOrStop) {
|
||||
setVisible(startOrStop);
|
||||
m_nextButton->setEnabled(mediaPlayer->canGoNext());
|
||||
onUpdateMediaInfo();
|
||||
statusChanged(mediaPlayer->status());
|
||||
});
|
||||
connect(mediaPlayer, &MediaPlayerModel::metadataChanged, this, &MediaWidget::onUpdateMediaInfo);
|
||||
connect(mediaPlayer, &MediaPlayerModel::statusChanged, this, &MediaWidget::statusChanged);
|
||||
connect(m_pausePlayButton, &MusicButton::clicked, this, &MediaWidget::onPlayClicked);
|
||||
connect(m_nextButton, &MusicButton::clicked, this, &MediaWidget::onNext);
|
||||
|
||||
m_pausePlayButton->setButtonType(mediaPlayer->status() == MediaPlayerModel::PlayStatus::Play ?
|
||||
MusicButton::ButtonType::Pause : MusicButton::ButtonType::Playing);
|
||||
m_nextButton->setButtonType(MusicButton::ButtonType::Next);
|
||||
}
|
||||
|
||||
void MediaWidget::onUpdateMediaInfo()
|
||||
{
|
||||
MediaPlayerModel *mediaPlayer = MediaPlayerModel::instance();
|
||||
m_musicName->setText(mediaPlayer->name());
|
||||
QString file = mediaPlayer->iconUrl();
|
||||
if (file.startsWith("file:///"))
|
||||
file.replace("file:///", "/");
|
||||
m_musicIcon->setPixmap(QPixmap(file).scaled(m_musicIcon->size()));
|
||||
m_musicSinger->setText(mediaPlayer->artist());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 音乐播放的相关按钮
|
||||
* @param parent
|
||||
*/
|
||||
MusicButton::MusicButton(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
installEventFilter(this);
|
||||
}
|
||||
|
||||
MusicButton::~MusicButton()
|
||||
{
|
||||
}
|
||||
|
||||
void MusicButton::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
#define ICONHEIGHT 20
|
||||
Q_UNUSED(event);
|
||||
int width = this->width();
|
||||
int height = this->height();
|
||||
int startX = 2;
|
||||
int startY = (height - ICONHEIGHT) / 2;
|
||||
QColor color(0, 0, 0);
|
||||
QPainter painter(this);
|
||||
painter.save();
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setPen(color);
|
||||
painter.setBrush(color);
|
||||
if (m_buttonType == ButtonType::Pause) {
|
||||
painter.drawRect(QRect(startX, startY, 6, ICONHEIGHT));
|
||||
painter.drawRect(QRect(width - 6 - 2, startY, 6, ICONHEIGHT));
|
||||
} else {
|
||||
QPainterPath trianglePath;
|
||||
trianglePath.moveTo(startX, startY);
|
||||
trianglePath.lineTo(width - 6, height / 2);
|
||||
trianglePath.lineTo(startX, startY + ICONHEIGHT);
|
||||
trianglePath.lineTo(startX, startY);
|
||||
painter.drawPath(trianglePath);
|
||||
if (m_buttonType == ButtonType::Next)
|
||||
painter.drawRect(width - 6, startY, 2, ICONHEIGHT);
|
||||
}
|
||||
painter.restore();
|
||||
}
|
||||
|
||||
void MusicButton::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
Q_EMIT clicked();
|
||||
}
|
74
frame/window/components/mediawidget.h
Normal file
@ -0,0 +1,74 @@
|
||||
#ifndef MEDIAWIDGET_H
|
||||
#define MEDIAWIDGET_H
|
||||
|
||||
#include "mediaplayermodel.h"
|
||||
|
||||
#include <DBlurEffectWidget>
|
||||
|
||||
class QLabel;
|
||||
class MusicButton;
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
|
||||
class MediaWidget : public DBlurEffectWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MediaWidget(QWidget *parent = nullptr);
|
||||
~MediaWidget() override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void visibleChanged(bool);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void statusChanged(const MediaPlayerModel::PlayStatus &newStatus);
|
||||
void onPlayClicked();
|
||||
void onNext();
|
||||
void onUpdateMediaInfo();
|
||||
|
||||
private:
|
||||
void initUi();
|
||||
void initConnection();
|
||||
|
||||
private:
|
||||
QLabel *m_musicIcon;
|
||||
QLabel *m_musicName;
|
||||
QLabel *m_musicSinger;
|
||||
MusicButton *m_pausePlayButton;
|
||||
MusicButton *m_nextButton;
|
||||
};
|
||||
|
||||
// 音乐播放按钮
|
||||
class MusicButton : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_SIGNALS:
|
||||
void clicked();
|
||||
|
||||
public:
|
||||
enum ButtonType { Playing = 0, Pause, Next };
|
||||
|
||||
public:
|
||||
MusicButton(QWidget *parent = Q_NULLPTR);
|
||||
~MusicButton() override;
|
||||
|
||||
inline void setButtonType(const ButtonType &bt) {
|
||||
m_buttonType = bt;
|
||||
update();
|
||||
}
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
|
||||
private:
|
||||
ButtonType m_buttonType;
|
||||
};
|
||||
|
||||
#endif // MEDIAWIDGER_H
|
90
frame/window/components/settingdelegate.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
#include "settingdelegate.h"
|
||||
|
||||
#include <DListView>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <DGuiApplicationHelper>
|
||||
#include <QPainterPath>
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
|
||||
SettingDelegate::SettingDelegate(QAbstractItemView *parent)
|
||||
: DStyledItemDelegate(parent)
|
||||
{
|
||||
parent->installEventFilter(this);
|
||||
}
|
||||
|
||||
SettingDelegate::~SettingDelegate()
|
||||
{
|
||||
}
|
||||
|
||||
void SettingDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
painter->save();
|
||||
|
||||
QRect indexRect = option.rect;
|
||||
// 绘制背景色
|
||||
bool isOver = option.state & QStyle::State_MouseOver;
|
||||
bool isDefault = index.data(itemCheckRole).toBool();
|
||||
if (isDefault) {
|
||||
QPainterPath path, path1;
|
||||
path.addRoundedRect(indexRect, 8, 8);
|
||||
|
||||
DPalette palette = DGuiApplicationHelper::instance()->applicationPalette();
|
||||
painter->fillPath(path, palette.color(QPalette::ColorRole::Highlight));
|
||||
} else {
|
||||
QPainterPath path;
|
||||
path.addRoundedRect(indexRect, 8, 8);
|
||||
painter->fillPath(path, isOver ? QColor(0, 0, 0, 100) : QColor(0, 0, 0, 64));
|
||||
}
|
||||
// 绘制图标
|
||||
QRect rectIcon = indexRect;
|
||||
rectIcon.setX(20);
|
||||
QIcon icon = index.data(Qt::DecorationRole).value<QIcon>();
|
||||
QPixmap pixmap(icon.pixmap(16, 16));
|
||||
rectIcon.setY(indexRect.y() + (rectIcon.height() - pixmap.height()) / 2);
|
||||
rectIcon.setWidth(pixmap.width());
|
||||
rectIcon.setHeight(pixmap.height());
|
||||
painter->drawPixmap(rectIcon, pixmap);
|
||||
#define RIGHTSPACE 11
|
||||
#define SELECTICONSIZE 10
|
||||
// 绘制文本
|
||||
QRect rectText;
|
||||
rectText.setX(rectIcon.left() + rectIcon.width() + 8);
|
||||
rectText.setWidth(indexRect.width() - rectText.x() - RIGHTSPACE - SELECTICONSIZE - 5);
|
||||
QPen pen(isDefault ? QColor(255, 255, 255) : QColor(0, 0, 0));
|
||||
pen.setWidth(2);
|
||||
painter->setPen(pen);
|
||||
QFont ft(DFontSizeManager::instance()->t6());
|
||||
QFontMetrics ftm(ft);
|
||||
QString text = QFontMetrics(ft).elidedText(index.data(Qt::DisplayRole).toString(), Qt::TextElideMode::ElideRight,
|
||||
rectText.width());
|
||||
painter->setFont(ft);
|
||||
rectText.setY(indexRect.y() + (indexRect.height() - QFontMetrics(ft).height()) / 2);
|
||||
rectText.setHeight(QFontMetrics(ft).height());
|
||||
painter->drawText(rectText, text);
|
||||
// 如果当前是默认的输出设备,则绘制右侧的对钩
|
||||
if (isDefault) {
|
||||
QPointF points[3] = {
|
||||
QPointF(indexRect.width() - RIGHTSPACE - SELECTICONSIZE, indexRect.center().y()),
|
||||
QPointF(indexRect.width() - RIGHTSPACE - SELECTICONSIZE / 2, rectIcon.bottom() + 2),
|
||||
QPointF(indexRect.width() - RIGHTSPACE, rectIcon.top() - 2)
|
||||
};
|
||||
painter->drawPolyline(points, 3);
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
bool SettingDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
|
||||
{
|
||||
if (event->type() == QEvent::MouseButtonRelease) {
|
||||
QRect rctIndex = option.rect;
|
||||
rctIndex.setHeight(rctIndex.height() - spacing());
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
if (rctIndex.contains(mouseEvent->pos()))
|
||||
Q_EMIT selectIndexChanged(index);
|
||||
}
|
||||
|
||||
return DStyledItemDelegate::editorEvent(event, model, option, index);
|
||||
}
|
27
frame/window/components/settingdelegate.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef SETTINGDELEGATE_H
|
||||
#define SETTINGDELEGATE_H
|
||||
|
||||
#include <DStyledItemDelegate>
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
|
||||
static const int itemCheckRole = Dtk::UserRole + 1;
|
||||
static const int itemDataRole = Dtk::UserRole + 2;
|
||||
|
||||
class SettingDelegate : public DStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_SIGNALS:
|
||||
void selectIndexChanged(const QModelIndex &);
|
||||
|
||||
public:
|
||||
explicit SettingDelegate(QAbstractItemView *parent = nullptr);
|
||||
~SettingDelegate() override;
|
||||
|
||||
protected:
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override;
|
||||
};
|
||||
|
||||
#endif // SETTINGDELEGATE_H
|
206
frame/window/components/volumedeviceswidget.cpp
Normal file
@ -0,0 +1,206 @@
|
||||
#include "volumedeviceswidget.h"
|
||||
#include "customslider.h"
|
||||
#include "volumemodel.h"
|
||||
#include "settingdelegate.h"
|
||||
|
||||
#include <DListView>
|
||||
#include <DPushButton>
|
||||
#include <DLabel>
|
||||
#include <DGuiApplicationHelper>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QScrollBar>
|
||||
#include <QEvent>
|
||||
#include <QProcess>
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusConnection>
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
|
||||
#define HEADERHEIGHT 30
|
||||
#define ITEMSPACE 16
|
||||
|
||||
VolumeDevicesWidget::VolumeDevicesWidget(VolumeModel *model, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_volumeSlider(new CustomSlider(CustomSlider::Normal, this))
|
||||
, m_descriptionLabel(new QLabel(tr("Output Device"), this))
|
||||
, m_deviceList(new DListView(this))
|
||||
, m_volumeModel(model)
|
||||
, m_audioSink(nullptr)
|
||||
, m_model(new QStandardItemModel(this))
|
||||
, m_delegate(new SettingDelegate(m_deviceList))
|
||||
{
|
||||
initUi();
|
||||
initConnection();
|
||||
reloadAudioDevices();
|
||||
|
||||
QMetaObject::invokeMethod(this, [ this ] {
|
||||
resetVolumeInfo();
|
||||
resizeHeight();
|
||||
}, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
VolumeDevicesWidget::~VolumeDevicesWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void VolumeDevicesWidget::initUi()
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(6);
|
||||
|
||||
m_volumeSlider->setIconSize(QSize(36, 36));
|
||||
m_volumeSlider->setLeftIcon(QIcon(leftIcon()));
|
||||
m_volumeSlider->setRightIcon(QIcon(rightIcon()));
|
||||
|
||||
layout->addWidget(m_volumeSlider);
|
||||
layout->addSpacing(4);
|
||||
layout->addWidget(m_descriptionLabel);
|
||||
|
||||
m_deviceList->setModel(m_model);
|
||||
m_deviceList->setViewMode(QListView::ListMode);
|
||||
m_deviceList->setMovement(QListView::Free);
|
||||
m_deviceList->setItemRadius(12);
|
||||
m_deviceList->setWordWrap(false);
|
||||
m_deviceList->verticalScrollBar()->setVisible(false);
|
||||
m_deviceList->horizontalScrollBar()->setVisible(false);
|
||||
m_deviceList->setOrientation(QListView::Flow::TopToBottom, false);
|
||||
layout->addWidget(m_deviceList);
|
||||
m_deviceList->setSpacing(10);
|
||||
|
||||
m_deviceList->setItemDelegate(m_delegate);
|
||||
}
|
||||
|
||||
void VolumeDevicesWidget::reloadAudioDevices()
|
||||
{
|
||||
QList<AudioPorts *> ports = m_volumeModel->ports();
|
||||
for (AudioPorts *port : ports) {
|
||||
DStandardItem *item = new DStandardItem;
|
||||
item->setText(QString("%1(%2)").arg(port->description()).arg(port->cardName()));
|
||||
item->setIcon(QIcon(soundIconFile(port)));
|
||||
item->setFlags(Qt::NoItemFlags);
|
||||
item->setData(port->isChecked(), itemCheckRole);
|
||||
item->setData(QVariant::fromValue(port), itemDataRole);
|
||||
m_model->appendRow(item);
|
||||
if (port->isChecked())
|
||||
m_deviceList->setCurrentIndex(m_model->indexFromItem(item));
|
||||
}
|
||||
|
||||
DStandardItem *settingItem = new DStandardItem;
|
||||
settingItem->setText(tr("Sound settings"));
|
||||
settingItem->setFlags(Qt::NoItemFlags);
|
||||
settingItem->setData(false, itemCheckRole);
|
||||
m_model->appendRow(settingItem);
|
||||
}
|
||||
|
||||
void VolumeDevicesWidget::initConnection()
|
||||
{
|
||||
m_audioSink = m_volumeModel->defaultSink();
|
||||
auto adjustVolumeSlider = [ this ](int volume) {
|
||||
m_volumeSlider->blockSignals(true);
|
||||
m_volumeSlider->setValue(volume);
|
||||
m_volumeSlider->blockSignals(false);
|
||||
};
|
||||
if (m_audioSink)
|
||||
connect(m_audioSink, &AudioSink::volumeChanged, this, adjustVolumeSlider);
|
||||
connect(m_volumeModel, &VolumeModel::defaultSinkChanged, this, [ this, adjustVolumeSlider ](AudioSink *sink) {
|
||||
if (m_audioSink)
|
||||
disconnect(m_audioSink);
|
||||
|
||||
m_audioSink = sink;
|
||||
if (m_audioSink)
|
||||
connect(m_audioSink, &AudioSink::volumeChanged, this, adjustVolumeSlider);
|
||||
|
||||
resetVolumeInfo();
|
||||
m_deviceList->update();
|
||||
});
|
||||
|
||||
connect(m_volumeSlider, &CustomSlider::valueChanged, this, [ this ](int value) {
|
||||
AudioSink *defSink = m_volumeModel->defaultSink();
|
||||
if (!defSink)
|
||||
return;
|
||||
|
||||
defSink->setVolume(value, true);
|
||||
});
|
||||
connect(m_volumeModel, &VolumeModel::checkPortChanged, this, [ this ] {
|
||||
for (int i = 0; i < m_model->rowCount(); i++) {
|
||||
QModelIndex index = m_model->index(i, 0);
|
||||
AudioPorts *port = index.data(itemDataRole).value<AudioPorts *>();
|
||||
if (port)
|
||||
m_model->setData(index, port->isChecked(), itemCheckRole);
|
||||
}
|
||||
m_deviceList->update();
|
||||
});
|
||||
|
||||
connect(m_delegate, &SettingDelegate::selectIndexChanged, this, [ this ](const QModelIndex &index) {
|
||||
AudioPorts *port = index.data(itemDataRole).value<AudioPorts *>();
|
||||
if (port) {
|
||||
m_volumeModel->setActivePort(port);
|
||||
m_deviceList->update();
|
||||
} else {
|
||||
// 打开控制中心的声音模块
|
||||
QDBusInterface controlcenter("com.deepin.dde.ControlCenter", "/com/deepin/dde/ControlCenter",
|
||||
"com.deepin.dde.ControlCenter", QDBusConnection::sessionBus());
|
||||
controlcenter.call("ShowModule", "sound");
|
||||
hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QString VolumeDevicesWidget::leftIcon()
|
||||
{
|
||||
QString iconLeft = QString(":/icons/resources/audio-volume-%1").arg(m_volumeModel->isMute() ? "muted" : "low");
|
||||
if (DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::LightType)
|
||||
iconLeft.append("-dark");
|
||||
|
||||
return iconLeft;
|
||||
}
|
||||
|
||||
QString VolumeDevicesWidget::rightIcon()
|
||||
{
|
||||
QString iconRight = QString(":/icons/resources/audio-volume-high");
|
||||
if (DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::LightType)
|
||||
iconRight.append("-dark");
|
||||
|
||||
return iconRight;
|
||||
}
|
||||
|
||||
const QString VolumeDevicesWidget::soundIconFile(AudioPorts *port) const
|
||||
{
|
||||
if (!port)
|
||||
return QString();
|
||||
|
||||
if (port->isHeadPhone()) {
|
||||
if (DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::LightType)
|
||||
return QString(":/icons/resources/ICON_Device_Headphone_dark.svg");
|
||||
|
||||
return QString(":/icons/resources/ICON_Device_Headphone.svg");
|
||||
}
|
||||
|
||||
if (DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::LightType)
|
||||
return QString(":/icons/resources/ICON_Device_Laptop_dark.svg");
|
||||
|
||||
return QString(":/icons/resources/ICON_Device_Laptop.svg");
|
||||
}
|
||||
|
||||
void VolumeDevicesWidget::resizeHeight()
|
||||
{
|
||||
m_deviceList->adjustSize();
|
||||
QMargins m = layout()->contentsMargins();
|
||||
int height = m.top() + m.bottom() + HEADERHEIGHT + m_volumeSlider->height() + ITEMSPACE
|
||||
+ m_descriptionLabel->height() + m_deviceList->height();
|
||||
|
||||
setFixedHeight(height);
|
||||
}
|
||||
|
||||
void VolumeDevicesWidget::resetVolumeInfo()
|
||||
{
|
||||
AudioSink *defaultSink = m_volumeModel->defaultSink();
|
||||
if (!defaultSink)
|
||||
return;
|
||||
|
||||
m_volumeSlider->blockSignals(true);
|
||||
m_volumeSlider->setValue(defaultSink->volume());
|
||||
m_volumeSlider->blockSignals(false);
|
||||
}
|
50
frame/window/components/volumedeviceswidget.h
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef VOLUMEDEVICESWIDGET_H
|
||||
#define VOLUMEDEVICESWIDGET_H
|
||||
|
||||
#include <DStyledItemDelegate>
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace Dtk { namespace Widget { class DListView; } }
|
||||
|
||||
using namespace Dtk::Widget;
|
||||
|
||||
class CustomSlider;
|
||||
class QStandardItemModel;
|
||||
class QLabel;
|
||||
class VolumeModel;
|
||||
class AudioPorts;
|
||||
class AudioSink;
|
||||
class SettingDelegate;
|
||||
|
||||
class VolumeDevicesWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit VolumeDevicesWidget(VolumeModel *model, QWidget *parent = nullptr);
|
||||
~VolumeDevicesWidget() override;
|
||||
|
||||
private:
|
||||
void initUi();
|
||||
void reloadAudioDevices();
|
||||
void initConnection();
|
||||
QString leftIcon();
|
||||
QString rightIcon();
|
||||
const QString soundIconFile(AudioPorts *port) const;
|
||||
|
||||
void resizeHeight();
|
||||
|
||||
void resetVolumeInfo();
|
||||
|
||||
private:
|
||||
CustomSlider *m_volumeSlider;
|
||||
QLabel *m_descriptionLabel;
|
||||
DListView *m_deviceList;
|
||||
VolumeModel *m_volumeModel;
|
||||
AudioSink *m_audioSink;
|
||||
QStandardItemModel *m_model;
|
||||
SettingDelegate *m_delegate;
|
||||
};
|
||||
|
||||
#endif // VOLUMEDEVICESWIDGET_H
|
134
frame/window/components/volumewidget.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
#include "volumewidget.h"
|
||||
#include "customslider.h"
|
||||
#include "imageutil.h"
|
||||
#include "volumemodel.h"
|
||||
|
||||
#include <DGuiApplicationHelper>
|
||||
|
||||
#include <QDBusConnectionInterface>
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusPendingCall>
|
||||
#include <QDBusPendingReply>
|
||||
#include <QDebug>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QLabel>
|
||||
#include <QEvent>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMetaMethod>
|
||||
|
||||
DGUI_USE_NAMESPACE
|
||||
|
||||
#define ICON_SIZE 24
|
||||
|
||||
VolumeWidget::VolumeWidget(QWidget *parent)
|
||||
: DBlurEffectWidget(parent)
|
||||
, m_volumeController(new VolumeModel(this))
|
||||
, m_volumnCtrl(new CustomSlider(Qt::Horizontal, this))
|
||||
, m_defaultSink(m_volumeController->defaultSink())
|
||||
{
|
||||
initUi();
|
||||
initConnection();
|
||||
}
|
||||
|
||||
VolumeWidget::~VolumeWidget()
|
||||
{
|
||||
}
|
||||
|
||||
void VolumeWidget::initUi()
|
||||
{
|
||||
if (m_defaultSink)
|
||||
m_volumnCtrl->setValue(m_defaultSink->volume());
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout(this);
|
||||
mainLayout->setContentsMargins(20, 0, 20, 0);
|
||||
mainLayout->addWidget(m_volumnCtrl);
|
||||
|
||||
m_volumnCtrl->setIconSize(QSize(36, 36));
|
||||
m_volumnCtrl->setLeftIcon(QIcon(leftIcon()));
|
||||
m_volumnCtrl->setRightIcon(QIcon(rightIcon()));
|
||||
|
||||
bool existActiveOutputDevice = m_volumeController->existActiveOutputDevice();
|
||||
setEnabled(existActiveOutputDevice);
|
||||
}
|
||||
|
||||
void VolumeWidget::initConnection()
|
||||
{
|
||||
auto setCtrlVolumeValue = [this](int volume) {
|
||||
m_volumnCtrl->blockSignals(true);
|
||||
m_volumnCtrl->setValue(volume);
|
||||
m_volumnCtrl->blockSignals(false);
|
||||
};
|
||||
if (m_defaultSink)
|
||||
connect(m_defaultSink, &AudioSink::volumeChanged, this, setCtrlVolumeValue);
|
||||
|
||||
connect(m_volumeController, &VolumeModel::defaultSinkChanged, this, [ this, setCtrlVolumeValue ](AudioSink *sink) {
|
||||
if (m_defaultSink)
|
||||
disconnect(m_defaultSink);
|
||||
|
||||
m_defaultSink = sink;
|
||||
if (sink) {
|
||||
setCtrlVolumeValue(sink->volume());
|
||||
connect(m_defaultSink, &AudioSink::volumeChanged, this, setCtrlVolumeValue);
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_volumnCtrl, &DTK_WIDGET_NAMESPACE::DSlider::valueChanged, this, [ this ](int value) {
|
||||
AudioSink *sink = m_volumeController->defaultSink();
|
||||
if (sink)
|
||||
sink->setVolume(value, true);
|
||||
});
|
||||
|
||||
connect(m_volumeController, &VolumeModel::muteChanged, this, [ this ] {
|
||||
m_volumnCtrl->setLeftIcon(QIcon(leftIcon()));
|
||||
});
|
||||
|
||||
connect(m_volumnCtrl, &CustomSlider::iconClicked, this, [ this ](DSlider::SliderIcons icon, bool) {
|
||||
switch (icon) {
|
||||
case DSlider::SliderIcons::LeftIcon: {
|
||||
if (m_volumeController->existActiveOutputDevice())
|
||||
m_volumeController->setMute(!m_volumeController->isMute());
|
||||
break;
|
||||
}
|
||||
case DSlider::SliderIcons::RightIcon: {
|
||||
// 弹出音量选择对话框
|
||||
Q_EMIT rightIconClick();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
VolumeModel *VolumeWidget::model()
|
||||
{
|
||||
return m_volumeController;
|
||||
}
|
||||
|
||||
void VolumeWidget::showEvent(QShowEvent *event)
|
||||
{
|
||||
DBlurEffectWidget::showEvent(event);
|
||||
Q_EMIT visibleChanged(true);
|
||||
}
|
||||
|
||||
void VolumeWidget::hideEvent(QHideEvent *event)
|
||||
{
|
||||
DBlurEffectWidget::hideEvent(event);
|
||||
Q_EMIT visibleChanged(false);
|
||||
}
|
||||
|
||||
const QString VolumeWidget::leftIcon()
|
||||
{
|
||||
bool existActiveOutputDevice = m_volumeController->existActiveOutputDevice();
|
||||
const bool mute = existActiveOutputDevice ? m_volumeController->isMute() : true;
|
||||
if (mute)
|
||||
return QString(":/icons/resources/audio-volume-muted-dark");
|
||||
|
||||
return QString(":/icons/resources/volume");
|
||||
}
|
||||
|
||||
const QString VolumeWidget::rightIcon()
|
||||
{
|
||||
return QString(":/icons/resources/broadcast");
|
||||
}
|
45
frame/window/components/volumewidget.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef VOLUMEWIDGET_H
|
||||
#define VOLUMEWIDGET_H
|
||||
|
||||
#include <DBlurEffectWidget>
|
||||
#include <QWidget>
|
||||
|
||||
class VolumeModel;
|
||||
class QDBusMessage;
|
||||
class CustomSlider;
|
||||
class QLabel;
|
||||
class AudioSink;
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
|
||||
class VolumeWidget : public DBlurEffectWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit VolumeWidget(QWidget *parent = nullptr);
|
||||
~VolumeWidget() override;
|
||||
VolumeModel *model();
|
||||
|
||||
Q_SIGNALS:
|
||||
void visibleChanged(bool);
|
||||
void rightIconClick();
|
||||
|
||||
protected:
|
||||
void initUi();
|
||||
void initConnection();
|
||||
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
|
||||
private:
|
||||
const QString leftIcon();
|
||||
const QString rightIcon();
|
||||
|
||||
private:
|
||||
VolumeModel *m_volumeController;
|
||||
CustomSlider *m_volumnCtrl;
|
||||
AudioSink *m_defaultSink;
|
||||
};
|
||||
|
||||
#endif // VOLUMEWIDGET_H
|
@ -389,6 +389,7 @@ void MainPanelControl::insertItem(int index, DockItem *item)
|
||||
case DockItem::Plugins:
|
||||
addPluginAreaItem(index, item);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
// 同removeItem处 注意:不能屏蔽此接口,否则会造成插件插入时无法显示
|
||||
@ -420,6 +421,7 @@ void MainPanelControl::removeItem(DockItem *item)
|
||||
case DockItem::Plugins:
|
||||
removePluginAreaItem(item);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
item->removeEventFilter(this);
|
||||
|
323
frame/window/quickpluginwindow.cpp
Normal file
@ -0,0 +1,323 @@
|
||||
#include "quickpluginwindow.h"
|
||||
#include "quicksettingcontroller.h"
|
||||
#include "quicksettingitem.h"
|
||||
#include "pluginsiteminterface.h"
|
||||
#include "quicksettingcontainer.h"
|
||||
#include "appdrag.h"
|
||||
|
||||
#include <DStyleOption>
|
||||
#include <DStandardItem>
|
||||
|
||||
#include <QDrag>
|
||||
#include <QScrollBar>
|
||||
#include <QStringList>
|
||||
#include <QSize>
|
||||
#include <QMouseEvent>
|
||||
|
||||
#define ITEMSIZE 22
|
||||
#define ITEMSPACE 6
|
||||
|
||||
static QStringList fixedPluginKeys{ "network-item-key", "sound-item-key", "power" };
|
||||
const int itemDataRole = Dtk::UserRole + 1;
|
||||
const int itemSortRole = Dtk::UserRole + 2;
|
||||
|
||||
QuickPluginWindow::QuickPluginWindow(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_listView(new DListView(this))
|
||||
, m_model(new QStandardItemModel(this))
|
||||
, m_position(Dock::Position::Bottom)
|
||||
{
|
||||
initUi();
|
||||
initConnection();
|
||||
|
||||
setAcceptDrops(true);
|
||||
setMouseTracking(true);
|
||||
|
||||
this->installEventFilter(this);
|
||||
}
|
||||
|
||||
QuickPluginWindow::~QuickPluginWindow()
|
||||
{
|
||||
}
|
||||
|
||||
void QuickPluginWindow::initUi()
|
||||
{
|
||||
m_listView->setModel(m_model);
|
||||
m_listView->setViewMode(QListView::IconMode);
|
||||
m_listView->setMovement(QListView::Free);
|
||||
m_listView->setWordWrap(false);
|
||||
m_listView->verticalScrollBar()->setVisible(false);
|
||||
m_listView->horizontalScrollBar()->setVisible(false);
|
||||
m_listView->setOrientation(QListView::Flow::LeftToRight, false);
|
||||
m_listView->setGridSize(QSize(ITEMSIZE + 10, ITEMSIZE + 10));
|
||||
m_listView->setSpacing(ITEMSPACE);
|
||||
m_listView->setContentsMargins(0,0,0,0);
|
||||
m_model->setSortRole(itemSortRole);
|
||||
|
||||
QHBoxLayout *layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(0,0,0,0);
|
||||
layout->setSpacing(0);
|
||||
layout->addWidget(m_listView);
|
||||
|
||||
const QList<QuickSettingItem *> &items = QuickSettingController::instance()->settingItems();
|
||||
for (QuickSettingItem *settingItem : items) {
|
||||
const QString itemKey = settingItem->itemKey();
|
||||
if (!fixedPluginKeys.contains(itemKey))
|
||||
return;
|
||||
|
||||
addPlugin(settingItem);
|
||||
}
|
||||
}
|
||||
|
||||
void QuickPluginWindow::setPositon(Position position)
|
||||
{
|
||||
if (m_position == position)
|
||||
return;
|
||||
|
||||
m_position = position;
|
||||
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom)
|
||||
m_listView->setOrientation(QListView::Flow::LeftToRight, false);
|
||||
else
|
||||
m_listView->setOrientation(QListView::Flow::TopToBottom, false);
|
||||
}
|
||||
|
||||
void QuickPluginWindow::addPlugin(QuickSettingItem *item)
|
||||
{
|
||||
// 判断当前的插件是否存在,如果存在,则不插入
|
||||
for (int i = 0; i < m_model->rowCount(); i++) {
|
||||
QStandardItem *myItem = m_model->item(i, 0);
|
||||
QuickSettingItem *settingItem = myItem->data(itemDataRole).value<QuickSettingItem *>();
|
||||
if (settingItem == item) {
|
||||
m_model->sort(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DStandardItem *standItem = createStandItem(item);
|
||||
if (!standItem)
|
||||
return;
|
||||
|
||||
m_model->appendRow(standItem);
|
||||
resetSortRole();
|
||||
m_model->sort(0);
|
||||
Q_EMIT itemCountChanged();
|
||||
}
|
||||
|
||||
QSize QuickPluginWindow::suitableSize()
|
||||
{
|
||||
if (m_position == Dock::Position::Top || m_position == Dock::Position::Bottom)
|
||||
return QSize((ITEMSIZE + ITEMSPACE) * m_model->rowCount() + ITEMSPACE, ITEMSIZE);
|
||||
|
||||
return QSize(ITEMSIZE, (ITEMSIZE + ITEMSPACE) * m_model->rowCount() + ITEMSPACE);
|
||||
}
|
||||
|
||||
void QuickPluginWindow::removePlugin(QuickSettingItem *item)
|
||||
{
|
||||
for (int i = 0; i < m_model->rowCount(); i++) {
|
||||
QModelIndex index = m_model->index(i, 0);
|
||||
QuickSettingItem *quickItem = index.data(itemDataRole).value<QuickSettingItem *>();
|
||||
if (quickItem == item) {
|
||||
m_model->removeRow(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_model->sort(0);
|
||||
|
||||
Q_EMIT itemCountChanged();
|
||||
}
|
||||
|
||||
void QuickPluginWindow::resetSortRole()
|
||||
{
|
||||
QList<QPair<QStandardItem *, int>> fixedItems;
|
||||
QList<QStandardItem *> activeItems;
|
||||
for (int i = 0; i < m_model->rowCount(); i++) {
|
||||
QModelIndex index = m_model->index(i, 0);
|
||||
if (!index.data(itemDataRole).canConvert<QuickSettingItem *>())
|
||||
continue;
|
||||
|
||||
QuickSettingItem *settingItem = index.data(itemDataRole).value<QuickSettingItem *>();
|
||||
if (fixedPluginKeys.contains(settingItem->itemKey()))
|
||||
fixedItems.push_back({ m_model->item(i, 0), fixedPluginKeys.indexOf(settingItem->itemKey()) });
|
||||
else
|
||||
activeItems << m_model->item(i, 0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < activeItems.size(); i++) {
|
||||
QStandardItem *item = activeItems[i];
|
||||
item->setData(i, itemSortRole);
|
||||
}
|
||||
|
||||
for (QPair<QStandardItem *, int> item : fixedItems)
|
||||
item.first->setData(activeItems.size() + item.second, itemSortRole);
|
||||
}
|
||||
|
||||
DStandardItem *QuickPluginWindow::createStandItem(QuickSettingItem *item)
|
||||
{
|
||||
const QString itemKey = item->itemKey();
|
||||
QWidget *itemWidget = item->pluginItem()->itemWidget(itemKey);
|
||||
if (!itemWidget)
|
||||
return nullptr;
|
||||
|
||||
itemWidget->setParent(m_listView);
|
||||
DStandardItem *standItem = new DStandardItem;
|
||||
standItem->setFlags(Qt::ItemIsEnabled);
|
||||
standItem->setBackground(Qt::transparent);
|
||||
standItem->setData(QVariant::fromValue(item), itemDataRole);
|
||||
|
||||
DViewItemAction *action = new DViewItemAction(Qt::AlignCenter, QSize(ITEMSIZE, ITEMSIZE), QSize(ITEMSIZE, ITEMSIZE), true);
|
||||
action->setWidget(itemWidget);
|
||||
connect(action, &DViewItemAction::triggered, this, [ this ] {
|
||||
QPoint ptCurrent = pos();
|
||||
QWidget *callWidget = parentWidget();
|
||||
if (callWidget)
|
||||
ptCurrent = callWidget->mapToGlobal(ptCurrent);
|
||||
|
||||
QuickSettingContainer::popWindow()->show(ptCurrent);
|
||||
});
|
||||
connect(action, &DViewItemAction::destroyed, this, [ itemWidget ] {
|
||||
itemWidget->setParent(nullptr);
|
||||
itemWidget->hide();
|
||||
});
|
||||
|
||||
standItem->setActionList(Qt::LeftEdge, { action });
|
||||
return standItem;
|
||||
}
|
||||
|
||||
void QuickPluginWindow::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
QModelIndex selectedIndex = m_listView->indexAt(mouseEvent->pos());
|
||||
if (!selectedIndex.isValid())
|
||||
return;
|
||||
|
||||
QuickSettingItem *moveItem = selectedIndex.data(itemDataRole).value<QuickSettingItem *>();
|
||||
if (!moveItem)
|
||||
return;
|
||||
|
||||
if (fixedPluginKeys.contains(moveItem->itemKey())) {
|
||||
QPoint currentPoint = pos();
|
||||
QWidget *callWidget = parentWidget();
|
||||
if (callWidget)
|
||||
currentPoint = callWidget->mapToGlobal(currentPoint);
|
||||
|
||||
QuickSettingContainer::popWindow()->show(currentPoint);
|
||||
}
|
||||
}
|
||||
|
||||
void QuickPluginWindow::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
QModelIndex selectedIndex = m_listView->indexAt(event->pos());
|
||||
if (!selectedIndex.isValid()) {
|
||||
QWidget::mousePressEvent(event);
|
||||
return;
|
||||
}
|
||||
|
||||
QuickSettingItem *moveItem = selectedIndex.data(itemDataRole).value<QuickSettingItem *>();
|
||||
if (!moveItem) {
|
||||
QWidget::mousePressEvent(event);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fixedPluginKeys.contains(moveItem->itemKey())) {
|
||||
QWidget::mousePressEvent(event);
|
||||
return;
|
||||
}
|
||||
|
||||
startDrag(moveItem);
|
||||
}
|
||||
|
||||
void QuickPluginWindow::startDrag(QuickSettingItem *moveItem)
|
||||
{
|
||||
AppDrag *drag = new AppDrag(this, new QuickDragWidget);
|
||||
CustomMimeData *mimedata = new CustomMimeData;
|
||||
mimedata->setData(moveItem);
|
||||
drag->setMimeData(mimedata);
|
||||
drag->appDragWidget()->setDockInfo(m_position, QRect(mapToGlobal(pos()), size()));
|
||||
QPixmap dragPixmap = moveItem->pluginItem()->icon()->pixmap(QSize(ITEMSIZE, ITEMSIZE));
|
||||
drag->setPixmap(dragPixmap);
|
||||
drag->setHotSpot(QPoint(dragPixmap.width() / 2, dragPixmap.height() / 2));
|
||||
|
||||
connect(drag->appDragWidget(), &AppDragWidget::requestRemoveItem, this, [ this, moveItem ] {
|
||||
removePlugin(moveItem);
|
||||
});
|
||||
|
||||
connect(static_cast<QuickDragWidget *>(drag->appDragWidget()), &QuickDragWidget::requestDropItem, this, [ this, moveItem ](){
|
||||
addPlugin(moveItem);
|
||||
});
|
||||
connect(static_cast<QuickDragWidget *>(drag->appDragWidget()), &QuickDragWidget::requestDragMove, this, [ this ](QDragMoveEvent *eve){
|
||||
QPoint ptCurrent = m_listView->mapFromGlobal(QCursor::pos());
|
||||
QModelIndex index = m_listView->indexAt(ptCurrent);
|
||||
if (!index.isValid())
|
||||
return;
|
||||
|
||||
CustomMimeData *data = const_cast<CustomMimeData *>(qobject_cast<const CustomMimeData *>(eve->mimeData()));
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
QuickSettingItem *sourceItem = static_cast<QuickSettingItem *>(data->data());
|
||||
if (!sourceItem)
|
||||
return;
|
||||
|
||||
QuickSettingItem *targetItem = index.data(itemDataRole).value<QuickSettingItem *>();
|
||||
if (!targetItem || fixedPluginKeys.contains(targetItem->itemKey()) || sourceItem == targetItem)
|
||||
return;
|
||||
|
||||
// recall all sortroles
|
||||
QList<QPair<QModelIndex, QuickSettingItem *>> allItems;
|
||||
for (int i = 0; i < m_model->rowCount(); i++) {
|
||||
QModelIndex rowIndex = m_model->index(i, 0);
|
||||
allItems.push_back({ rowIndex, rowIndex.data(itemDataRole).value<QuickSettingItem *>() });
|
||||
}
|
||||
auto findIndex = [ allItems ](QuickSettingItem *item) {
|
||||
for (int i = 0; i < allItems.size(); i++) {
|
||||
const QPair<QModelIndex, QuickSettingItem *> &rowItem = allItems[i];
|
||||
if (rowItem.second == item)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
int sourceIndex = findIndex(sourceItem);
|
||||
int targetIndex = findIndex(targetItem);
|
||||
if (sourceIndex < 0 || targetIndex < 0 || sourceIndex == targetIndex)
|
||||
return;
|
||||
|
||||
allItems.move(sourceIndex, targetIndex);
|
||||
|
||||
for (int i = 0; i < allItems.size(); i++) {
|
||||
const QPair<QModelIndex, QuickSettingItem *> &rowItem = allItems[i];
|
||||
m_model->setData(rowItem.first, i, itemSortRole);
|
||||
}
|
||||
|
||||
eve->accept();
|
||||
});
|
||||
|
||||
drag->exec(Qt::MoveAction | Qt::CopyAction);
|
||||
}
|
||||
|
||||
void QuickPluginWindow::initConnection()
|
||||
{
|
||||
connect(QuickSettingController::instance(), &QuickSettingController::pluginInsert, this, [ this ](QuickSettingItem * settingItem) {
|
||||
const QString itemKey = settingItem->itemKey();
|
||||
if (!fixedPluginKeys.contains(itemKey))
|
||||
return;
|
||||
|
||||
addPlugin(settingItem);
|
||||
});
|
||||
|
||||
connect(QuickSettingController::instance(), &QuickSettingController::pluginRemove, this, [ this ](QuickSettingItem *settingItem) {
|
||||
removePlugin(settingItem);
|
||||
});
|
||||
}
|
||||
|
||||
int QuickPluginWindow::fixedItemCount()
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i < m_model->rowCount(); i++) {
|
||||
QModelIndex index = m_model->index(i, 0);
|
||||
QuickSettingItem *item = index.data(itemDataRole).value<QuickSettingItem *>();
|
||||
if (item && fixedPluginKeys.contains(item->itemKey()))
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
56
frame/window/quickpluginwindow.h
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef QUICKPLUGINWINDOW_H
|
||||
#define QUICKPLUGINWINDOW_H
|
||||
|
||||
#include "constants.h"
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QuickSettingItem;
|
||||
class PluginsItemInterface;
|
||||
class QHBoxLayout;
|
||||
class QuickSettingContainer;
|
||||
class QStandardItemModel;
|
||||
class QStandardItem;
|
||||
class QMouseEvent;
|
||||
|
||||
namespace Dtk { namespace Gui { class DRegionMonitor; }
|
||||
namespace Widget { class DListView; class DStandardItem; } }
|
||||
|
||||
using namespace Dtk::Widget;
|
||||
|
||||
class QuickPluginWindow : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_SIGNALS:
|
||||
void itemCountChanged();
|
||||
|
||||
public:
|
||||
explicit QuickPluginWindow(QWidget *parent = nullptr);
|
||||
~QuickPluginWindow() override;
|
||||
|
||||
void setPositon(Dock::Position position);
|
||||
void addPlugin(QuickSettingItem *item);
|
||||
|
||||
QSize suitableSize();
|
||||
|
||||
protected:
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
|
||||
private:
|
||||
void initUi();
|
||||
void initConnection();
|
||||
void resetSortRole();
|
||||
int fixedItemCount();
|
||||
DStandardItem *createStandItem(QuickSettingItem *item);
|
||||
void removePlugin(QuickSettingItem *item);
|
||||
void startDrag(QuickSettingItem *moveItem);
|
||||
|
||||
private:
|
||||
DListView *m_listView;
|
||||
QStandardItemModel *m_model;
|
||||
Dock::Position m_position;
|
||||
};
|
||||
|
||||
#endif // QUICKPLUGINWINDOW_H
|
415
frame/window/quicksettingcontainer.cpp
Normal file
@ -0,0 +1,415 @@
|
||||
#include "quicksettingcontainer.h"
|
||||
#include "quicksettingcontroller.h"
|
||||
#include "pluginsiteminterface.h"
|
||||
#include "quicksettingitem.h"
|
||||
#include "mediawidget.h"
|
||||
#include "dockpopupwindow.h"
|
||||
#include "brightnesswidget.h"
|
||||
#include "volumewidget.h"
|
||||
#include "volumedeviceswidget.h"
|
||||
#include "brightnessmonitorwidget.h"
|
||||
|
||||
#include <DListView>
|
||||
#include <DStyle>
|
||||
#include <QDrag>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QMetaObject>
|
||||
#include <QStackedLayout>
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
|
||||
static const int QuickItemRole = Dtk::UserRole + 10;
|
||||
|
||||
#define ITEMWIDTH 70
|
||||
#define ITEMHEIGHT 60
|
||||
#define CTRLHEIGHT 56
|
||||
#define ITEMSPACE 10
|
||||
#define COLUMNCOUNT 4
|
||||
|
||||
QuickSettingContainer::QuickSettingContainer(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_switchLayout(new QStackedLayout(this))
|
||||
, m_mainWidget(new QWidget(this))
|
||||
, m_pluginWidget(new QWidget(m_mainWidget))
|
||||
, m_mainlayout(new QVBoxLayout(m_mainWidget))
|
||||
, m_pluginLoader(QuickSettingController::instance())
|
||||
, m_playerWidget(new MediaWidget(m_mainWidget))
|
||||
, m_volumnWidget(new VolumeWidget(m_mainWidget))
|
||||
, m_brihtnessWidget(new BrightnessWidget(m_mainWidget))
|
||||
, m_volumeSettingWidget(new VolumeDevicesWidget(m_volumnWidget->model(), this))
|
||||
, m_brightSettingWidget(new BrightnessMonitorWidget(m_brihtnessWidget->model(), this))
|
||||
, m_childPage(new PluginChildPage(this))
|
||||
{
|
||||
initUi();
|
||||
initConnection();
|
||||
}
|
||||
|
||||
QuickSettingContainer::~QuickSettingContainer()
|
||||
{
|
||||
}
|
||||
|
||||
void QuickSettingContainer::showHomePage()
|
||||
{
|
||||
m_switchLayout->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
DockPopupWindow *QuickSettingContainer::popWindow()
|
||||
{
|
||||
static DockPopupWindow *popView = nullptr;
|
||||
if (!popView) {
|
||||
popView = new DockPopupWindow;
|
||||
popView->setWindowFlag(Qt::Popup);
|
||||
popView->setShadowBlurRadius(20);
|
||||
popView->setRadius(18);
|
||||
popView->setShadowYOffset(2);
|
||||
popView->setShadowXOffset(0);
|
||||
popView->setArrowWidth(18);
|
||||
popView->setArrowHeight(10);
|
||||
|
||||
QuickSettingContainer *container = new QuickSettingContainer(popView);
|
||||
popView->setContent(container);
|
||||
} else {
|
||||
QuickSettingContainer *container = static_cast<QuickSettingContainer *>(popView->getContent());
|
||||
container->showHomePage();
|
||||
}
|
||||
|
||||
return popView;
|
||||
}
|
||||
|
||||
void QuickSettingContainer::initQuickItem(QuickSettingItem *quickItem)
|
||||
{
|
||||
int pluginWidth = ITEMWIDTH;
|
||||
if (quickItem->pluginItem()->isPrimary())
|
||||
pluginWidth = ITEMWIDTH * 2 + ITEMSPACE;
|
||||
|
||||
quickItem->setFixedSize(pluginWidth, ITEMHEIGHT);
|
||||
quickItem->setParent(m_pluginWidget);
|
||||
quickItem->setMouseTracking(true);
|
||||
quickItem->installEventFilter(this);
|
||||
connect(quickItem, &QuickSettingItem::detailClicked, this, &QuickSettingContainer::onItemDetailClick);
|
||||
}
|
||||
|
||||
void QuickSettingContainer::onItemDetailClick(PluginsItemInterface *pluginInter)
|
||||
{
|
||||
QuickSettingItem *quickItemWidget = static_cast<QuickSettingItem *>(sender());
|
||||
if (!quickItemWidget)
|
||||
return;
|
||||
|
||||
QWidget *widget = pluginInter->itemWidget(quickItemWidget->itemKey());
|
||||
if (!widget)
|
||||
return;
|
||||
|
||||
showWidget(widget, pluginInter->pluginDisplayName());
|
||||
}
|
||||
|
||||
bool QuickSettingContainer::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if (watched == m_childPage && event->type() == QEvent::Resize)
|
||||
resizeView();
|
||||
|
||||
return QWidget::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void QuickSettingContainer::showWidget(QWidget *widget, const QString &title)
|
||||
{
|
||||
m_childPage->setTitle(title);
|
||||
m_childPage->pushWidget(widget);
|
||||
m_switchLayout->setCurrentWidget(m_childPage);
|
||||
}
|
||||
|
||||
void QuickSettingContainer::onPluginInsert(QuickSettingItem *quickItem)
|
||||
{
|
||||
initQuickItem(quickItem);
|
||||
resetItemPosition();
|
||||
resizeView();
|
||||
}
|
||||
|
||||
void QuickSettingContainer::onPluginRemove(QuickSettingItem *quickItem)
|
||||
{
|
||||
QObjectList childrens = m_pluginWidget->children();
|
||||
for (QObject *child : childrens) {
|
||||
if (child != quickItem)
|
||||
continue;
|
||||
|
||||
disconnect(quickItem, &QuickSettingItem::detailClicked, this, &QuickSettingContainer::onItemDetailClick);
|
||||
quickItem->setParent(nullptr);
|
||||
quickItem->removeEventFilter(this);
|
||||
quickItem->setMouseTracking(false);
|
||||
quickItem->hide();
|
||||
break;
|
||||
}
|
||||
//调整子控件的位置
|
||||
resetItemPosition();
|
||||
resizeView();
|
||||
}
|
||||
|
||||
void QuickSettingContainer::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() != Qt::LeftButton)
|
||||
return;
|
||||
|
||||
QuickSettingItem *moveItem = qobject_cast<QuickSettingItem *>(childAt(event->pos()));
|
||||
if (!moveItem || moveItem->pluginItem()->isPrimary())
|
||||
return QWidget::mousePressEvent(event);
|
||||
|
||||
QDrag *drag = new QDrag(this);
|
||||
CustomMimeData *mimedata = new CustomMimeData;
|
||||
mimedata->setData(moveItem);
|
||||
drag->setMimeData(mimedata);
|
||||
QPixmap dragPixmap = moveItem->dragPixmap();
|
||||
drag->setPixmap(dragPixmap);
|
||||
drag->setHotSpot(QPoint(dragPixmap.width() / 2, dragPixmap.height() / 2));
|
||||
|
||||
drag->exec(Qt::MoveAction | Qt::CopyAction);
|
||||
}
|
||||
|
||||
void QuickSettingContainer::resetItemPosition()
|
||||
{
|
||||
QObjectList childrens = m_pluginWidget->children();
|
||||
QList<QuickSettingItem *> primaryQuickItems;
|
||||
QList<QuickSettingItem *> quickItems;
|
||||
for (QObject *child : childrens) {
|
||||
QuickSettingItem *quickItem = qobject_cast<QuickSettingItem *>(child);
|
||||
if (!quickItem || quickItem->isHidden())
|
||||
continue;
|
||||
|
||||
if (quickItem->pluginItem()->isPrimary())
|
||||
primaryQuickItems << quickItem;
|
||||
else
|
||||
quickItems << quickItem;
|
||||
}
|
||||
static QStringList existKeys = {"network-item-key", "sound-item-key", "VPN", "PROJECTSCREEN"};
|
||||
qSort(primaryQuickItems.begin(), primaryQuickItems.end(), [ = ](QuickSettingItem *item1, QuickSettingItem *item2) {
|
||||
int index1 = existKeys.indexOf(item1->itemKey());
|
||||
int index2 = existKeys.indexOf(item2->itemKey());
|
||||
if (index1 >= 0 || index2 >= 0) {
|
||||
return index1 < index2;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
int primaryColumnCount = COLUMNCOUNT / 2;
|
||||
for (int i = 0; i < primaryQuickItems.size(); i++) {
|
||||
QuickSettingItem *quickitem = primaryQuickItems[i];
|
||||
QPoint ptItem(ITEMSPACE + (ITEMWIDTH + ITEMSPACE) * 2 * (i % primaryColumnCount),
|
||||
(ITEMHEIGHT + ITEMSPACE) * (static_cast<int>(i / primaryColumnCount)));
|
||||
quickitem->move(ptItem);
|
||||
}
|
||||
int startCount = primaryQuickItems.size() * 2;
|
||||
for (int i = 0; i < quickItems.size(); i++) {
|
||||
QuickSettingItem *qsi = quickItems[i];
|
||||
int columnIndex = (startCount + i) % COLUMNCOUNT;
|
||||
int rowIndex = (startCount + i) / COLUMNCOUNT;
|
||||
int x = (ITEMWIDTH + ITEMSPACE) * columnIndex + ITEMSPACE;
|
||||
int y = (ITEMHEIGHT + ITEMSPACE) * rowIndex;
|
||||
qsi->move(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void QuickSettingContainer::initUi()
|
||||
{
|
||||
auto setWidgetStyle = [](DBlurEffectWidget *widget) {
|
||||
widget->setMaskColor(QColor(239, 240, 245));
|
||||
widget->setBlurRectXRadius(8);
|
||||
widget->setBlurRectYRadius(8);
|
||||
};
|
||||
|
||||
// 添加音乐播放插件
|
||||
m_playerWidget->setFixedHeight(CTRLHEIGHT);
|
||||
m_volumnWidget->setFixedHeight(CTRLHEIGHT);
|
||||
m_brihtnessWidget->setFixedHeight(CTRLHEIGHT);
|
||||
|
||||
setWidgetStyle(m_playerWidget);
|
||||
setWidgetStyle(m_volumnWidget);
|
||||
setWidgetStyle(m_brihtnessWidget);
|
||||
|
||||
m_mainlayout->setSpacing(0);
|
||||
m_mainlayout->setContentsMargins(0, ITEMSPACE, 0, ITEMSPACE);
|
||||
|
||||
m_mainlayout->addWidget(m_pluginWidget);
|
||||
|
||||
QWidget *ctrlWidget = new QWidget(m_mainWidget);
|
||||
QVBoxLayout *ctrlLayout = new QVBoxLayout(ctrlWidget);
|
||||
ctrlLayout->setContentsMargins(ITEMSPACE, ITEMSPACE, ITEMSPACE, ITEMSPACE);
|
||||
|
||||
ctrlLayout->addSpacing(ITEMSPACE);
|
||||
ctrlLayout->addWidget(m_playerWidget);
|
||||
ctrlLayout->setSpacing(ITEMSPACE);
|
||||
ctrlLayout->addWidget(m_volumnWidget);
|
||||
ctrlLayout->setSpacing(ITEMSPACE);
|
||||
ctrlLayout->addWidget(m_brihtnessWidget);
|
||||
|
||||
m_mainlayout->addWidget(ctrlWidget);
|
||||
// 加载所有的插件
|
||||
QList<QuickSettingItem *> pluginItems = m_pluginLoader->settingItems();
|
||||
for (QuickSettingItem *quickItem: pluginItems)
|
||||
initQuickItem(quickItem);
|
||||
|
||||
m_switchLayout->addWidget(m_mainWidget);
|
||||
m_switchLayout->addWidget(m_childPage);
|
||||
|
||||
m_volumeSettingWidget->hide();
|
||||
m_brightSettingWidget->hide();
|
||||
|
||||
setMouseTracking(true);
|
||||
setAcceptDrops(true);
|
||||
|
||||
QMetaObject::invokeMethod(this, [ = ] {
|
||||
if (pluginItems.size() > 0)
|
||||
resetItemPosition();
|
||||
// 设置当前窗口的大小
|
||||
resizeView();
|
||||
setFixedWidth(ITEMWIDTH * 4 + (ITEMSPACE * 5));
|
||||
}, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void QuickSettingContainer::initConnection()
|
||||
{
|
||||
connect(m_pluginLoader, &QuickSettingController::pluginInsert, this, &QuickSettingContainer::onPluginInsert);
|
||||
connect(m_pluginLoader, &QuickSettingController::pluginRemove, this, &QuickSettingContainer::onPluginRemove);
|
||||
connect(m_playerWidget, &MediaWidget::visibleChanged, this, [ this ] { resizeView(); });
|
||||
connect(m_volumnWidget, &VolumeWidget::visibleChanged, this, [ this ] { resizeView(); });
|
||||
connect(m_volumnWidget, &VolumeWidget::rightIconClick, this, [ this ] {
|
||||
showWidget(m_volumeSettingWidget, tr("voice"));
|
||||
resizeView();
|
||||
});
|
||||
connect(m_brihtnessWidget, &BrightnessWidget::visibleChanged, this, [ this ] { resizeView(); });
|
||||
connect(m_brihtnessWidget, &BrightnessWidget::rightIconClicked, this, [ this ] {
|
||||
showWidget(m_brightSettingWidget, tr("brightness"));
|
||||
resizeView();
|
||||
});
|
||||
connect(m_childPage, &PluginChildPage::back, this, [ this ] {
|
||||
m_switchLayout->setCurrentWidget(m_mainWidget);
|
||||
});
|
||||
connect(m_childPage, &PluginChildPage::closeSelf, this, [ this ] {
|
||||
if (!m_childPage->isBack())
|
||||
topLevelWidget()->hide();
|
||||
});
|
||||
m_childPage->installEventFilter(this);
|
||||
}
|
||||
|
||||
void QuickSettingContainer::resizeView()
|
||||
{
|
||||
if (m_switchLayout->currentWidget() == m_mainWidget) {
|
||||
QList<QuickSettingItem *> pluginItems = m_pluginLoader->settingItems();
|
||||
int selfPluginCount = 0;
|
||||
for (QuickSettingItem *item : pluginItems) {
|
||||
// 如果是置顶的插件,则认为它占用两个普通插件的位置
|
||||
int increCount = (item->pluginItem()->isPrimary() ? 2 : 1);
|
||||
selfPluginCount += increCount;
|
||||
}
|
||||
int rowCount = selfPluginCount / COLUMNCOUNT;
|
||||
if (selfPluginCount % COLUMNCOUNT > 0)
|
||||
rowCount++;
|
||||
|
||||
m_pluginWidget->setFixedHeight(ITEMHEIGHT * rowCount + ITEMSPACE * (rowCount - 1));
|
||||
|
||||
int panelCount = 0;
|
||||
if (m_playerWidget->isVisible())
|
||||
panelCount++;
|
||||
if (m_volumnWidget->isVisible())
|
||||
panelCount++;
|
||||
if (m_brihtnessWidget->isVisible())
|
||||
panelCount++;
|
||||
|
||||
int topHeight = ((ITEMHEIGHT + ITEMSPACE) * rowCount) + ITEMSPACE;
|
||||
setFixedHeight(topHeight + (CTRLHEIGHT + ITEMSPACE) * panelCount + ITEMSPACE);
|
||||
} else if (m_switchLayout->currentWidget() == m_childPage) {
|
||||
setFixedHeight(m_childPage->height());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief PluginChildPage::PluginChildPage
|
||||
* @param parent
|
||||
*/
|
||||
PluginChildPage::PluginChildPage(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_headerWidget(new QWidget(this))
|
||||
, m_back(new QLabel(m_headerWidget))
|
||||
, m_title(new QLabel(m_headerWidget))
|
||||
, m_container(new QWidget(this))
|
||||
, m_topWidget(nullptr)
|
||||
, m_containerLayout(new QVBoxLayout(m_container))
|
||||
, m_isBack(false)
|
||||
{
|
||||
initUi();
|
||||
m_back->installEventFilter(this);
|
||||
}
|
||||
|
||||
PluginChildPage::~PluginChildPage()
|
||||
{
|
||||
}
|
||||
|
||||
void PluginChildPage::pushWidget(QWidget *widget)
|
||||
{
|
||||
// 首先将界面其他的窗体移除
|
||||
for (int i = m_containerLayout->count() - 1; i >= 0; i--) {
|
||||
QLayoutItem *item = m_containerLayout->itemAt(i);
|
||||
item->widget()->removeEventFilter(this);
|
||||
item->widget()->hide();
|
||||
m_containerLayout->removeItem(item);
|
||||
}
|
||||
m_topWidget = widget;
|
||||
widget->installEventFilter(this);
|
||||
m_containerLayout->addWidget(widget);
|
||||
widget->show();
|
||||
m_isBack = false;
|
||||
QMetaObject::invokeMethod(this, &PluginChildPage::resetHeight, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void PluginChildPage::setTitle(const QString &text)
|
||||
{
|
||||
m_title->setText(text);
|
||||
}
|
||||
|
||||
bool PluginChildPage::isBack()
|
||||
{
|
||||
return m_isBack;
|
||||
}
|
||||
|
||||
void PluginChildPage::initUi()
|
||||
{
|
||||
m_back->setFixedWidth(24);
|
||||
m_title->setAlignment(Qt::AlignCenter);
|
||||
QHBoxLayout *headerLayout = new QHBoxLayout(m_headerWidget);
|
||||
headerLayout->setContentsMargins(11, 12, 24 + 11, 12);
|
||||
headerLayout->setSpacing(0);
|
||||
headerLayout->addWidget(m_back);
|
||||
headerLayout->addWidget(m_title);
|
||||
m_headerWidget->setFixedHeight(48);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mainLayout->setSpacing(0);
|
||||
|
||||
mainLayout->addWidget(m_headerWidget);
|
||||
mainLayout->addWidget(m_container);
|
||||
m_containerLayout->setContentsMargins(11, 0, 11, 0);
|
||||
m_containerLayout->setSpacing(0);
|
||||
}
|
||||
|
||||
bool PluginChildPage::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if (watched == m_back && event->type() == QEvent::MouseButtonRelease) {
|
||||
m_isBack = true;
|
||||
Q_EMIT back();
|
||||
return true;
|
||||
}
|
||||
if (watched == m_topWidget) {
|
||||
if (event->type() == QEvent::Hide) {
|
||||
Q_EMIT closeSelf();
|
||||
return true;
|
||||
}
|
||||
if (event->type() == QEvent::Resize)
|
||||
resetHeight();
|
||||
}
|
||||
return QWidget::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void PluginChildPage::resetHeight()
|
||||
{
|
||||
QMargins m = m_containerLayout->contentsMargins();
|
||||
m_container->setFixedHeight(m.top() + m.bottom() + m_topWidget->height());
|
||||
setFixedHeight(m_headerWidget->height() + m_container->height());
|
||||
}
|
122
frame/window/quicksettingcontainer.h
Normal file
@ -0,0 +1,122 @@
|
||||
#ifndef QUICKSETTINGCONTAINER_H
|
||||
#define QUICKSETTINGCONTAINER_H
|
||||
|
||||
#include "pluginproxyinterface.h"
|
||||
|
||||
#include "dtkwidget_global.h"
|
||||
|
||||
#include <DListView>
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class DockItem;
|
||||
class QVBoxLayout;
|
||||
class QuickSettingController;
|
||||
class MediaWidget;
|
||||
class VolumeWidget;
|
||||
class BrightnessWidget;
|
||||
class QuickSettingItem;
|
||||
class DockPopupWindow;
|
||||
class QStackedLayout;
|
||||
class VolumeDevicesWidget;
|
||||
class BrightnessMonitorWidget;
|
||||
class QLabel;
|
||||
class PluginChildPage;
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
|
||||
class QuickSettingContainer : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static DockPopupWindow *popWindow();
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
explicit QuickSettingContainer(QWidget *parent = nullptr);
|
||||
~QuickSettingContainer() override;
|
||||
void showHomePage();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onPluginInsert(QuickSettingItem *quickItem);
|
||||
void onPluginRemove(QuickSettingItem *quickItem);
|
||||
void onItemDetailClick(PluginsItemInterface *pluginInter);
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
|
||||
private:
|
||||
// 加载UI
|
||||
void initUi();
|
||||
// 初始化槽函数
|
||||
void initConnection();
|
||||
// 调整尺寸
|
||||
void resizeView();
|
||||
// 调整控件位置
|
||||
void resetItemPosition();
|
||||
// 初始化控件项目
|
||||
void initQuickItem(QuickSettingItem *quickItem);
|
||||
// 显示具体的窗体
|
||||
void showWidget(QWidget *widget, const QString &title);
|
||||
|
||||
private:
|
||||
QStackedLayout *m_switchLayout;
|
||||
QWidget *m_mainWidget;
|
||||
QWidget *m_pluginWidget;
|
||||
QVBoxLayout *m_mainlayout;
|
||||
QuickSettingController *m_pluginLoader;
|
||||
MediaWidget *m_playerWidget;
|
||||
VolumeWidget *m_volumnWidget;
|
||||
BrightnessWidget *m_brihtnessWidget;
|
||||
|
||||
VolumeDevicesWidget *m_volumeSettingWidget;
|
||||
BrightnessMonitorWidget *m_brightSettingWidget;
|
||||
PluginChildPage *m_childPage;
|
||||
};
|
||||
|
||||
class CustomMimeData : public QMimeData
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CustomMimeData() : QMimeData(), m_data(nullptr) {}
|
||||
~CustomMimeData() {}
|
||||
void setData(void *data) { m_data = data; }
|
||||
void *data() { return m_data; }
|
||||
|
||||
private:
|
||||
void *m_data;
|
||||
};
|
||||
|
||||
class PluginChildPage : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_SIGNALS:
|
||||
void back();
|
||||
void closeSelf();
|
||||
|
||||
public:
|
||||
explicit PluginChildPage(QWidget *parent);
|
||||
~PluginChildPage() override;
|
||||
void pushWidget(QWidget *widget);
|
||||
void setTitle(const QString &text);
|
||||
bool isBack();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
|
||||
private:
|
||||
void initUi();
|
||||
void resetHeight();
|
||||
|
||||
private:
|
||||
QWidget *m_headerWidget;
|
||||
QLabel *m_back;
|
||||
QLabel *m_title;
|
||||
QWidget *m_container;
|
||||
QWidget *m_topWidget;
|
||||
QVBoxLayout *m_containerLayout;
|
||||
bool m_isBack;
|
||||
};
|
||||
|
||||
#endif // PLUGINCONTAINER_H
|
@ -48,6 +48,12 @@ public:
|
||||
Custom = 1 << 1 // The custom
|
||||
};
|
||||
|
||||
enum PluginStatus {
|
||||
Deactive = 0,
|
||||
Active,
|
||||
Disabled
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief ~PluginsItemInterface
|
||||
/// DON'T try to delete m_proxyInter.
|
||||
@ -243,6 +249,30 @@ public:
|
||||
///
|
||||
virtual PluginSizePolicy pluginSizePolicy() const { return System; }
|
||||
|
||||
///
|
||||
/// the icon display on plugin panel
|
||||
///
|
||||
///
|
||||
virtual const QIcon *icon() { return nullptr; }
|
||||
|
||||
///
|
||||
/// the plugin status
|
||||
///
|
||||
///
|
||||
virtual PluginStatus status() const { return PluginStatus::Deactive; }
|
||||
|
||||
///
|
||||
/// return is primary plugin,if true, the plugin will display on top
|
||||
/// the default value is false
|
||||
///
|
||||
virtual bool isPrimary() const { return false; }
|
||||
|
||||
///
|
||||
/// return the detail value, it will display in the center
|
||||
///
|
||||
///
|
||||
virtual QString description() const { return QString(); }
|
||||
|
||||
protected:
|
||||
///
|
||||
/// \brief m_proxyInter
|
||||
|