diff --git a/src/handler/CharacterHandler.cpp b/src/handler/CharacterHandler.cpp index 21746905..43a99943 100644 --- a/src/handler/CharacterHandler.cpp +++ b/src/handler/CharacterHandler.cpp @@ -2,7 +2,7 @@ #include -// Stores a new character in the vector +// Stores a new character void CharacterHandler::storeCharacter( QString name, @@ -16,7 +16,7 @@ CharacterHandler::storeCharacter( } -// Sort all created characters +// Sort all created characters, depending on the used rulset void CharacterHandler::sortCharacters(const RuleSettings::Ruleset& ruleset, bool rollAutomatically) { @@ -38,29 +38,29 @@ CharacterHandler::sortCharacters(const RuleSettings::Ruleset& ruleset, bool roll return c1.initiative > c2.initiative; } switch (ruleset) { - // PF 1E/D&D 3.5/Starfinder rules: Sort for higher INI mod - // If that's equal, sort automatically or let the party decide - case RuleSettings::Ruleset::PATHFINDER_1E_DND_35E: - case RuleSettings::Ruleset::STARFINDER: - // D&D 3.0 uses the dex value for ties, but this is essentially another variant - // of the mod value, so no additional changes are necessary - case RuleSettings::Ruleset::DND_30E: - if (c1.modifier != c2.modifier) { - return c1.modifier > c2.modifier; - } - return sortUsingHashes(c1, c2); - // PF 2E rules: If there is a tie between player and foe, foe goes first - // Otherwise sort automatically or let the party decide - case RuleSettings::Ruleset::PATHFINDER_2E: - if (c1.isEnemy != c2.isEnemy) { - return c1.isEnemy > c2.isEnemy; - } - return sortUsingHashes(c1, c2); - // D&D 5E rules: Just sort automatically or let the party decide - case RuleSettings::Ruleset::DND_5E: - return sortUsingHashes(c1, c2); - default: - return false; + // PF 1E/D&D 3.5/Starfinder rules: Sort for higher INI mod + // If that's equal, sort automatically or let the party decide + case RuleSettings::Ruleset::PATHFINDER_1E_DND_35E: + case RuleSettings::Ruleset::STARFINDER: + // D&D 3.0 uses the dex value for ties, but this is essentially another variant + // of the mod value, so no additional changes are necessary + case RuleSettings::Ruleset::DND_30E: + if (c1.modifier != c2.modifier) { + return c1.modifier > c2.modifier; + } + return sortUsingHashes(c1, c2); + // PF 2E rules: If there is a tie between player and foe, foe goes first + // Otherwise sort automatically or let the party decide + case RuleSettings::Ruleset::PATHFINDER_2E: + if (c1.isEnemy != c2.isEnemy) { + return c1.isEnemy > c2.isEnemy; + } + return sortUsingHashes(c1, c2); + // D&D 5E rules: Just sort automatically or let the party decide + case RuleSettings::Ruleset::DND_5E: + return sortUsingHashes(c1, c2); + default: + return false; } }); } diff --git a/src/handler/CharacterHandler.hpp b/src/handler/CharacterHandler.hpp index 164ba711..3b18dde9 100644 --- a/src/handler/CharacterHandler.hpp +++ b/src/handler/CharacterHandler.hpp @@ -18,16 +18,16 @@ class CharacterHandler { int initiative = 0; // Modifiers only int modifier = 0; - // The hp for this character. Optional. + // The hp for this character int hp = 0; // Is the character an enemy or not bool isEnemy = false; - // Additional information (e.g. status effects). Optional. + // Additional information (e.g. status effects) QString additionalInf = QString(); }; public: - // Store a new character + void storeCharacter(QString name, int initiative = 0, @@ -36,7 +36,6 @@ class CharacterHandler { bool isEnemy = false, QString additionalInf = QString()); - // Sort the stored characters, depending on the ruleset void sortCharacters(const RuleSettings::Ruleset& ruleset, bool rollAutomatically); diff --git a/src/handler/FileHandler.cpp b/src/handler/FileHandler.cpp index f1471055..1fb134d1 100644 --- a/src/handler/FileHandler.cpp +++ b/src/handler/FileHandler.cpp @@ -4,7 +4,7 @@ #include #include -// Stores a table as a csv +// Stores table data as csv bool FileHandler::saveTable( const QVector >& tableData, @@ -14,10 +14,10 @@ FileHandler::saveTable( const RuleSettings::Ruleset& ruleset, bool rollAutomatically) const { - // Create a file + // Create file QFile file(filename); - // Check if device is open for writing + // Check if the device is open for writing if (file.open(QFile::WriteOnly | QFile::Truncate)) { QTextStream data(&file); data.setCodec("UTF-8"); @@ -25,10 +25,11 @@ FileHandler::saveTable( QStringList strList; - // Store the header of the table, used for checking the correct table format if the table is reloaded + // Store the table data header strList << "Name" << "Initiative" << "INI modifier" << "HP" << "Is Enemy" << "Additional information"; data << strList.join(";") + "\n"; + // Store main table data auto firstRow = true; for (const auto& row : tableData) { // Clear the list at the beginning of every row iteration @@ -43,7 +44,7 @@ FileHandler::saveTable( << QString::number(ruleset) << QString::number(rollAutomatically); } - // The "\n" guarantees that the rows are set correctly in the csv table + // Line break data << strList.join(";") + "\n"; } @@ -54,7 +55,7 @@ FileHandler::saveTable( } -// Open an existing csv table and stream it's data +// Open an existing csv table and stream its data int FileHandler::getCSVData(const QString& filename) { @@ -67,14 +68,14 @@ FileHandler::getCSVData(const QString& filename) in.setGenerateByteOrderMark(false); m_data = QString(); - // Import file line by line + // Import file while (!in.atEnd()) { m_data.append(in.readLine() + "\n"); } importedCSV.close(); if (checkTableFormat(m_data)) { - // Successfully checked table + // Success return 0; } // Table in false format @@ -85,7 +86,7 @@ FileHandler::getCSVData(const QString& filename) } -// Checks if a table is in the correct format before using +// Checks if a table is in the correct format bool FileHandler::checkTableFormat(const QString& data) const { @@ -93,11 +94,10 @@ FileHandler::checkTableFormat(const QString& data) const return false; } - // Get the stored table row data information const auto rowDataHeader = data.split("\n").at(0).split(";"); const auto rowDataFirstRow = data.split("\n").at(1).split(";"); - // Test if the table has the correct header columns + // Test if the stored data has the correct header columns if (rowDataHeader.size() == 6 && rowDataHeader[0] == "Name" && rowDataHeader[1] == "Initiative" @@ -106,7 +106,6 @@ FileHandler::checkTableFormat(const QString& data) const && rowDataHeader[4] == "Is Enemy" && rowDataHeader[5] == "Additional information" - // The second row is checked // 7th entry should contain the player on the move, 8th the round counter, // 9th the ruleset and 10th the roll automatically option && rowDataFirstRow.size() == 10) { diff --git a/src/handler/FileHandler.hpp b/src/handler/FileHandler.hpp index 3fa18e5a..94715894 100644 --- a/src/handler/FileHandler.hpp +++ b/src/handler/FileHandler.hpp @@ -7,10 +7,10 @@ #include "RuleSettings.hpp" -// This class handles the saving and reopening of tables as csv data +// This class handles the saving and opening of csv table data class FileHandler { public: - // Save a table of characters + // Save the characters [[nodiscard]] bool saveTable(const QVector >& tableData, const QString& filename, @@ -19,7 +19,7 @@ class FileHandler { const RuleSettings::Ruleset& ruleset, bool rollAutomatically) const; - // Reopen a saved table + // Open a saved table [[nodiscard]] int getCSVData(const QString& filename); @@ -30,7 +30,7 @@ class FileHandler { } private: - // Checks if a table is in the right format + // Checks if data is in the right format bool checkTableFormat(const QString& data) const; diff --git a/src/ui/MainWindow.cpp b/src/ui/MainWindow.cpp index 5b9a5811..011f97e7 100644 --- a/src/ui/MainWindow.cpp +++ b/src/ui/MainWindow.cpp @@ -58,6 +58,7 @@ MainWindow::MainWindow() auto *const aboutQtAction = new QAction(style()->standardIcon(QStyle::SP_TitleBarMenuButton), tr("About &Qt"), this); connect(aboutQtAction, &QAction::triggered, qApp, &QApplication::aboutQt); + // Add actions auto *const fileMenu = menuBar()->addMenu(tr("&File")); fileMenu->addAction(newCombatAction); fileMenu->addAction(openTableAction); @@ -132,7 +133,7 @@ MainWindow::saveTable() } else { fileName = m_dirSettings->openDir; } - + // Save the table const auto tableDataWidget = Utils::Table::tableDataFromWidget(m_combatWidget->getTableWidget()); if (m_file->saveTable(tableDataWidget, fileName, m_combatWidget->getRowEntered(), m_combatWidget->getRoundCounter(), m_ruleSettings->ruleset, m_ruleSettings->rollAutomatical)) { @@ -149,6 +150,7 @@ MainWindow::saveTable() } +// Reopen the file dialog, even if the table has been saved already void MainWindow::saveAs() { @@ -156,7 +158,7 @@ MainWindow::saveAs() const auto saveChangeOccured = isWindowModified(); const auto saveTableInFile = m_tableInFile; - // Change variables so saveTable calls the file dialog + // Change variables to call the file dialog setWindowModified(true); m_tableInFile = false; // Restore old state if the save fails @@ -178,10 +180,8 @@ MainWindow::openTable() return; } } - const auto fileName = - QFileDialog::getOpenFileName(this, "Open Table", m_dirSettings->openDir, ("csv File(*.csv)")); + const auto fileName = QFileDialog::getOpenFileName(this, "Open Table", m_dirSettings->openDir, ("csv File(*.csv)")); const auto code = m_file->getCSVData(fileName); - auto rulesModified = false; switch (code) { @@ -238,9 +238,9 @@ void MainWindow::about() { QMessageBox::about(this, tr("About Light Combat Manager"), - tr("

Light Combat Manager. A small and simple Combat Manager for D&D-like games.
" + tr("

Light Combat Manager. A small, lightweight Combat Manager for d20-based role playing games.
" "Code available on Github.

" - "

Version 1.9.1.
" + "

Version 1.9.2.
" "Changelog

")); } @@ -305,8 +305,6 @@ MainWindow::setTableWidget(bool isDataStored, bool newCombatStarted, const QStri m_combatWidget->openAddCharacterDialog(); } else { m_combatWidget->generateTable(); - // Setting the table emits changeOccured because the cells are altered, so reset - setCombatTitle(false); const auto height = m_combatWidget->getHeight(); setFixedHeight(height > START_HEIGHT ? height : START_HEIGHT); } @@ -336,10 +334,9 @@ MainWindow::createSaveMessageBox(const QString& tableMessage, bool isClosing) { auto *const msgBox = new QMessageBox(this); msgBox->setIcon(QMessageBox::Question); - msgBox->setStandardButtons( - isWindowModified() ? - QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel : - QMessageBox::Yes | QMessageBox::No); + msgBox->setStandardButtons(isWindowModified() ? + QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel : + QMessageBox::Yes | QMessageBox::No); msgBox->setText(tableMessage); if (isClosing) { isWindowModified() ? msgBox->setWindowTitle(tr("Save and exit?")) : msgBox->setWindowTitle(tr("Exit application?")); @@ -371,7 +368,7 @@ MainWindow::createSaveMessageBox(const QString& tableMessage, bool isClosing) } -QMessageBox * +QMessageBox* MainWindow::createRuleChangeMessageBox() { const auto message = tr("The Table you are trying to load uses another ruleset than you have stored in your rule settings!

" @@ -406,10 +403,9 @@ MainWindow::closeEvent(QCloseEvent *event) break; } case QMessageBox::Discard: + case QMessageBox::Yes: event->accept(); break; - case QMessageBox::Yes: - return; case QMessageBox::Cancel: case QMessageBox::No: event->ignore(); diff --git a/src/ui/MainWindow.hpp b/src/ui/MainWindow.hpp index 52a9f05c..0d3ebace 100644 --- a/src/ui/MainWindow.hpp +++ b/src/ui/MainWindow.hpp @@ -14,8 +14,7 @@ class RuleSettings; class WelcomeWidget; // This class handles the creation and managing of the main GUI window. It also serves -// as "main anchor point", switching between the different widgets the Combat Manager can have. -// The widgets are created in other classes and given to this class. +// as "main anchor point", switching between LCM's widgets, which are created in other classes. class MainWindow : public QMainWindow { Q_OBJECT diff --git a/src/ui/SettingsDialog.cpp b/src/ui/SettingsDialog.cpp index 1681b5c6..8e9df027 100644 --- a/src/ui/SettingsDialog.cpp +++ b/src/ui/SettingsDialog.cpp @@ -38,8 +38,8 @@ SettingsDialog::SettingsDialog(std::shared_ptr RuleSettings, m_rollTieBox = new QCheckBox; m_rollTieBox->setChecked(m_ruleSettings->rollAutomatical); auto *const rollTieLabel = new QLabel(tr("Roll automatically for tie")); - rollTieLabel->setToolTip(tr("If a tie occurs while Characters are generated for a Combat, the app will " - "automatically decide the turn order.")); + rollTieLabel->setToolTip(tr("If a tie occurs while Characters are generated for a Combat,\n" + "the app will automatically decide the turn order.")); auto *const rollTieLayout = new QHBoxLayout; rollTieLayout->setAlignment(Qt::AlignLeft); @@ -73,7 +73,7 @@ bool SettingsDialog::applyClicked() { if (m_rulesetBox->currentIndex() != m_ruleSettings->ruleset || m_rollTieBox->isChecked() != m_ruleSettings->rollAutomatical) { - // It could be dangerous to change the combat rules while a combat is active, so abort instead + // It could be dangerous to change the combat rules while a combat is active, so abort if (m_isTableActive) { auto const reply = QMessageBox::critical(this, tr("Combat active!"), tr("You changed the ruleset while a Combat is active. Please save and exit " diff --git a/src/ui/SettingsDialog.hpp b/src/ui/SettingsDialog.hpp index 52516e96..a9f2f5ec 100644 --- a/src/ui/SettingsDialog.hpp +++ b/src/ui/SettingsDialog.hpp @@ -8,7 +8,7 @@ class RuleSettings; class QCheckBox; class QComboBox; -// Dialog for the main program settings +// Dialog for the main application settings class SettingsDialog : public QDialog { Q_OBJECT @@ -30,5 +30,5 @@ private slots: QPointer m_rollTieBox; std::shared_ptr m_ruleSettings; - bool m_isTableActive; + const bool m_isTableActive; }; diff --git a/src/ui/settings/DirSettings.hpp b/src/ui/settings/DirSettings.hpp index eb04cfe0..7c1b5e8f 100644 --- a/src/ui/settings/DirSettings.hpp +++ b/src/ui/settings/DirSettings.hpp @@ -4,7 +4,7 @@ #include "BaseSettings.hpp" -// Store data used for the opening and saving directories +// Store data used for handling the opening and saving directories class DirSettings : public BaseSettings { public: DirSettings(); diff --git a/src/ui/table/CombatWidget.cpp b/src/ui/table/CombatWidget.cpp index 3b969152..2032f8d9 100644 --- a/src/ui/table/CombatWidget.cpp +++ b/src/ui/table/CombatWidget.cpp @@ -51,7 +51,7 @@ CombatWidget::CombatWidget(bool isDataStored, std::shared_ptr Rule m_tableWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); m_tableWidget->setFocusPolicy(Qt::ClickFocus); - // Adjust row width to main widget size + m_tableWidget->setColumnWidth(COL_NAME, mainWidgetWidth * WIDTH_NAME); m_tableWidget->setColumnWidth(COL_INI, mainWidgetWidth * WIDTH_INI); m_tableWidget->setColumnWidth(COL_MODIFIER, mainWidgetWidth * WIDTH_MODIFIER); @@ -64,12 +64,12 @@ CombatWidget::CombatWidget(bool isDataStored, std::shared_ptr Rule auto *const downButton = new QToolButton; downButton->setArrowType(Qt::DownArrow); - downButton->setToolTip(tr("Select next Character (Ctrl + Arrow Down).")); + downButton->setToolTip(tr("Select the next Character (Ctrl + Arrow Down).")); downButton->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Down)); auto *const upButton = new QToolButton; upButton->setArrowType(Qt::UpArrow); - upButton->setToolTip(tr("Select previous Character (Ctrl + Arrow Up).")); + upButton->setToolTip(tr("Select the previous Character (Ctrl + Arrow Up).")); upButton->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Up)); auto *const exitButton = new QPushButton(tr("Return to Main Window")); @@ -122,7 +122,6 @@ CombatWidget::CombatWidget(bool isDataStored, std::shared_ptr Rule m_redoAction->setShortcuts(QKeySequence::Redo); this->addAction(m_redoAction); - // Shortcuts auto *const duplicateShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_D), this); auto *const deleteShortcut = new QShortcut(QKeySequence(Qt::Key_Delete), this); auto *const statusEffectShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_E), this); @@ -167,7 +166,7 @@ CombatWidget::generateTable() // Then create the table pushOnUndoStack(); - // We do not need a save step directly after table creation, so setup the table and reset the stack + // We do not need a save step directly after table creation, so reset the stack m_undoStack->clear(); } @@ -183,6 +182,7 @@ CombatWidget::getHeight() const } +// Save the old table state before a change occurs, which is important for the undo command void CombatWidget::saveOldState() { @@ -207,7 +207,7 @@ CombatWidget::pushOnUndoStack(bool resynchronize) // Assemble the new data const auto tableDataNew = Utils::Table::tableDataFromCharacterVector(m_char); const auto newData = Undo::UndoData{ tableDataNew, m_rowEntered, m_roundCounter }; - + // We got everything, so push m_undoStack->push(new Undo(oldData, newData, this, &m_rowEntered, &m_roundCounter, m_roundCounterLabel, m_currentPlayerLabel)); // Update table @@ -227,7 +227,7 @@ CombatWidget::openAddCharacterDialog() bool isEnemy, QString addInfo, int instanceCount) { addCharacter(name, ini, mod, hp, isEnemy, addInfo, instanceCount); }); - // Lock this widget, wait until Dialog is closed + if (dialog->exec() == QDialog::Accepted) { // Only ask to sort if there are enough chars and additional chars have been added if (m_char->getCharacters().size() > 1 && m_char->getCharacters().size() != sizeBeforeDialog) { @@ -263,6 +263,7 @@ CombatWidget::dragAndDrop(int logicalIndex, int oldVisualIndex, int newVisualInd // Then set the table pushOnUndoStack(); + // Highlight the row which has been dragged m_tableWidget->clearSelection(); m_tableWidget->selectRow(newVisualIndex); } @@ -277,7 +278,7 @@ CombatWidget::openStatusEffectDialog() // Open dialog auto *const dialog = new StatusEffectDialog(m_ruleSettings, this); - // Lock until dialog is closed + if (dialog->exec() == QDialog::Accepted) { saveOldState(); Utils::Table::resynchronizeCharacters(m_tableWidget, m_char); @@ -287,7 +288,7 @@ CombatWidget::openStatusEffectDialog() for (const auto& i : m_tableWidget->selectionModel()->selectedRows()) { auto itemText = characters.at(i.row()).additionalInf; itemText = itemText.trimmed(); - // Append a comma, if something is already there and does not end with a comma + // Append a comma, if the content does not end with one already if (!itemText.isEmpty()) { itemText += itemText.back() == "," ? " " : ", "; } @@ -352,7 +353,7 @@ CombatWidget::rerollIni() } -// Set the data vector, if the data has been stored in a table +// Set the characters vector, if the table data has been stored in a csv file void CombatWidget::setTableDataWithFileData() { @@ -374,8 +375,8 @@ CombatWidget::setTableDataWithFileData() rowData.at(COL_NAME), rowData.at(COL_INI).toInt(), rowData.at(COL_MODIFIER).toInt(), rowData.at(COL_HP).toInt(), rowData.at(COL_ENEMY) == "true", rowData.at(COL_ADDITIONAL) }); - // If at the first row (which contains information about round counter and the - // player on the move), get this data + // If at the first row (which contains information about the round counter + // and the player on the move), get this data if (x == 1) { m_rowEntered = rowData[ROW_ENTERED].toInt(); m_roundCounter = rowData[ROUND_CTR].toInt(); @@ -489,7 +490,7 @@ CombatWidget::enteredRowChanged(bool goDown) m_rowEntered++; } } else { - // Stop if first round and first char selected + // Stop for the first round and first char selected if (m_rowEntered == 0 && m_roundCounter == 1) { return; } @@ -502,7 +503,7 @@ CombatWidget::enteredRowChanged(bool goDown) } } - // Recreate table for updated font + // Recreate the table for the updated font Utils::Table::resynchronizeCharacters(m_tableWidget, m_char); setRowAndPlayer(); pushOnUndoStack(); @@ -574,8 +575,8 @@ CombatWidget::contextMenuEvent(QContextMenuEvent *event) auto *const menu = new QMenu(this); // Map from MainWindow coordinates to Table Widget coordinates - // Status Effect, reroll, duplication and removal only if the cursor is above an item if (m_tableWidget->indexAt(m_tableWidget->viewport()->mapFrom(this, event->pos())).row() >= 0) { + // Status Effect, reroll, duplication and removal only if the cursor is above an item auto *const statusEffectAction = menu->addAction(tr("Add Status Effect(s)..."), this, [this] () { openStatusEffectDialog(); }); diff --git a/src/ui/table/CombatWidget.hpp b/src/ui/table/CombatWidget.hpp index 0f11f9e7..9d303852 100644 --- a/src/ui/table/CombatWidget.hpp +++ b/src/ui/table/CombatWidget.hpp @@ -13,7 +13,7 @@ class QUndoStack; class RuleSettings; class TableSettings; -// This class handles the creation of the table widget +// This class handles the main combat widget class CombatWidget : public QWidget { Q_OBJECT @@ -138,7 +138,6 @@ private slots: contextMenuEvent(QContextMenuEvent *event) override; private: - // Main table widget QPointer m_tableWidget; QPointer m_roundCounterLabel; @@ -183,7 +182,6 @@ private slots: static constexpr float COL_LENGTH_NAME_BUFFER = 20; static constexpr float COL_LENGTH_ADD_BUFFER = 20; - // Width rations of the first five columns static constexpr float WIDTH_NAME = 0.25f; static constexpr float WIDTH_INI = 0.05f; static constexpr float WIDTH_MODIFIER = 0.05f; diff --git a/src/ui/table/Undo.cpp b/src/ui/table/Undo.cpp index 57beb7c4..8be38a09 100644 --- a/src/ui/table/Undo.cpp +++ b/src/ui/table/Undo.cpp @@ -44,6 +44,7 @@ Undo::setCombatWidget(bool undo) tableWidget->blockSignals(true); tableWidget->setRowCount(undoData.tableData.size()); + // Main table creation for (int i = 0; i < undoData.tableData.size(); ++i) { for (int j = 0; j < undoData.tableData.at(i).size(); ++j) { j == COL_ENEMY ? diff --git a/src/ui/table/Undo.hpp b/src/ui/table/Undo.hpp index 2ee84bff..04389459 100644 --- a/src/ui/table/Undo.hpp +++ b/src/ui/table/Undo.hpp @@ -8,7 +8,7 @@ class QTableWidget; class CombatWidget; -// Manage the main combat table widget creation and recreation +// Manage the main combat table widget undoing and redoing class Undo : public QUndoCommand { public: diff --git a/src/ui/table/dialog/AddCharacterDialog.cpp b/src/ui/table/dialog/AddCharacterDialog.cpp index 7a4996ef..ebd7b775 100644 --- a/src/ui/table/dialog/AddCharacterDialog.cpp +++ b/src/ui/table/dialog/AddCharacterDialog.cpp @@ -23,30 +23,53 @@ AddCharacterDialog::AddCharacterDialog(std::shared_ptr RuleSetting { setWindowTitle(tr("Add new Character(s)")); + auto *const nameLabel = new QLabel(tr("Name:")); m_nameEdit = new QLineEdit; + m_nameEdit->setToolTip(tr("Set the name of the Character.\n" + "A Character can't be stored without a name.")); + + auto *const iniLabel = new QLabel(tr("Initiative:")); m_iniBox = new QSpinBox; m_iniBox->setMinimum(-20); + m_iniBox->setToolTip(tr("Set the initiative, including all modifiers. Optional.")); + + auto *const iniModifierLabel = new QLabel(m_ruleSettings->ruleset == RuleSettings::Ruleset::DND_30E ? + tr("DEX value:") : + tr("INI Modifier:")); m_iniModifierBox = new QSpinBox; m_iniModifierBox->setMinimum(-10); + m_iniModifierBox->setToolTip(m_ruleSettings->ruleset == RuleSettings::Ruleset::DND_30E ? + tr("Set the dexterity value of this Character. Optional.") : + tr("Set the modifier of the initiative. Optional.")); + m_labelRolled = new QLabel; + auto *const rollButton = new QPushButton(tr("Roll random INI value")); + rollButton->setToolTip(tr("Roll the Initiative.\n" + "The modifier is added to the rolled value.")); + + auto *const hpLabel = new QLabel(tr("HP:")); m_hpBox = new QSpinBox; m_hpBox->setRange(-10000, 10000); + m_hpBox->setToolTip(tr("Set the HP of this Character. Optional.")); + + auto *const enemyLabel = new QLabel(tr("Is Enemy:")); m_enemyBox = new QCheckBox; - m_addInfoEdit = new QLineEdit; + m_enemyBox->setToolTip(tr("Set if the Character is an enemy. Optional.")); - m_multipleEnabledBox = new QCheckBox(tr("Add Character multiple times:")); - m_multipleEnabledBox->setTristate(false); - m_multipleEnabledBox->setCheckState(Qt::Unchecked); - QObject::connect(m_multipleEnabledBox, &QCheckBox::stateChanged, this, [this] { - m_instanceNumberBox->setEnabled(m_multipleEnabledBox->checkState() == Qt::Checked); - }); + auto *const addInfoLabel = new QLabel(tr("Add. Info:")); + m_addInfoEdit = new QLineEdit; + m_addInfoEdit->setToolTip(tr("Set additional information,\n" + "for example status effects. Optional.")); m_instanceNumberBox = new QSpinBox; m_instanceNumberBox->setRange(2, 10); m_instanceNumberBox->setEnabled(false); - auto *const rollButton = new QPushButton(tr("Roll random INI value")); - rollButton->setToolTip(tr("Roll the Initiative. The modifier is added to the rolled value.")); + m_multipleEnabledBox = new QCheckBox(tr("Add Character multiple times:")); + m_multipleEnabledBox->setTristate(false); + m_multipleEnabledBox->setCheckState(Qt::Unchecked); + m_multipleEnabledBox->setToolTip(tr("If this is selected and 'Save' is pressed,\n" + "the Character is added multiple times to the Table.")); auto *const buttonBox = new QDialogButtonBox; auto *const saveButton = buttonBox->addButton(QDialogButtonBox::Save); @@ -65,29 +88,6 @@ AddCharacterDialog::AddCharacterDialog(std::shared_ptr RuleSetting m_timer = new QTimer(this); m_timer->setSingleShot(true); - // Labels for character stats - auto *const nameLabel = new QLabel(tr("Name:")); - nameLabel->setToolTip(tr("Set the name of the Character. A Character can't be stored without a name.")); - - auto *const iniLabel = new QLabel(tr("Initiative:")); - iniLabel->setToolTip(tr("Set the initiative, including all modifiers. Optional.")); - - auto *const iniModifierLabel = new QLabel(m_ruleSettings->ruleset == RuleSettings::Ruleset::DND_30E ? - tr("DEX value:") : - tr("INI Modifier:")); - iniModifierLabel->setToolTip(m_ruleSettings->ruleset == RuleSettings::Ruleset::DND_30E ? - tr("Set the dexterity value of this character. Optional.") : - tr("Set the modifier of the initiative. Optional.")); - - auto *const hpLabel = new QLabel(tr("HP:")); - hpLabel->setToolTip(tr("Set the HP of this Character. Optional.")); - - auto *const enemyLabel = new QLabel(tr("Is Enemy:")); - enemyLabel->setToolTip(tr("Set if the Character is an enemy. Optional.")); - - auto *const addInfoLabel = new QLabel(tr("Add. Info:")); - addInfoLabel->setToolTip(tr("Set additional information, for example status effects. Optional.")); - auto *const layout = new QGridLayout(this); layout->addWidget(nameLabel, 0, 0); layout->addWidget(m_nameEdit, 0, 1, 1, 3); @@ -132,6 +132,9 @@ AddCharacterDialog::AddCharacterDialog(std::shared_ptr RuleSetting connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); connect(m_timer, &QTimer::timeout, this, &AddCharacterDialog::animateLabel); + connect(m_multipleEnabledBox, &QCheckBox::stateChanged, this, [this] { + m_instanceNumberBox->setEnabled(m_multipleEnabledBox->checkState() == Qt::Checked); + }); } @@ -147,6 +150,7 @@ AddCharacterDialog::setLabelRolled() void AddCharacterDialog::animateLabel() { + // Create a small fading text if a character has been stored auto *const effect = new QGraphicsOpacityEffect; m_animatedLabel->setGraphicsEffect(effect); @@ -175,12 +179,13 @@ AddCharacterDialog::saveButtonClicked() resetButtonClicked(); setFocus(); - // Only set the label text after first stored character + // Only set the label text after the first stored character, + // otherwise it will be displayed constantly until something is stored if (!m_isFirstCharStored) { m_isFirstCharStored = true; m_animatedLabel->setText(tr("Character saved!")); } - // Rest graphics effect and kickoff animation + // Reset the graphics effect and kickoff the animation m_animatedLabel->setGraphicsEffect(0); m_timer->start(LABEL_SHOWN); } @@ -218,7 +223,6 @@ AddCharacterDialog::openStatusEffectDialog() { // Open dialog auto *const dialog = new StatusEffectDialog(m_ruleSettings, this); - // Lock until dialog is closed if (dialog->exec() == QDialog::Accepted) { // If accepted, add status effect auto itemText = m_addInfoEdit->text(); @@ -237,8 +241,8 @@ AddCharacterDialog::setFocus() } -// Normally, pressing the Enter closes a QDialog, calling reject but we do not want that -// The user has to press Escape or the Return or closing "X" button +// Normally, pressing the Enter key closes a QDialog, calling reject but we do not want that +// The user has to press Escape, the Return key or the closing "X" button void AddCharacterDialog::keyPressEvent(QKeyEvent *event) { diff --git a/src/ui/table/dialog/AddCharacterDialog.hpp b/src/ui/table/dialog/AddCharacterDialog.hpp index 2a21b8a9..486f1b35 100644 --- a/src/ui/table/dialog/AddCharacterDialog.hpp +++ b/src/ui/table/dialog/AddCharacterDialog.hpp @@ -77,7 +77,7 @@ private slots: bool m_somethingStored{ false }; bool m_isFirstCharStored{ false }; - std::shared_ptr m_ruleSettings; + const std::shared_ptr m_ruleSettings; static constexpr int LABEL_SHOWN = 1000; static constexpr int LABEL_FADEOUT = 2000; diff --git a/src/ui/table/dialog/StatusEffectDialog.cpp b/src/ui/table/dialog/StatusEffectDialog.cpp index a6df7b87..c4a64e1d 100644 --- a/src/ui/table/dialog/StatusEffectDialog.cpp +++ b/src/ui/table/dialog/StatusEffectDialog.cpp @@ -24,7 +24,8 @@ StatusEffectDialog::StatusEffectDialog(std::shared_ptr RuleSetting }); m_lineEdit->setPlaceholderText(tr("Type in effect or search (%1)").arg(shortcut->key().toString(QKeySequence::NativeText))); - m_lineEdit->setToolTip(tr("Selected list items are returned as effect. If nothing is selected, the entered text will be returned.")); + m_lineEdit->setToolTip(tr("Selected list items are returned as effect.\n" + "If nothing is selected, the entered text will be returned.")); m_listWidget = new QListWidget(this); m_listWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); @@ -58,8 +59,10 @@ StatusEffectDialog::StatusEffectDialog(std::shared_ptr RuleSetting void StatusEffectDialog::okButtonClicked() { + // If nothing is selected, add the line edit text as status effect if (m_listWidget->selectedItems().empty() && !m_lineEdit->text().isEmpty()) { m_effect = m_lineEdit->text(); + // Otherwise, add the effect in the list } else { for (auto* const item : m_listWidget->selectedItems()) { m_effect += item->text(); diff --git a/src/ui/table/dialog/StatusEffectDialog.hpp b/src/ui/table/dialog/StatusEffectDialog.hpp index a3484267..7f0eee9b 100644 --- a/src/ui/table/dialog/StatusEffectDialog.hpp +++ b/src/ui/table/dialog/StatusEffectDialog.hpp @@ -37,5 +37,5 @@ private slots: QString m_effect; - std::shared_ptr m_ruleSettings; + const std::shared_ptr m_ruleSettings; }; diff --git a/src/utils/UtilsGeneral.cpp b/src/utils/UtilsGeneral.cpp index 7a553d59..77a96d67 100644 --- a/src/utils/UtilsGeneral.cpp +++ b/src/utils/UtilsGeneral.cpp @@ -11,9 +11,6 @@ namespace Utils { namespace General { -// If a user manages a Combat, it is likely that value are separated using a semicolon -// But the file storing uses semicolons to separate the values for the csv, -// so the name and additional info columns are checked for these bool containsSemicolon(const QTableWidget *tableWidget) { @@ -28,7 +25,6 @@ containsSemicolon(const QTableWidget *tableWidget) } -// Roll a 20 sided dice int rollDice() { diff --git a/src/utils/UtilsGeneral.hpp b/src/utils/UtilsGeneral.hpp index 73c9b11d..c0567360 100644 --- a/src/utils/UtilsGeneral.hpp +++ b/src/utils/UtilsGeneral.hpp @@ -10,16 +10,21 @@ namespace Utils { namespace General { +// CSV files use semicolons to separate the cells, so the name and additional info columns +// are checked for these to prevent additional, user entered semicolons being saved [[nodiscard]] bool containsSemicolon(const QTableWidget *tableWidget); +// Roll a 20 sided dice [[nodiscard]] int rollDice(); +// Get a QString width in pixels [[nodiscard]] int getStringWidth(const QString& str, const QFont& font); +// Trim a file's path so only the file name remains [[nodiscard]] QString getCSVName(const QString& filePath); diff --git a/src/utils/UtilsTable.cpp b/src/utils/UtilsTable.cpp index 58588832..8c6aea9f 100644 --- a/src/utils/UtilsTable.cpp +++ b/src/utils/UtilsTable.cpp @@ -14,12 +14,10 @@ namespace Utils { namespace Table { -// Resynchronize the characters stored in the char handler vector void resynchronizeCharacters(const QTableWidget *tableWidget, CharacterHandlerRef characterHandler) { - // Clear everything, then use the table cells to refill the character handler characterHandler->clearCharacters(); for (int i = 0; i < tableWidget->rowCount(); i++) { @@ -37,7 +35,6 @@ resynchronizeCharacters(const QTableWidget *tableWidget, } -// Create checkboxes to show the is enemy status void setTableCheckBox(CombatWidget *combatWidget, unsigned int row, bool checked) { @@ -71,11 +68,9 @@ setTableCheckBox(CombatWidget *combatWidget, unsigned int row, bool checked) } -// Set the labels displaying the current player and round number void setRowAndPlayer(QTableWidget *tableWidget, QLabel *roundCounterLabel, QLabel *currentPlayerLabel, int rowEntered, int roundCounter) { - // Select row entered with Return key tableWidget->selectionModel()->clearSelection(); // Setting fonts may trigger unwished item setting events, so block the signals tableWidget->blockSignals(true); @@ -114,9 +109,8 @@ setRowAndPlayer(QTableWidget *tableWidget, QLabel *roundCounterLabel, QLabel *cu } -// Store the table cell values in a vector QVector > -tableDataFromWidget(QTableWidget *tableWidget) +tableDataFromWidget(const QTableWidget *tableWidget) { QVector > tableData; for (int i = 0; i < tableWidget->rowCount(); i++) { @@ -134,7 +128,6 @@ tableDataFromWidget(QTableWidget *tableWidget) } -// Reformat the character vector in a QVariant vector QVector > tableDataFromCharacterVector(CharacterHandlerRef characterHandler) { diff --git a/src/utils/UtilsTable.hpp b/src/utils/UtilsTable.hpp index b7fa1b83..fecbd08e 100644 --- a/src/utils/UtilsTable.hpp +++ b/src/utils/UtilsTable.hpp @@ -15,15 +15,19 @@ namespace Utils { namespace Table { +// Resynchronize the characters stored in the char handler vector +// with the data in the table widget void resynchronizeCharacters(const QTableWidget *tableWidget, CharacterHandlerRef characterHandler); +// Create checkboxes in the table to show the is enemy status void setTableCheckBox(CombatWidget *CombatWidget, unsigned int row, bool checked); +// Set the labels displaying the current player and round number void setRowAndPlayer(QTableWidget *tableWidget, QLabel* roundCounterLabel, @@ -31,10 +35,11 @@ setRowAndPlayer(QTableWidget *tableWidget, int rowEntered, int roundCounter); - +// Store the table cell values in a vector [[nodiscard]] QVector > -tableDataFromWidget(QTableWidget *tableWidget); +tableDataFromWidget(const QTableWidget *tableWidget); +// Reformat the character vector in a QVariant vector [[nodiscard]] QVector > tableDataFromCharacterVector(CharacterHandlerRef characterHandler); diff --git a/uncrustify.cfg b/uncrustify.cfg index e22da0ed..98dc60b0 100644 --- a/uncrustify.cfg +++ b/uncrustify.cfg @@ -3,7 +3,7 @@ # indent_with_tabs = 0 -indent_columns = 4 +indent_columns = 4 indent_col1_comment = true indent_class = true @@ -16,20 +16,20 @@ indent_cpp_lambda_body = false nl_enum_brace = remove nl_union_brace = remove -nl_struct_brace = remove -nl_do_brace = remove +nl_struct_brace = remove +nl_do_brace = remove nl_if_brace = remove -nl_for_brace = remove +nl_for_brace = remove nl_else_brace = remove nl_while_brace = remove nl_switch_brace = remove -nl_brace_while = remove -nl_brace_else = remove -sp_brace_else = force -sp_else_brace = force +nl_brace_while = remove +nl_brace_else = remove +sp_brace_else = force +sp_else_brace = force nl_func_var_def_blk = 0 nl_fcall_brace = remove -nl_fdef_brace = add +nl_fdef_brace = add nl_after_label_colon = true @@ -37,49 +37,49 @@ nl_after_label_colon = true # Source code modifications # -mod_paren_on_return = remove -mod_full_brace_if = force -mod_full_brace_if_chain = force -mod_full_brace_for = force -mod_full_brace_do = force -mod_full_brace_while = force -mod_full_brace_nl = 3 +mod_paren_on_return = remove +mod_full_brace_if = force +mod_full_brace_if_chain = force +mod_full_brace_for = force +mod_full_brace_do = force +mod_full_brace_while = force +mod_full_brace_nl = 3 # # inter-character spacing options # -sp_return_paren = force -sp_sizeof_paren = force -sp_before_sparen = force -sp_after_sparen = force -sp_after_cast = force -sp_inside_braces = force -sp_inside_braces_struct = force -sp_inside_braces_enum = force -sp_assign = force -sp_arith = force -sp_bool = force -sp_compare = force -sp_assign = force -sp_after_comma = force -sp_func_def_paren = remove -sp_func_call_paren = remove -sp_func_proto_paren = remove +sp_return_paren = force +sp_sizeof_paren = force +sp_before_sparen = force +sp_after_sparen = force +sp_after_cast = force +sp_inside_braces = force +sp_inside_braces_struct = force +sp_inside_braces_enum = force +sp_assign = force +sp_arith = force +sp_bool = force +sp_compare = force +sp_assign = force +sp_after_comma = force +sp_func_def_paren = remove +sp_func_call_paren = remove +sp_func_proto_paren = remove # # Aligning stuff # -align_with_tabs = FALSE -align_on_tabstop = FALSE -align_enum_equ_span = 4 +align_with_tabs = FALSE +align_on_tabstop = FALSE +align_enum_equ_span = 4 align_struct_init_span = 3 -align_right_cmt_span = 3 +align_right_cmt_span = 3 -cmt_star_cont = true +cmt_star_cont = true nl_after_func_body = 3 nl_after_func_body_class = 2