1 // Copyright (c) 2017-2018 Matthew Brennan Jones <matthew.brennan.jones@gmail.com> 2 // Boost Software License - Version 1.0 3 // A simple message box for the D programming language 4 // https://github.com/workhorsy/d-message-box 5 6 7 /++ 8 A simple message box for the D programming language 9 10 It should work without requiring any 3rd party GUI toolkits. But will work with what 11 it can find on your OS at runtime. 12 13 It tries to use the following: 14 15 * DlangUI (win32 on Windows or SDL2 on Linux) 16 17 * SDL_ShowSimpleMessageBox (Derelict SDL2) 18 19 * MessageBoxW (Windows) 20 21 * Zenity (Gtk/Gnome) 22 23 * Kdialog (KDE) 24 25 * gxmessage (X11) 26 27 Home page: 28 $(LINK https://github.com/workhorsy/d-message-box) 29 30 Version: 0.3.0 31 32 License: 33 Boost Software License - Version 1.0 34 35 Examples: 36 ---- 37 import std.stdio : stdout, stderr; 38 import message_box : MessageBox, IconType, RUN_MAIN; 39 40 mixin RUN_MAIN; 41 42 extern (C) int UIAppMain(string[] args) { 43 // Create the message box 44 auto dialog = new MessageBox("Party Time", "The roof is on fire!", IconType.Warning); 45 46 // Set the error handler 47 dialog.onError((Throwable err) { 48 stderr.writefln("Failed to show message box: %s", err); 49 }); 50 51 // Show the message box 52 dialog.show(); 53 54 return 0; 55 } 56 ---- 57 +/ 58 59 module message_box; 60 61 bool is_sdl2_loadable = false; 62 bool use_log = false; 63 64 static this() { 65 import std.stdio : stdout; 66 67 // Figure out if the SDL2 libraries can be loaded 68 version (Have_derelict_sdl2) { 69 import derelict.util.exception : SharedLibLoadException; 70 import derelict.sdl2.sdl : DerelictSDL2, SharedLibVersion; 71 try { 72 DerelictSDL2.load(SharedLibVersion(2, 0, 2)); 73 is_sdl2_loadable = true; 74 stdout.writefln("SDL was found ..."); 75 } catch (SharedLibLoadException) { 76 stdout.writefln("SDL was NOT found ..."); 77 } 78 } 79 } 80 81 /++ 82 This should be called once at the start of a program. It generates the proper 83 main function for your environment (win32/posix/dmain) and boot straps the 84 main loop for the GUI. This will call your UIAppMain function when ready. 85 +/ 86 mixin template RUN_MAIN() { 87 version (unittest) { } else { 88 // On Windows use the normal dlangui main 89 version (Windows) { 90 import dlangui; 91 mixin APP_ENTRY_POINT; 92 // On Linux use a custom main that checks if SDL is installed 93 } else { 94 int main(string[] args) { 95 import message_box : is_sdl2_loadable; 96 // If SDL2 can be loaded, start the SDL2 main 97 if (is_sdl2_loadable) { 98 import dlangui.platforms.sdl.sdlapp : sdlmain; 99 return sdlmain(args); 100 // If not, use the normal main provided by the user 101 } else { 102 return UIAppMain(args); 103 } 104 } 105 } 106 } 107 } 108 109 110 /++ 111 If true will print output of external program to console. 112 Params: 113 is_logging = If true will print to output 114 +/ 115 public void setUseLog(bool is_logging) { 116 use_log = is_logging; 117 } 118 119 /++ 120 Returns if external program logging is on or off. 121 +/ 122 public bool getUseLog() { 123 return use_log; 124 } 125 126 /++ 127 The type of icon to show in the message box. Some message boxes will not show 128 the icon. 129 130 ---- 131 enum IconType { 132 None, 133 Information, 134 Error, 135 Warning, 136 } 137 ---- 138 +/ 139 140 enum IconType { 141 None, 142 Information, 143 Error, 144 Warning, 145 } 146 147 abstract class MessageBoxBase { 148 this(string title, string message, IconType icon_type) { 149 _title = title; 150 _message = message; 151 _icon_type = icon_type; 152 } 153 154 void onError(void delegate(Throwable err) cb) { 155 _on_error_cb = cb; 156 } 157 158 void fireOnError(Throwable err) { 159 auto old_cb = _on_error_cb; 160 _on_error_cb = null; 161 162 if (old_cb) old_cb(err); 163 } 164 165 void show(); 166 167 string _title; 168 string _message; 169 IconType _icon_type; 170 void delegate(Throwable err) _on_error_cb; 171 } 172 173 /++ 174 The MessageBox class 175 +/ 176 class MessageBox { 177 import message_box_dlangui : MessageBoxDlangUI; 178 import message_box_sdl : MessageBoxSDL; 179 import message_box_win32 : MessageBoxWin32; 180 import message_box_zenity : MessageBoxZenity; 181 import message_box_kdialog : MessageBoxKdialog; 182 import message_box_gxmessage : MessageBoxGxmessage; 183 184 /++ 185 Sets up the message box with the desired title, message, and icon. Does not 186 show it until the show method is called. 187 Params: 188 title = The string to show in the message box title 189 message = The string to show in the message box body 190 icon = The type of icon to show in the message box 191 Throws: 192 If it fails to find any programs or libraries to make a message box with. 193 +/ 194 this(string title, string message, IconType icon_type) { 195 if (MessageBoxDlangUI.isSupported()) { 196 _dialog = new MessageBoxDlangUI(title, message, icon_type); 197 } else if (MessageBoxSDL.isSupported()) { 198 _dialog = new MessageBoxSDL(title, message, icon_type); 199 } else if (MessageBoxWin32.isSupported()) { 200 _dialog = new MessageBoxWin32(title, message, icon_type); 201 } else if (MessageBoxZenity.isSupported()) { 202 _dialog = new MessageBoxZenity(title, message, icon_type); 203 } else if (MessageBoxKdialog.isSupported()) { 204 _dialog = new MessageBoxKdialog(title, message, icon_type); 205 } else if (MessageBoxGxmessage.isSupported()) { 206 _dialog = new MessageBoxGxmessage(title, message, icon_type); 207 } else { 208 throw new Exception("Failed to find a way to make a message box."); 209 } 210 } 211 212 /++ 213 This method is called if there is an error when showing the message box. 214 Params: 215 cb = The call back to fire when there is an error. 216 +/ 217 void onError(void delegate(Throwable err) cb) { 218 _dialog._on_error_cb = cb; 219 } 220 221 /++ 222 Shows the message box. Will block until it is closed. 223 +/ 224 void show() { 225 _dialog.show(); 226 } 227 228 MessageBoxBase _dialog; 229 }