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