first
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// Created by Administrator on 2025/3/4.
|
||||
//
|
||||
|
||||
#ifndef AIRI_DESKTOPGRIL_AUDIOPAGE_H
|
||||
#define AIRI_DESKTOPGRIL_AUDIOPAGE_H
|
||||
|
||||
#include "BasePage.h"
|
||||
#include "ElaPushButton.h"
|
||||
class ElaComboBox;
|
||||
class ElaSpinBox;
|
||||
class ElaProgressBar;
|
||||
class ElaPushButton;
|
||||
class AudioPage : public BasePage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE explicit AudioPage(QWidget* parent = nullptr);
|
||||
~AudioPage() override;
|
||||
|
||||
private:
|
||||
ElaComboBox* audioInputDeviceComboBox = nullptr;
|
||||
ElaSpinBox* audioInputSpinBox = nullptr;
|
||||
ElaProgressBar* audioInputProgressBar = nullptr;
|
||||
ElaPushButton* audioAutoThresholdStartButton = nullptr;
|
||||
ElaPushButton* audioManualThresholdStartButton = nullptr;
|
||||
|
||||
ElaPushButton* testAudioPlayButton = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //AIRI_DESKTOPGRIL_AUDIOPAGE_H
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Created by Administrator on 2025/2/27.
|
||||
//
|
||||
|
||||
#ifndef AIRI_DESKTOPGRIL_BASEPAGE_H
|
||||
#define AIRI_DESKTOPGRIL_BASEPAGE_H
|
||||
|
||||
#include <ElaScrollPage.h>
|
||||
class QVBoxLayout;
|
||||
class BasePage : public ElaScrollPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE explicit BasePage(QWidget* parent = nullptr);
|
||||
~BasePage();
|
||||
|
||||
protected:
|
||||
void createCustomWidget(QString desText);
|
||||
};
|
||||
|
||||
#endif //AIRI_DESKTOPGRIL_BASEPAGE_H
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Created by Administrator on 2025/2/28.
|
||||
//
|
||||
|
||||
#ifndef AIRI_DESKTOPGRIL_HOMEPAGE_H
|
||||
#define AIRI_DESKTOPGRIL_HOMEPAGE_H
|
||||
|
||||
#include "BasePage.h"
|
||||
class ElaMenu;
|
||||
class HomePage : public BasePage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE explicit HomePage(QWidget* parent = nullptr);
|
||||
~HomePage();
|
||||
Q_SIGNALS:
|
||||
Q_SIGNAL void audioNavigation();
|
||||
Q_SIGNAL void modelShopNavigation();
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //AIRI_DESKTOPGRIL_HOMEPAGE_H
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Created by Administrator on 2025/4/1.
|
||||
//
|
||||
|
||||
/**
|
||||
* @brief 模型页面
|
||||
* 暂时只做最简单功能切换模型
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "BasePage.h"
|
||||
#include "ElaPushButton.h"
|
||||
#include "ElaLineEdit.h"
|
||||
#include "ElaComboBox.h"
|
||||
#include "ElaSlider.h"
|
||||
|
||||
#include <QUrl>
|
||||
#include <utility>
|
||||
|
||||
class ModelPage final : public BasePage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE explicit ModelPage(QWidget* parent = nullptr);
|
||||
|
||||
std::pair<QString, QString> splitPath(const QString& fullPath);
|
||||
|
||||
~ModelPage() override;
|
||||
|
||||
|
||||
private:
|
||||
// 设置当前模型
|
||||
ElaLineEdit* modelUrlEdit = nullptr; /// 模型Url 编辑框
|
||||
ElaPushButton* modelChoosePushButton = nullptr; /// 选择模型按钮
|
||||
ElaPushButton* modelUsePushButton = nullptr; /// 使用模型按钮
|
||||
ElaSlider* modelSlider = nullptr; /// 滑块(用于设置模型实时大小)
|
||||
|
||||
QUrl modelFileUrl;
|
||||
QString modelFilePathFirst;
|
||||
QString modelFilePathSecond;
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// Created by Administrator on 2025/3/2.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "BasePage.h"
|
||||
#include "ElaPushButton.h"
|
||||
#include "ElaLineEdit.h"
|
||||
|
||||
class ElaPushButton;
|
||||
class ElaLineEdit;
|
||||
class NetWorkPage final : public BasePage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE explicit NetWorkPage(QWidget* parent = nullptr);
|
||||
~NetWorkPage() override;
|
||||
|
||||
private:
|
||||
void initUI();
|
||||
void initWebSocketClient();
|
||||
|
||||
|
||||
|
||||
private:
|
||||
// websocket 控件
|
||||
ElaPushButton* websocketPushButton = nullptr;
|
||||
ElaLineEdit* websocketLineEdit = nullptr;
|
||||
|
||||
// 连接测试
|
||||
ElaPushButton* connectTestPushButton = nullptr;
|
||||
// 连接
|
||||
ElaPushButton* connectPushButton = nullptr;
|
||||
// 断开
|
||||
ElaPushButton* disconnectPushButton = nullptr;
|
||||
|
||||
// 发送测试按钮
|
||||
ElaPushButton* sendTestPushButton = nullptr;
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// Created by Administrator on 2025/3/30.
|
||||
//
|
||||
|
||||
#ifndef YOSUGA_RENDERPAGE_H
|
||||
#define YOSUGA_RENDERPAGE_H
|
||||
|
||||
#include "BasePage.h"
|
||||
#include "ElaPushButton.h"
|
||||
#include "ElaLineEdit.h"
|
||||
#include "ElaComboBox.h"
|
||||
class RenderPage : public BasePage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE explicit RenderPage(QWidget* parent = nullptr);
|
||||
~RenderPage();
|
||||
|
||||
|
||||
private:
|
||||
// 帧率设置
|
||||
ElaComboBox* frameRateComboBox = nullptr;
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //YOSUGA_RENDERPAGE_H
|
||||
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// Created by Administrator on 2025/1/21.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ElaWidget.h>
|
||||
#include <ElaWindow.h>
|
||||
#include <ElaPushButton.h>
|
||||
#include <ElaScrollPage.h>
|
||||
#include <QStackedWidget>
|
||||
|
||||
#include "HomePage.h"
|
||||
#include "NetworkPage.h"
|
||||
#include "UISetting.h"
|
||||
#include "AudioPage.h"
|
||||
#include "RenderPage.h"
|
||||
#include "ModelPage.h"
|
||||
class Setting : public ElaWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Setting(QWidget *parent = nullptr);
|
||||
~Setting();
|
||||
|
||||
private:
|
||||
/**
|
||||
* 初始化所有页面指针
|
||||
* @author : Misaki
|
||||
*/
|
||||
void initPages();
|
||||
|
||||
/**
|
||||
* 初始化导航栏
|
||||
* @author : Misaki
|
||||
*/
|
||||
void initNavigationBar();
|
||||
|
||||
/**
|
||||
* 初始化上下文切换
|
||||
* @author : Misaki
|
||||
*/
|
||||
void initContent();
|
||||
|
||||
private slots:
|
||||
void toggleTheme();
|
||||
|
||||
private:
|
||||
// 页面指针
|
||||
HomePage *homePage;
|
||||
NetWorkPage *networkPage;
|
||||
UISetting *uiSetting;
|
||||
AudioPage *audioPage;
|
||||
RenderPage *renderPage;
|
||||
ModelPage *modelPage;
|
||||
|
||||
// 节点键值
|
||||
QString basePageKey;
|
||||
|
||||
//
|
||||
ElaPushButton *themeToggleButton;
|
||||
|
||||
};
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// Created by Administrator on 2025/3/2.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BasePage.h"
|
||||
class ElaRadioButton;
|
||||
class ElaToggleSwitch;
|
||||
class ElaComboBox;
|
||||
class UISetting : public BasePage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE explicit UISetting(QWidget* parent = nullptr);
|
||||
~UISetting();
|
||||
|
||||
private:
|
||||
ElaComboBox* _themeComboBox = nullptr;
|
||||
ElaToggleSwitch* _micaSwitchButton = nullptr;
|
||||
ElaToggleSwitch* _logSwitchButton = nullptr;
|
||||
ElaRadioButton* _minimumButton = nullptr;
|
||||
ElaRadioButton* _compactButton = nullptr;
|
||||
ElaRadioButton* _maximumButton = nullptr;
|
||||
ElaRadioButton* _autoButton = nullptr;
|
||||
};
|
||||
@@ -0,0 +1,132 @@
|
||||
//
|
||||
// Created by Administrator on 2025/3/4.
|
||||
//
|
||||
|
||||
#include "AudioPage.h"
|
||||
|
||||
|
||||
#include <QHBoxLayout>
|
||||
|
||||
#include "ElaComboBox.h"
|
||||
#include "ElaPlainTextEdit.h"
|
||||
#include "ElaProgressBar.h"
|
||||
#include "ElaScrollPageArea.h"
|
||||
#include "ElaSlider.h"
|
||||
#include "ElaSpinBox.h"
|
||||
#include "ElaText.h"
|
||||
#include "ElaMessageBar.h"
|
||||
|
||||
#include "AudioInput.h"
|
||||
#include "AudioOutput.h"
|
||||
#include "TextRenderer.h"
|
||||
#include "LAppLive2DManager.hpp"
|
||||
AudioPage::AudioPage(QWidget* parent)
|
||||
: BasePage(parent)
|
||||
{
|
||||
// 预览窗口标题
|
||||
setWindowTitle("AudioPage");
|
||||
|
||||
audioInputDeviceComboBox = new ElaComboBox(this);
|
||||
audioInputDeviceComboBox->setToolTip("选择可用的录音设备");
|
||||
QStringList comboList = AudioInput::getAvailableAudioInputDevices();
|
||||
|
||||
audioInputDeviceComboBox->addItems(comboList);
|
||||
ElaScrollPageArea* comboBoxArea = new ElaScrollPageArea(this);
|
||||
QHBoxLayout* comboBoxLayout = new QHBoxLayout(comboBoxArea);
|
||||
ElaText* comboBoxText = new ElaText("录音设备", this);
|
||||
comboBoxText->setTextPixelSize(15);
|
||||
comboBoxLayout->addWidget(comboBoxText);
|
||||
comboBoxLayout->addWidget(audioInputDeviceComboBox);
|
||||
comboBoxLayout->addStretch();
|
||||
comboBoxLayout->addSpacing(10);
|
||||
connect(audioInputDeviceComboBox, &ElaComboBox::currentTextChanged, [this](const QString& text) {
|
||||
AudioInput::getInstance()->setAudioInputDevice(text);
|
||||
ElaMessageBar::success(ElaMessageBarType::TopRight, "音频设置", "成功设置 " + text + " 为当前录音设备", 800.0, this);
|
||||
});
|
||||
|
||||
|
||||
audioInputSpinBox = new ElaSpinBox(this); // SpinBox
|
||||
audioInputSpinBox->setRange(0, 10000);
|
||||
audioInputProgressBar = new ElaProgressBar(this);
|
||||
audioInputProgressBar->setRange(0, 10000);
|
||||
// 关闭ProgressBar的百分比显示
|
||||
audioInputProgressBar->setTextVisible(false);
|
||||
// 将SpinBox和ProgressBar的数值相互绑定
|
||||
connect(audioInputSpinBox, QOverload<int>::of(&ElaSpinBox::valueChanged), [this](int value) {
|
||||
audioInputProgressBar->setValue(value);
|
||||
});
|
||||
connect(audioInputProgressBar, QOverload<int>::of(&ElaProgressBar::valueChanged), [this](int value) {
|
||||
audioInputSpinBox->setValue(value);
|
||||
});
|
||||
|
||||
// 绑定实时录音阈值到ProgressBar,同时归一到0~1000范围内
|
||||
connect(AudioInput::getInstance(), &AudioInput::rmsRealValue, [this](const qreal value) {
|
||||
audioInputProgressBar->setValue(value);
|
||||
});
|
||||
// 当计算完成最优阈值
|
||||
connect(AudioInput::getInstance(), &AudioInput::thresholdCalculated, [this](qreal value) {
|
||||
ElaMessageBar::success(ElaMessageBarType::TopRight, "音频设置", "自动计算出的最优阈值为:" + QString::number(value), 1000, this);
|
||||
// AudioInput会自动设置计算出的最优阈值
|
||||
});
|
||||
audioAutoThresholdStartButton = new ElaPushButton("自动最优阈值", this);
|
||||
audioAutoThresholdStartButton->setToolTip("点击后保持当前环境音5秒,自动计算出最合适的静音检测阈值");
|
||||
connect(audioAutoThresholdStartButton, &ElaPushButton::clicked, [=]() {
|
||||
AudioInput::getInstance()->startAutoThresholdClu(5000);
|
||||
qDebug("开始计算最优阈值");
|
||||
});
|
||||
audioManualThresholdStartButton = new ElaPushButton("手动设置阈值", this);
|
||||
audioManualThresholdStartButton->setToolTip("如果你觉得自动计算的不准的话");
|
||||
connect(audioManualThresholdStartButton, &ElaPushButton::clicked, [this]() {
|
||||
AudioInput::getInstance()->setSilenceThreshold(audioInputSpinBox->value());
|
||||
ElaMessageBar::success(ElaMessageBarType::TopRight, "音频设置", "手动设置的阈值为:" + QString::number(audioInputSpinBox->value()), 1000, this);
|
||||
});
|
||||
|
||||
ElaScrollPageArea* audioInputProgressBarArea = new ElaScrollPageArea(this);
|
||||
QHBoxLayout* audioInputProgressBarLayout = new QHBoxLayout(audioInputProgressBarArea);
|
||||
ElaText* audioInputProgressBarText = new ElaText("静音检测阈值", this);
|
||||
audioInputProgressBarText->setToolTip("测试当前环境的静音阈值,用于对话中的静音检测");
|
||||
audioInputProgressBarText->setTextPixelSize(15);
|
||||
audioInputProgressBarLayout->addWidget(audioInputProgressBarText);
|
||||
audioInputProgressBarLayout->addWidget(audioInputProgressBar, 1);
|
||||
audioInputProgressBarLayout->addWidget(audioInputSpinBox);
|
||||
audioInputProgressBarLayout->addStretch(); // 添加弹性空间将后续控件推到右侧
|
||||
audioInputProgressBarLayout->addWidget(audioAutoThresholdStartButton);
|
||||
audioInputProgressBarLayout->addWidget(audioManualThresholdStartButton);
|
||||
audioInputProgressBarLayout->addStretch();
|
||||
audioInputProgressBarLayout->addSpacing(10);
|
||||
|
||||
testAudioPlayButton = new ElaPushButton("播放测试", this);
|
||||
testAudioPlayButton->setToolTip("播放一段测试音频来检测播放功能是否正常,注意观察模型嘴唇以及文字下落动画");
|
||||
ElaScrollPageArea* testAudioArea = new ElaScrollPageArea(this);
|
||||
QHBoxLayout* testAudioLayout = new QHBoxLayout(testAudioArea);
|
||||
ElaText* testAudioText = new ElaText("测试", this);
|
||||
testAudioText->setTextPixelSize(15);
|
||||
testAudioLayout->addWidget(testAudioText);
|
||||
testAudioLayout->addStretch(); // 添加弹性空间将后续控件推到右侧
|
||||
testAudioLayout->addWidget(testAudioPlayButton);
|
||||
testAudioLayout->addSpacing(10);
|
||||
connect(testAudioPlayButton, &ElaPushButton::clicked, [this]() {
|
||||
const QString text = "あれアイリーじゃないよ!急にいなくなるからどこに行ったのかと思えば~";
|
||||
constexpr float duration = 6.0f; // 音频时长
|
||||
TextRenderer::getInstance()->addText(text, 40.0f, QColor("#FF69B4"), duration);
|
||||
LAppLive2DManager::GetInstance()->StartLipSync("Resources/TestFiles/test.wav");
|
||||
AudioOutput::getInstance()->playUrl(QUrl("Resources/TestFiles/test.wav"));
|
||||
});
|
||||
|
||||
|
||||
QWidget* centralWidget = new QWidget(this);
|
||||
centralWidget->setWindowTitle("音频设置");
|
||||
QVBoxLayout* centerLayout = new QVBoxLayout(centralWidget);
|
||||
centerLayout->addWidget(comboBoxArea);
|
||||
centerLayout->addWidget(audioInputProgressBarArea);
|
||||
centerLayout->addWidget(testAudioArea);
|
||||
centerLayout->addStretch();
|
||||
centerLayout->setContentsMargins(0, 0, 0, 0);
|
||||
addCentralWidget(centralWidget, true, true, 0);
|
||||
|
||||
}
|
||||
|
||||
AudioPage::~AudioPage()
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// Created by Administrator on 2025/2/27.
|
||||
//
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "BasePage.h"
|
||||
#include "ElaMenu.h"
|
||||
#include "ElaText.h"
|
||||
#include "ElaTheme.h"
|
||||
#include "ElaToolButton.h"
|
||||
|
||||
BasePage::BasePage(QWidget* parent)
|
||||
: ElaScrollPage(parent)
|
||||
{
|
||||
connect(eTheme, &ElaTheme::themeModeChanged, this, [=, this]() {
|
||||
if (!parent)
|
||||
{
|
||||
update();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
BasePage::~BasePage()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BasePage::createCustomWidget(QString desText)
|
||||
{
|
||||
// 顶部元素
|
||||
QWidget* customWidget = new QWidget(this);
|
||||
ElaText* subTitleText = new ElaText(this);
|
||||
subTitleText->setText("https://github.com/Liniyous/ElaWidgetTools");
|
||||
subTitleText->setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
subTitleText->setTextPixelSize(11);
|
||||
|
||||
ElaToolButton* documentationButton = new ElaToolButton(this);
|
||||
documentationButton->setFixedHeight(35);
|
||||
documentationButton->setIsTransparent(false);
|
||||
documentationButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||
//_toolButton->setPopupMode(QToolButton::MenuButtonPopup);
|
||||
documentationButton->setText("Documentation");
|
||||
documentationButton->setElaIcon(ElaIconType::FileDoc);
|
||||
ElaMenu* documentationMenu = new ElaMenu(this);
|
||||
documentationMenu->addElaIconAction(ElaIconType::CardsBlank, "CardsBlank");
|
||||
documentationMenu->addElaIconAction(ElaIconType::EarthAmericas, "EarthAmericas");
|
||||
documentationButton->setMenu(documentationMenu);
|
||||
|
||||
ElaToolButton* sourceButton = new ElaToolButton(this);
|
||||
sourceButton->setFixedHeight(35);
|
||||
sourceButton->setIsTransparent(false);
|
||||
sourceButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||
sourceButton->setText("Source");
|
||||
sourceButton->setElaIcon(ElaIconType::NfcSymbol);
|
||||
ElaMenu* sourceMenu = new ElaMenu(this);
|
||||
sourceMenu->addElaIconAction(ElaIconType::FireBurner, "FireBurner");
|
||||
sourceMenu->addElaIconAction(ElaIconType::Galaxy, "Galaxy~~~~");
|
||||
sourceButton->setMenu(sourceMenu);
|
||||
|
||||
ElaToolButton* themeButton = new ElaToolButton(this);
|
||||
themeButton->setFixedSize(35, 35);
|
||||
themeButton->setIsTransparent(false);
|
||||
themeButton->setElaIcon(ElaIconType::MoonStars);
|
||||
connect(themeButton, &ElaToolButton::clicked, this, [=]() {
|
||||
eTheme->setThemeMode(eTheme->getThemeMode() == ElaThemeType::Light ? ElaThemeType::Dark : ElaThemeType::Light);
|
||||
});
|
||||
|
||||
QHBoxLayout* buttonLayout = new QHBoxLayout();
|
||||
buttonLayout->addWidget(documentationButton);
|
||||
buttonLayout->addSpacing(5);
|
||||
buttonLayout->addWidget(sourceButton);
|
||||
buttonLayout->addStretch();
|
||||
buttonLayout->addWidget(themeButton);
|
||||
buttonLayout->addSpacing(15);
|
||||
|
||||
ElaText* descText = new ElaText(this);
|
||||
descText->setText(desText);
|
||||
descText->setTextPixelSize(13);
|
||||
|
||||
QVBoxLayout* topLayout = new QVBoxLayout(customWidget);
|
||||
topLayout->setContentsMargins(0, 0, 0, 0);
|
||||
topLayout->addWidget(subTitleText);
|
||||
topLayout->addSpacing(5);
|
||||
topLayout->addLayout(buttonLayout);
|
||||
topLayout->addSpacing(5);
|
||||
topLayout->addWidget(descText);
|
||||
setCustomWidget(customWidget);
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
//
|
||||
// Created by Administrator on 2025/2/28.
|
||||
//
|
||||
#include "HomePage.h"
|
||||
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDesktopServices>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "ElaAcrylicUrlCard.h"
|
||||
#include "ElaFlowLayout.h"
|
||||
#include "ElaImageCard.h"
|
||||
#include "ElaMenu.h"
|
||||
#include "ElaMessageBar.h"
|
||||
#include "ElaNavigationRouter.h"
|
||||
#include "ElaPopularCard.h"
|
||||
#include "ElaScrollArea.h"
|
||||
#include "ElaText.h"
|
||||
#include "ElaToolTip.h"
|
||||
HomePage::HomePage(QWidget* parent)
|
||||
: BasePage(parent)
|
||||
{
|
||||
// 预览窗口标题
|
||||
setWindowTitle("Home");
|
||||
|
||||
setTitleVisible(false);
|
||||
setContentsMargins(2, 2, 0, 0);
|
||||
// 标题卡片区域
|
||||
ElaText* desText = new ElaText("UI By ElaWidgetTools", this);
|
||||
desText->setTextPixelSize(18);
|
||||
ElaText* titleText = new ElaText("Yosuga!", this);
|
||||
titleText->setTextPixelSize(35);
|
||||
|
||||
QVBoxLayout* titleLayout = new QVBoxLayout();
|
||||
titleLayout->setContentsMargins(30, 60, 0, 0);
|
||||
titleLayout->addWidget(desText);
|
||||
titleLayout->addWidget(titleText);
|
||||
|
||||
ElaImageCard* backgroundCard = new ElaImageCard(this);
|
||||
backgroundCard->setBorderRadius(10);
|
||||
backgroundCard->setFixedHeight(400);
|
||||
backgroundCard->setMaximumAspectRatio(1.7);
|
||||
backgroundCard->setCardImage(QImage("Resources/Pic/Airi/Airi_Background.png"));
|
||||
|
||||
ElaAcrylicUrlCard* urlCard1 = new ElaAcrylicUrlCard(this);
|
||||
urlCard1->setCardPixmapSize(QSize(62, 62));
|
||||
urlCard1->setFixedSize(195, 225);
|
||||
urlCard1->setTitlePixelSize(17);
|
||||
urlCard1->setTitleSpacing(25);
|
||||
urlCard1->setSubTitleSpacing(13);
|
||||
urlCard1->setUrl("https://github.com/Misakityan/Yosuga");
|
||||
urlCard1->setCardPixmap(QPixmap("Resources/Pic/Others/img.png"));
|
||||
urlCard1->setTitle("Yosuga Github");
|
||||
urlCard1->setSubTitle("Star++!");
|
||||
ElaToolTip* urlCard1ToolTip = new ElaToolTip(urlCard1);
|
||||
urlCard1ToolTip->setToolTip("点击前往本项目GitHub");
|
||||
|
||||
ElaAcrylicUrlCard* urlCard2 = new ElaAcrylicUrlCard(this);
|
||||
urlCard2->setCardPixmapSize(QSize(62, 62));
|
||||
urlCard2->setFixedSize(195, 225);
|
||||
urlCard2->setTitlePixelSize(17);
|
||||
urlCard2->setTitleSpacing(25);
|
||||
urlCard2->setSubTitleSpacing(13);
|
||||
urlCard2->setUrl("https://space.bilibili.com/140315806");
|
||||
urlCard2->setCardPixmap(QPixmap("Resources/Pic/Others/Misaki.jpg"));
|
||||
urlCard2->setTitle("Misaki");
|
||||
urlCard2->setSubTitle("1841738040@qq.com");
|
||||
ElaToolTip* urlCard2ToolTip = new ElaToolTip(urlCard2);
|
||||
urlCard2ToolTip->setToolTip("点击前往 Misaki 的个人主页");
|
||||
|
||||
ElaScrollArea* cardScrollArea = new ElaScrollArea(this);
|
||||
cardScrollArea->setWidgetResizable(true);
|
||||
cardScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
cardScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
cardScrollArea->setIsGrabGesture(true, 0);
|
||||
cardScrollArea->setIsOverShoot(Qt::Horizontal, true);
|
||||
QWidget* cardScrollAreaWidget = new QWidget(this);
|
||||
cardScrollAreaWidget->setStyleSheet("background-color:transparent;");
|
||||
cardScrollArea->setWidget(cardScrollAreaWidget);
|
||||
QHBoxLayout* urlCardLayout = new QHBoxLayout();
|
||||
urlCardLayout->setSpacing(15);
|
||||
urlCardLayout->setContentsMargins(30, 0, 0, 6);
|
||||
urlCardLayout->addWidget(urlCard1);
|
||||
urlCardLayout->addWidget(urlCard2);
|
||||
urlCardLayout->addStretch();
|
||||
QVBoxLayout* cardScrollAreaWidgetLayout = new QVBoxLayout(cardScrollAreaWidget);
|
||||
cardScrollAreaWidgetLayout->setContentsMargins(0, 0, 0, 0);
|
||||
cardScrollAreaWidgetLayout->addStretch();
|
||||
cardScrollAreaWidgetLayout->addLayout(urlCardLayout);
|
||||
|
||||
QVBoxLayout* backgroundLayout = new QVBoxLayout(backgroundCard);
|
||||
backgroundLayout->setContentsMargins(0, 0, 0, 0);
|
||||
backgroundLayout->addLayout(titleLayout);
|
||||
backgroundLayout->addWidget(cardScrollArea);
|
||||
|
||||
// 推荐卡片
|
||||
ElaText* flowText = new ElaText("快速转到", this);
|
||||
flowText->setTextPixelSize(20);
|
||||
QHBoxLayout* flowTextLayout = new QHBoxLayout();
|
||||
flowTextLayout->setContentsMargins(33, 0, 0, 0);
|
||||
flowTextLayout->addWidget(flowText);
|
||||
// ElaFlowLayout
|
||||
// 模型商店卡片
|
||||
ElaPopularCard* ModeShopCard = new ElaPopularCard(this);
|
||||
connect(ModeShopCard, &ElaPopularCard::popularCardButtonClicked, this, [=, this]() {
|
||||
Q_EMIT modelShopNavigation();
|
||||
});
|
||||
ModeShopCard->setCardPixmap(QPixmap("Resources/Pic/Others/Live2D.png"));
|
||||
ModeShopCard->setTitle("模型设置");
|
||||
ModeShopCard->setSubTitle("属于你的Live2D模型");
|
||||
ModeShopCard->setInteractiveTips("By Misaki");
|
||||
ModeShopCard->setDetailedText("选择你喜欢的Live2D模型");
|
||||
// 音频设置卡片
|
||||
ElaPopularCard* AudioSettingCard = new ElaPopularCard(this);
|
||||
connect(AudioSettingCard, &ElaPopularCard::popularCardButtonClicked, this, [=, this]() {
|
||||
Q_EMIT audioNavigation();
|
||||
});
|
||||
AudioSettingCard->setTitle("音频设置");
|
||||
AudioSettingCard->setSubTitle("录音与播放的设置");
|
||||
AudioSettingCard->setCardPixmap(QPixmap("Resources/Pic/control/AutomationProperties.png"));
|
||||
AudioSettingCard->setInteractiveTips("By Misaki");
|
||||
AudioSettingCard->setDetailedText("自定义音频与播放的相关设定,打造最舒适的交流环境。");
|
||||
|
||||
ElaFlowLayout* flowLayout = new ElaFlowLayout(0, 5, 5);
|
||||
flowLayout->setContentsMargins(30, 0, 0, 0);
|
||||
flowLayout->setIsAnimation(true);
|
||||
flowLayout->addWidget(ModeShopCard);
|
||||
flowLayout->addWidget(AudioSettingCard);
|
||||
|
||||
|
||||
QWidget* centralWidget = new QWidget(this);
|
||||
centralWidget->setWindowTitle("Home");
|
||||
QVBoxLayout* centerVLayout = new QVBoxLayout(centralWidget);
|
||||
centerVLayout->setSpacing(0);
|
||||
centerVLayout->setContentsMargins(0, 0, 0, 0);
|
||||
centerVLayout->addWidget(backgroundCard);
|
||||
centerVLayout->addSpacing(20);
|
||||
centerVLayout->addLayout(flowTextLayout);
|
||||
centerVLayout->addSpacing(10);
|
||||
centerVLayout->addLayout(flowLayout);
|
||||
centerVLayout->addStretch();
|
||||
addCentralWidget(centralWidget);
|
||||
}
|
||||
|
||||
HomePage::~HomePage()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
//
|
||||
// Created by Administrator on 2025/4/1.
|
||||
//
|
||||
#include "ModelPage.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QHBoxLayout>
|
||||
#include "ElaMessageBar.h"
|
||||
#include "ElaScrollPageArea.h"
|
||||
#include "ElaText.h"
|
||||
#include <QtConcurrent>
|
||||
#include <QOpenGLContext>
|
||||
#include <QOffscreenSurface>
|
||||
#include <QFutureWatcher>
|
||||
#include "LAppLive2DManager.hpp"
|
||||
|
||||
ModelPage::ModelPage(QWidget *parent)
|
||||
: BasePage(parent) {
|
||||
// 预览窗口标题
|
||||
setWindowTitle("ModelPage");
|
||||
|
||||
|
||||
modelUrlEdit = new ElaLineEdit(this); // 模型Url Edit
|
||||
modelUrlEdit->setFixedWidth(300);
|
||||
modelUrlEdit->setPlaceholderText("用于显示当前的模型Url");
|
||||
|
||||
modelChoosePushButton = new ElaPushButton("选择模型", this);
|
||||
modelChoosePushButton->setToolTip("选择.model3.json结尾的文件");
|
||||
|
||||
modelUsePushButton = new ElaPushButton("使用模型", this);
|
||||
modelUsePushButton->setToolTip("使用选择的模型或Url对应的模型");
|
||||
|
||||
ElaScrollPageArea *modelSetArea = new ElaScrollPageArea(this);
|
||||
QHBoxLayout *modelSetLayout = new QHBoxLayout(modelSetArea);
|
||||
ElaText *modelSetText = new ElaText("模型设置", this);
|
||||
modelSetText->setTextPixelSize(15);
|
||||
modelSetLayout->addWidget(modelSetText);
|
||||
modelSetLayout->addWidget(modelUrlEdit);
|
||||
modelSetLayout->addStretch();
|
||||
modelSetLayout->addWidget(modelChoosePushButton);
|
||||
modelSetLayout->addWidget(modelUsePushButton);
|
||||
modelSetLayout->addSpacing(10);
|
||||
|
||||
// 创建滑块控件和标签
|
||||
ElaText *modelSizeText = new ElaText("模型大小比例设置", this);
|
||||
modelSizeText->setToolTip("实时调整模型大小");
|
||||
modelSizeText->setTextPixelSize(15);
|
||||
modelSlider = new ElaSlider(this); // 滑块(用于设置模型实时大小)
|
||||
modelSlider->setRange(0, 99); // 设置范围
|
||||
modelSlider->setValue(85); // 设置默认值
|
||||
modelSlider->setOrientation(Qt::Horizontal); // 水平方向
|
||||
// 创建独立的区域容器
|
||||
ElaScrollPageArea *modelSliderArea = new ElaScrollPageArea(this);
|
||||
QHBoxLayout *modelSliderLayout = new QHBoxLayout(modelSliderArea);
|
||||
|
||||
// 添加到布局(加一个标签显示数值)
|
||||
ElaText *modelSliderValueText = new ElaText("85%", this);
|
||||
modelSliderValueText->setTextPixelSize(14);
|
||||
connect(modelSlider, &ElaSlider::valueChanged, this, [modelSliderValueText](const int value){
|
||||
modelSliderValueText->setText(QString("%1%").arg(value + 1));
|
||||
LAppLive2DManager::GetInstance()->ModelSizeChange(100 - value); // 实时更新模型大小
|
||||
});
|
||||
modelSliderLayout->addWidget(modelSizeText);
|
||||
modelSliderLayout->addWidget(modelSlider);
|
||||
modelSliderLayout->addWidget(modelSliderValueText);
|
||||
modelSliderLayout->addStretch(); // 让内容靠左
|
||||
|
||||
connect(modelChoosePushButton, &ElaPushButton::clicked, this, [this]() {
|
||||
// 创建对话框对象(使用 heap 分配,由 Qt 对象树管理内存)
|
||||
auto *fileDialog = new QFileDialog(this);
|
||||
fileDialog->setWindowTitle("选择模型文件");
|
||||
fileDialog->setNameFilter("Live2D Model (*.model3.json)");
|
||||
|
||||
// 设置初始目录
|
||||
const QString exeDir = QCoreApplication::applicationDirPath(); // 获取当前exe所在目录的本地路径
|
||||
fileDialog->setDirectory(exeDir); // 设置初始目录为当前 exe 所在目录
|
||||
|
||||
// 连接信号:当用户选中文件并点击打开时
|
||||
connect(fileDialog, &QFileDialog::fileSelected, this, [this, fileDialog](const QString &file) {
|
||||
modelFileUrl = QUrl::fromLocalFile(file);
|
||||
if (!modelFileUrl.isEmpty()) {
|
||||
const QString t = modelFileUrl.toLocalFile();
|
||||
const std::pair<QString, QString> path = this->splitPath(t);
|
||||
this->modelFilePathFirst = path.first;
|
||||
this->modelFilePathSecond = path.second;
|
||||
this->modelUrlEdit->setText(t);
|
||||
ElaMessageBar::success(ElaMessageBarType::BottomRight, "模型设置", "模型选择成功", 2000, this);
|
||||
}
|
||||
// 用完即弃,自动清理内存
|
||||
fileDialog->deleteLater();
|
||||
});
|
||||
// 处理取消的情况(防止内存泄漏)
|
||||
connect(fileDialog, &QFileDialog::rejected, fileDialog, &QObject::deleteLater);
|
||||
// 显示对话框(非阻塞,不会卡住主界面)
|
||||
fileDialog->open();
|
||||
});
|
||||
connect(modelUsePushButton, &ElaPushButton::clicked, this, [this]() {
|
||||
// 模型使用
|
||||
if (modelFileUrl.isEmpty()) {
|
||||
ElaMessageBar::information(ElaMessageBarType::BottomRight, "模型设置", "似乎并没有选择模型", 800.0, this);
|
||||
return;
|
||||
}
|
||||
// UI 状态设置为加载中
|
||||
modelUsePushButton->setEnabled(false); // 禁用使用按钮
|
||||
modelUsePushButton->setText("加载中"); // 修改按钮文本
|
||||
modelChoosePushButton->setEnabled(false); // 禁用选择按钮
|
||||
|
||||
// 获取路径字符串 (必须按值传递给lambda)
|
||||
std::string dir = this->modelFilePathFirst.toStdString();
|
||||
std::string filename = this->modelFilePathSecond.toStdString();
|
||||
|
||||
// 启动异步任务
|
||||
QFuture<LAppModel *> future = QtConcurrent::run([dir, filename]() -> LAppModel * {
|
||||
// 以下代码在子线程执行
|
||||
// 创建临时 OpenGL 上下文
|
||||
auto *context = new QOpenGLContext();
|
||||
// 关键点:设置与全局共享上下文共享 (这样主线程才能看到纹理)
|
||||
context->setShareContext(QOpenGLContext::globalShareContext());
|
||||
if (!context->create()) {
|
||||
delete context;
|
||||
return nullptr;
|
||||
}
|
||||
// 创建离屏表面 (因为子线程没有窗口,需要一个假的绘制表面)
|
||||
auto *surface = new QOffscreenSurface();
|
||||
surface->setFormat(context->format());
|
||||
surface->create();
|
||||
// 绑定上下文
|
||||
if (!context->makeCurrent(surface)) {
|
||||
delete surface;
|
||||
delete context;
|
||||
return nullptr;
|
||||
}
|
||||
// 执行真正的耗时加载
|
||||
// 调用在 Manager 里新写的函数
|
||||
LAppModel *model = LAppLive2DManager::GetInstance()->LoadModelInstance(dir, filename);
|
||||
// 清理子线程资源
|
||||
context->doneCurrent();
|
||||
delete surface;
|
||||
delete context;
|
||||
|
||||
return model;
|
||||
});
|
||||
|
||||
// 监控任务结束
|
||||
auto *watcher = new QFutureWatcher<LAppModel *>();
|
||||
connect(watcher, &QFutureWatcher<LAppModel *>::finished, this, [this, watcher]() {
|
||||
// 下面的代码在主线程中执行
|
||||
LAppModel *newModel = watcher->result();
|
||||
if (newModel) {
|
||||
// 调用挂载函数,瞬间完成切换
|
||||
LAppLive2DManager::GetInstance()->MountLoadedModel(newModel);
|
||||
ElaMessageBar::success(ElaMessageBarType::BottomRight, "成功", "模型加载完成", 2000, this);
|
||||
} else {
|
||||
ElaMessageBar::error(ElaMessageBarType::BottomRight, "错误", "模型加载失败 (OpenGL环境异常)", 2000, this);
|
||||
}
|
||||
// 恢复 UI
|
||||
modelUsePushButton->setEnabled(true);
|
||||
modelUsePushButton->setText("使用模型");
|
||||
modelChoosePushButton->setEnabled(true);
|
||||
watcher->deleteLater();
|
||||
});
|
||||
// 开始监控
|
||||
watcher->setFuture(future);
|
||||
});
|
||||
|
||||
|
||||
QWidget *centralWidget = new QWidget(this);
|
||||
centralWidget->setWindowTitle("模型设置");
|
||||
QVBoxLayout *centerLayout = new QVBoxLayout(centralWidget);
|
||||
centerLayout->addWidget(modelSetArea);
|
||||
centerLayout->addWidget(modelSliderArea);
|
||||
centerLayout->addStretch();
|
||||
centerLayout->setContentsMargins(0, 0, 0, 0);
|
||||
addCentralWidget(centralWidget, true, true, 0);
|
||||
}
|
||||
|
||||
// 返回 pair<目录路径, 文件名>
|
||||
std::pair<QString, QString> ModelPage::splitPath(const QString &fullPath) {
|
||||
const QFileInfo fileInfo(fullPath);
|
||||
|
||||
// 获取目录部分(自动处理末尾斜杠)
|
||||
QString dirPath = fileInfo.dir().absolutePath() + "/";
|
||||
|
||||
// 获取文件名部分(如果是目录则返回空)
|
||||
QString fileName = fileInfo.fileName();
|
||||
|
||||
return {dirPath, fileName};
|
||||
}
|
||||
|
||||
ModelPage::~ModelPage() {
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
//
|
||||
// Created by Administrator on 2025/3/2.
|
||||
//
|
||||
|
||||
#include "NetworkPage.h"
|
||||
#include <QHBoxLayout>
|
||||
#include "ElaScrollPageArea.h"
|
||||
#include "ElaText.h"
|
||||
#include "ElaMessageBar.h"
|
||||
#include "websocketmanager.h"
|
||||
#include "NetWorkDO.h"
|
||||
#include <QFile>
|
||||
|
||||
NetWorkPage::NetWorkPage(QWidget* parent)
|
||||
: BasePage(parent)
|
||||
{
|
||||
// 预览窗口标题
|
||||
setWindowTitle("NetworkPage");
|
||||
|
||||
this->initUI(); // 初始化UI
|
||||
this->initWebSocketClient(); // 初始化websocket客户端(主要是相关的信号与槽)
|
||||
}
|
||||
|
||||
NetWorkPage::~NetWorkPage()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void NetWorkPage::initUI() {
|
||||
// websocket UI
|
||||
websocketPushButton = new ElaPushButton("设定",this);
|
||||
websocketPushButton->setToolTip("设定服务端WebSocket地址");
|
||||
websocketLineEdit = new ElaLineEdit(this);
|
||||
websocketLineEdit->setPlaceholderText("请输入服务端WebSocket地址");
|
||||
websocketLineEdit->setFixedWidth(300); // 设置websocketLineEdit框的宽度
|
||||
|
||||
ElaScrollPageArea* websocketToggleSwitchArea = new ElaScrollPageArea(this);
|
||||
QHBoxLayout* websocketToggleSwitchLayout = new QHBoxLayout(websocketToggleSwitchArea);
|
||||
ElaText* websocketToggleSwitchText = new ElaText("服务端WebSocket地址:", this);
|
||||
websocketToggleSwitchText->setTextPixelSize(15);
|
||||
websocketToggleSwitchLayout->addWidget(websocketToggleSwitchText);
|
||||
websocketToggleSwitchLayout->addWidget(websocketLineEdit);
|
||||
websocketToggleSwitchLayout->addStretch();
|
||||
websocketToggleSwitchLayout->addWidget(websocketPushButton);
|
||||
websocketToggleSwitchLayout->addSpacing(10);
|
||||
// 连通测试按钮
|
||||
connectTestPushButton = new ElaPushButton("连通测试",this);
|
||||
connectTestPushButton->setToolTip("测试与服务器连通性(如果成功连通会自动连上服务器)");
|
||||
connectPushButton = new ElaPushButton("连接",this);
|
||||
disconnectPushButton = new ElaPushButton("断开",this);
|
||||
sendTestPushButton = new ElaPushButton("发送测试",this);
|
||||
ElaScrollPageArea* connectTestArea = new ElaScrollPageArea(this); // 创建一个滚动页面
|
||||
QHBoxLayout* connectTestLayout = new QHBoxLayout(connectTestArea);
|
||||
connectTestLayout->addWidget(connectTestPushButton); // 将连通测试按钮添加到布局中
|
||||
connectTestLayout->addStretch(); // 添加一个空格
|
||||
connectTestLayout->addWidget(sendTestPushButton); // 将发送测试按钮添加到布局中
|
||||
connectTestLayout->addWidget(disconnectPushButton); // 将断开按钮添加到布局中
|
||||
connectTestLayout->addWidget(connectPushButton); // 将连接按钮添加到布局中
|
||||
connectTestLayout->addSpacing(10);
|
||||
// 添加到布局
|
||||
QWidget* centralWidget = new QWidget(this); // 中心部件
|
||||
centralWidget->setWindowTitle("连接设置"); // 中心部件标题
|
||||
QVBoxLayout* centerLayout = new QVBoxLayout(centralWidget); // 中心部件布局
|
||||
centerLayout->addWidget(websocketToggleSwitchArea); // 将websocketToggleSwitchArea添加到布局中
|
||||
centerLayout->addWidget(connectTestArea); // 将connectTestArea添加到布局中
|
||||
|
||||
centerLayout->addStretch();
|
||||
centerLayout->setContentsMargins(0, 0, 0, 0); // 设置布局的边距
|
||||
addCentralWidget(centralWidget, true, true, 0); // 添加中心部件
|
||||
}
|
||||
|
||||
void NetWorkPage::initWebSocketClient() {
|
||||
auto* client = WebSocketClient::getInstance(); // 获取单例实例(设置一个默认地址)
|
||||
auto* netDO = NetworkDO::getInstance();
|
||||
// 注入:将底层发送能力赋予 NetworkDO
|
||||
netDO->registerSender([client](const QString& type, const QJsonObject& data){
|
||||
client->sendJson(type, data);
|
||||
});
|
||||
// 监听:底层收到数据 -> NetworkDO 解析
|
||||
connect(client, &WebSocketClient::jsonReceived,
|
||||
netDO, &NetworkDO::onDataReceived);
|
||||
// 连接成功的处理
|
||||
connect(client, &WebSocketClient::connected, this, [this]() {
|
||||
ElaMessageBar::success(ElaMessageBarType::TopRight, "WebSocket", "连接成功", 800.0, this);
|
||||
});
|
||||
// 连接失败的处理
|
||||
connect(client, &WebSocketClient::error, this, [this](const QString& errorMsg) {
|
||||
ElaMessageBar::error(ElaMessageBarType::TopLeft, "WebSocket错误", errorMsg, 1500.0, this);
|
||||
});
|
||||
// 断开连接的处理
|
||||
connect(client, &WebSocketClient::disconnected, this, [this]() {
|
||||
ElaMessageBar::information(ElaMessageBarType::BottomRight, "WebSocket", "连接已断开", 800.0, this);
|
||||
});
|
||||
// 接收数据处理
|
||||
connect(client, &WebSocketClient::jsonReceived, this, [](const QString &type, const QJsonObject &data) {
|
||||
qDebug() << "Received JSON data: " << type << " " << data;
|
||||
});
|
||||
|
||||
connect(websocketPushButton, &ElaPushButton::clicked, this, [this, client]() { // 设置服务端websocket地址
|
||||
const QUrl url(websocketLineEdit->text().trimmed()); // 从LineEdit中获取服务端websocket地址
|
||||
// 初始化客户端
|
||||
if (client->setConfiguration(url)) {
|
||||
ElaMessageBar::success(ElaMessageBarType::TopRight, "连接设置",
|
||||
QString("服务器地址已设置为: %1").arg(url.toString()), 800.0, this);
|
||||
return;
|
||||
}
|
||||
ElaMessageBar::warning(ElaMessageBarType::TopLeft, "连接设置",
|
||||
QString("服务器地址存在问题"), 800.0, this);
|
||||
});
|
||||
|
||||
connect(connectTestPushButton, &ElaPushButton::clicked, this, [this, client]() {
|
||||
if (client->isConnected()) {
|
||||
ElaMessageBar::success(ElaMessageBarType::TopRight, "连通测试",
|
||||
"当前已连通", 800.0, this);
|
||||
return;
|
||||
}
|
||||
client->connectToServer(); // 连接
|
||||
// 使用定时器延迟检查连接状态
|
||||
QTimer::singleShot(1000, this, [this, client]() {
|
||||
if (!client->isConnected()) {
|
||||
ElaMessageBar::warning(ElaMessageBarType::TopLeft, "连通测试",
|
||||
"无法连接到服务器,请检查地址和服务器状态", 1500.0, this);
|
||||
return;
|
||||
}
|
||||
ElaMessageBar::success(ElaMessageBarType::TopRight, "连通测试",
|
||||
"连通测试成功", 800.0, this);
|
||||
});
|
||||
});
|
||||
connect(connectPushButton, &ElaPushButton::clicked, this, [this, client]() {
|
||||
if (client->isConnected()) {
|
||||
ElaMessageBar::information(ElaMessageBarType::TopRight, "连接状态",
|
||||
"已连接,无需重复连接", 800.0, this);
|
||||
return;
|
||||
}
|
||||
const QString urlStr = websocketLineEdit->text().trimmed();
|
||||
if (urlStr.isEmpty()) {
|
||||
ElaMessageBar::warning(ElaMessageBarType::TopLeft, "连接",
|
||||
"请先设置服务器地址", 800.0, this);
|
||||
return;
|
||||
}
|
||||
// 确保使用正确的地址
|
||||
client->setConfiguration(QUrl(urlStr));
|
||||
client->connectToServer();
|
||||
// 连接结果会在 connected/error 信号中处理
|
||||
ElaMessageBar::information(ElaMessageBarType::TopRight, "连接",
|
||||
"正在连接服务器...", 800.0, this);
|
||||
});
|
||||
connect(disconnectPushButton, &ElaPushButton::clicked, this, [this, client]() {
|
||||
if (!client->isConnected()) {
|
||||
ElaMessageBar::information(ElaMessageBarType::BottomRight, "断开连接",
|
||||
"当前未连接", 800.0, this);
|
||||
return;
|
||||
}
|
||||
client->disconnectFromServer();
|
||||
ElaMessageBar::success(ElaMessageBarType::TopRight, "断开连接",
|
||||
"已断开连接", 800.0, this);
|
||||
});
|
||||
connect(sendTestPushButton, &ElaPushButton::clicked, this, [this, netDO, client]() {
|
||||
if (!client->isConnected()) {
|
||||
ElaMessageBar::information(ElaMessageBarType::BottomRight, "断开连接",
|
||||
"当前未连接", 800.0, this);
|
||||
return;
|
||||
}
|
||||
// 创建数据包
|
||||
QFile test_wav_file("Resources/TestFiles/test.wav");
|
||||
if (!test_wav_file.open(QIODevice::ReadOnly)) {
|
||||
qDebug() << "Failed to open test.wav";
|
||||
ElaMessageBar::warning(ElaMessageBarType::TopLeft, "发送测试",
|
||||
"无法打开测试音频文件", 1500.0, this);
|
||||
return;
|
||||
}
|
||||
QByteArray wavData = test_wav_file.readAll();
|
||||
QString base64Str = QString::fromLatin1(wavData.toBase64());
|
||||
AudioDataTransferObject packet;
|
||||
packet.setData("Owner", "client")
|
||||
.setData("isStream", true)
|
||||
.setData("sequence", 42)
|
||||
.setData("text", "Hello World")
|
||||
.setData("data", base64Str); // 填入测试音频数据
|
||||
netDO->sendPacket(packet);
|
||||
ElaMessageBar::success(ElaMessageBarType::TopRight, "发送测试",
|
||||
"已成功发送数据包", 1000.0, this);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// Created by Administrator on 2025/3/30.
|
||||
//
|
||||
|
||||
#include "RenderPage.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QtWidgets>
|
||||
#include "ElaComboBox.h"
|
||||
#include "ElaMessageBar.h"
|
||||
#include "ElaScrollPageArea.h"
|
||||
#include "ElaText.h"
|
||||
|
||||
#include "GLCore.h"
|
||||
#include "AppContext.h"
|
||||
RenderPage::RenderPage(QWidget* parent)
|
||||
: BasePage(parent)
|
||||
{
|
||||
// 预览窗口标题
|
||||
setWindowTitle("RenderPage");
|
||||
|
||||
frameRateComboBox = new ElaComboBox(this);
|
||||
QStringList frameRateComboList = GLCore::getFrameRateList();
|
||||
frameRateComboBox->addItems(frameRateComboList);
|
||||
ElaScrollPageArea* frameRateComboBoxArea = new ElaScrollPageArea(this);
|
||||
QHBoxLayout* frameRateComboBoxLayout = new QHBoxLayout(frameRateComboBoxArea);
|
||||
ElaText* frameRateComboBoxText = new ElaText("帧率设置", this);
|
||||
frameRateComboBoxText->setTextPixelSize(15);
|
||||
frameRateComboBoxLayout->addWidget(frameRateComboBoxText);
|
||||
frameRateComboBoxLayout->addStretch();
|
||||
frameRateComboBoxLayout->addWidget(frameRateComboBox);
|
||||
frameRateComboBoxLayout->addSpacing(10);
|
||||
connect(frameRateComboBox, &ElaComboBox::currentTextChanged, this, [this](const QString& text) {
|
||||
AppContext::GetGLCore()->setFrameRate(GLCore::getFrameRateMap().value(text));
|
||||
});
|
||||
|
||||
|
||||
QWidget* centralWidget = new QWidget(this);
|
||||
centralWidget->setWindowTitle("渲染设置");
|
||||
QVBoxLayout* centerLayout = new QVBoxLayout(centralWidget);
|
||||
centerLayout->addWidget(frameRateComboBoxArea);
|
||||
centerLayout->addStretch();
|
||||
centerLayout->setContentsMargins(0, 0, 0, 0);
|
||||
addCentralWidget(centralWidget, true, true, 0);
|
||||
|
||||
}
|
||||
|
||||
RenderPage::~RenderPage()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
//
|
||||
// Created by Administrator on 2025/1/21.
|
||||
//
|
||||
|
||||
|
||||
#include <ElaTheme.h>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QSvgRenderer>
|
||||
#include <QPainter>
|
||||
|
||||
|
||||
#include "Setting.h"
|
||||
|
||||
#include "socketmanager.h"
|
||||
Setting::Setting(QWidget *parent)
|
||||
: ElaWindow(parent)
|
||||
{
|
||||
// 设置窗口标题
|
||||
setWindowTitle("设置");
|
||||
// 设置窗口图标
|
||||
setWindowIcon(QIcon("Resources/Pic/Airi/Airi_s.svg"));
|
||||
// 初始化窗口
|
||||
resize(1000, 740);
|
||||
// 禁用窗口缩放按钮
|
||||
setWindowButtonFlag(ElaAppBarType::MaximizeButtonHint, false); // 隐藏最大化按钮
|
||||
setWindowButtonFlag(ElaAppBarType::MinimizeButtonHint, false); // 隐藏最小化按钮
|
||||
// 移动窗口到屏幕中心
|
||||
this->moveToCenter();
|
||||
|
||||
this->setWindowFlag(Qt::Tool); // 隐藏应用程序图标
|
||||
this->setWindowFlag(Qt::WindowStaysOnTopHint); // 默认设置窗口始终在顶部
|
||||
// 设置用户信息卡
|
||||
this->setUserInfoCardTitle("Yosuga");
|
||||
this->setUserInfoCardSubTitle("联系维度的桥梁!");
|
||||
// 加载 SVG 图片
|
||||
QSvgRenderer renderer(QString("Resources/Pic/Airi/Airi.svg"));
|
||||
// 创建 QPixmap 并绘制 SVG
|
||||
QPixmap pixmap(64, 64);
|
||||
pixmap.fill(Qt::transparent); // 设置透明背景
|
||||
QPainter painter(&pixmap);
|
||||
renderer.render(&painter);
|
||||
this->setUserInfoCardPixmap(pixmap);
|
||||
|
||||
// 初始化页面
|
||||
initPages();
|
||||
|
||||
// 创建导航栏和内容区域
|
||||
initNavigationBar();
|
||||
|
||||
// 创建上下文
|
||||
initContent();
|
||||
|
||||
// 设置初始主题
|
||||
eTheme->setThemeMode(ElaThemeType::Dark);
|
||||
}
|
||||
|
||||
Setting::~Setting()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Setting::initPages()
|
||||
{
|
||||
homePage = new HomePage(this);
|
||||
networkPage = new NetWorkPage(this);
|
||||
uiSetting = new UISetting(this);
|
||||
audioPage = new AudioPage(this);
|
||||
renderPage = new RenderPage(this);
|
||||
modelPage = new ModelPage(this);
|
||||
}
|
||||
|
||||
void Setting::initNavigationBar()
|
||||
{
|
||||
// 添加主页节点(顶级节点)
|
||||
addPageNode("主页", homePage, ElaIconType::House);
|
||||
|
||||
// 添加模型商店节点
|
||||
addPageNode("模型设置", modelPage, ElaIconType::Shop);
|
||||
|
||||
// 添加网络连接设置节点
|
||||
addPageNode("连接设置", networkPage, ElaIconType::NetworkWired);
|
||||
// 添加音频设置节点
|
||||
addPageNode("音频设置", audioPage, ElaIconType::MusicNote);
|
||||
// 添加渲染设置节点
|
||||
addPageNode("渲染设置", renderPage, ElaIconType::ArrowsRotate);
|
||||
|
||||
QString uiSettingKey;
|
||||
addFooterNode("UI设置", uiSetting, uiSettingKey, 0, ElaIconType::GearComplex);
|
||||
}
|
||||
|
||||
void Setting::initContent()
|
||||
{
|
||||
connect(homePage, &HomePage::modelShopNavigation, this, [&](){
|
||||
this->navigation(modelPage->property("ElaPageKey").toString());
|
||||
});
|
||||
connect(homePage, &HomePage::audioNavigation, this, [&](){
|
||||
this->navigation(audioPage->property("ElaPageKey").toString());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Setting::toggleTheme()
|
||||
{
|
||||
if (eTheme->getThemeMode() == ElaThemeType::Light) {
|
||||
eTheme->setThemeMode(ElaThemeType::Dark);
|
||||
} else {
|
||||
eTheme->setThemeMode(ElaThemeType::Light);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
//
|
||||
// Created by Administrator on 2025/3/2.
|
||||
//
|
||||
#include "UISetting.h"
|
||||
|
||||
|
||||
#include <QDebug>
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "ElaApplication.h"
|
||||
#include "ElaComboBox.h"
|
||||
#include "ElaLog.h"
|
||||
#include "ElaRadioButton.h"
|
||||
#include "ElaScrollPageArea.h"
|
||||
#include "ElaText.h"
|
||||
#include "ElaTheme.h"
|
||||
#include "ElaToggleSwitch.h"
|
||||
#include "ElaWindow.h"
|
||||
UISetting::UISetting(QWidget* parent)
|
||||
: BasePage(parent)
|
||||
{
|
||||
// 预览窗口标题
|
||||
ElaWindow* window = dynamic_cast<ElaWindow*>(parent);
|
||||
setWindowTitle("Setting");
|
||||
|
||||
ElaText* themeText = new ElaText("主题设置", this);
|
||||
themeText->setWordWrap(false);
|
||||
themeText->setTextPixelSize(18);
|
||||
|
||||
_themeComboBox = new ElaComboBox(this);
|
||||
_themeComboBox->addItem("日间模式");
|
||||
_themeComboBox->addItem("夜间模式");
|
||||
ElaScrollPageArea* themeSwitchArea = new ElaScrollPageArea(this);
|
||||
QHBoxLayout* themeSwitchLayout = new QHBoxLayout(themeSwitchArea);
|
||||
ElaText* themeSwitchText = new ElaText("主题切换", this);
|
||||
themeSwitchText->setWordWrap(false);
|
||||
themeSwitchText->setTextPixelSize(15);
|
||||
themeSwitchLayout->addWidget(themeSwitchText);
|
||||
themeSwitchLayout->addStretch();
|
||||
themeSwitchLayout->addWidget(_themeComboBox);
|
||||
connect(_themeComboBox, QOverload<int>::of(&ElaComboBox::currentIndexChanged), this, [=](int index) {
|
||||
if (index == 0)
|
||||
{
|
||||
eTheme->setThemeMode(ElaThemeType::Light);
|
||||
}
|
||||
else
|
||||
{
|
||||
eTheme->setThemeMode(ElaThemeType::Dark);
|
||||
}
|
||||
});
|
||||
connect(eTheme, &ElaTheme::themeModeChanged, this, [=, this](ElaThemeType::ThemeMode themeMode) {
|
||||
_themeComboBox->blockSignals(true);
|
||||
if (themeMode == ElaThemeType::Light)
|
||||
{
|
||||
_themeComboBox->setCurrentIndex(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
_themeComboBox->setCurrentIndex(1);
|
||||
}
|
||||
_themeComboBox->blockSignals(false);
|
||||
});
|
||||
|
||||
ElaText* helperText = new ElaText("应用程序设置", this);
|
||||
helperText->setWordWrap(false);
|
||||
helperText->setTextPixelSize(18);
|
||||
|
||||
_micaSwitchButton = new ElaToggleSwitch(this);
|
||||
ElaScrollPageArea* micaSwitchArea = new ElaScrollPageArea(this);
|
||||
QHBoxLayout* micaSwitchLayout = new QHBoxLayout(micaSwitchArea);
|
||||
ElaText* micaSwitchText = new ElaText("启用云母效果", this);
|
||||
micaSwitchText->setWordWrap(false);
|
||||
micaSwitchText->setTextPixelSize(15);
|
||||
micaSwitchLayout->addWidget(micaSwitchText);
|
||||
micaSwitchLayout->addStretch();
|
||||
micaSwitchLayout->addWidget(_micaSwitchButton);
|
||||
connect(_micaSwitchButton, &ElaToggleSwitch::toggled, this, [=](bool checked) {
|
||||
eApp->setIsEnableMica(checked);
|
||||
});
|
||||
|
||||
_logSwitchButton = new ElaToggleSwitch(this);
|
||||
ElaScrollPageArea* logSwitchArea = new ElaScrollPageArea(this);
|
||||
QHBoxLayout* logSwitchLayout = new QHBoxLayout(logSwitchArea);
|
||||
ElaText* logSwitchText = new ElaText("启用日志功能", this);
|
||||
logSwitchText->setWordWrap(false);
|
||||
logSwitchText->setTextPixelSize(15);
|
||||
logSwitchLayout->addWidget(logSwitchText);
|
||||
logSwitchLayout->addStretch();
|
||||
logSwitchLayout->addWidget(_logSwitchButton);
|
||||
connect(_logSwitchButton, &ElaToggleSwitch::toggled, this, [=](bool checked) {
|
||||
ElaLog::getInstance()->initMessageLog(checked);
|
||||
if (checked)
|
||||
{
|
||||
qDebug() << "日志已启用!";
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "日志已关闭!";
|
||||
}
|
||||
});
|
||||
|
||||
_minimumButton = new ElaRadioButton("Minimum", this);
|
||||
_compactButton = new ElaRadioButton("Compact", this);
|
||||
_maximumButton = new ElaRadioButton("Maximum", this);
|
||||
_autoButton = new ElaRadioButton("Auto", this);
|
||||
_autoButton->setChecked(true);
|
||||
ElaScrollPageArea* displayModeArea = new ElaScrollPageArea(this);
|
||||
QHBoxLayout* displayModeLayout = new QHBoxLayout(displayModeArea);
|
||||
ElaText* displayModeText = new ElaText("导航栏模式选择", this);
|
||||
displayModeText->setWordWrap(false);
|
||||
displayModeText->setTextPixelSize(15);
|
||||
displayModeLayout->addWidget(displayModeText);
|
||||
displayModeLayout->addStretch();
|
||||
displayModeLayout->addWidget(_minimumButton);
|
||||
displayModeLayout->addWidget(_compactButton);
|
||||
displayModeLayout->addWidget(_maximumButton);
|
||||
displayModeLayout->addWidget(_autoButton);
|
||||
connect(_minimumButton, &ElaRadioButton::toggled, this, [=](bool checked) {
|
||||
if (checked)
|
||||
{
|
||||
window->setNavigationBarDisplayMode(ElaNavigationType::Minimal);
|
||||
}
|
||||
});
|
||||
connect(_compactButton, &ElaRadioButton::toggled, this, [=](bool checked) {
|
||||
if (checked)
|
||||
{
|
||||
window->setNavigationBarDisplayMode(ElaNavigationType::Compact);
|
||||
}
|
||||
});
|
||||
connect(_maximumButton, &ElaRadioButton::toggled, this, [=](bool checked) {
|
||||
if (checked)
|
||||
{
|
||||
window->setNavigationBarDisplayMode(ElaNavigationType::Maximal);
|
||||
}
|
||||
});
|
||||
connect(_autoButton, &ElaRadioButton::toggled, this, [=](bool checked) {
|
||||
if (checked)
|
||||
{
|
||||
window->setNavigationBarDisplayMode(ElaNavigationType::Auto);
|
||||
}
|
||||
});
|
||||
|
||||
QWidget* centralWidget = new QWidget(this);
|
||||
centralWidget->setWindowTitle("UI设置");
|
||||
QVBoxLayout* centerLayout = new QVBoxLayout(centralWidget);
|
||||
centerLayout->addSpacing(30);
|
||||
centerLayout->addWidget(themeText);
|
||||
centerLayout->addSpacing(10);
|
||||
centerLayout->addWidget(themeSwitchArea);
|
||||
centerLayout->addSpacing(15);
|
||||
centerLayout->addWidget(helperText);
|
||||
centerLayout->addSpacing(10);
|
||||
centerLayout->addWidget(logSwitchArea);
|
||||
centerLayout->addWidget(micaSwitchArea);
|
||||
centerLayout->addWidget(displayModeArea);
|
||||
centerLayout->addStretch();
|
||||
centerLayout->setContentsMargins(0, 0, 0, 0);
|
||||
addCentralWidget(centralWidget, true, true, 0);
|
||||
}
|
||||
|
||||
UISetting::~UISetting()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
设置界面,UI使用Ela UI
|
||||
Reference in New Issue
Block a user