frontend: Split Qt UI dialogs into single files per C++ class

This commit is contained in:
PatTheMav
2025-01-08 15:36:55 +01:00
parent e4a43f6555
commit 085c6245b0
27 changed files with 114 additions and 7119 deletions
+7 -315
View File
@@ -1,29 +1,14 @@
#include "moc_window-extra-browsers.cpp"
#include "window-dock-browser.hpp"
#include "window-basic-main.hpp"
#include "ExtraBrowsersModel.hpp"
#include <components/DelButton.hpp>
#include <docks/BrowserDock.hpp>
#include <widgets/OBSBasic.hpp>
#include <qt-wrappers.hpp>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QUuid>
#include <json11.hpp>
#include <QTableView>
#include "ui_OBSExtraBrowsers.h"
using namespace json11;
#define OBJ_NAME_SUFFIX "_extraBrowser"
enum class Column : int {
Title,
Url,
Delete,
Count,
};
/* ------------------------------------------------------------------------- */
#include "moc_ExtraBrowsersModel.cpp"
void ExtraBrowsersModel::Reset()
{
@@ -105,21 +90,6 @@ Qt::ItemFlags ExtraBrowsersModel::flags(const QModelIndex &index) const
return flags;
}
class DelButton : public QPushButton {
public:
inline DelButton(QModelIndex index_) : QPushButton(), index(index_) {}
QPersistentModelIndex index;
};
class EditWidget : public QLineEdit {
public:
inline EditWidget(QWidget *parent, QModelIndex index_) : QLineEdit(parent), index(index_) {}
QPersistentModelIndex index;
};
void ExtraBrowsersModel::AddDeleteButton(int idx)
{
QTableView *widget = reinterpret_cast<QTableView *>(parent());
@@ -282,281 +252,3 @@ void ExtraBrowsersModel::Init()
for (int i = 0; i < items.count(); i++)
AddDeleteButton(i);
}
/* ------------------------------------------------------------------------- */
QWidget *ExtraBrowsersDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &,
const QModelIndex &index) const
{
QLineEdit *text = new EditWidget(parent, index);
text->installEventFilter(const_cast<ExtraBrowsersDelegate *>(this));
text->setSizePolicy(QSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding,
QSizePolicy::ControlType::LineEdit));
return text;
}
void ExtraBrowsersDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QLineEdit *text = reinterpret_cast<QLineEdit *>(editor);
text->blockSignals(true);
text->setText(index.data().toString());
text->blockSignals(false);
}
bool ExtraBrowsersDelegate::eventFilter(QObject *object, QEvent *event)
{
QLineEdit *edit = qobject_cast<QLineEdit *>(object);
if (!edit)
return false;
if (LineEditCanceled(event)) {
RevertText(edit);
}
if (LineEditChanged(event)) {
UpdateText(edit);
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Tab) {
model->TabSelection(true);
} else if (keyEvent->key() == Qt::Key_Backtab) {
model->TabSelection(false);
}
}
return true;
}
return false;
}
bool ExtraBrowsersDelegate::ValidName(const QString &name) const
{
for (auto &item : model->items) {
if (name.compare(item.title, Qt::CaseInsensitive) == 0) {
return false;
}
}
return true;
}
void ExtraBrowsersDelegate::RevertText(QLineEdit *edit_)
{
EditWidget *edit = reinterpret_cast<EditWidget *>(edit_);
int row = edit->index.row();
int col = edit->index.column();
bool newItem = (row == model->items.size());
QString oldText;
if (col == (int)Column::Title) {
oldText = newItem ? model->newTitle : model->items[row].title;
} else {
oldText = newItem ? model->newURL : model->items[row].url;
}
edit->setText(oldText);
}
bool ExtraBrowsersDelegate::UpdateText(QLineEdit *edit_)
{
EditWidget *edit = reinterpret_cast<EditWidget *>(edit_);
int row = edit->index.row();
int col = edit->index.column();
bool newItem = (row == model->items.size());
QString text = edit->text().trimmed();
if (!newItem && text.isEmpty()) {
return false;
}
if (col == (int)Column::Title) {
QString oldText = newItem ? model->newTitle : model->items[row].title;
bool same = oldText.compare(text, Qt::CaseInsensitive) == 0;
if (!same && !ValidName(text)) {
edit->setText(oldText);
return false;
}
}
if (!newItem) {
/* if edited existing item, update it*/
switch (col) {
case (int)Column::Title:
model->items[row].title = text;
break;
case (int)Column::Url:
model->items[row].url = text;
break;
}
} else {
/* if both new values filled out, create new one */
switch (col) {
case (int)Column::Title:
model->newTitle = text;
break;
case (int)Column::Url:
model->newURL = text;
break;
}
model->CheckToAdd();
}
emit commitData(edit);
return true;
}
/* ------------------------------------------------------------------------- */
OBSExtraBrowsers::OBSExtraBrowsers(QWidget *parent) : QDialog(parent), ui(new Ui::OBSExtraBrowsers)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose, true);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
model = new ExtraBrowsersModel(ui->table);
ui->table->setModel(model);
ui->table->setItemDelegateForColumn((int)Column::Title, new ExtraBrowsersDelegate(model));
ui->table->setItemDelegateForColumn((int)Column::Url, new ExtraBrowsersDelegate(model));
ui->table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::Stretch);
ui->table->horizontalHeader()->setSectionResizeMode((int)Column::Delete, QHeaderView::ResizeMode::Fixed);
ui->table->setEditTriggers(QAbstractItemView::EditTrigger::CurrentChanged);
}
OBSExtraBrowsers::~OBSExtraBrowsers() {}
void OBSExtraBrowsers::closeEvent(QCloseEvent *event)
{
QDialog::closeEvent(event);
model->Apply();
}
void OBSExtraBrowsers::on_apply_clicked()
{
model->Apply();
}
/* ------------------------------------------------------------------------- */
void OBSBasic::ClearExtraBrowserDocks()
{
extraBrowserDockTargets.clear();
extraBrowserDockNames.clear();
extraBrowserDocks.clear();
}
void OBSBasic::LoadExtraBrowserDocks()
{
const char *jsonStr = config_get_string(App()->GetUserConfig(), "BasicWindow", "ExtraBrowserDocks");
std::string err;
Json json = Json::parse(jsonStr, err);
if (!err.empty())
return;
Json::array array = json.array_items();
if (!array.empty())
extraBrowserMenuDocksSeparator = ui->menuDocks->addSeparator();
for (Json &item : array) {
std::string title = item["title"].string_value();
std::string url = item["url"].string_value();
std::string uuid = item["uuid"].string_value();
AddExtraBrowserDock(title.c_str(), url.c_str(), uuid.c_str(), false);
}
}
void OBSBasic::SaveExtraBrowserDocks()
{
Json::array array;
for (int i = 0; i < extraBrowserDocks.size(); i++) {
QDockWidget *dock = extraBrowserDocks[i].get();
QString title = extraBrowserDockNames[i];
QString url = extraBrowserDockTargets[i];
QString uuid = dock->property("uuid").toString();
Json::object obj{
{"title", QT_TO_UTF8(title)},
{"url", QT_TO_UTF8(url)},
{"uuid", QT_TO_UTF8(uuid)},
};
array.push_back(obj);
}
std::string output = Json(array).dump();
config_set_string(App()->GetUserConfig(), "BasicWindow", "ExtraBrowserDocks", output.c_str());
}
void OBSBasic::ManageExtraBrowserDocks()
{
if (!extraBrowsers.isNull()) {
extraBrowsers->show();
extraBrowsers->raise();
return;
}
extraBrowsers = new OBSExtraBrowsers(this);
extraBrowsers->show();
}
void OBSBasic::AddExtraBrowserDock(const QString &title, const QString &url, const QString &uuid, bool firstCreate)
{
static int panel_version = -1;
if (panel_version == -1) {
panel_version = obs_browser_qcef_version();
}
BrowserDock *dock = new BrowserDock(title);
QString bId(uuid.isEmpty() ? QUuid::createUuid().toString() : uuid);
bId.replace(QRegularExpression("[{}-]"), "");
dock->setProperty("uuid", bId);
dock->setObjectName(title + OBJ_NAME_SUFFIX);
dock->resize(460, 600);
dock->setMinimumSize(80, 80);
dock->setWindowTitle(title);
dock->setAllowedAreas(Qt::AllDockWidgetAreas);
QCefWidget *browser = cef->create_widget(dock, QT_TO_UTF8(url), nullptr);
if (browser && panel_version >= 1)
browser->allowAllPopups(true);
dock->SetWidget(browser);
/* Add support for Twitch Dashboard panels */
if (url.contains("twitch.tv/popout") && url.contains("dashboard/live")) {
QRegularExpression re("twitch.tv\\/popout\\/([^/]+)\\/");
QRegularExpressionMatch match = re.match(url);
QString username = match.captured(1);
if (username.length() > 0) {
std::string script;
script = "Object.defineProperty(document, 'referrer', { get: () => '";
script += "https://twitch.tv/";
script += QT_TO_UTF8(username);
script += "/dashboard/live";
script += "'});";
browser->setStartupScript(script);
}
}
AddDockWidget(dock, Qt::RightDockWidgetArea, true);
extraBrowserDocks.push_back(std::shared_ptr<QDockWidget>(dock));
extraBrowserDockNames.push_back(title);
extraBrowserDockTargets.push_back(url);
if (firstCreate) {
dock->setFloating(true);
QPoint curPos = pos();
QSize wSizeD2 = size() / 2;
QSize dSizeD2 = dock->size() / 2;
curPos.setX(curPos.x() + wSizeD2.width() - dSizeD2.width());
curPos.setY(curPos.y() + wSizeD2.height() - dSizeD2.height());
dock->move(curPos);
dock->setVisible(true);
}
}