mirror of
https://github.com/iDescriptor/iDescriptor.git
synced 2026-06-21 19:35:49 +08:00
Refactor and enhance UI components
- Updated `CableInfoWidget` to include a TODO comment regarding manufacturer verification. - Refactored `CustomTab` and `CustomTabWidget` to remove notification label functionality, simplifying the class structure. - Improved `DeviceInfoWidget` by adding a destructor to manage graphics view memory and initializing graphics scene properly. - Introduced `DiskUsageBar` and `DiskUsageWidget` classes to manage disk usage visualization, including hover popover functionality for detailed information. - Enhanced `MediaPreviewDialog` to include more descriptive window titles and adjusted status label styling based on platform. - Added platform-specific functionality in `macos.h` and `macos.mm` for popover management. - Cleaned up `ToolboxWidget` by adjusting label styles and removing fixed sizes for better responsiveness.
This commit is contained in:
+34
-48
@@ -58,19 +58,16 @@ void AppsWidget::setupUI()
|
||||
mainLayout->setSpacing(0);
|
||||
|
||||
// Header with login
|
||||
QFrame *headerFrame = new QFrame();
|
||||
headerFrame->setFixedHeight(60);
|
||||
headerFrame->setStyleSheet("border-bottom: 1px solid #dee2e6;");
|
||||
QWidget *headerWidget = new QWidget();
|
||||
headerWidget->setFixedHeight(60);
|
||||
headerWidget->setStyleSheet("border-bottom: 1px solid #dee2e6;");
|
||||
|
||||
QHBoxLayout *headerLayout = new QHBoxLayout(headerFrame);
|
||||
QHBoxLayout *headerLayout = new QHBoxLayout(headerWidget);
|
||||
headerLayout->setContentsMargins(20, 10, 20, 10);
|
||||
|
||||
QLabel *titleLabel = new QLabel("App Store");
|
||||
titleLabel->setStyleSheet(
|
||||
"font-size: 24px; font-weight: bold; color: #333;");
|
||||
headerLayout->addWidget(titleLabel);
|
||||
|
||||
headerLayout->addStretch();
|
||||
|
||||
// Create status label first
|
||||
m_statusLabel = new QLabel("Not signed in");
|
||||
@@ -120,22 +117,17 @@ void AppsWidget::setupUI()
|
||||
}
|
||||
}
|
||||
m_statusLabel->setStyleSheet("font-size: 14px; color: #666;");
|
||||
headerLayout->addWidget(m_statusLabel);
|
||||
|
||||
m_loginButton = new QPushButton(m_isLoggedIn ? "Sign Out" : "Sign In");
|
||||
m_loginButton->setStyleSheet(
|
||||
"background-color: #007AFF; color: white; border: none; border-radius: "
|
||||
"4px; padding: 8px 16px; font-size: 14px;");
|
||||
headerLayout->addWidget(m_loginButton);
|
||||
|
||||
mainLayout->addWidget(headerFrame);
|
||||
|
||||
// --- Search Bar ---
|
||||
QHBoxLayout *searchContainerLayout = new QHBoxLayout();
|
||||
searchContainerLayout->setContentsMargins(20, 15, 20, 15);
|
||||
mainLayout->addWidget(headerWidget);
|
||||
|
||||
m_searchEdit = new QLineEdit();
|
||||
m_searchEdit->setPlaceholderText("Search for apps...");
|
||||
m_searchEdit->setPlaceholderText(m_isLoggedIn ? "Search for apps..."
|
||||
: "Sign in to search");
|
||||
m_searchEdit->setMaximumWidth(400);
|
||||
m_searchEdit->setStyleSheet("QLineEdit { "
|
||||
" padding: 8px; "
|
||||
@@ -151,19 +143,21 @@ void AppsWidget::setupUI()
|
||||
connect(searchAction, &QAction::triggered, this,
|
||||
&AppsWidget::performSearch);
|
||||
|
||||
searchContainerLayout->addStretch();
|
||||
searchContainerLayout->addWidget(m_searchEdit);
|
||||
searchContainerLayout->addStretch();
|
||||
headerLayout->addWidget(titleLabel);
|
||||
|
||||
mainLayout->addLayout(searchContainerLayout);
|
||||
|
||||
// --- Status and Login Button ---
|
||||
headerLayout->addStretch();
|
||||
headerLayout->addWidget(m_searchEdit);
|
||||
headerLayout->addStretch();
|
||||
headerLayout->addWidget(m_statusLabel);
|
||||
headerLayout->addWidget(m_loginButton);
|
||||
|
||||
// Scroll area for apps
|
||||
m_scrollArea = new QScrollArea();
|
||||
m_scrollArea->setWidgetResizable(true);
|
||||
m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
m_scrollArea->setStyleSheet("border: none;");
|
||||
m_scrollArea->setStyleSheet(
|
||||
"QScrollArea { background: transparent; border: none; }");
|
||||
m_scrollArea->viewport()->setStyleSheet("background: transparent;");
|
||||
|
||||
m_contentWidget = new QWidget();
|
||||
QGridLayout *gridLayout = new QGridLayout(m_contentWidget);
|
||||
@@ -254,20 +248,11 @@ void AppsWidget::createAppCard(const QString &name, const QString &bundleId,
|
||||
const QString &iconPath, QGridLayout *gridLayout,
|
||||
int row, int col)
|
||||
{
|
||||
QFrame *cardFrame = new QFrame();
|
||||
cardFrame->setObjectName("cardFrame");
|
||||
cardFrame->setFixedSize(200, 250);
|
||||
cardFrame->setStyleSheet("#cardFrame {"
|
||||
" border: 1px solid #ddd;"
|
||||
" border-radius: 8px;"
|
||||
" background-color: #fff;"
|
||||
"}"
|
||||
"#cardFrame:hover {"
|
||||
" border: 1.5px solid #007AFF;"
|
||||
"}");
|
||||
cardFrame->setCursor(Qt::PointingHandCursor);
|
||||
QWidget *cardWidget = new QWidget();
|
||||
// cardWidget->setFixedSize(200, 250);
|
||||
cardWidget->setCursor(Qt::PointingHandCursor);
|
||||
|
||||
QVBoxLayout *cardLayout = new QVBoxLayout(cardFrame);
|
||||
QHBoxLayout *cardLayout = new QHBoxLayout(cardWidget);
|
||||
cardLayout->setContentsMargins(15, 15, 15, 15);
|
||||
cardLayout->setSpacing(10);
|
||||
|
||||
@@ -301,24 +286,29 @@ void AppsWidget::createAppCard(const QString &name, const QString &bundleId,
|
||||
iconLabel->setPixmap(rounded);
|
||||
}
|
||||
},
|
||||
cardFrame);
|
||||
cardWidget);
|
||||
|
||||
// Vertical layout for name and description
|
||||
QVBoxLayout *textLayout = new QVBoxLayout();
|
||||
|
||||
// App name
|
||||
QLabel *nameLabel = new QLabel(name);
|
||||
nameLabel->setStyleSheet(
|
||||
"font-size: 16px; font-weight: bold; color: #333;");
|
||||
nameLabel->setStyleSheet("font-size: 16px;");
|
||||
nameLabel->setAlignment(Qt::AlignCenter);
|
||||
nameLabel->setWordWrap(true);
|
||||
cardLayout->addWidget(nameLabel);
|
||||
textLayout->addWidget(nameLabel);
|
||||
|
||||
// App description
|
||||
QLabel *descLabel = new QLabel(description);
|
||||
descLabel->setStyleSheet("font-size: 12px; color: #666;");
|
||||
descLabel->setAlignment(Qt::AlignCenter);
|
||||
descLabel->setWordWrap(true);
|
||||
cardLayout->addWidget(descLabel);
|
||||
textLayout->addWidget(descLabel);
|
||||
|
||||
cardLayout->addStretch();
|
||||
cardLayout->addLayout(textLayout);
|
||||
|
||||
QVBoxLayout *buttonsLayout = new QVBoxLayout();
|
||||
|
||||
// Install button placeholder
|
||||
QPushButton *installLabel = new QPushButton("Install");
|
||||
@@ -336,15 +326,11 @@ void AppsWidget::createAppCard(const QString &name, const QString &bundleId,
|
||||
connect(downloadIpaLabel, &QPushButton::clicked, this,
|
||||
[this, name, bundleId]() { onDownloadIpaClicked(name, bundleId); });
|
||||
|
||||
cardLayout->addWidget(installLabel);
|
||||
cardLayout->addWidget(downloadIpaLabel);
|
||||
buttonsLayout->addWidget(installLabel);
|
||||
buttonsLayout->addWidget(downloadIpaLabel);
|
||||
|
||||
// Make the entire card clickable
|
||||
// cardFrame->mousePressEvent = [this, name, description](QMouseEvent *) {
|
||||
// onAppCardClicked(name, description);
|
||||
// };
|
||||
|
||||
gridLayout->addWidget(cardFrame, row, col);
|
||||
cardLayout->addLayout(buttonsLayout);
|
||||
gridLayout->addWidget(cardWidget, row, col);
|
||||
}
|
||||
void AppsWidget::onDownloadIpaClicked(const QString &name,
|
||||
const QString &bundleId)
|
||||
|
||||
@@ -201,7 +201,8 @@ void CableInfoWidget::updateUI()
|
||||
QString statusText;
|
||||
QString statusStyle;
|
||||
QString iconText;
|
||||
|
||||
// todo: sometimes they fake the manufacturer even if it's not genuine
|
||||
// compare m_cableInfo.isTypeC to the actual values we get from ioreg
|
||||
if (m_cableInfo.isGenuine) {
|
||||
statusText = QString("Genuine %1")
|
||||
.arg(m_cableInfo.isTypeC ? "USB-C to Lightning Cable"
|
||||
|
||||
+6
-112
@@ -8,35 +8,11 @@
|
||||
|
||||
// CustomTab implementation
|
||||
CustomTab::CustomTab(const QString &text, QWidget *parent)
|
||||
: QPushButton(text, parent), m_notificationLabel(nullptr),
|
||||
m_notificationCount(0)
|
||||
: QPushButton(text, parent)
|
||||
{
|
||||
setCheckable(true);
|
||||
setFixedHeight(54);
|
||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
|
||||
// Set up notification label
|
||||
m_notificationLabel = new QLabel(this);
|
||||
m_notificationLabel->setAlignment(Qt::AlignCenter);
|
||||
m_notificationLabel->hide();
|
||||
m_notificationLabel->setStyleSheet("QLabel {"
|
||||
" background-color: #e6eef9;"
|
||||
" border-radius: 16px;"
|
||||
" color: #333;"
|
||||
" font-weight: 500;"
|
||||
" min-width: 32px;"
|
||||
" min-height: 32px;"
|
||||
" max-width: 32px;"
|
||||
" max-height: 32px;"
|
||||
"}");
|
||||
|
||||
updateNotificationDisplay();
|
||||
}
|
||||
|
||||
void CustomTab::setNotificationCount(int count)
|
||||
{
|
||||
m_notificationCount = count;
|
||||
updateNotificationDisplay();
|
||||
}
|
||||
|
||||
void CustomTab::setIcon(const QIcon &icon)
|
||||
@@ -45,58 +21,6 @@ void CustomTab::setIcon(const QIcon &icon)
|
||||
setIconSize(QSize(20, 20));
|
||||
}
|
||||
|
||||
void CustomTab::updateNotificationDisplay()
|
||||
{
|
||||
if (m_notificationCount > 0) {
|
||||
m_notificationLabel->setText(QString::number(m_notificationCount));
|
||||
m_notificationLabel->show();
|
||||
|
||||
// Position notification label to the right of the text
|
||||
QFontMetrics fm(font());
|
||||
int textWidth = fm.horizontalAdvance(text());
|
||||
int iconWidth = iconSize().width();
|
||||
int totalContentWidth = (iconWidth > 0 ? iconWidth + 8 : 0) + textWidth;
|
||||
|
||||
int x = (width() - totalContentWidth) / 2 + totalContentWidth + 12;
|
||||
int y = (height() - 32) / 2;
|
||||
|
||||
m_notificationLabel->setGeometry(x, y, 32, 32);
|
||||
} else {
|
||||
m_notificationLabel->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void CustomTab::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QPushButton::paintEvent(event);
|
||||
updateNotificationDisplay();
|
||||
|
||||
// Update notification label style based on checked state
|
||||
if (isChecked()) {
|
||||
m_notificationLabel->setStyleSheet("QLabel {"
|
||||
" background-color: #185ee0;"
|
||||
" border-radius: 16px;"
|
||||
" color: white;"
|
||||
" font-weight: 500;"
|
||||
" min-width: 32px;"
|
||||
" min-height: 32px;"
|
||||
" max-width: 32px;"
|
||||
" max-height: 32px;"
|
||||
"}");
|
||||
} else {
|
||||
m_notificationLabel->setStyleSheet("QLabel {"
|
||||
" background-color: #e6eef9;"
|
||||
" border-radius: 16px;"
|
||||
" color: #333;"
|
||||
" font-weight: 500;"
|
||||
" min-width: 32px;"
|
||||
" min-height: 32px;"
|
||||
" max-width: 32px;"
|
||||
" max-height: 32px;"
|
||||
"}");
|
||||
}
|
||||
}
|
||||
|
||||
// CustomTabWidget implementation
|
||||
CustomTabWidget::CustomTabWidget(QWidget *parent)
|
||||
: QWidget(parent), m_currentIndex(0)
|
||||
@@ -115,7 +39,7 @@ CustomTabWidget::CustomTabWidget(QWidget *parent)
|
||||
// Style the tab bar
|
||||
m_tabBar->setStyleSheet("QWidget {"
|
||||
// " background-color: white;"
|
||||
" border-radius: 35px;"
|
||||
// " border-radius: 35px;"
|
||||
"}");
|
||||
|
||||
// Add drop shadow effect
|
||||
@@ -142,7 +66,7 @@ void CustomTabWidget::setupGlider()
|
||||
{
|
||||
m_glider = new QWidget(m_tabBar);
|
||||
m_glider->setStyleSheet("QWidget {"
|
||||
" background-color: #185ee0;"
|
||||
" background-color: #2b5693;"
|
||||
" border-radius: 1px;"
|
||||
"}");
|
||||
// Set initial size - will be updated in animateGlider
|
||||
@@ -215,13 +139,6 @@ QWidget *CustomTabWidget::widget(int index) const
|
||||
return m_widgets[index];
|
||||
}
|
||||
|
||||
void CustomTabWidget::setTabNotification(int index, int count)
|
||||
{
|
||||
if (index >= 0 && index < m_tabs.count()) {
|
||||
m_tabs[index]->setNotificationCount(count);
|
||||
}
|
||||
}
|
||||
|
||||
void CustomTabWidget::onTabClicked()
|
||||
{
|
||||
CustomTab *clickedTab = qobject_cast<CustomTab *>(sender());
|
||||
@@ -268,11 +185,11 @@ void CustomTabWidget::updateTabStyles()
|
||||
if (tab->isChecked()) {
|
||||
tab->setStyleSheet("CustomTab {"
|
||||
" color: #185ee0;"
|
||||
// " color: #d7e1f4ff;"
|
||||
" font-weight: 500;"
|
||||
" font-size: 20px;"
|
||||
" border: none;"
|
||||
" outline: none;"
|
||||
" border-radius: 27px;"
|
||||
" background-color: transparent;"
|
||||
"}"
|
||||
"CustomTab:hover {"
|
||||
@@ -281,11 +198,11 @@ void CustomTabWidget::updateTabStyles()
|
||||
} else {
|
||||
tab->setStyleSheet("CustomTab {"
|
||||
" color: #666;"
|
||||
// " color: #2b5693;"
|
||||
" font-weight: 500;"
|
||||
" font-size: 20px;"
|
||||
" border: none;"
|
||||
" outline: none;"
|
||||
" border-radius: 27px;"
|
||||
" background-color: transparent;"
|
||||
"}"
|
||||
"CustomTab:hover {"
|
||||
@@ -305,27 +222,4 @@ void CustomTabWidget::resizeEvent(QResizeEvent *event)
|
||||
// Use a timer to ensure layout has been updated
|
||||
QTimer::singleShot(0, [this]() { animateGlider(m_currentIndex); });
|
||||
}
|
||||
}
|
||||
|
||||
// #ifdef Q_OS_MAC
|
||||
// void CustomTabWidget::ensureTitlebarIntegration()
|
||||
// {
|
||||
// // Ensure the tab bar maintains the correct height and margins for
|
||||
// titlebar integration m_tabBar->setFixedHeight(98); // 70px + 28px
|
||||
// titlebar height m_tabLayout->setContentsMargins(12, 36, 12, 8); // Add
|
||||
// top margin for titlebar
|
||||
|
||||
// // Ensure the parent window attribute is maintained
|
||||
// if (QMainWindow *mainWindow = qobject_cast<QMainWindow*>(window())) {
|
||||
// mainWindow->setAttribute(Qt::WA_ContentsMarginsRespectsSafeArea,
|
||||
// false);
|
||||
// }
|
||||
|
||||
// // Update glider position after titlebar integration changes
|
||||
// if (m_currentIndex >= 0 && m_currentIndex < m_tabs.count()) {
|
||||
// QTimer::singleShot(0, [this]() {
|
||||
// animateGlider(m_currentIndex);
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// #endif
|
||||
}
|
||||
@@ -17,16 +17,7 @@ class CustomTab : public QPushButton
|
||||
|
||||
public:
|
||||
explicit CustomTab(const QString &text, QWidget *parent = nullptr);
|
||||
void setNotificationCount(int count);
|
||||
void setIcon(const QIcon &icon);
|
||||
|
||||
private:
|
||||
QLabel *m_notificationLabel;
|
||||
int m_notificationCount;
|
||||
void updateNotificationDisplay();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
};
|
||||
|
||||
class CustomTabWidget : public QWidget
|
||||
@@ -41,7 +32,6 @@ public:
|
||||
void setCurrentIndex(int index);
|
||||
int currentIndex() const;
|
||||
QWidget *widget(int index) const;
|
||||
void setTabNotification(int index, int count);
|
||||
|
||||
signals:
|
||||
void currentChanged(int index);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <QDebug>
|
||||
#include <QGraphicsDropShadowEffect>
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsView>
|
||||
#include <QGridLayout>
|
||||
#include <QHBoxLayout>
|
||||
@@ -30,19 +31,18 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent)
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout(this);
|
||||
mainLayout->setContentsMargins(2, 2, 2, 2);
|
||||
mainLayout->setSpacing(2);
|
||||
|
||||
QGraphicsScene *scene = new QGraphicsScene(this);
|
||||
m_graphicsScene = new QGraphicsScene(this); // no parent
|
||||
QGraphicsPixmapItem *pixmapItem =
|
||||
new QGraphicsPixmapItem(QPixmap(":/resources/iphone.png"));
|
||||
scene->addItem(pixmapItem);
|
||||
m_graphicsScene->addItem(pixmapItem);
|
||||
|
||||
QGraphicsView *graphicsView = new ResponsiveGraphicsView(scene, this);
|
||||
graphicsView->setRenderHint(QPainter::Antialiasing);
|
||||
graphicsView->setMinimumWidth(200);
|
||||
graphicsView->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Expanding);
|
||||
graphicsView->setStyleSheet("background: transparent; border: none;");
|
||||
m_graphicsView = new ResponsiveGraphicsView(m_graphicsScene, this);
|
||||
m_graphicsView->setRenderHint(QPainter::Antialiasing);
|
||||
m_graphicsView->setMinimumWidth(200);
|
||||
m_graphicsView->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Expanding);
|
||||
m_graphicsView->setStyleSheet("background: transparent; border: none;");
|
||||
|
||||
mainLayout->addWidget(graphicsView, 1); // Stretch factor 1
|
||||
mainLayout->addWidget(m_graphicsView, 1); // Stretch factor 1
|
||||
|
||||
// Right side: Info Table
|
||||
QWidget *infoContainer = new QWidget();
|
||||
@@ -161,6 +161,8 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent)
|
||||
" background-color: " +
|
||||
background.name() +
|
||||
";"
|
||||
// " background-color: #161d37;"
|
||||
// " border: 1px solid #29356b;"
|
||||
" border-radius: 8px;"
|
||||
"}");
|
||||
|
||||
@@ -317,6 +319,15 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent)
|
||||
m_updateTimer->start(30000); // Update every 30 seconds
|
||||
}
|
||||
|
||||
DeviceInfoWidget::~DeviceInfoWidget()
|
||||
{
|
||||
if (m_graphicsView) {
|
||||
m_graphicsView->setScene(
|
||||
nullptr); // prevents QGraphicsScene from calling into view during
|
||||
// its destructor only needed on macos ?
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceInfoWidget::onBatteryMoreClicked()
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
|
||||
@@ -2,16 +2,18 @@
|
||||
#define DEVICEINFOWIDGET_H
|
||||
#include "batterywidget.h"
|
||||
#include "iDescriptor.h"
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsView>
|
||||
#include <QLabel>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
class DeviceInfoWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DeviceInfoWidget(iDescriptorDevice *device,
|
||||
QWidget *parent = nullptr);
|
||||
~DeviceInfoWidget(); // added destructor
|
||||
|
||||
private slots:
|
||||
void onBatteryMoreClicked();
|
||||
@@ -26,6 +28,9 @@ private:
|
||||
QLabel *m_chargingWattsWithCableTypeLabel;
|
||||
BatteryWidget *m_batteryWidget;
|
||||
QLabel *m_lightningIconLabel;
|
||||
|
||||
QGraphicsView *m_graphicsView = nullptr;
|
||||
QGraphicsScene *m_graphicsScene = nullptr;
|
||||
};
|
||||
|
||||
#endif // DEVICEINFOWIDGET_H
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
#include "diskusagebar.h"
|
||||
#include "platform/macos.h"
|
||||
|
||||
#include <QEnterEvent>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
|
||||
DiskUsageBar::DiskUsageBar(QWidget *parent) : QWidget(parent), m_percentage(0.0)
|
||||
{
|
||||
m_hoverTimer = new QTimer(this);
|
||||
m_hoverTimer->setSingleShot(true);
|
||||
m_hoverTimer->setInterval(500); // 500ms delay before showing popover
|
||||
connect(m_hoverTimer, &QTimer::timeout, this, &DiskUsageBar::showPopover);
|
||||
setAttribute(Qt::WA_Hover, true);
|
||||
|
||||
QHBoxLayout *layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(0);
|
||||
|
||||
// Add an invisible spacer to give the widget content
|
||||
QWidget *spacer = new QWidget(this);
|
||||
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
layout->addWidget(spacer);
|
||||
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
}
|
||||
|
||||
void DiskUsageBar::setUsageInfo(const QString &type,
|
||||
const QString &formattedSize,
|
||||
const QString &color, double percentage)
|
||||
{
|
||||
m_type = type;
|
||||
m_formattedSize = formattedSize;
|
||||
m_color = color;
|
||||
m_percentage = percentage;
|
||||
}
|
||||
|
||||
void DiskUsageBar::enterEvent(QEnterEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
m_hoverTimer->start();
|
||||
QWidget::enterEvent(event);
|
||||
}
|
||||
|
||||
void DiskUsageBar::leaveEvent(QEvent *event)
|
||||
{
|
||||
m_hoverTimer->stop();
|
||||
hidePopoverForBarWidget();
|
||||
QWidget::leaveEvent(event);
|
||||
}
|
||||
|
||||
void DiskUsageBar::showPopover()
|
||||
{
|
||||
if (m_type.isEmpty())
|
||||
return;
|
||||
|
||||
UsageInfo info;
|
||||
info.type = m_type;
|
||||
info.formattedSize = m_formattedSize;
|
||||
info.color = m_color;
|
||||
info.percentage = m_percentage;
|
||||
|
||||
showPopoverForBarWidget(this, info);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef DISKUSAGEBAR_H
|
||||
#define DISKUSAGEBAR_H
|
||||
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
class DiskUsageBar : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DiskUsageBar(QWidget *parent = nullptr);
|
||||
|
||||
void setUsageInfo(const QString &type, const QString &formattedSize,
|
||||
const QString &color, double percentage);
|
||||
|
||||
protected:
|
||||
void enterEvent(QEnterEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void showPopover();
|
||||
|
||||
private:
|
||||
QString m_type;
|
||||
QString m_formattedSize;
|
||||
QString m_color;
|
||||
double m_percentage;
|
||||
QTimer *m_hoverTimer;
|
||||
};
|
||||
|
||||
#endif // DISKUSAGEBAR_H
|
||||
+251
-74
@@ -1,9 +1,10 @@
|
||||
#include "diskusagewidget.h"
|
||||
#include "diskusagebar.h"
|
||||
#include "iDescriptor.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QFutureWatcher>
|
||||
#include <QPainter>
|
||||
#include <QVariantMap>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
@@ -17,107 +18,283 @@ DiskUsageWidget::DiskUsageWidget(iDescriptorDevice *device, QWidget *parent)
|
||||
m_freeSpace(0)
|
||||
{
|
||||
setMinimumHeight(80);
|
||||
setupUI();
|
||||
fetchData();
|
||||
}
|
||||
|
||||
void DiskUsageWidget::setupUI()
|
||||
{
|
||||
m_mainLayout = new QVBoxLayout(this);
|
||||
m_mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
m_mainLayout->setSpacing(0);
|
||||
|
||||
// Title
|
||||
m_titleLabel = new QLabel("Disk Usage", this);
|
||||
QFont titleFont = font();
|
||||
titleFont.setBold(true);
|
||||
m_titleLabel->setFont(titleFont);
|
||||
m_titleLabel->setAlignment(Qt::AlignCenter);
|
||||
m_mainLayout->addWidget(m_titleLabel);
|
||||
|
||||
// Status label (for loading/error states)
|
||||
m_statusLabel = new QLabel(this);
|
||||
m_statusLabel->setAlignment(Qt::AlignCenter);
|
||||
m_statusLabel->setText("Loading disk usage...");
|
||||
m_mainLayout->addWidget(m_statusLabel);
|
||||
|
||||
// Disk usage bar container
|
||||
m_diskBarContainer = new QWidget(this);
|
||||
m_diskBarContainer->setMinimumHeight(20);
|
||||
m_diskBarContainer->setMaximumHeight(20);
|
||||
m_diskBarContainer->setStyleSheet(
|
||||
"QWidget#diskBarContainer { margin: 0; padding: 0; border: none; }");
|
||||
m_diskBarContainer->setObjectName("diskBarContainer");
|
||||
m_diskBarLayout = new QHBoxLayout(m_diskBarContainer);
|
||||
m_diskBarLayout->setContentsMargins(0, 0, 0, 0);
|
||||
m_diskBarLayout->setSpacing(0);
|
||||
|
||||
// Create colored segments
|
||||
#ifdef Q_OS_MAC
|
||||
m_systemBar = new DiskUsageBar();
|
||||
m_appsBar = new DiskUsageBar();
|
||||
m_mediaBar = new DiskUsageBar();
|
||||
m_othersBar = new DiskUsageBar();
|
||||
m_freeBar = new DiskUsageBar();
|
||||
#else
|
||||
m_systemBar = new QWidget();
|
||||
m_appsBar = new QWidget();
|
||||
m_mediaBar = new QWidget();
|
||||
m_othersBar = new QWidget();
|
||||
m_freeBar = new QWidget();
|
||||
#endif
|
||||
// Set size policies to prevent any extra spacing
|
||||
// m_systemBar->setSizePolicy(QSizePolicy::Expanding,
|
||||
// QSizePolicy::Expanding); m_appsBar->setSizePolicy(QSizePolicy::Expanding,
|
||||
// QSizePolicy::Expanding);
|
||||
// m_mediaBar->setSizePolicy(QSizePolicy::Expanding,
|
||||
// QSizePolicy::Expanding);
|
||||
// m_othersBar->setSizePolicy(QSizePolicy::Expanding,
|
||||
// QSizePolicy::Expanding); m_freeBar->setSizePolicy(QSizePolicy::Expanding,
|
||||
// QSizePolicy::Expanding);
|
||||
|
||||
// Set colors
|
||||
m_systemBar->setStyleSheet(
|
||||
"background-color: #a1384d; border: 1px solid"
|
||||
"#e64a5b; padding: 0; margin: 0; border-top-left-radius: 3px; "
|
||||
"border-bottom-left-radius: 3px;");
|
||||
m_appsBar->setStyleSheet("background-color: #4f869f; border: 1px solid "
|
||||
"#63b4da; padding: 0; margin: 0;");
|
||||
m_mediaBar->setStyleSheet(
|
||||
"background-color: #2ECC71; border: none; padding: 0; margin: 0;");
|
||||
m_othersBar->setStyleSheet("background-color: #a28729; border: 1px solid "
|
||||
"#c4a32d; padding: 0; margin: 0;");
|
||||
m_freeBar->setStyleSheet(
|
||||
"background-color: #474747; border: 1px solid "
|
||||
"#4f4f4f; padding: 0; margin: 0; border-top-right-radius: 3px; "
|
||||
"border-bottom-right-radius: 3px;");
|
||||
|
||||
m_diskBarLayout->addWidget(m_systemBar);
|
||||
m_diskBarLayout->addWidget(m_appsBar);
|
||||
m_diskBarLayout->addWidget(m_mediaBar);
|
||||
m_diskBarLayout->addWidget(m_othersBar);
|
||||
m_diskBarLayout->addWidget(m_freeBar);
|
||||
|
||||
m_diskBarContainer->hide(); // Initially hidden
|
||||
m_mainLayout->addWidget(m_diskBarContainer);
|
||||
|
||||
// Legend layout
|
||||
m_legendLayout = new QHBoxLayout();
|
||||
m_legendLayout->setSpacing(0);
|
||||
m_legendLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
// Legend labels
|
||||
m_systemLabel = new QLabel("System", this);
|
||||
m_appsLabel = new QLabel("Apps", this);
|
||||
m_mediaLabel = new QLabel("Media", this);
|
||||
m_othersLabel = new QLabel("Others", this);
|
||||
m_freeLabel = new QLabel("Free", this);
|
||||
|
||||
// Style legend labels with colored backgrounds
|
||||
QString labelStyle = "QLabel { padding: 2px 6px; margin: 0px; "
|
||||
"border-radius: 3px; color: white; font-size: 10px; }";
|
||||
m_systemLabel->setStyleSheet(labelStyle + "background-color: #a1384d;");
|
||||
m_appsLabel->setStyleSheet(labelStyle + "background-color: #3498DB;");
|
||||
m_mediaLabel->setStyleSheet(labelStyle + "background-color: #2ECC71;");
|
||||
m_othersLabel->setStyleSheet(labelStyle + "background-color: #F39C12;");
|
||||
m_freeLabel->setStyleSheet(labelStyle +
|
||||
"background-color: #BDC3C7; color: black;");
|
||||
|
||||
m_legendLayout->addWidget(m_systemLabel);
|
||||
m_legendLayout->addWidget(m_appsLabel);
|
||||
m_legendLayout->addWidget(m_mediaLabel);
|
||||
m_legendLayout->addWidget(m_othersLabel);
|
||||
m_legendLayout->addWidget(m_freeLabel);
|
||||
m_legendLayout->addStretch();
|
||||
|
||||
// Hide legend initially
|
||||
m_systemLabel->hide();
|
||||
m_appsLabel->hide();
|
||||
m_mediaLabel->hide();
|
||||
m_othersLabel->hide();
|
||||
m_freeLabel->hide();
|
||||
|
||||
m_mainLayout->addLayout(m_legendLayout);
|
||||
}
|
||||
|
||||
QSize DiskUsageWidget::sizeHint() const { return QSize(400, 80); }
|
||||
|
||||
void DiskUsageWidget::paintEvent(QPaintEvent *event)
|
||||
void DiskUsageWidget::updateUI()
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
QColor textColor = qApp->palette().text().color();
|
||||
|
||||
if (m_state == Loading) {
|
||||
painter.setPen(textColor);
|
||||
painter.drawText(rect(), Qt::AlignCenter, "Loading disk usage...");
|
||||
m_statusLabel->setText("Loading disk usage...");
|
||||
m_statusLabel->show();
|
||||
m_diskBarContainer->hide();
|
||||
m_systemLabel->hide();
|
||||
m_appsLabel->hide();
|
||||
m_mediaLabel->hide();
|
||||
m_othersLabel->hide();
|
||||
m_freeLabel->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_state == Error) {
|
||||
painter.setPen(textColor);
|
||||
painter.drawText(rect(), Qt::AlignCenter, "Error: " + m_errorMessage);
|
||||
m_statusLabel->setText("Error: " + m_errorMessage);
|
||||
m_statusLabel->show();
|
||||
m_diskBarContainer->hide();
|
||||
m_systemLabel->hide();
|
||||
m_appsLabel->hide();
|
||||
m_mediaLabel->hide();
|
||||
m_othersLabel->hide();
|
||||
m_freeLabel->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// Title
|
||||
QFont titleFont = font();
|
||||
titleFont.setBold(true);
|
||||
painter.setFont(titleFont);
|
||||
painter.setPen(textColor);
|
||||
QRectF titleRect(0, 5, width(), 20);
|
||||
painter.drawText(titleRect, Qt::AlignHCenter | Qt::AlignTop, "Disk Usage");
|
||||
painter.setFont(font()); // Reset font
|
||||
|
||||
if (m_totalCapacity == 0) {
|
||||
painter.setPen(Qt::black);
|
||||
painter.drawText(QRect(0, 30, width(), height() - 30), Qt::AlignCenter,
|
||||
"No disk information available.");
|
||||
m_statusLabel->setText("No disk information available.");
|
||||
m_statusLabel->show();
|
||||
m_diskBarContainer->hide();
|
||||
m_systemLabel->hide();
|
||||
m_appsLabel->hide();
|
||||
m_mediaLabel->hide();
|
||||
m_othersLabel->hide();
|
||||
m_freeLabel->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
painter.setPen(Qt::NoPen);
|
||||
// Hide status label and show disk bar and legend
|
||||
m_statusLabel->hide();
|
||||
m_diskBarContainer->show();
|
||||
m_systemLabel->show();
|
||||
m_appsLabel->show();
|
||||
m_mediaLabel->show();
|
||||
m_othersLabel->show();
|
||||
m_freeLabel->show();
|
||||
|
||||
const int barHeight = 20;
|
||||
QRectF barRect(10, 30, width() - 20, barHeight);
|
||||
// Calculate proportions for each segment
|
||||
int totalWidth = m_diskBarContainer->width();
|
||||
|
||||
double scale = (double)barRect.width() / m_totalCapacity;
|
||||
double currentX = barRect.left();
|
||||
int systemWidth =
|
||||
(int)((double)m_systemUsage / m_totalCapacity * totalWidth);
|
||||
int appsWidth = (int)((double)m_appsUsage / m_totalCapacity * totalWidth);
|
||||
int mediaWidth = (int)((double)m_mediaUsage / m_totalCapacity * totalWidth);
|
||||
int othersWidth =
|
||||
(int)((double)m_othersUsage / m_totalCapacity * totalWidth);
|
||||
int freeWidth = (int)((double)m_freeSpace / m_totalCapacity * totalWidth);
|
||||
|
||||
auto drawSegment = [&](uint64_t value, const QColor &color) {
|
||||
if (value > 0) {
|
||||
double segmentWidth = value * scale;
|
||||
painter.fillRect(
|
||||
QRectF(currentX, barRect.top(), segmentWidth, barRect.height()),
|
||||
color);
|
||||
currentX += segmentWidth;
|
||||
// Ensure at least 1 pixel width for non-zero values
|
||||
if (m_systemUsage > 0 && systemWidth == 0)
|
||||
systemWidth = 1;
|
||||
if (m_appsUsage > 0 && appsWidth == 0)
|
||||
appsWidth = 1;
|
||||
if (m_mediaUsage > 0 && mediaWidth == 0)
|
||||
mediaWidth = 1;
|
||||
if (m_othersUsage > 0 && othersWidth == 0)
|
||||
othersWidth = 1;
|
||||
if (m_freeSpace > 0 && freeWidth == 0)
|
||||
freeWidth = 1;
|
||||
|
||||
m_diskBarLayout->setStretchFactor(m_systemBar, systemWidth);
|
||||
m_diskBarLayout->setStretchFactor(m_appsBar, appsWidth);
|
||||
m_diskBarLayout->setStretchFactor(m_mediaBar, mediaWidth);
|
||||
m_diskBarLayout->setStretchFactor(m_othersBar, othersWidth);
|
||||
m_diskBarLayout->setStretchFactor(m_freeBar, freeWidth);
|
||||
|
||||
// Hide segments with zero usage
|
||||
// m_systemBar->setVisible(m_systemUsage > 0);
|
||||
// m_appsBar->setVisible(m_appsUsage > 0);
|
||||
// m_mediaBar->setVisible(m_mediaUsage > 0);
|
||||
// m_othersBar->setVisible(m_othersUsage > 0);
|
||||
// m_freeBar->setVisible(m_freeSpace > 0);
|
||||
|
||||
// Format sizes for display
|
||||
auto formatSize = [](uint64_t bytes) -> QString {
|
||||
const char *units[] = {"B", "KB", "MB", "GB", "TB"};
|
||||
int unitIndex = 0;
|
||||
double size = bytes;
|
||||
|
||||
while (size >= 1024 && unitIndex < 4) {
|
||||
size /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
|
||||
return QString("%1 %2")
|
||||
.arg(QString::number(size, 'f', 1))
|
||||
.arg(units[unitIndex]);
|
||||
};
|
||||
|
||||
const QColor systemColor("#E74C3C");
|
||||
const QColor appsColor("#3498DB");
|
||||
const QColor mediaColor("#2ECC71");
|
||||
const QColor othersColor("#F39C12");
|
||||
const QColor freeColor("#BDC3C7");
|
||||
// Update legend labels with sizes
|
||||
m_systemLabel->setText(
|
||||
QString("System (%1)").arg(formatSize(m_systemUsage)));
|
||||
m_appsLabel->setText(QString("Apps (%1)").arg(formatSize(m_appsUsage)));
|
||||
m_mediaLabel->setText(QString("Media (%1)").arg(formatSize(m_mediaUsage)));
|
||||
m_othersLabel->setText(
|
||||
QString("Others (%1)").arg(formatSize(m_othersUsage)));
|
||||
m_freeLabel->setText(QString("Free (%1)").arg(formatSize(m_freeSpace)));
|
||||
|
||||
// System
|
||||
drawSegment(m_systemUsage, systemColor);
|
||||
// Apps
|
||||
drawSegment(m_appsUsage, appsColor);
|
||||
// Media
|
||||
drawSegment(m_mediaUsage, mediaColor);
|
||||
// Others
|
||||
drawSegment(m_othersUsage, othersColor);
|
||||
// Free
|
||||
drawSegment(m_freeSpace, freeColor);
|
||||
qDebug() << "Disk Usage Updated:"
|
||||
<< "System:" << m_systemUsage << "Apps:" << m_appsUsage
|
||||
<< "Media:" << m_mediaUsage << "Others:" << m_othersUsage
|
||||
<< "Free:" << m_freeSpace;
|
||||
|
||||
// Legend
|
||||
painter.setPen(textColor);
|
||||
qreal legendY = barRect.bottom() + 15;
|
||||
const int legendBoxSize = 10;
|
||||
const int legendSpacing = 5;
|
||||
qreal currentLegendX = barRect.left();
|
||||
// Set stretch factors and ensure minimum visibility
|
||||
int systemStretch = std::max(
|
||||
1, (int)(m_systemUsage / 1000000)); // Convert to MB for stretch
|
||||
int appsStretch = std::max(1, (int)(m_appsUsage / 1000000));
|
||||
int mediaStretch = std::max(1, (int)(m_mediaUsage / 1000000));
|
||||
int othersStretch = std::max(1, (int)(m_othersUsage / 1000000));
|
||||
int freeStretch = std::max(1, (int)(m_freeSpace / 1000000));
|
||||
|
||||
auto drawLegendItem = [&](const QColor &color, const QString &text) {
|
||||
painter.fillRect(
|
||||
QRectF(currentLegendX, legendY, legendBoxSize, legendBoxSize),
|
||||
color);
|
||||
currentLegendX += legendBoxSize + legendSpacing;
|
||||
painter.setPen(textColor);
|
||||
m_diskBarLayout->setStretchFactor(m_systemBar, systemStretch);
|
||||
m_diskBarLayout->setStretchFactor(m_appsBar, appsStretch);
|
||||
m_diskBarLayout->setStretchFactor(m_mediaBar, mediaStretch);
|
||||
m_diskBarLayout->setStretchFactor(m_othersBar, othersStretch);
|
||||
m_diskBarLayout->setStretchFactor(m_freeBar, freeStretch);
|
||||
|
||||
QFontMetrics fm(font());
|
||||
QRect textRect = fm.boundingRect(text);
|
||||
painter.drawText(QPointF(currentLegendX, legendY + legendBoxSize),
|
||||
text);
|
||||
currentLegendX += textRect.width() + legendSpacing * 2;
|
||||
};
|
||||
// Set usage info for popovers
|
||||
#ifdef Q_OS_MAC
|
||||
m_systemBar->setUsageInfo("System", formatSize(m_systemUsage), "#a1384d",
|
||||
(double)m_systemUsage / m_totalCapacity);
|
||||
m_appsBar->setUsageInfo("Apps", formatSize(m_appsUsage), "#3498DB",
|
||||
(double)m_appsUsage / m_totalCapacity);
|
||||
m_mediaBar->setUsageInfo("Media", formatSize(m_mediaUsage), "#2ECC71",
|
||||
(double)m_mediaUsage / m_totalCapacity);
|
||||
m_othersBar->setUsageInfo("Others", formatSize(m_othersUsage), "#F39C12",
|
||||
(double)m_othersUsage / m_totalCapacity);
|
||||
m_freeBar->setUsageInfo("Free", formatSize(m_freeSpace), "#BDC3C7",
|
||||
(double)m_freeSpace / m_totalCapacity);
|
||||
#endif
|
||||
// Hide segments with zero usage
|
||||
// m_systemBar->setVisible(m_systemUsage > 0);
|
||||
// m_appsBar->setVisible(m_appsUsage > 0);
|
||||
// m_mediaBar->setVisible(m_mediaUsage > 0);
|
||||
// m_othersBar->setVisible(m_othersUsage > 0);
|
||||
// m_freeBar->setVisible(m_freeSpace > 0);
|
||||
}
|
||||
|
||||
drawLegendItem(systemColor, "System");
|
||||
drawLegendItem(appsColor, "Apps");
|
||||
drawLegendItem(mediaColor, "Media");
|
||||
drawLegendItem(othersColor, "Others");
|
||||
drawLegendItem(freeColor, "Free");
|
||||
void DiskUsageWidget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
// No custom painting needed - using widgets and layouts
|
||||
}
|
||||
|
||||
void DiskUsageWidget::fetchData()
|
||||
@@ -147,7 +324,7 @@ void DiskUsageWidget::fetchData()
|
||||
|
||||
m_state = Ready;
|
||||
}
|
||||
update(); // Trigger repaint
|
||||
updateUI(); // Update the UI instead of triggering repaint
|
||||
watcher->deleteLater();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
#ifndef DISKUSAGEWIDGET_H
|
||||
#define DISKUSAGEWIDGET_H
|
||||
#include "diskusagebar.h"
|
||||
#include "iDescriptor.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QProgressBar>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <cstdint>
|
||||
|
||||
@@ -18,6 +23,8 @@ protected:
|
||||
|
||||
private:
|
||||
void fetchData();
|
||||
void setupUI();
|
||||
void updateUI();
|
||||
|
||||
enum State { Loading, Ready, Error };
|
||||
|
||||
@@ -25,6 +32,33 @@ private:
|
||||
State m_state;
|
||||
QString m_errorMessage;
|
||||
|
||||
// UI widgets
|
||||
QVBoxLayout *m_mainLayout;
|
||||
QLabel *m_titleLabel;
|
||||
QLabel *m_statusLabel;
|
||||
QWidget *m_diskBarContainer;
|
||||
QHBoxLayout *m_diskBarLayout;
|
||||
#ifdef Q_OS_MAC
|
||||
DiskUsageBar *m_systemBar;
|
||||
DiskUsageBar *m_appsBar;
|
||||
DiskUsageBar *m_mediaBar;
|
||||
DiskUsageBar *m_othersBar;
|
||||
DiskUsageBar *m_freeBar;
|
||||
#else
|
||||
QWidget *m_systemBar;
|
||||
QWidget *m_appsBar;
|
||||
QWidget *m_mediaBar;
|
||||
QWidget *m_othersBar;
|
||||
QWidget *m_freeBar;
|
||||
#endif
|
||||
|
||||
QHBoxLayout *m_legendLayout;
|
||||
QLabel *m_systemLabel;
|
||||
QLabel *m_appsLabel;
|
||||
QLabel *m_mediaLabel;
|
||||
QLabel *m_othersLabel;
|
||||
QLabel *m_freeLabel;
|
||||
|
||||
uint64_t m_totalCapacity;
|
||||
uint64_t m_systemUsage;
|
||||
uint64_t m_appsUsage;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <QVBoxLayout>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
// todo: create a service
|
||||
QByteArray read_afc_file_to_byte_array(afc_client_t afcClient, const char *path)
|
||||
{
|
||||
uint64_t fd_handle = 0;
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
#include <QMouseEvent>
|
||||
#include <QWidget>
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#include "./platform/macos.h"
|
||||
#endif
|
||||
|
||||
#define COLOR_GREEN QColor(0, 180, 0) // Green
|
||||
#define COLOR_ORANGE QColor(255, 140, 0) // Orange
|
||||
#define COLOR_RED QColor(255, 0, 0) // Red
|
||||
@@ -50,10 +54,6 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
void setupMacOSWindow(QMainWindow *window);
|
||||
#endif
|
||||
|
||||
enum class iDescriptorTool {
|
||||
Airplayer,
|
||||
RealtimeScreen,
|
||||
|
||||
+4
-4
@@ -7,12 +7,12 @@ class iFuseManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
// explicit iFuseManager(QObject *parent = nullptr);
|
||||
static QList<QString> getMountPoints();
|
||||
// explicit iFuseManager(QObject *parent = nullptr);
|
||||
#ifdef Q_OS_LINUX
|
||||
static QStringList getMountArg(std::string &udid, QString &path);
|
||||
static QList<QString> getMountPoints();
|
||||
#endif
|
||||
// TODO: need to implement a cross-platform mount and unmount function
|
||||
static QStringList getMountArg(std::string &udid, QString &path);
|
||||
// TODO: need to implement a cross-platform mount and unmount method
|
||||
static bool linuxUnmount(const QString &path);
|
||||
signals:
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ MediaPreviewDialog::MediaPreviewDialog(iDescriptorDevice *device,
|
||||
m_fitToWindowBtn(nullptr), m_zoomFactor(1.0), m_isRepeatEnabled(true),
|
||||
m_isDraggingTimeline(false), m_videoDuration(0)
|
||||
{
|
||||
setWindowTitle(QFileInfo(filePath).fileName());
|
||||
setWindowTitle(QFileInfo(filePath).fileName() + " - iDescriptor");
|
||||
|
||||
// Make dialog fullscreen
|
||||
setWindowState(Qt::WindowMaximized);
|
||||
@@ -88,9 +88,13 @@ void MediaPreviewDialog::setupUI()
|
||||
}
|
||||
|
||||
// Status bar
|
||||
// more margin because of border radius on macOS
|
||||
m_statusLabel = new QLabel(this);
|
||||
m_statusLabel->setStyleSheet(
|
||||
"QLabel { background: #f0f0f0; padding: 5px; font-size: 12px; }");
|
||||
#ifdef Q_OS_MAC
|
||||
m_statusLabel->setStyleSheet("QLabel { margin-left: 15px; }");
|
||||
#else
|
||||
m_statusLabel->setStyleSheet("QLabel { margin-left: 5px; }");
|
||||
#endif
|
||||
m_mainLayout->addWidget(m_statusLabel);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#include <QMainWindow>
|
||||
#include <QPoint>
|
||||
#include <QString>
|
||||
#include <QWidget>
|
||||
|
||||
struct UsageInfo {
|
||||
QString type;
|
||||
QString formattedSize;
|
||||
QString color;
|
||||
double percentage;
|
||||
};
|
||||
|
||||
void setupMacOSWindow(QMainWindow *window);
|
||||
|
||||
void showPopoverForBarWidget(QWidget *widget, const UsageInfo &info);
|
||||
|
||||
void hidePopoverForBarWidget();
|
||||
+122
-1
@@ -1,3 +1,4 @@
|
||||
#include "./macos.h"
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <QDebug>
|
||||
#include <QMainWindow>
|
||||
@@ -39,4 +40,124 @@ void setupMacOSWindow(QMainWindow *window)
|
||||
// [nativeWindow setContentBorderThickness:0.0 forEdge:NSMinYEdge];
|
||||
|
||||
[nativeWindow center];
|
||||
}
|
||||
}
|
||||
|
||||
@interface DiskUsagePopoverViewController : NSViewController
|
||||
@property(nonatomic, strong) NSTextField *typeLabel;
|
||||
@property(nonatomic, strong) NSTextField *sizeLabel;
|
||||
@property(nonatomic, strong) NSTextField *percentageLabel;
|
||||
@end
|
||||
|
||||
// Static variables for popover management
|
||||
NSPopover *s_popover = nil;
|
||||
NSViewController *s_viewController = nil;
|
||||
|
||||
@implementation DiskUsagePopoverViewController
|
||||
- (void)loadView
|
||||
{
|
||||
NSView *view = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 180, 80)];
|
||||
|
||||
// Type label
|
||||
self.typeLabel =
|
||||
[[NSTextField alloc] initWithFrame:NSMakeRect(40, 55, 130, 16)];
|
||||
self.typeLabel.editable = NO;
|
||||
self.typeLabel.selectable = NO;
|
||||
self.typeLabel.bordered = NO;
|
||||
self.typeLabel.backgroundColor = [NSColor clearColor];
|
||||
self.typeLabel.font = [NSFont boldSystemFontOfSize:13];
|
||||
[view addSubview:self.typeLabel];
|
||||
|
||||
// Size label
|
||||
self.sizeLabel =
|
||||
[[NSTextField alloc] initWithFrame:NSMakeRect(10, 30, 160, 16)];
|
||||
self.sizeLabel.editable = NO;
|
||||
self.sizeLabel.selectable = NO;
|
||||
self.sizeLabel.bordered = NO;
|
||||
self.sizeLabel.backgroundColor = [NSColor clearColor];
|
||||
self.sizeLabel.font = [NSFont systemFontOfSize:11];
|
||||
[view addSubview:self.sizeLabel];
|
||||
|
||||
// Percentage label
|
||||
self.percentageLabel =
|
||||
[[NSTextField alloc] initWithFrame:NSMakeRect(10, 10, 160, 16)];
|
||||
self.percentageLabel.editable = NO;
|
||||
self.percentageLabel.selectable = NO;
|
||||
self.percentageLabel.bordered = NO;
|
||||
self.percentageLabel.backgroundColor = [NSColor clearColor];
|
||||
self.percentageLabel.font = [NSFont systemFontOfSize:11];
|
||||
self.percentageLabel.textColor = [NSColor secondaryLabelColor];
|
||||
[view addSubview:self.percentageLabel];
|
||||
|
||||
self.view = view;
|
||||
}
|
||||
|
||||
- (void)updateWithInfo:(const UsageInfo &)info
|
||||
{
|
||||
self.typeLabel.stringValue =
|
||||
[NSString stringWithUTF8String:info.type.toUtf8().constData()];
|
||||
self.sizeLabel.stringValue =
|
||||
[NSString stringWithUTF8String:info.formattedSize.toUtf8().constData()];
|
||||
self.percentageLabel.stringValue = [NSString
|
||||
stringWithFormat:@"%.1f%% of total capacity", info.percentage];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
void hidePopoverForBarWidget()
|
||||
{
|
||||
if (s_popover) {
|
||||
[s_popover close];
|
||||
[s_popover release];
|
||||
s_popover = nil;
|
||||
}
|
||||
if (s_viewController) {
|
||||
[s_viewController release];
|
||||
s_viewController = nil;
|
||||
}
|
||||
}
|
||||
// TODO: bug report to Qt, window becomes blurry, shifted or resized after
|
||||
// showing popover
|
||||
void showPopoverForBarWidget(QWidget *widget, const UsageInfo &info)
|
||||
{
|
||||
if (!widget)
|
||||
return;
|
||||
|
||||
// Hide existing popover if any
|
||||
hidePopoverForBarWidget();
|
||||
|
||||
// Get the native view
|
||||
NSView *nativeView = reinterpret_cast<NSView *>(widget->winId());
|
||||
if (!nativeView)
|
||||
return;
|
||||
|
||||
NSWindow *window = [nativeView window];
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
// Create view controller and force view loading
|
||||
DiskUsagePopoverViewController *viewController =
|
||||
[[DiskUsagePopoverViewController alloc] init];
|
||||
|
||||
// Force the view to load before updating
|
||||
[viewController loadView];
|
||||
[viewController updateWithInfo:info];
|
||||
|
||||
// Create popover
|
||||
NSPopover *popover = [[NSPopover alloc] init];
|
||||
[popover setContentSize:NSMakeSize(180, 80)];
|
||||
[popover setBehavior:NSPopoverBehaviorTransient];
|
||||
[popover setAnimates:YES];
|
||||
[popover setContentViewController:viewController];
|
||||
|
||||
// Use the widget's bounds for a simpler approach
|
||||
NSRect widgetBounds = nativeView.bounds;
|
||||
|
||||
// Show popover
|
||||
[popover showRelativeToRect:widgetBounds
|
||||
ofView:nativeView
|
||||
preferredEdge:NSMinYEdge];
|
||||
|
||||
// Store references (retain them)
|
||||
s_popover = [popover retain];
|
||||
s_viewController = [viewController retain];
|
||||
}
|
||||
|
||||
@@ -167,7 +167,6 @@ ClickableWidget *ToolboxWidget::createToolbox(iDescriptorTool tool,
|
||||
{
|
||||
ClickableWidget *b = new ClickableWidget();
|
||||
b->setStyleSheet("padding: 5px; border: none; outline: none;");
|
||||
b->setFixedSize(200, 120);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(b);
|
||||
|
||||
@@ -235,15 +234,13 @@ ClickableWidget *ToolboxWidget::createToolbox(iDescriptorTool tool,
|
||||
}
|
||||
// Title
|
||||
QLabel *titleLabel = new QLabel(title);
|
||||
titleLabel->setFont(QFont("Arial", 10, QFont::Bold));
|
||||
titleLabel->setAlignment(Qt::AlignCenter);
|
||||
|
||||
// Description
|
||||
QLabel *descLabel = new QLabel(description);
|
||||
descLabel->setFont(QFont("Arial", 8));
|
||||
descLabel->setWordWrap(true);
|
||||
descLabel->setAlignment(Qt::AlignCenter);
|
||||
descLabel->setStyleSheet("color: #666;");
|
||||
descLabel->setStyleSheet("color: #666; font-size: 12px;");
|
||||
|
||||
layout->addWidget(iconLabel);
|
||||
layout->addWidget(titleLabel);
|
||||
|
||||
Reference in New Issue
Block a user