1 /* 2 This file is part of Warzone 2100. 3 Copyright (C) 2020 Warzone 2100 Project 4 5 Warzone 2100 is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 Warzone 2100 is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with Warzone 2100; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 /** @file 20 * Interface to the initialisation routines. 21 */ 22 23 #ifndef __INCLUDED_SRC_NOTIFICATIONS_H__ 24 #define __INCLUDED_SRC_NOTIFICATIONS_H__ 25 26 #include <list> 27 #include <memory> 28 #include <functional> 29 #include <vector> 30 31 class WZ_Notification_Display_Options 32 { 33 public: 34 // The default WZ_Notification_Display_Options is useful for notifications 35 // that should _always_ be displayed. WZ_Notification_Display_Options()36 WZ_Notification_Display_Options() {} 37 38 public: 39 // Sets a specific notification identifier to "display once". 40 // 41 // Once a notification with this identifier is seen once, future calls to `addNotification` with a 42 // matching "uniqueNotificationIdentifier" will be ignored. 43 // The "seen" status is persisted across application runs. 44 // 45 // Specify a uniqueNotificationIdentifier that uniquely identifies this notification, and is used to 46 // match against future notifications. makeOneTime(const std::string & uniqueNotificationIdentifier)47 static WZ_Notification_Display_Options makeOneTime(const std::string& uniqueNotificationIdentifier) 48 { 49 WZ_Notification_Display_Options options; 50 options._uniqueNotificationIdentifier = uniqueNotificationIdentifier; 51 options._isOneTimeNotification = true; 52 return options; 53 } 54 55 // Sets a specific notification identifier as "ignorable". 56 // 57 // This will cause a "Do Not Show Again" checkbox / option to be displayed after this 58 // uniquely identified notification is displayed `numTimesSeenBeforeDoNotShowAgainOption` 59 // times. (Prior instances of this notification will offer a "Dismiss" or "Not Now" option.) 60 // 61 // If the user selects / checks the "Do Not Show Again" option, future calls to 62 // `addNotification` with a matching "uniqueNotificationIdentifier" will be ignored. 63 // The display count / ignore state is persisted across application runs. 64 // 65 // Specify a uniqueNotificationIdentifier that uniquely identifies this notification, and is used to 66 // match against future notifications. 67 static WZ_Notification_Display_Options makeIgnorable(const std::string& uniqueNotificationIdentifier, uint8_t numTimesSeenBeforeDoNotShowAgainOption = 0) 68 { 69 WZ_Notification_Display_Options options; 70 options._uniqueNotificationIdentifier = uniqueNotificationIdentifier; 71 options._numTimesSeenBeforeDoNotShowAgainOption = numTimesSeenBeforeDoNotShowAgainOption; 72 return options; 73 } 74 public: uniqueNotificationIdentifier()75 const std::string& uniqueNotificationIdentifier() const { return _uniqueNotificationIdentifier; } numTimesSeenBeforeDoNotShowAgainOption()76 uint8_t numTimesSeenBeforeDoNotShowAgainOption() const { return _numTimesSeenBeforeDoNotShowAgainOption; } isOneTimeNotification()77 bool isOneTimeNotification() const { return _isOneTimeNotification; } 78 79 private: 80 // A string that uniquely identifies the notification 81 // (to match against future notifications) 82 std::string _uniqueNotificationIdentifier; 83 84 // The number of times this identified notification can be displayed 85 // before the "Do Not Show Again" option is offered 86 uint8_t _numTimesSeenBeforeDoNotShowAgainOption = 0; 87 88 bool _isOneTimeNotification = false; 89 }; 90 91 class WZ_Notification_Image 92 { 93 public: 94 enum class ImageType { 95 PNG 96 }; 97 public: WZ_Notification_Image()98 WZ_Notification_Image() 99 : _type(ImageType::PNG) 100 { } 101 102 explicit WZ_Notification_Image(const char* imagePath, const ImageType& imageType = ImageType::PNG) _imagePath(imagePath)103 : _imagePath(imagePath) 104 , _type(imageType) 105 { } 106 explicit WZ_Notification_Image(const std::string& imagePath, const ImageType& imageType = ImageType::PNG) _imagePath(imagePath)107 : _imagePath(imagePath) 108 , _type(imageType) 109 { } 110 explicit WZ_Notification_Image(const std::vector<unsigned char>& memoryBuffer, const ImageType& imageType = ImageType::PNG) _memoryBuffer(memoryBuffer)111 : _memoryBuffer(memoryBuffer) 112 , _type(imageType) 113 { } 114 public: empty()115 bool empty() const 116 { 117 return _imagePath.empty() && _memoryBuffer.empty(); 118 } imagePath()119 const std::string& imagePath() const { return _imagePath; } memoryBuffer()120 const std::vector<unsigned char>& memoryBuffer() const { return _memoryBuffer; } imageType()121 ImageType imageType() const { return _type; } 122 private: 123 std::string _imagePath; 124 std::vector<unsigned char> _memoryBuffer; 125 ImageType _type; 126 }; 127 128 class WZ_Notification; // forward-declare 129 130 class WZ_Notification_Action 131 { 132 public: WZ_Notification_Action()133 WZ_Notification_Action() {} WZ_Notification_Action(std::string actionTitle,const std::function<void (const WZ_Notification &)> & onAction)134 WZ_Notification_Action(std::string actionTitle, const std::function<void (const WZ_Notification&)>& onAction) 135 : title(actionTitle) 136 , onAction(onAction) 137 { } 138 public: 139 std::string title; 140 std::function<void (WZ_Notification&)> onAction; 141 }; 142 143 enum class WZ_Notification_Dismissal_Reason { 144 // the user pressed the "Dismiss" button (or dragged the notification upwards) 145 USER_DISMISSED, 146 // the notification was dismissed because the "Action" button was pressed 147 ACTION_BUTTON_CLICK, 148 // the notification was cancelled or dismissed by one of the `cancelOrDismissNotification*()` functions (or similar) 149 PROGRAMMATIC 150 }; 151 152 class WZ_Notification 153 { 154 public: 155 // [Required properties]: 156 157 // A title for the top of the notification - REQUIRED 158 std::string contentTitle; 159 // Content text for the notification - REQUIRED 160 std::string contentText; 161 // A duration, in game ticks (see: GAME_TICKS_PER_SEC), 162 // for the notification to be displayed before it auto-dismisses. 163 // 164 // Set to 0 for "until dismissed by user". 165 // 166 // Do not set this interval too short or users may not be able to 167 // read the text before the notification disappears! 168 uint32_t duration = 0; 169 170 // [Optional properties]: 171 172 // A PNG to be displayed on the right side of the notification. 173 // (Suggestion: Make sure the PNG is *at least* 72x72 pixels to ensure sharper display on higher resolution screens.) 174 WZ_Notification_Image largeIcon; 175 176 // Displays an Action button on the notification which calls the handler when clicked. 177 WZ_Notification_Action action; 178 // See: WZ_Notification_Display_Options 179 WZ_Notification_Display_Options displayOptions; 180 // An optional string tag that can be filtered on to cancel / dismiss existing notifications 181 // Multiple notifications can share the same tag, if they ought to be "grouped" for this purpose 182 std::string tag; 183 // Called when the notification is initially (fully) displayed 184 std::function<void (const WZ_Notification&)> onDisplay; 185 // Called when the notification is dismissed / closed 186 // see: `WZ_Notification_Dismissal_Reason` 187 std::function<void (const WZ_Notification&, WZ_Notification_Dismissal_Reason reason)> onDismissed; 188 // Called if an ignorable notification is ignored / not displayed 189 std::function<void (const WZ_Notification&)> onIgnored; 190 public: isIgnorable()191 bool isIgnorable() const { return !displayOptions.uniqueNotificationIdentifier().empty(); } 192 }; 193 194 class WZ_Notification_Trigger 195 { 196 public: 197 // A time interval, in game ticks (see: GAME_TICKS_PER_SEC), 198 // from the time the notification is submitted before it is displayed. WZ_Notification_Trigger(uint32_t timeInterval)199 WZ_Notification_Trigger(uint32_t timeInterval) 200 : timeInterval(timeInterval) 201 { } 202 203 // Can be displayed immediately. Immediate()204 static WZ_Notification_Trigger Immediate() 205 { 206 return WZ_Notification_Trigger(0); 207 } 208 public: 209 uint32_t timeInterval = 0; 210 }; 211 212 // Add a notification 213 // - must be called from the main thread 214 void addNotification(const WZ_Notification& notification, const WZ_Notification_Trigger& trigger); 215 216 // Remove notification preferences by unique notification identifier 217 // - must be called from the main thread 218 bool removeNotificationPreferencesIf(const std::function<bool (const std::string& uniqueNotificationIdentifier)>& matchIdentifierFunc); 219 220 enum class NotificationScope { 221 DISPLAYED_ONLY, 222 QUEUED_ONLY, 223 DISPLAYED_AND_QUEUED 224 }; 225 226 // Whether one or more notifications with the specified tag (exact match) are currently-displayed or queued 227 // If `scope` is `DISPLAYED_ONLY`, only currently-displayed notifications will be processed 228 // If `scope` is `QUEUED_ONLY`, only queued notifications will be processed 229 bool hasNotificationsWithTag(const std::string& tag, NotificationScope scope = NotificationScope::DISPLAYED_AND_QUEUED); 230 231 // Cancel or dismiss existing notifications by tag (exact match) 232 // If `scope` is `DISPLAYED_ONLY`, only currently-displayed notifications will be processed 233 // If `scope` is `QUEUED_ONLY`, only queued notifications will be processed 234 // 235 // Returns: `true` if one or more notifications were cancelled or dismissed 236 bool cancelOrDismissNotificationsWithTag(const std::string& tag, NotificationScope scope = NotificationScope::DISPLAYED_AND_QUEUED); 237 238 // Cancel or dismiss existing notifications by tag 239 // Accepts a `matchTagFunc` that receives each (queued / currently-displayed) notification's tag, 240 // and returns "true" if it should be cancelled or dismissed (if queued / currently-displayed) 241 // If `scope` is `DISPLAYED_ONLY`, only currently-displayed notifications will be processed 242 // If `scope` is `QUEUED_ONLY`, only queued notifications will be processed 243 // 244 // Returns: `true` if one or more notifications were cancelled or dismissed 245 bool cancelOrDismissNotificationIfTag(const std::function<bool (const std::string& tag)>& matchTagFunc, NotificationScope scope = NotificationScope::DISPLAYED_AND_QUEUED); 246 247 // In-Game Notifications System 248 bool notificationsInitialize(); 249 void notificationsShutDown(); 250 void runNotifications(); 251 bool isDraggingInGameNotification(); 252 253 #endif // __INCLUDED_SRC_NOTIFICATIONS_H__ 254