From a601a99817158bf8fe634a5b2f89065216fd2f93 Mon Sep 17 00:00:00 2001 From: RickyRister Date: Tue, 3 Mar 2026 01:33:51 -0800 Subject: [PATCH] Change to JournalWidget --- cockatrice/CMakeLists.txt | 2 + .../interface/widgets/game/journal_widget.cpp | 104 ++++++++++++++++++ .../interface/widgets/game/journal_widget.h | 51 +++++++++ .../src/interface/widgets/tabs/tab_game.cpp | 38 ++++--- .../src/interface/widgets/tabs/tab_game.h | 6 +- 5 files changed, 181 insertions(+), 20 deletions(-) create mode 100644 cockatrice/src/interface/widgets/game/journal_widget.cpp create mode 100644 cockatrice/src/interface/widgets/game/journal_widget.h diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index d675b809d..b2043b0fd 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -180,6 +180,8 @@ set(cockatrice_SOURCES src/interface/widgets/deck_editor/deck_list_style_proxy.cpp src/interface/widgets/deck_editor/deck_state_manager.cpp src/interface/widgets/deck_editor/printing_disabled_info_widget.cpp + src/interface/widgets/game/journal_widget.cpp + src/interface/widgets/game/journal_widget.h src/interface/widgets/general/background_sources.cpp src/interface/widgets/general/display/background_plate_widget.cpp src/interface/widgets/general/display/banner_widget.cpp diff --git a/cockatrice/src/interface/widgets/game/journal_widget.cpp b/cockatrice/src/interface/widgets/game/journal_widget.cpp new file mode 100644 index 000000000..9d8ab0be2 --- /dev/null +++ b/cockatrice/src/interface/widgets/game/journal_widget.cpp @@ -0,0 +1,104 @@ +#include "journal_widget.h" + +#include "../../../client/settings/cache_settings.h" + +#include +#include +#include + +static const QString BACKUP_FILE_NAME = "journal.txt"; + +JournalRestoreWidget::JournalRestoreWidget(QWidget *parent) : QWidget(parent) +{ + auto layout = new QVBoxLayout(this); + layout->setSpacing(3); + layout->setAlignment(Qt::AlignCenter); + setLayout(layout); + + textLabel = new QLabel(this); + restoreButton = new QPushButton(this); + discardButton = new QPushButton(this); + + layout->addWidget(textLabel); + layout->addWidget(restoreButton); + layout->addWidget(discardButton); + + connect(restoreButton, &QPushButton::clicked, this, &JournalRestoreWidget::restorePushed); + connect(discardButton, &QPushButton::clicked, this, &JournalRestoreWidget::discardPushed); + + connect(&SettingsCache::instance(), &SettingsCache::langChanged, this, &JournalRestoreWidget::retranslateUi); + + retranslateUi(); +} + +void JournalRestoreWidget::retranslateUi() +{ + textLabel->setText(tr("Previous journal text detected.")); + restoreButton->setText(tr("Restore")); + discardButton->setText(tr("Discard")); +} + +static QString getJournalBackupPath() +{ + return SettingsCache::instance().getDataPath() + "/" + BACKUP_FILE_NAME; +} + +static bool hasSavedBackupText() +{ + QFileInfo fileInfo = QFileInfo(getJournalBackupPath()); + return fileInfo.size() != 0; +} + +JournalWidget::JournalWidget(QWidget *parent) : QWidget(parent) +{ + auto layout = new QHBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + setLayout(layout); + + textEdit = new QPlainTextEdit(this); + restoreWidget = new JournalRestoreWidget(this); + + layout->addWidget(textEdit); + layout->addWidget(restoreWidget); + + showRestorePrompt(hasSavedBackupText()); + + connect(restoreWidget, &JournalRestoreWidget::discardPushed, this, [this] { showRestorePrompt(false); }); + connect(restoreWidget, &JournalRestoreWidget::restorePushed, this, [this] { + restoreText(); + showRestorePrompt(false); + }); + + // Debounce setup + debounceTimer.setSingleShot(true); + connect(&debounceTimer, &QTimer::timeout, this, &JournalWidget::backupText); + connect(textEdit, &QPlainTextEdit::textChanged, this, [this] { debounceTimer.start(300); }); +} + +void JournalWidget::showRestorePrompt(bool show) +{ + restoreWidget->setVisible(show); + textEdit->setVisible(!show); +} + +void JournalWidget::backupText() +{ + QFile file(getJournalBackupPath()); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + return; + } + + QString text = textEdit->toPlainText(); + file.write(text.toUtf8()); +} + +void JournalWidget::restoreText() +{ + QFile file(getJournalBackupPath()); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + return; + } + + QByteArray byteArray = file.readAll(); + textEdit->setPlainText(QString::fromUtf8(byteArray)); +} \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/game/journal_widget.h b/cockatrice/src/interface/widgets/game/journal_widget.h new file mode 100644 index 000000000..b34ceaf16 --- /dev/null +++ b/cockatrice/src/interface/widgets/game/journal_widget.h @@ -0,0 +1,51 @@ +#ifndef COCKATRICE_JOURNAL_WIDGET_H +#define COCKATRICE_JOURNAL_WIDGET_H +#include +#include +#include +#include +#include +#include + +/** + * The widget that is used to show the journal restore prompt. + */ +class JournalRestoreWidget : public QWidget +{ + Q_OBJECT + + QLabel *textLabel; + QPushButton *restoreButton; + QPushButton *discardButton; + +public: + explicit JournalRestoreWidget(QWidget *parent = nullptr); + + void retranslateUi(); + +signals: + void restorePushed(); + void discardPushed(); +}; + +/** + * The widget used in the Journal dock in the game tab. + */ +class JournalWidget : public QWidget +{ + Q_OBJECT + + QPlainTextEdit *textEdit; + JournalRestoreWidget *restoreWidget; + QTimer debounceTimer; + +public: + explicit JournalWidget(QWidget *parent = nullptr); + +private slots: + void showRestorePrompt(bool show); + void backupText(); + void restoreText(); +}; + +#endif // COCKATRICE_JOURNAL_WIDGET_H diff --git a/cockatrice/src/interface/widgets/tabs/tab_game.cpp b/cockatrice/src/interface/widgets/tabs/tab_game.cpp index ef75bf817..5d5248496 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_game.cpp +++ b/cockatrice/src/interface/widgets/tabs/tab_game.cpp @@ -16,6 +16,7 @@ #include "../interface/card_picture_loader/card_picture_loader.h" #include "../interface/widgets/cards/card_info_frame_widget.h" #include "../interface/widgets/dialogs/dlg_create_game.h" +#include "../interface/widgets/game/journal_widget.h" #include "../interface/widgets/server/user/user_list_manager.h" #include "../interface/widgets/utility/line_edit_completer.h" #include "../interface/window_main.h" @@ -52,7 +53,7 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, GameReplay *_replay) createCardInfoDock(true); createPlayerListDock(true); - createNotesDock(true); + createJournalDock(true); createMessageDock(true); createPlayAreaWidget(true); createDeckViewContainerWidget(true); @@ -60,7 +61,7 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, GameReplay *_replay) addDockWidget(Qt::RightDockWidgetArea, cardInfoDock); addDockWidget(Qt::RightDockWidgetArea, playerListDock); - addDockWidget(Qt::RightDockWidgetArea, notesDock); + addDockWidget(Qt::RightDockWidgetArea, journalDock); addDockWidget(Qt::RightDockWidgetArea, messageLayoutDock); addDockWidget(Qt::BottomDockWidgetArea, replayDock); @@ -98,7 +99,7 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, createCardInfoDock(); createPlayerListDock(); - createNotesDock(); + createJournalDock(); createMessageDock(); createPlayAreaWidget(); createDeckViewContainerWidget(); @@ -106,7 +107,7 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, addDockWidget(Qt::RightDockWidgetArea, cardInfoDock); addDockWidget(Qt::RightDockWidgetArea, playerListDock); - addDockWidget(Qt::RightDockWidgetArea, notesDock); + addDockWidget(Qt::RightDockWidgetArea, journalDock); addDockWidget(Qt::RightDockWidgetArea, messageLayoutDock); mainWidget = new QStackedWidget(this); @@ -283,7 +284,7 @@ void TabGame::retranslateUi() updatePlayerListDockTitle(); cardInfoDock->setWindowTitle(tr("Card Info") + (cardInfoDock->isWindow() ? tabText : QString())); - notesDock->setWindowTitle(tr("Notes") + (notesDock->isWindow() ? tabText : QString())); + journalDock->setWindowTitle(tr("Journal") + (journalDock->isWindow() ? tabText : QString())); messageLayoutDock->setWindowTitle(tr("Messages") + (messageLayoutDock->isWindow() ? tabText : QString())); if (replayDock) replayDock->setWindowTitle(tr("Replay Timeline") + (replayDock->isWindow() ? tabText : QString())); @@ -347,7 +348,7 @@ void TabGame::retranslateUi() dockToActions[cardInfoDock].menu->setTitle(tr("Card Info")); dockToActions[messageLayoutDock].menu->setTitle(tr("Messages")); - dockToActions[notesDock].menu->setTitle(tr("Notes")); + dockToActions[journalDock].menu->setTitle(tr("Journal")); dockToActions[playerListDock].menu->setTitle(tr("Player List")); if (replayDock) { @@ -1042,7 +1043,7 @@ void TabGame::createViewMenuItems() registerDockWidget(viewMenu, cardInfoDock, {250, 360}); registerDockWidget(viewMenu, messageLayoutDock, {250, 200}); registerDockWidget(viewMenu, playerListDock, {250, 50}); - registerDockWidget(viewMenu, notesDock, {250, 50}); + registerDockWidget(viewMenu, journalDock, {250, 50}); if (replayDock) { registerDockWidget(viewMenu, replayDock, {900, 100}); @@ -1132,17 +1133,17 @@ void TabGame::actResetLayout() { cardInfoDock->setVisible(true); playerListDock->setVisible(true); - notesDock->setVisible(false); + journalDock->setVisible(false); messageLayoutDock->setVisible(true); cardInfoDock->setFloating(false); playerListDock->setFloating(false); - notesDock->setFloating(false); + journalDock->setFloating(false); messageLayoutDock->setFloating(false); addDockWidget(Qt::RightDockWidgetArea, cardInfoDock); addDockWidget(Qt::RightDockWidgetArea, playerListDock); - addDockWidget(Qt::RightDockWidgetArea, notesDock); + addDockWidget(Qt::RightDockWidgetArea, journalDock); addDockWidget(Qt::RightDockWidgetArea, messageLayoutDock); if (replayDock) { @@ -1251,19 +1252,20 @@ void TabGame::createPlayerListDock(bool bReplay) playerListDock->setFloating(false); } -void TabGame::createNotesDock(bool bReplay) +void TabGame::createJournalDock(bool bReplay) { Q_UNUSED(bReplay); - auto textEdit = new QPlainTextEdit(this); - notesDock = new QDockWidget(this); - notesDock->setObjectName("notesDock"); - notesDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable | - QDockWidget::DockWidgetMovable); - notesDock->setWidget(textEdit); + journalWidget = new JournalWidget(this); + + journalDock = new QDockWidget(this); + journalDock->setObjectName("journalDock"); + journalDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable | + QDockWidget::DockWidgetMovable); + journalDock->setWidget(journalWidget); // Prevent text from autofocusing if there are no other focusable widgets (such as when loading replay) - QTimer::singleShot(1, textEdit, &QWidget::clearFocus); + QTimer::singleShot(1, journalWidget, &QWidget::clearFocus); } void TabGame::createMessageDock(bool bReplay) diff --git a/cockatrice/src/interface/widgets/tabs/tab_game.h b/cockatrice/src/interface/widgets/tabs/tab_game.h index dd7290297..dc9337cad 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_game.h +++ b/cockatrice/src/interface/widgets/tabs/tab_game.h @@ -20,6 +20,7 @@ #include #include +class JournalWidget; class ServerInfo_PlayerProperties; class TabbedDeckViewContainer; inline Q_LOGGING_CATEGORY(TabGameLog, "tab_game"); @@ -66,6 +67,7 @@ private: CardInfoFrameWidget *cardInfoFrameWidget; PlayerListWidget *playerListWidget; + JournalWidget *journalWidget; QLabel *timeElapsedLabel; MessageLogWidget *messageLog; QLabel *sayLabel; @@ -76,7 +78,7 @@ private: QMap deckViewContainers; QVBoxLayout *deckViewContainerLayout; QWidget *gamePlayAreaWidget, *deckViewContainerWidget; - QDockWidget *cardInfoDock, *playerListDock, *notesDock, *messageLayoutDock, *replayDock; + QDockWidget *cardInfoDock, *playerListDock, *journalDock, *messageLayoutDock, *replayDock; QAction *playersSeparator; QMenu *gameMenu, *viewMenu; TearOffMenu *phasesMenu; @@ -121,7 +123,7 @@ private: void registerDockWidget(QMenu *_viewMenu, QDockWidget *widget, const QSize &defaultSize); void createCardInfoDock(bool bReplay = false); void createPlayerListDock(bool bReplay = false); - void createNotesDock(bool bReplay = false); + void createJournalDock(bool bReplay = false); void createMessageDock(bool bReplay = false); void createPlayAreaWidget(bool bReplay = false); void createDeckViewContainerWidget(bool bReplay = false);