1 // Copyright (c) 2017 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.sdl2.sdl : DerelictSDL2, SharedLibVersion, SharedLibLoadException; 79 try { 80 DerelictSDL2.load(SharedLibVersion(2, 0, 2)); 81 is_sdl2_loadable = true; 82 stdout.writefln("SDL was found ..."); 83 } catch (SharedLibLoadException) { 84 stdout.writefln("SDL was NOT found ..."); 85 } 86 } 87 } 88 89 /++ 90 This should be called once at the start of a program. It generates the proper 91 main function for your environment (win32/posix/dmain) and boot straps the 92 main loop for the GUI. This will call your UIAppMain function when ready. 93 +/ 94 mixin template RUN_MAIN() { 95 version (unittest) { } else { 96 // On Windows use the normal dlangui main 97 version (Windows) { 98 import dlangui; 99 mixin APP_ENTRY_POINT; 100 // On Linux use a custom main that checks if SDL is installed 101 } else { 102 int main(string[] args) { 103 import progress_dialog : is_sdl2_loadable; 104 // If SDL2 can be loaded, start the SDL2 main 105 if (is_sdl2_loadable) { 106 import dlangui.platforms.sdl.sdlapp : sdlmain; 107 return sdlmain(args); 108 // If not, use the normal main provided by the user 109 } else { 110 return UIAppMain(args); 111 } 112 } 113 } 114 } 115 } 116 117 /++ 118 If true will print output of external program to console. 119 Params: 120 is_logging = If true will print to output 121 +/ 122 public void setUseLog(bool is_logging) { 123 use_log = is_logging; 124 } 125 126 /++ 127 Returns if external program logging is on or off. 128 +/ 129 public bool getUseLog() { 130 return use_log; 131 } 132 133 abstract class ProgressDialogBase { 134 this(string title, string message) { 135 _title = title; 136 _message = message; 137 } 138 139 void onError(void delegate(Throwable err) cb) { 140 _on_error_cb = cb; 141 } 142 143 void fireOnError(Throwable err) { 144 auto old_cb = _on_error_cb; 145 _on_error_cb = null; 146 147 if (old_cb) old_cb(err); 148 } 149 150 void show(void delegate() cb); 151 void setPercent(int percent); 152 void close(); 153 154 string _title; 155 string _message; 156 void delegate(Throwable err) _on_error_cb; 157 } 158 159 /++ 160 The ProgressDialog class 161 +/ 162 class ProgressDialog { 163 import progress_dialog_zenity : ProgressDialogZenity; 164 import progress_dialog_kdialog : ProgressDialogKDialog; 165 //import progress_dialog_win32 : ProgressDialogWin32; 166 import progress_dialog_dlangui : ProgressDialogDlangUI; 167 168 /++ 169 Sets up the progress dialog with the desired title, and message. Does not 170 show it until the show method is called. 171 Params: 172 title = The string to show in the progress dialog title 173 message = The string to show in the progress dialog body 174 Throws: 175 If it fails to find any programs or libraries to make a progress dialog with. 176 +/ 177 this(string title, string message) { 178 /*if (ProgressDialogWin32.isSupported()) { 179 _dialog = new ProgressDialogWin32(title, message); 180 } else */ 181 182 if (ProgressDialogDlangUI.isSupported()) { 183 _dialog = new ProgressDialogDlangUI(title, message); 184 } else if (ProgressDialogZenity.isSupported()) { 185 _dialog = new ProgressDialogZenity(title, message); 186 } else if (ProgressDialogKDialog.isSupported()) { 187 _dialog = new ProgressDialogKDialog(title, message); 188 } else { 189 throw new Exception("Failed to find a way to make a progress dialog."); 190 } 191 } 192 193 /++ 194 This method is called if there is an error when showing the progress dialog. 195 Params: 196 cb = The call back to fire when there is an error. 197 +/ 198 void onError(void delegate(Throwable err) cb) { 199 _dialog._on_error_cb = cb; 200 } 201 202 /++ 203 Shows the progress dialog. Will run the callback in a thread and 204 block until it is closed or percent reaches 100. 205 +/ 206 void show(void delegate() cb) { 207 _dialog.show(cb); 208 } 209 210 /++ 211 Set the percent of the progess bar. Will close on 100. 212 Params: 213 percent = from 0 to 100 214 +/ 215 void setPercent(int percent) { 216 _dialog.setPercent(percent); 217 } 218 219 /++ 220 Close the dialog. 221 +/ 222 void close() { 223 _dialog.close(); 224 } 225 226 ProgressDialogBase _dialog; 227 }