File indexing completed on 2024-05-12 04:06:06

0001 /*
0002     SPDX-FileCopyrightText: 1998 Sandro Sigala <ssigala@globalnet.it>
0003     SPDX-FileCopyrightText: 2001 Waldo Bastian <bastian@kde.org>
0004     SPDX-FileCopyrightText: 2007 Matt Williams <matt@milliams.com>
0005 
0006     SPDX-License-Identifier: ICS
0007 */
0008 
0009 #ifndef KGAMEHIGHSCOREDIALOG_H
0010 #define KGAMEHIGHSCOREDIALOG_H
0011 
0012 // own
0013 #include <kdegames_export.h>
0014 // Qt
0015 #include <QDialog>
0016 #include <QMap>
0017 // Std
0018 #include <memory>
0019 
0020 class KGameDifficulty;
0021 
0022 /**
0023  * \class KGameHighScoreDialog kgamehighscoredialog.h <KGameHighScoreDialog>
0024  *
0025  * @short A simple high score implementation
0026  *
0027  * This class can be used both for displaying the current high scores
0028  * and also for adding new highscores. It is the recommended way of
0029  * implementing a simple highscore table.
0030  *
0031  * To display the current highscores it is simply a case of creating
0032  * a KGameHighScoreDialog object and calling exec(). This example code will
0033  * display the Name and Score (the score is always added automatically
0034  * unless hidden @ref hideField since it is used for sorting) of the
0035  * top 10 players:
0036  * \code
0037  * KGameHighScoreDialog ksdialog(this);
0038  * ksdialog.exec();
0039  * \endcode
0040  *
0041  * To add a new highscore, e.g. at the end of a game you simply create an
0042  * object with the @ref Fields you want to write (i.e. KGameHighScoreDialog::Name |
0043  * KGameHighScoreDialog::Score), call addScore and then (optionally) display
0044  * the dialog.
0045  * This code will allow you to add a highscore with a Name and Score
0046  * field. If it's the first time a player has a score on the table, they
0047  * will be prompted for their name but subsequent times they will have
0048  * their name filled in automatically.
0049  * \code
0050  * KGameHighScoreDialog ksdialog(this);
0051  * ksdialog.addScore(playersScore);
0052  * ksdialog.exec();
0053  * \endcode
0054  *
0055  * Or if you want to fill the name in from the code you can pass a default
0056  * name by doing
0057  * \code
0058  * KGameHighScoreDialog::FieldInfo scoreInfo;
0059  * scoreInfo[KGameHighScoreDialog::Name] = "Matt";
0060  * scoreInfo[KGameHighScoreDialog::Score].setNum(playersScore);
0061  * ksdialog.addScore(scoreInfo);
0062  * \endcode
0063  *
0064  * If you want to add an extra field (e.g. the number of moves taken) then
0065  * do
0066  * \code
0067  * KGameHighScoreDialog::FieldInfo scoreInfo;
0068  * scoreInfo[KGameHighScoreDialog::Name] = "Matt";
0069  * scoreInfo[KGameHighScoreDialog::Score].setNum(playersScore);
0070  *
0071  * ksdialog.addField(KGameHighScoreDialog::Custom1, "Num of Moves", "moves");
0072  * scoreInfo[KGameHighScoreDialog::Custom1].setNum(42);
0073  *
0074  * ksdialog.addScore(scoreInfo);
0075  * \endcode
0076  * You can define up to 5 Custom fields.
0077  * @author Matt Williams <matt@milliams.com>
0078  */
0079 class KDEGAMES_EXPORT KGameHighScoreDialog : public QDialog
0080 {
0081     Q_OBJECT
0082 
0083 public:
0084     /// Highscore fields
0085     enum Fields {
0086         Name = 1 << 0,
0087         Level = 1 << 1,
0088         Date = 1 << 2,
0089         Time = 1 << 3,
0090         Score = 1 << 4,
0091 
0092         Custom1 = 1 << 10, ///< Field for custom information
0093         Custom2 = 1 << 11,
0094         Custom3 = 1 << 12,
0095         Custom4 = 1 << 13,
0096         Custom5 = 1 << 14,
0097 
0098         Max = 1 << 30 ///< Only for setting a maximum
0099     };
0100 
0101     /// Flags for setting preferences for adding scores
0102     enum AddScoreFlag {
0103         AskName = 0x1, /**< Promt the player for their name */
0104         LessIsMore = 0x2 /**< A lower numerical score means higher placing on the table */
0105     };
0106     /**
0107      * Stores a combination of #AddScoreFlag values.
0108      */
0109     Q_DECLARE_FLAGS(AddScoreFlags, AddScoreFlag)
0110 
0111     typedef QMap<int, QString> FieldInfo;
0112 
0113     /**
0114      * @param fields Bitwise OR of the @ref Fields that should be listed (Score is always present)
0115      * @param parent passed to parent QWidget constructor.
0116      */
0117     explicit KGameHighScoreDialog(int fields = Name, QWidget *parent = nullptr);
0118 
0119     ~KGameHighScoreDialog() override;
0120 
0121     /**
0122      * The group name must be passed though i18n() in order for the
0123      * group name to be translated. i.e.
0124      * \code ksdialog.setConfigGroup(qMakePair(QByteArrayLiteral("Easy"), i18n("Easy"))); \endcode
0125      * If you set a group, it will be prefixed in the config file by
0126      * 'KHighscore_' otherwise the group will simply be 'KHighscore'.
0127      *
0128      * @param group to use for reading/writing highscores from/to.
0129      */
0130     void setConfigGroup(const QPair<QByteArray, QString> &group);
0131 
0132     /**
0133      * You must add the translations of all group names to the dialog. This
0134      * is best done by passing the name through i18n().
0135      * The group set through setConfigGroup(const QPair<QByteArray, QString>& group)
0136      * will be added automatically
0137      *
0138      * @param group the translated group name
0139      */
0140     void addLocalizedConfigGroupName(const QPair<QByteArray, QString> &group);
0141 
0142     /**
0143      * You must add the translations of all group names to the dialog. This
0144      * is best done by passing the name through i18n().
0145      * The group set through setConfigGroup(const QPair<QByteArray, QString>& group)
0146      * will be added automatically.
0147      *
0148      * This function can be used directly with KGameDifficulty::localizedLevelStrings().
0149      *
0150      * @param groups the list of translated group names
0151      */
0152     void addLocalizedConfigGroupNames(const QMap<QByteArray, QString> &groups);
0153 
0154     /**
0155      * Hide some config groups so that they are not shown on the dialog
0156      * (but are still stored in the configuration file).
0157      * \code
0158      * ksdialog.setHiddenConfigGroups(QList<QByteArray>{QByteArrayLiteral("Very Easy"), QByteArrayLiteral("Easy")});
0159      * \endcode
0160      *
0161      * @param hiddenGroups the list of group names you want to hide
0162      *
0163      * @since KDE 4.6
0164      */
0165     void setHiddenConfigGroups(const QList<QByteArray> &hiddenGroups);
0166 
0167     /**
0168      * It is a good idea giving config group weights, otherwise tabs
0169      * get ordered by their tab name that is not probably what you want.
0170      *
0171      * This function can be used directly with KGameDifficulty::levelWeights().
0172      *
0173      * @param weights the list of untranslated group weights
0174      *
0175      * @since KDE 4.2
0176      */
0177     void setConfigGroupWeights(const QMap<int, QByteArray> &weights);
0178 
0179     /**
0180      * @param comment to add when showing high-scores.
0181      * The comment is only used once.
0182      */
0183     void setComment(const QString &comment);
0184 
0185     /**
0186      * Define an extra FieldInfo entry.
0187      * @param field id of this field @ref Fields e.g. KGameHighScoreDialog::Custom1
0188      * @param header text shown in the header in the dialog for this field. e.g. "Number of Moves"
0189      * @param key unique key used to store this field. e.g. "moves"
0190      */
0191     void addField(int field, const QString &header, const QString &key);
0192 
0193     /**
0194      * Hide a field so that it is not shown on the table (but is still stored in the configuration file).
0195      * @param field id of this field @ref Fields e.g. KGameHighScoreDialog::Score
0196      */
0197     void hideField(int field);
0198 
0199     /**
0200      * Adds a new score to the list.
0201      *
0202      * @param newInfo info about the score.
0203      * @param flags set whether the user should be prompted for their name and how the scores should be sorted
0204      *
0205      * @returns The highscore position if the score was good enough to
0206      * make it into the list (1 being topscore) or 0 otherwise.
0207      */
0208     int addScore(const FieldInfo &newInfo = FieldInfo(), AddScoreFlags flags = {});
0209 
0210     /**
0211      * Convenience function for ease of use.
0212      *
0213      * @param newScore the score of the player.
0214      * @param flags set whether the user should be prompted for their name and how the scores should be sorted
0215      *
0216      * @returns The highscore position if the score was good enough to
0217      * make it into the list (1 being topscore) or 0 otherwise.
0218      */
0219     int addScore(int newScore, AddScoreFlags flags = {});
0220 
0221     /**
0222      * @returns the current best score in the group
0223      */
0224     int highScore();
0225 
0226     /**
0227      * Assume that config groups (incl. current selection) are equal to
0228      * difficulty levels, and initialize them. This is usually equal to the
0229      * following code using KGameDifficulty:
0230      * @code
0231      * addLocalizedConfigGroupNames(KGameDifficulty::localizedLevelStrings());
0232      * setConfigGroupWeights(KGameDifficulty::levelWeights());
0233      * setConfigGroup(KGameDifficulty::localizedLevelString());
0234      * @endcode
0235      */
0236     void initFromDifficulty(const KGameDifficulty *difficulty, bool setConfigGroup = true);
0237 
0238     /// Display the dialog as non-modal
0239     virtual void show();
0240     /// Display the dialog as modal
0241     int exec() override;
0242 
0243 private Q_SLOTS:
0244     void slotGotReturn();
0245     void slotGotName();
0246     void slotForgetScore();
0247 
0248 private:
0249     void keyPressEvent(QKeyEvent *ev) override;
0250 
0251 private:
0252     friend class KGameHighScoreDialogPrivate;
0253     std::unique_ptr<class KGameHighScoreDialogPrivate> const d_ptr;
0254     Q_DECLARE_PRIVATE(KGameHighScoreDialog)
0255 };
0256 
0257 Q_DECLARE_OPERATORS_FOR_FLAGS(KGameHighScoreDialog::AddScoreFlags)
0258 
0259 #endif // KGAMEHIGHSCOREDIALOG_H