mirror of
https://github.com/iDescriptor/iDescriptor.git
synced 2026-06-21 19:35:49 +08:00
refactor ui
- Implemented CustomTab class with notification support and custom painting. - Created CustomTabWidget to manage multiple tabs with a stacked widget layout. - Integrated glider animation for smooth tab transitions. - Updated DeviceInfoWidget to improve layout and visual appearance with shadows. - Refactored DeviceMenuWidget to use QStackedWidget instead of QTabWidget for better flexibility. - Enhanced main window setup with custom tab widget and improved device management UI. - Added macOS specific window styling for a more native look. - Improved ToolboxWidget layout and styling for better user experience.
This commit is contained in:
@@ -140,6 +140,9 @@ file(GLOB PROJECT_SOURCES
|
||||
src/*.cpp
|
||||
src/core/helpers/*.cpp
|
||||
src/core/services/*.cpp
|
||||
src/platform/*.cpp
|
||||
src/platform/*.mm
|
||||
src/platform/*.m
|
||||
src/*.h
|
||||
src/*.ui
|
||||
resources.qrc
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 9.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
@@ -2,6 +2,8 @@
|
||||
<qresource prefix="/">
|
||||
<file>icons/ArrowMoveDownRight.svg</file>
|
||||
<file>icons/video-x-generic.png</file>
|
||||
<file>icons/MdiLightningBolt.png</file>
|
||||
<file>icons/MingcuteSettings7Line.png</file>
|
||||
<file>qml/MapView.qml</file>
|
||||
<file>resources/dump.js</file>
|
||||
<file>resources/iphone.png</file>
|
||||
|
||||
@@ -153,6 +153,11 @@ void AppContext::instanceRemoveDevice(QString _udid)
|
||||
// return true;
|
||||
}
|
||||
|
||||
int AppContext::getConnectedDeviceCount() const
|
||||
{
|
||||
return m_devices.size() + m_recoveryDevices.size();
|
||||
}
|
||||
|
||||
void AppContext::removeDevice(QString _udid)
|
||||
|
||||
{
|
||||
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
QList<RecoveryDeviceInfo *> getAllRecoveryDevices();
|
||||
~AppContext();
|
||||
void instanceRemoveDevice(QString _udid);
|
||||
int getConnectedDeviceCount() const;
|
||||
|
||||
private:
|
||||
QMap<std::string, iDescriptorDevice *> m_devices;
|
||||
|
||||
+3
-12
@@ -10,8 +10,8 @@
|
||||
BatteryWidget::BatteryWidget(float value, bool isCharging, QWidget *parent)
|
||||
: QWidget(parent), m_value(value), m_isCharging(isCharging)
|
||||
{
|
||||
setMinimumSize(50, 40);
|
||||
setMaximumSize(60, 40);
|
||||
setMinimumSize(30, 30);
|
||||
setMaximumSize(40, 40);
|
||||
}
|
||||
|
||||
void BatteryWidget::resizeEvent(QResizeEvent *)
|
||||
@@ -111,7 +111,7 @@ void BatteryWidget::paintEvent(QPaintEvent *)
|
||||
pen.setColor(Qt::white);
|
||||
painter.setPen(pen);
|
||||
QFont textFont = QFont();
|
||||
textFont.setPixelSize(widgetFrame.height() / 2);
|
||||
textFont.setPixelSize(widgetFrame.height() / 1.65);
|
||||
painter.setFont(textFont);
|
||||
QFontMetrics fm(textFont);
|
||||
QString percentageLevelString = QString("%1%").arg(m_value);
|
||||
@@ -121,13 +121,4 @@ void BatteryWidget::paintEvent(QPaintEvent *)
|
||||
QPointF textPosition = QPointF(widgetFrame.center().x() - textWidth / 2,
|
||||
widgetFrame.center().y() + textHeight / 3);
|
||||
painter.drawText(textPosition, percentageLevelString);
|
||||
|
||||
float chargerSize = widgetFrame.height() / 2;
|
||||
|
||||
// if (isCharging) {
|
||||
// QPixmap pixmap(":/img/charge.png");
|
||||
// painter.drawPixmap(widgetFrame.center().x() - chargerSize * 1.5,
|
||||
// widgetFrame.top() + chargerSize / 2, chargerSize,
|
||||
// chargerSize, pixmap);
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,329 @@
|
||||
#include "customtabwidget.h"
|
||||
#include <QEasingCurve>
|
||||
#include <QGraphicsDropShadowEffect>
|
||||
#include <QMainWindow>
|
||||
#include <QPainter>
|
||||
#include <QStyleOption>
|
||||
#include <QTimer>
|
||||
|
||||
// CustomTab implementation
|
||||
CustomTab::CustomTab(const QString &text, QWidget *parent)
|
||||
: QPushButton(text, parent), m_notificationLabel(nullptr),
|
||||
m_notificationCount(0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
QPushButton::setIcon(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)
|
||||
{
|
||||
m_mainLayout = new QVBoxLayout(this);
|
||||
m_mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
m_mainLayout->setSpacing(0);
|
||||
|
||||
// Create tab bar container
|
||||
m_tabBar = new QWidget();
|
||||
m_tabBar->setFixedHeight(70); // 54px height + 16px padding
|
||||
m_tabLayout = new QHBoxLayout(m_tabBar);
|
||||
// m_tabLayout->setContentsMargins(12, 8, 12, 8);
|
||||
m_tabLayout->setSpacing(0);
|
||||
|
||||
// Style the tab bar
|
||||
m_tabBar->setStyleSheet("QWidget {"
|
||||
// " background-color: white;"
|
||||
" border-radius: 35px;"
|
||||
"}");
|
||||
|
||||
// Add drop shadow effect
|
||||
QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect();
|
||||
shadow->setBlurRadius(20);
|
||||
shadow->setColor(QColor(24, 94, 224, 38)); // rgba(24, 94, 224, 0.15)
|
||||
shadow->setOffset(0, 6);
|
||||
m_tabBar->setGraphicsEffect(shadow);
|
||||
|
||||
m_buttonGroup = new QButtonGroup(this);
|
||||
m_buttonGroup->setExclusive(true);
|
||||
|
||||
// Create stacked widget for content
|
||||
m_stackedWidget = new QStackedWidget();
|
||||
|
||||
// Add widgets to layout
|
||||
m_mainLayout->addWidget(m_tabBar);
|
||||
m_mainLayout->addWidget(m_stackedWidget, 1);
|
||||
|
||||
setupGlider();
|
||||
}
|
||||
|
||||
void CustomTabWidget::setupGlider()
|
||||
{
|
||||
m_glider = new QWidget(m_tabBar);
|
||||
m_glider->setStyleSheet("QWidget {"
|
||||
" background-color: #185ee0;"
|
||||
" border-radius: 1px;"
|
||||
"}");
|
||||
// Set initial size - will be updated in animateGlider
|
||||
m_glider->setFixedSize(100, 2); // 2px height for bottom border effect
|
||||
m_glider->lower(); // Make sure glider is behind tabs
|
||||
|
||||
m_gliderAnimation = new QPropertyAnimation(m_glider, "pos");
|
||||
m_gliderAnimation->setDuration(250);
|
||||
m_gliderAnimation->setEasingCurve(QEasingCurve::OutCubic);
|
||||
}
|
||||
|
||||
int CustomTabWidget::addTab(QWidget *widget, const QString &label)
|
||||
{
|
||||
return addTab(widget, QIcon(), label);
|
||||
}
|
||||
|
||||
int CustomTabWidget::addTab(QWidget *widget, const QIcon &icon,
|
||||
const QString &label)
|
||||
{
|
||||
CustomTab *tab = new CustomTab(label, m_tabBar);
|
||||
if (!icon.isNull()) {
|
||||
tab->setIcon(icon);
|
||||
}
|
||||
connect(tab, &CustomTab::clicked, this, &CustomTabWidget::onTabClicked);
|
||||
int index = m_tabs.count();
|
||||
m_tabs.append(tab);
|
||||
m_widgets.append(widget);
|
||||
|
||||
m_tabLayout->addWidget(tab);
|
||||
m_stackedWidget->addWidget(widget);
|
||||
m_buttonGroup->addButton(tab, index);
|
||||
|
||||
// Set first tab as checked by default
|
||||
if (index == 0) {
|
||||
tab->setChecked(true);
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void CustomTabWidget::setCurrentIndex(int index)
|
||||
{
|
||||
if (index < 0 || index >= m_tabs.count() || index == m_currentIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_currentIndex = index;
|
||||
m_tabs[index]->setChecked(true);
|
||||
m_stackedWidget->setCurrentIndex(index);
|
||||
updateTabStyles();
|
||||
animateGlider(index);
|
||||
|
||||
emit currentChanged(index);
|
||||
}
|
||||
|
||||
void CustomTabWidget::finalizeStyles()
|
||||
{
|
||||
updateTabStyles();
|
||||
// Position glider for first tab
|
||||
QTimer::singleShot(0, [this]() { animateGlider(0); });
|
||||
}
|
||||
|
||||
int CustomTabWidget::currentIndex() const { return m_currentIndex; }
|
||||
|
||||
QWidget *CustomTabWidget::widget(int index) const
|
||||
{
|
||||
if (index < 0 || index >= m_widgets.count()) {
|
||||
return nullptr;
|
||||
}
|
||||
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());
|
||||
if (!clickedTab)
|
||||
return;
|
||||
|
||||
int index = m_tabs.indexOf(clickedTab);
|
||||
if (index != -1) {
|
||||
setCurrentIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
void CustomTabWidget::animateGlider(int index)
|
||||
{
|
||||
if (index < 0 || index >= m_tabs.count())
|
||||
return;
|
||||
|
||||
CustomTab *targetTab = m_tabs[index];
|
||||
if (!targetTab)
|
||||
return;
|
||||
|
||||
// Get the actual position and size of the target tab
|
||||
QPoint targetTabPos = targetTab->pos();
|
||||
QSize targetTabSize = targetTab->size();
|
||||
|
||||
// Set glider width to match tab width and height to 2px for bottom border
|
||||
m_glider->setFixedSize(targetTabSize.width(), 2);
|
||||
|
||||
// Position glider at the bottom of the target tab
|
||||
int targetX = targetTabPos.x();
|
||||
int targetY =
|
||||
targetTabPos.y() + targetTabSize.height() - 2; // Position at bottom
|
||||
|
||||
m_gliderAnimation->stop();
|
||||
m_gliderAnimation->setStartValue(m_glider->pos());
|
||||
m_gliderAnimation->setEndValue(QPoint(targetX, targetY));
|
||||
m_gliderAnimation->start();
|
||||
}
|
||||
|
||||
void CustomTabWidget::updateTabStyles()
|
||||
{
|
||||
for (int i = 0; i < m_tabs.count(); ++i) {
|
||||
CustomTab *tab = m_tabs[i];
|
||||
if (tab->isChecked()) {
|
||||
tab->setStyleSheet("CustomTab {"
|
||||
" color: #185ee0;"
|
||||
" font-weight: 500;"
|
||||
" font-size: 20px;"
|
||||
" border: none;"
|
||||
" border-radius: 27px;"
|
||||
" background-color: transparent;"
|
||||
"}"
|
||||
"CustomTab:hover {"
|
||||
" background-color: transparent;"
|
||||
"}");
|
||||
} else {
|
||||
tab->setStyleSheet("CustomTab {"
|
||||
" color: #666;"
|
||||
" font-weight: 500;"
|
||||
" font-size: 20px;"
|
||||
" border: none;"
|
||||
" border-radius: 27px;"
|
||||
" background-color: transparent;"
|
||||
"}"
|
||||
"CustomTab:hover {"
|
||||
" color: #185ee0;"
|
||||
" background-color: transparent;"
|
||||
"}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CustomTabWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
|
||||
// Update glider position when widget is resized
|
||||
if (m_currentIndex >= 0 && m_currentIndex < m_tabs.count()) {
|
||||
// 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
|
||||
@@ -0,0 +1,72 @@
|
||||
#ifndef CUSTOMTABWIDGET_H
|
||||
#define CUSTOMTABWIDGET_H
|
||||
|
||||
#include <QButtonGroup>
|
||||
#include <QHBoxLayout>
|
||||
#include <QIcon>
|
||||
#include <QLabel>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QPushButton>
|
||||
#include <QStackedWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
class CustomTab : public QPushButton
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
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
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CustomTabWidget(QWidget *parent = nullptr);
|
||||
void finalizeStyles();
|
||||
int addTab(QWidget *widget, const QString &label);
|
||||
int addTab(QWidget *widget, const QIcon &icon, const QString &label);
|
||||
void setCurrentIndex(int index);
|
||||
int currentIndex() const;
|
||||
QWidget *widget(int index) const;
|
||||
void setTabNotification(int index, int count);
|
||||
|
||||
signals:
|
||||
void currentChanged(int index);
|
||||
|
||||
private slots:
|
||||
void onTabClicked();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
QHBoxLayout *m_tabLayout;
|
||||
QVBoxLayout *m_mainLayout;
|
||||
QWidget *m_tabBar;
|
||||
QStackedWidget *m_stackedWidget;
|
||||
QButtonGroup *m_buttonGroup;
|
||||
QWidget *m_glider;
|
||||
QPropertyAnimation *m_gliderAnimation;
|
||||
QList<CustomTab *> m_tabs;
|
||||
QList<QWidget *> m_widgets;
|
||||
int m_currentIndex;
|
||||
|
||||
void setupGlider();
|
||||
void animateGlider(int index);
|
||||
void updateTabStyles();
|
||||
};
|
||||
|
||||
#endif // CUSTOMTABWIDGET_H
|
||||
+95
-27
@@ -5,6 +5,7 @@
|
||||
#include "iDescriptor-ui.h"
|
||||
#include "iDescriptor.h"
|
||||
#include <QDebug>
|
||||
#include <QGraphicsDropShadowEffect>
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QGraphicsView>
|
||||
#include <QGridLayout>
|
||||
@@ -75,30 +76,50 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent)
|
||||
QString::number(device->deviceInfo.diskInfo.totalDiskCapacity /
|
||||
(1000 * 1000 * 1000)) +
|
||||
" GB");
|
||||
|
||||
diskCapacityLabel->setAttribute(Qt::WA_StyledBackground, true);
|
||||
diskCapacityLabel->setStyleSheet("background-color: rgba(0, 255, 30, 0.12);"
|
||||
"padding: 4px;"
|
||||
"border-radius: 4px;");
|
||||
|
||||
m_chargingStatusLabel =
|
||||
new QLabel(device->deviceInfo.batteryInfo.isCharging ? "Charging"
|
||||
: "Not Charging");
|
||||
m_chargingStatusLabel->setStyleSheet("font-size: 1rem;");
|
||||
m_chargingStatusLabel->setStyleSheet(
|
||||
device->deviceInfo.batteryInfo.isCharging ? "color: green;"
|
||||
: "color: white;");
|
||||
|
||||
m_chargingWattsLabel =
|
||||
new QLabel(QString::number(device->deviceInfo.batteryInfo.watts) + "W");
|
||||
|
||||
m_cableTypeLabel =
|
||||
new QLabel(device->deviceInfo.batteryInfo.usbConnectionType ==
|
||||
BatteryInfo::ConnectionType::USB
|
||||
? "USB"
|
||||
: "USB-C");
|
||||
// Create the layout without a parent widget
|
||||
QHBoxLayout *chargingLayout = new QHBoxLayout();
|
||||
chargingLayout->setContentsMargins(0, 0, 0, 0);
|
||||
chargingLayout->setSpacing(5);
|
||||
|
||||
// Create icon label
|
||||
m_lightningIconLabel = new QLabel();
|
||||
QPixmap lightningIcon(":/icons/MdiLightningBolt.png");
|
||||
QPixmap scaledIcon = lightningIcon.scaled(16, 16, Qt::KeepAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
m_lightningIconLabel->setPixmap(scaledIcon);
|
||||
m_batteryWidget =
|
||||
new BatteryWidget(device->deviceInfo.batteryInfo.currentBatteryLevel,
|
||||
device->deviceInfo.batteryInfo.isCharging, this);
|
||||
|
||||
// Add the widgets to the new layout
|
||||
chargingLayout->addWidget(m_chargingStatusLabel);
|
||||
chargingLayout->addWidget(m_lightningIconLabel);
|
||||
chargingLayout->addWidget(m_batteryWidget);
|
||||
|
||||
m_chargingWattsWithCableTypeLabel = new QLabel(
|
||||
QString::number(device->deviceInfo.batteryInfo.watts) + "W" + "/" +
|
||||
(device->deviceInfo.batteryInfo.usbConnectionType ==
|
||||
BatteryInfo::ConnectionType::USB
|
||||
? "USB"
|
||||
: "USB-C"));
|
||||
|
||||
headerLayout->addWidget(devProductType);
|
||||
headerLayout->addWidget(diskCapacityLabel);
|
||||
headerLayout->addWidget(m_chargingStatusLabel);
|
||||
headerLayout->addWidget(m_batteryWidget);
|
||||
headerLayout->addWidget(m_chargingWattsLabel);
|
||||
headerLayout->addWidget(m_cableTypeLabel);
|
||||
headerLayout->addLayout(chargingLayout);
|
||||
headerLayout->addWidget(m_chargingWattsWithCableTypeLabel);
|
||||
|
||||
infoLayout->addWidget(headerWidget);
|
||||
// add spacer
|
||||
@@ -107,14 +128,47 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent)
|
||||
// Add maximum stretch between header and grid
|
||||
infoLayout->addStretch();
|
||||
|
||||
// Grid for device details
|
||||
// --- Neumorphic Grid Widget ---
|
||||
|
||||
// 1. Create a container for the shadows
|
||||
QWidget *shadowContainer = new QWidget();
|
||||
// The container must be transparent to not hide the main window background
|
||||
shadowContainer->setStyleSheet("background: transparent;");
|
||||
// Use a layout to make the gridWidget fill the container
|
||||
QVBoxLayout *shadowLayout = new QVBoxLayout(shadowContainer);
|
||||
shadowLayout->setContentsMargins(15, 15, 15,
|
||||
15); // Margins to make space for shadows
|
||||
|
||||
// 2. Create the dark (bottom-right) shadow and apply to the container
|
||||
QGraphicsDropShadowEffect *darkShadow = new QGraphicsDropShadowEffect();
|
||||
darkShadow->setBlurRadius(30);
|
||||
darkShadow->setColor(QColor(0, 0, 0, 70)); // Dark, semi-transparent color
|
||||
darkShadow->setOffset(0, 0);
|
||||
shadowContainer->setGraphicsEffect(darkShadow);
|
||||
|
||||
// 3. Create the grid widget (the main content)
|
||||
QWidget *gridWidget = new QWidget();
|
||||
gridWidget->setObjectName("infoGrid");
|
||||
gridWidget->setStyleSheet("QWidget#infoGrid { "
|
||||
" border: 1px solid #ccc; "
|
||||
" border-radius: 6px; "
|
||||
"}");
|
||||
QGridLayout *gridLayout = new QGridLayout();
|
||||
// Set a background color that matches the main window, with rounded corners
|
||||
gridWidget->setStyleSheet(
|
||||
"QWidget#infoGrid {"
|
||||
" background-color: #2e2e2e;" // Match your window background
|
||||
" border-radius: 8px;"
|
||||
"}");
|
||||
|
||||
// 4. Create the light (top-left) shadow and apply to the grid widget
|
||||
QGraphicsDropShadowEffect *lightShadow = new QGraphicsDropShadowEffect();
|
||||
lightShadow->setBlurRadius(30);
|
||||
lightShadow->setColor(
|
||||
QColor(255, 255, 255, 40)); // Light, semi-transparent color
|
||||
lightShadow->setOffset(0, 0);
|
||||
gridWidget->setGraphicsEffect(lightShadow);
|
||||
|
||||
// Add gridWidget to the container's layout
|
||||
shadowLayout->addWidget(gridWidget);
|
||||
|
||||
QGridLayout *gridLayout =
|
||||
new QGridLayout(gridWidget); // Set layout on gridWidget
|
||||
gridLayout->setSpacing(8);
|
||||
gridLayout->setColumnStretch(1, 1); // Allow value column to stretch
|
||||
gridLayout->setColumnStretch(
|
||||
@@ -228,7 +282,8 @@ DeviceInfoWidget::DeviceInfoWidget(iDescriptorDevice *device, QWidget *parent)
|
||||
}
|
||||
}
|
||||
|
||||
infoLayout->addWidget(gridWidget);
|
||||
infoLayout->addWidget(
|
||||
shadowContainer); // Add the container to the main layout
|
||||
// infoLayout->addStretch(); // Pushes footer to the bottom
|
||||
|
||||
// Footer
|
||||
@@ -310,14 +365,27 @@ void DeviceInfoWidget::updateBatteryInfo()
|
||||
else
|
||||
parseDeviceBattery(ioreg, d);
|
||||
/*UI*/
|
||||
m_chargingStatusLabel->setText(d.batteryInfo.isCharging ? "Charging"
|
||||
: "Not Charging");
|
||||
m_chargingWattsLabel->setText(QString::number(d.batteryInfo.watts) + "W");
|
||||
m_cableTypeLabel->setText(d.batteryInfo.usbConnectionType ==
|
||||
BatteryInfo::ConnectionType::USB
|
||||
? "USB"
|
||||
: "USB-C");
|
||||
updateChargingStatusIcon();
|
||||
m_chargingWattsWithCableTypeLabel->setText(
|
||||
QString::number(d.batteryInfo.watts) + "W" + "/" +
|
||||
(d.batteryInfo.usbConnectionType == BatteryInfo::ConnectionType::USB
|
||||
? "USB"
|
||||
: "USB-C"));
|
||||
|
||||
m_batteryWidget->updateContext(d.batteryInfo.isCharging,
|
||||
d.batteryInfo.currentBatteryLevel);
|
||||
}
|
||||
|
||||
void DeviceInfoWidget::updateChargingStatusIcon()
|
||||
{
|
||||
if (m_device->deviceInfo.batteryInfo.isCharging) {
|
||||
m_chargingStatusLabel->setText("Charging");
|
||||
m_chargingStatusLabel->setStyleSheet("color: green;");
|
||||
m_lightningIconLabel->show();
|
||||
|
||||
} else {
|
||||
m_chargingStatusLabel->setText("Not Charging");
|
||||
m_chargingStatusLabel->setStyleSheet("color: white;");
|
||||
m_lightningIconLabel->hide();
|
||||
}
|
||||
}
|
||||
@@ -21,10 +21,11 @@ private:
|
||||
iDescriptorDevice *m_device;
|
||||
QTimer *m_updateTimer;
|
||||
void updateBatteryInfo();
|
||||
void updateChargingStatusIcon();
|
||||
QLabel *m_chargingStatusLabel;
|
||||
QLabel *m_chargingWattsLabel;
|
||||
QLabel *m_cableTypeLabel;
|
||||
QLabel *m_chargingWattsWithCableTypeLabel;
|
||||
BatteryWidget *m_batteryWidget;
|
||||
QLabel *m_lightningIconLabel;
|
||||
};
|
||||
|
||||
#endif // DEVICEINFOWIDGET_H
|
||||
|
||||
+33
-24
@@ -5,37 +5,46 @@
|
||||
#include "iDescriptor.h"
|
||||
#include "installedappswidget.h"
|
||||
#include <QDebug>
|
||||
#include <QTabWidget>
|
||||
#include <QStackedWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
DeviceMenuWidget::DeviceMenuWidget(iDescriptorDevice *device, QWidget *parent)
|
||||
: QWidget{parent}, device(device)
|
||||
{
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mainLayout->setSpacing(0);
|
||||
|
||||
QWidget *centralWidget = new QWidget(this);
|
||||
tabWidget = new QTabWidget(this);
|
||||
tabWidget->tabBar()->hide();
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);
|
||||
mainLayout->addWidget(tabWidget);
|
||||
stackedWidget = new QStackedWidget(this);
|
||||
mainLayout->addWidget(stackedWidget);
|
||||
|
||||
FileExplorerWidget *explorer = new FileExplorerWidget(device, this);
|
||||
explorer->setMinimumHeight(300);
|
||||
// Create and add widgets to the stacked widget
|
||||
DeviceInfoWidget *deviceInfoWidget = new DeviceInfoWidget(device, this);
|
||||
InstalledAppsWidget *installedAppsWidget =
|
||||
new InstalledAppsWidget(device, this);
|
||||
GalleryWidget *galleryWidget = new GalleryWidget(device, this);
|
||||
FileExplorerWidget *fileExplorerWidget =
|
||||
new FileExplorerWidget(device, this);
|
||||
|
||||
GalleryWidget *gallery = new GalleryWidget(device, this);
|
||||
gallery->setMinimumHeight(300);
|
||||
setLayout(mainLayout);
|
||||
// Set minimum heights
|
||||
galleryWidget->setMinimumHeight(300);
|
||||
fileExplorerWidget->setMinimumHeight(300);
|
||||
|
||||
tabWidget->addTab(new DeviceInfoWidget(device, this), "");
|
||||
tabWidget->addTab(new InstalledAppsWidget(device, this), "");
|
||||
unsigned int galleryIndex = tabWidget->addTab(gallery, "");
|
||||
tabWidget->addTab(explorer, "");
|
||||
// Add widgets to stack (index 0, 1, 2, 3)
|
||||
stackedWidget->addWidget(deviceInfoWidget); // Index 0 - Info
|
||||
stackedWidget->addWidget(installedAppsWidget); // Index 1 - Apps
|
||||
stackedWidget->addWidget(galleryWidget); // Index 2 - Gallery
|
||||
stackedWidget->addWidget(fileExplorerWidget); // Index 3 - Files
|
||||
|
||||
// TODO : one time ?
|
||||
connect(tabWidget, &QTabWidget::currentChanged, this,
|
||||
[this, galleryIndex, gallery](int index) {
|
||||
if (index == galleryIndex) {
|
||||
// Set default to Info tab
|
||||
stackedWidget->setCurrentIndex(0);
|
||||
|
||||
// Connect to current changed signal for lazy loading
|
||||
connect(stackedWidget, &QStackedWidget::currentChanged, this,
|
||||
[this, galleryWidget](int index) {
|
||||
if (index == 2) { // Gallery tab
|
||||
qDebug() << "Switched to Gallery tab";
|
||||
gallery->load();
|
||||
galleryWidget->load();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -43,13 +52,13 @@ DeviceMenuWidget::DeviceMenuWidget(iDescriptorDevice *device, QWidget *parent)
|
||||
void DeviceMenuWidget::switchToTab(const QString &tabName)
|
||||
{
|
||||
if (tabName == "Info") {
|
||||
tabWidget->setCurrentIndex(0);
|
||||
stackedWidget->setCurrentIndex(0);
|
||||
} else if (tabName == "Apps") {
|
||||
tabWidget->setCurrentIndex(1);
|
||||
stackedWidget->setCurrentIndex(1);
|
||||
} else if (tabName == "Gallery") {
|
||||
tabWidget->setCurrentIndex(2);
|
||||
stackedWidget->setCurrentIndex(2);
|
||||
} else if (tabName == "Files") {
|
||||
tabWidget->setCurrentIndex(3);
|
||||
stackedWidget->setCurrentIndex(3);
|
||||
} else {
|
||||
qDebug() << "Tab not found:" << tabName;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef DEVICEMENUWIDGET_H
|
||||
#define DEVICEMENUWIDGET_H
|
||||
#include "iDescriptor.h"
|
||||
#include <QTabWidget>
|
||||
#include <QStackedWidget>
|
||||
#include <QWidget>
|
||||
class DeviceMenuWidget : public QWidget
|
||||
{
|
||||
@@ -12,8 +12,8 @@ public:
|
||||
void switchToTab(const QString &tabName);
|
||||
// ~DeviceMenuWidget();
|
||||
private:
|
||||
QTabWidget *tabWidget; // Pointer to the tab widget
|
||||
iDescriptorDevice *device; // Pointer to the iDescriptor device
|
||||
QStackedWidget *stackedWidget; // Pointer to the stacked widget
|
||||
iDescriptorDevice *device; // Pointer to the iDescriptor device
|
||||
signals:
|
||||
};
|
||||
|
||||
|
||||
@@ -218,7 +218,7 @@ const std::string &DeviceSidebarItem::getDeviceUuid() const { return m_uuid; }
|
||||
DeviceSidebarWidget::DeviceSidebarWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mainLayout->setContentsMargins(10, 10, 10, 10);
|
||||
mainLayout->setSpacing(0);
|
||||
|
||||
// Create scroll area
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
#include <QGraphicsView>
|
||||
#include <QMainWindow>
|
||||
|
||||
// A custom QGraphicsView that keeps the content fitted with aspect ratio on
|
||||
// resize
|
||||
class ResponsiveGraphicsView : public QGraphicsView
|
||||
@@ -18,4 +20,8 @@ protected:
|
||||
}
|
||||
QGraphicsView::resizeEvent(event);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
void setupMacOSWindow(QMainWindow *window);
|
||||
#endif
|
||||
|
||||
+103
-22
@@ -1,5 +1,6 @@
|
||||
#include "mainwindow.h"
|
||||
#include "./ui_mainwindow.h"
|
||||
#include "customtabwidget.h"
|
||||
#include "detailwindow.h"
|
||||
#include "settingswidget.h"
|
||||
#include <QDialog>
|
||||
@@ -7,6 +8,7 @@
|
||||
#include <QGraphicsSvgItem>
|
||||
#include <QMessageBox>
|
||||
#include <QSvgRenderer>
|
||||
#include <QTimer>
|
||||
#include <QtSvg>
|
||||
|
||||
#include <libimobiledevice/libimobiledevice.h>
|
||||
@@ -15,6 +17,7 @@
|
||||
|
||||
#include "appswidget.h"
|
||||
#include "devicemanagerwidget.h"
|
||||
#include "iDescriptor-ui.h"
|
||||
#include "iDescriptor.h"
|
||||
#include "libirecovery.h"
|
||||
#include "toolboxwidget.h"
|
||||
@@ -24,6 +27,7 @@
|
||||
#include <QPushButton>
|
||||
#include <QScrollArea>
|
||||
#include <QStack>
|
||||
#include <QStackedWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
@@ -33,6 +37,10 @@
|
||||
#include "fileexplorerwidget.h"
|
||||
#include "jailbrokenwidget.h"
|
||||
#include "recoverydeviceinfowidget.h"
|
||||
#include <QApplication>
|
||||
#include <QMenu>
|
||||
#include <QMenuBar>
|
||||
#include <QMessageBox>
|
||||
#include <libusb-1.0/libusb.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -116,16 +124,67 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent), ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowTitle("iDescriptor");
|
||||
|
||||
// Create custom tab widget
|
||||
m_customTabWidget = new CustomTabWidget(this);
|
||||
m_customTabWidget->setAttribute(Qt::WA_ContentsMarginsRespectsSafeArea,
|
||||
false);
|
||||
|
||||
setContentsMargins(0, 0, 0, 0);
|
||||
#ifdef Q_OS_MAC
|
||||
setupMacOSWindow(this);
|
||||
setAttribute(Qt::WA_ContentsMarginsRespectsSafeArea, false);
|
||||
#endif
|
||||
setCentralWidget(m_customTabWidget);
|
||||
|
||||
// Create device manager and stacked widget for main tab
|
||||
m_mainStackedWidget = new QStackedWidget();
|
||||
|
||||
// No devices page
|
||||
QWidget *noDevicesPage = new QWidget();
|
||||
QVBoxLayout *noDeviceLayout = new QVBoxLayout(noDevicesPage);
|
||||
noDeviceLayout->addStretch();
|
||||
QHBoxLayout *labelLayout = new QHBoxLayout();
|
||||
labelLayout->addStretch();
|
||||
QLabel *noDeviceLabel = new QLabel("No devices detected");
|
||||
noDeviceLabel->setAlignment(Qt::AlignCenter);
|
||||
labelLayout->addWidget(noDeviceLabel);
|
||||
labelLayout->addStretch();
|
||||
noDeviceLayout->addLayout(labelLayout);
|
||||
noDeviceLayout->addStretch();
|
||||
|
||||
m_deviceManager = new DeviceManagerWidget(this);
|
||||
ui->stackedWidget->insertWidget(1, m_deviceManager);
|
||||
|
||||
m_mainStackedWidget->addWidget(noDevicesPage);
|
||||
m_mainStackedWidget->addWidget(m_deviceManager);
|
||||
|
||||
connect(m_deviceManager, &DeviceManagerWidget::updateNoDevicesConnected,
|
||||
this, &MainWindow::updateNoDevicesConnected);
|
||||
|
||||
// Add tabs with icons
|
||||
QIcon deviceIcon(":/icons/MdiLightningBolt.png");
|
||||
m_customTabWidget->addTab(m_mainStackedWidget, deviceIcon, "iDevice");
|
||||
m_customTabWidget->addTab(new AppsWidget(this), "Apps");
|
||||
m_customTabWidget->addTab(new ToolboxWidget(this), "Toolbox");
|
||||
|
||||
auto *jailbrokenWidget = new JailbrokenWidget(this);
|
||||
m_customTabWidget->addTab(jailbrokenWidget, "Jailbroken");
|
||||
m_customTabWidget->finalizeStyles();
|
||||
|
||||
// todo: is this ok ?
|
||||
auto connection = std::make_shared<QMetaObject::Connection>();
|
||||
*connection =
|
||||
connect(m_customTabWidget, &CustomTabWidget::currentChanged, this,
|
||||
[this, jailbrokenWidget, connection](int index) {
|
||||
if (index == 3) { // Jailbroken tab
|
||||
jailbrokenWidget->initWidget();
|
||||
QObject::disconnect(*connection);
|
||||
}
|
||||
});
|
||||
|
||||
// settings button
|
||||
QPushButton *settingsButton = new QPushButton();
|
||||
settingsButton->setIcon(QIcon::fromTheme("preferences-system"));
|
||||
settingsButton->setIcon(QIcon(":/icons/MingcuteSettings7Line.png"));
|
||||
settingsButton->setToolTip("Settings");
|
||||
settingsButton->setFlat(true);
|
||||
settingsButton->setCursor(Qt::PointingHandCursor);
|
||||
@@ -141,23 +200,23 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
settingsDialog.setLayout(layout);
|
||||
settingsDialog.exec();
|
||||
});
|
||||
// ui->centralwidget->layout()->addWidget(settingsButton);
|
||||
ui->mainTabWidget->widget(1)->layout()->addWidget(new AppsWidget(this));
|
||||
ui->mainTabWidget->widget(2)->layout()->addWidget(new ToolboxWidget(this));
|
||||
auto *jailbrokenWidget = new JailbrokenWidget(this);
|
||||
ui->mainTabWidget->widget(3)->layout()->addWidget(jailbrokenWidget);
|
||||
m_connectedDeviceCountLabel = new QLabel("iDescriptor: no devices");
|
||||
m_connectedDeviceCountLabel->setContentsMargins(5, 0, 5, 0);
|
||||
m_connectedDeviceCountLabel->setStyleSheet(
|
||||
"QLabel:hover { background-color : #13131319; }");
|
||||
|
||||
// TODO: is this a good idea?
|
||||
auto connection = std::make_shared<QMetaObject::Connection>();
|
||||
*connection = connect(ui->mainTabWidget, &QTabWidget::currentChanged, this,
|
||||
[this, jailbrokenWidget, connection](int index) {
|
||||
if (index == 3) { // Jailbroken tab
|
||||
jailbrokenWidget->initWidget();
|
||||
QObject::disconnect(*connection);
|
||||
}
|
||||
});
|
||||
ui->statusbar->addWidget(m_connectedDeviceCountLabel);
|
||||
|
||||
ui->statusbar->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
// QWidget *statusSpacer = new QWidget();
|
||||
// statusSpacer->setSizePolicy(QSizePolicy::Expanding,
|
||||
// QSizePolicy::Preferred);
|
||||
// statusSpacer->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
// ui->statusbar->addWidget(statusSpacer);
|
||||
|
||||
ui->statusbar->addPermanentWidget(settingsButton);
|
||||
|
||||
irecv_error_t res_recovery =
|
||||
irecv_device_event_subscribe(&context, handleCallbackRecovery, nullptr);
|
||||
|
||||
@@ -169,16 +228,38 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
if (res != IDEVICE_E_SUCCESS) {
|
||||
printf("ERROR: Unable to subscribe to device events.\n");
|
||||
}
|
||||
createMenus();
|
||||
}
|
||||
|
||||
void MainWindow::createMenus()
|
||||
{
|
||||
QMenu *actionsMenu = menuBar()->addMenu("&Actions");
|
||||
|
||||
// Add a custom "About" action for your app
|
||||
QAction *aboutAct = new QAction("&About iDescriptor", this);
|
||||
connect(aboutAct, &QAction::triggered, this, [=]() {
|
||||
QMessageBox::about(this, "About iDescriptor",
|
||||
"<b>iDescriptor</b><br>"
|
||||
"A modern device management tool.");
|
||||
});
|
||||
actionsMenu->addAction(aboutAct);
|
||||
}
|
||||
|
||||
void MainWindow::updateNoDevicesConnected()
|
||||
{
|
||||
qDebug() << "Is there no devices connected? "
|
||||
<< AppContext::sharedInstance()->noDevicesConnected();
|
||||
if (AppContext::sharedInstance()->noDevicesConnected())
|
||||
return ui->stackedWidget->setCurrentIndex(
|
||||
0); // Show "No Devices Connected" page
|
||||
ui->stackedWidget->setCurrentIndex(1); // Show device list page
|
||||
if (AppContext::sharedInstance()->noDevicesConnected()) {
|
||||
|
||||
m_connectedDeviceCountLabel->setText("iDescriptor: no devices");
|
||||
return m_mainStackedWidget->setCurrentIndex(
|
||||
0); // Show "No Devices Connected" page
|
||||
}
|
||||
int deviceCount = AppContext::sharedInstance()->getConnectedDeviceCount();
|
||||
m_connectedDeviceCountLabel->setText(
|
||||
"iDescriptor: " + QString::number(deviceCount) +
|
||||
(deviceCount == 1 ? " device" : " devices") + " connected");
|
||||
m_mainStackedWidget->setCurrentIndex(1); // Show device list page
|
||||
}
|
||||
|
||||
void MainWindow::onRecoveryDeviceAdded(QObject *recoveryDeviceInfoObj)
|
||||
@@ -187,7 +268,7 @@ void MainWindow::onRecoveryDeviceAdded(QObject *recoveryDeviceInfoObj)
|
||||
// TODO: handle
|
||||
return;
|
||||
try {
|
||||
ui->stackedWidget->setCurrentIndex(1);
|
||||
m_mainStackedWidget->setCurrentIndex(1);
|
||||
RecoveryDeviceInfo *device =
|
||||
qobject_cast<RecoveryDeviceInfo *>(recoveryDeviceInfoObj);
|
||||
if (!device) {
|
||||
|
||||
+11
-11
@@ -1,11 +1,12 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
#include "customtabwidget.h"
|
||||
#include "devicemanagerwidget.h"
|
||||
#include "devicemenuwidget.h"
|
||||
#include "iDescriptor.h"
|
||||
#include "libirecovery.h"
|
||||
#include <QLabel>
|
||||
#include <QMainWindow>
|
||||
#include <libimobiledevice/libimobiledevice.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui
|
||||
@@ -21,21 +22,20 @@ class MainWindow : public QMainWindow
|
||||
public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
signals:
|
||||
void deviceAdded(QString udid); // Signal for device connections
|
||||
void onRecoveryDeviceAdded(QObject *recoveryDeviceInfoObj);
|
||||
void onRecoveryDeviceRemoved(QObject *deviceInfoObj);
|
||||
|
||||
public slots:
|
||||
void onRecoveryDeviceAdded(
|
||||
QObject *device_info); // Slot for recovery device connections
|
||||
void onRecoveryDeviceRemoved(
|
||||
QObject *device_info); // Slot for recovery device disconnections
|
||||
void onDeviceInitFailed(QString udid, lockdownd_error_t err);
|
||||
|
||||
private:
|
||||
void updateNoDevicesConnected();
|
||||
|
||||
private:
|
||||
void createMenus();
|
||||
|
||||
Ui::MainWindow *ui;
|
||||
DeviceManagerWidget *m_deviceManager; // Add this member
|
||||
CustomTabWidget *m_customTabWidget;
|
||||
DeviceManagerWidget *m_deviceManager;
|
||||
QStackedWidget *m_mainStackedWidget;
|
||||
QLabel *m_connectedDeviceCountLabel;
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
||||
|
||||
+2
-136
@@ -10,142 +10,6 @@
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="mainTabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="mainTab">
|
||||
<attribute name="title">
|
||||
<string>iDevice</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="mainTabLayout">
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="stackedWidget">
|
||||
<widget class="QWidget" name="page">
|
||||
<layout class="QVBoxLayout" name="noDeviceLayout">
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>No devices detected</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_2">
|
||||
<layout class="QVBoxLayout" name="devicePageLayout"/>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="appsTab">
|
||||
<attribute name="title">
|
||||
<string>Apps</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="appsTabLayout"/>
|
||||
</widget>
|
||||
<widget class="QWidget" name="toolboxTab">
|
||||
<attribute name="title">
|
||||
<string>Toolbox</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="toolboxTabLayout"/>
|
||||
</widget>
|
||||
<widget class="QWidget" name="jailbrokenTab">
|
||||
<attribute name="title">
|
||||
<string>Jailbroken</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="jailbrokenTabLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="jailbrokenLabel">
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
@@ -157,6 +21,8 @@
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <QDebug>
|
||||
#include <QMainWindow>
|
||||
|
||||
void setupMacOSWindow(QMainWindow *window)
|
||||
{
|
||||
|
||||
if (!window) {
|
||||
qWarning() << "setupMacOSWindow: window is null";
|
||||
return;
|
||||
}
|
||||
|
||||
NSView *nativeView = reinterpret_cast<NSView *>(window->winId());
|
||||
NSWindow *nativeWindow = [nativeView window];
|
||||
|
||||
if (!nativeWindow) {
|
||||
qWarning() << "setupMacOSWindow: native window is null";
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Setting up macOS window styles";
|
||||
|
||||
window->setUnifiedTitleAndToolBarOnMac(true);
|
||||
|
||||
[nativeWindow setStyleMask:[nativeWindow styleMask] |
|
||||
NSWindowStyleMaskFullSizeContentView |
|
||||
NSWindowTitleHidden];
|
||||
[nativeWindow setTitleVisibility:NSWindowTitleHidden];
|
||||
[nativeWindow setTitlebarAppearsTransparent:YES];
|
||||
|
||||
NSToolbar *toolbar =
|
||||
[[NSToolbar alloc] initWithIdentifier:@"HiddenInsetToolbar"];
|
||||
toolbar.showsBaselineSeparator =
|
||||
NO; // equivalent to HideToolbarSeparator: true
|
||||
[nativeWindow setToolbar:toolbar];
|
||||
// [toolbar setVisible:NO];
|
||||
// todo : is it ok ?
|
||||
[toolbar release];
|
||||
// [nativeWindow setContentBorderThickness:0.0 forEdge:NSMinYEdge];
|
||||
|
||||
[nativeWindow center];
|
||||
}
|
||||
+10
-6
@@ -71,6 +71,7 @@ ToolboxWidget::ToolboxWidget(QWidget *parent) : QWidget{parent}
|
||||
void ToolboxWidget::setupUI()
|
||||
{
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->setContentsMargins(5, 5, 5, 5);
|
||||
|
||||
// Device selection section
|
||||
QHBoxLayout *deviceLayout = new QHBoxLayout();
|
||||
@@ -80,6 +81,7 @@ void ToolboxWidget::setupUI()
|
||||
|
||||
deviceLayout->addWidget(m_deviceLabel);
|
||||
deviceLayout->addWidget(m_deviceCombo);
|
||||
deviceLayout->setContentsMargins(0, 0, 0, 0);
|
||||
deviceLayout->addStretch();
|
||||
|
||||
mainLayout->addLayout(deviceLayout);
|
||||
@@ -88,6 +90,9 @@ void ToolboxWidget::setupUI()
|
||||
m_scrollArea = new QScrollArea();
|
||||
m_scrollArea->setWidgetResizable(true);
|
||||
m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
m_scrollArea->setStyleSheet(
|
||||
"QScrollArea { background: transparent; border: none; }");
|
||||
m_scrollArea->viewport()->setStyleSheet("background: transparent;");
|
||||
|
||||
m_contentWidget = new QWidget();
|
||||
m_gridLayout = new QGridLayout(m_contentWidget);
|
||||
@@ -164,7 +169,7 @@ QWidget *ToolboxWidget::createToolbox(const QString &title,
|
||||
QFrame *frame = new QFrame();
|
||||
frame->setObjectName("toolboxFrame");
|
||||
frame->setFrameStyle(QFrame::Box);
|
||||
frame->setStyleSheet("#toolboxFrame { border: 1px solid #ccc; "
|
||||
frame->setStyleSheet("#toolboxFrame { "
|
||||
"border-radius: 5px; padding: 5px; }");
|
||||
frame->setFixedSize(200, 120);
|
||||
|
||||
@@ -261,13 +266,12 @@ void ToolboxWidget::updateToolboxStates()
|
||||
toolbox->setEnabled(enabled);
|
||||
|
||||
if (enabled) {
|
||||
toolbox->setStyleSheet("#toolboxFrame { border: 1px solid #ccc; "
|
||||
toolbox->setStyleSheet("#toolboxFrame { "
|
||||
"border-radius: 5px; padding: 5px; }");
|
||||
} else {
|
||||
toolbox->setStyleSheet(
|
||||
"#toolboxFrame { border: 1px solid #ccc; border-radius: 5px; "
|
||||
"padding: "
|
||||
"5px; background-color: #f0f0f0; color: #999; }");
|
||||
toolbox->setStyleSheet("#toolboxFrame { border-radius: 5px; "
|
||||
"padding: 5px;"
|
||||
"opacity: 0.45; }");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user