1 /* 2 SPDX-FileCopyrightText: 1998 Sandro Sigala <ssigala@globalnet.it> 3 SPDX-FileCopyrightText: 2001 Waldo Bastian <bastian@kde.org> 4 SPDX-FileCopyrightText: 2007 Matt Williams <matt@milliams.com> 5 6 SPDX-License-Identifier: ICS 7 */ 8 9 #ifndef KSCOREDIALOG_H 10 #define KSCOREDIALOG_H 11 12 // own 13 #include <libkdegames_export.h> 14 // Qt 15 #include <QMap> 16 #include <QFlags> 17 #include <QDialogButtonBox> 18 #include <QDialog> 19 // Std 20 #include <memory> 21 22 class KgDifficulty; 23 24 /** 25 * \class KScoreDialog kscoredialog.h <KScoreDialog> 26 * 27 * @short A simple high score implementation 28 * 29 * This class can be used both for displaying the current high scores 30 * and also for adding new highscores. It is the recommended way of 31 * implementing a simple highscore table. 32 * 33 * To display the current highscores it is simply a case of creating 34 * a KScoreDialog object and calling exec(). This example code will 35 * display the Name and Score (the score is always added automatically 36 * unless hidden @ref hideField since it is used for sorting) of the 37 * top 10 players: 38 * \code 39 * KScoreDialog ksdialog(this); 40 * ksdialog.exec(); 41 * \endcode 42 * 43 * To add a new highscore, e.g. at the end of a game you simply create an 44 * object with the @ref Fields you want to write (i.e. KScoreDialog::Name | 45 * KScoreDialog::Score), call addScore and then (optionally) display 46 * the dialog. 47 * This code will allow you to add a highscore with a Name and Score 48 * field. If it's the first time a player has a score on the table, they 49 * will be prompted for their name but subsequent times they will have 50 * their name filled in automatically. 51 * \code 52 * KScoreDialog ksdialog(this); 53 * ksdialog.addScore(playersScore); 54 * ksdialog.exec(); 55 * \endcode 56 * 57 * Or if you want to fill the name in from the code you can pass a default 58 * name by doing 59 * \code 60 * KScoreDialog::FieldInfo scoreInfo; 61 * scoreInfo[KScoreDialog::Name] = "Matt"; 62 * scoreInfo[KScoreDialog::Score].setNum(playersScore); 63 * ksdialog.addScore(scoreInfo); 64 * \endcode 65 * 66 * If you want to add an extra field (e.g. the number of moves taken) then 67 * do 68 * \code 69 * KScoreDialog::FieldInfo scoreInfo; 70 * scoreInfo[KScoreDialog::Name] = "Matt"; 71 * scoreInfo[KScoreDialog::Score].setNum(playersScore); 72 * 73 * ksdialog.addField(KScoreDialog::Custom1, "Num of Moves", "moves"); 74 * scoreInfo[KScoreDialog::Custom1].setNum(42); 75 * 76 * ksdialog.addScore(scoreInfo); 77 * \endcode 78 * You can define up to 5 Custom fields. 79 * @author Matt Williams <matt@milliams.com> 80 */ 81 class KDEGAMES_EXPORT KScoreDialog : public QDialog 82 { 83 Q_OBJECT 84 85 public: 86 ///Highscore fields 87 enum Fields { 88 Name = 1 << 0, 89 Level = 1 << 1, 90 Date = 1 << 2, 91 Time = 1 << 3, 92 Score = 1 << 4, 93 94 Custom1 = 1 << 10, ///<Field for custom information 95 Custom2 = 1 << 11, 96 Custom3 = 1 << 12, 97 Custom4 = 1 << 13, 98 Custom5 = 1 << 14, 99 100 Max = 1 << 30 ///<Only for setting a maximum 101 }; 102 103 ///Flags for setting preferences for adding scores 104 enum AddScoreFlag 105 { 106 AskName = 0x1, /**< Promt the player for their name */ 107 LessIsMore = 0x2 /**< A lower numerical score means higher placing on the table */ 108 }; 109 Q_DECLARE_FLAGS(AddScoreFlags, AddScoreFlag) 110 111 typedef QMap<int, QString> FieldInfo; 112 113 /** 114 * @param fields Bitwise OR of the @ref Fields that should be listed (Score is always present) 115 * @param parent passed to parent QWidget constructor. 116 */ 117 explicit KScoreDialog(int fields=Name, QWidget *parent=nullptr); 118 119 ~KScoreDialog() override; 120 121 #if KDEGAMES_ENABLE_DEPRECATED_SINCE(4, 1) 122 /** 123 * The group name must be passed though I18N_NOOP() in order for the 124 * group name to be translated. i.e. 125 * \code ksdialog.setConfigGroup(I18N_NOOP("Easy")); \endcode 126 * If you set a group, it will be prefixed in the config file by 127 * 'KHighscore_' otherwise the group will simply be 'KHighscore'. 128 * 129 * @param group to use for reading/writing highscores from/to. 130 * @deprecated Since 4.1, use setConfigGroup(const QPair<QByteArray, QString>&). 131 */ 132 KDEGAMES_DEPRECATED_VERSION(4, 1, "Use setConfigGroup(const QPair<QByteArray, QString>&)") 133 void setConfigGroup(const QString& group = QString()); 134 //void setConfigGroup(const QString& group, const QString& i18nName); 135 #endif 136 /** 137 * The group name must be passed though i18n() in order for the 138 * group name to be translated. i.e. 139 * \code ksdialog.setConfigGroup(qMakePair(QByteArray("Easy"), i18n("Easy"))); \endcode 140 * If you set a group, it will be prefixed in the config file by 141 * 'KHighscore_' otherwise the group will simply be 'KHighscore'. 142 * 143 * @param group to use for reading/writing highscores from/to. 144 */ 145 void setConfigGroup(const QPair<QByteArray, QString>& group); 146 147 /** 148 * You must add the translations of all group names to the dialog. This 149 * is best done by passing the name through i18n(). 150 * The group set through setConfigGroup(const QPair<QByteArray, QString>& group) 151 * will be added automatically 152 * 153 * @param group the translated group name 154 */ 155 void addLocalizedConfigGroupName(const QPair<QByteArray, QString>& group); 156 157 /** 158 * You must add the translations of all group names to the dialog. This 159 * is best done by passing the name through i18n(). 160 * The group set through setConfigGroup(const QPair<QByteArray, QString>& group) 161 * will be added automatically. 162 * 163 * This function can be used directly with KGameDifficulty::localizedLevelStrings(). 164 * 165 * @param groups the list of translated group names 166 */ 167 void addLocalizedConfigGroupNames(const QMap<QByteArray, QString>& groups); 168 169 /** 170 * Hide some config groups so that they are not shown on the dialog 171 * (but are still stored in the configuration file). 172 * \code 173 * ksdialog.setHiddenConfigGroups(QList<QByteArray>() << "Very Easy" << "Easy"); 174 * \endcode 175 * 176 * @param hiddenGroups the list of group names you want to hide 177 * 178 * @since KDE 4.6 179 */ 180 void setHiddenConfigGroups(const QList<QByteArray>& hiddenGroups); 181 182 /** 183 * It is a good idea giving config group weights, otherwise tabs 184 * get ordered by their tab name that is not probably what you want. 185 * 186 * This function can be used directly with KGameDifficulty::levelWeights(). 187 * 188 * @param weights the list of untranslated group weights 189 * 190 * @since KDE 4.2 191 */ 192 void setConfigGroupWeights(const QMap<int, QByteArray>& weights); 193 194 /** 195 * @param comment to add when showing high-scores. 196 * The comment is only used once. 197 */ 198 void setComment(const QString& comment); 199 200 /** 201 * Define an extra FieldInfo entry. 202 * @param field id of this field @ref Fields e.g. KScoreDialog::Custom1 203 * @param header text shown in the header in the dialog for this field. e.g. "Number of Moves" 204 * @param key unique key used to store this field. e.g. "moves" 205 */ 206 void addField(int field, const QString& header, const QString& key); 207 208 /** 209 * Hide a field so that it is not shown on the table (but is still stored in the configuration file). 210 * @param field id of this field @ref Fields e.g. KScoreDialog::Score 211 */ 212 void hideField(int field); 213 214 /** 215 * Adds a new score to the list. 216 * 217 * @param newInfo info about the score. 218 * @param flags set whether the user should be prompted for their name and how the scores should be sorted 219 * 220 * @returns The highscore position if the score was good enough to 221 * make it into the list (1 being topscore) or 0 otherwise. 222 */ 223 int addScore(const FieldInfo& newInfo = FieldInfo(), const AddScoreFlags& flags={}); 224 225 /** 226 * Convenience function for ease of use. 227 * 228 * @param newScore the score of the player. 229 * @param flags set whether the user should be prompted for their name and how the scores should be sorted 230 * 231 * @returns The highscore position if the score was good enough to 232 * make it into the list (1 being topscore) or 0 otherwise. 233 */ 234 int addScore(int newScore, const AddScoreFlags& flags={}); 235 236 /** 237 * @returns the current best score in the group 238 */ 239 int highScore(); 240 241 /** 242 * Assume that config groups (incl. current selection) are equal to 243 * difficulty levels, and initialize them. This is usually equal to the 244 * following code using KGameDifficulty: 245 * @code 246 * addLocalizedConfigGroupNames(KGameDifficulty::localizedLevelStrings()); 247 * setConfigGroupWeights(KGameDifficulty::levelWeights()); 248 * setConfigGroup(KGameDifficulty::localizedLevelString()); 249 * @endcode 250 */ 251 void initFromDifficulty(const KgDifficulty* difficulty, bool setConfigGroup = true); 252 253 ///Display the dialog as non-modal 254 virtual void show(); 255 ///Display the dialog as modal 256 int exec() override; 257 258 private Q_SLOTS: 259 void slotGotReturn(); 260 void slotGotName(); 261 void slotForgetScore(); 262 263 private: 264 void keyPressEvent(QKeyEvent *ev) override; 265 266 private: 267 friend class KScoreDialogPrivate; 268 std::unique_ptr<class KScoreDialogPrivate> const d; 269 }; 270 Q_DECLARE_OPERATORS_FOR_FLAGS(KScoreDialog::AddScoreFlags) 271 272 #endif //KSCOREDIALOG_H 273