1 #ifndef _melder_progress_h_
2 #define _melder_progress_h_
3 /* melder_progress.h
4  *
5  * Copyright (C) 1992-2018,2020 Paul Boersma
6  *
7  * This code is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or (at
10  * your option) any later version.
11  *
12  * This code is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15  * See the GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this work. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 /*
22 	SYNOPSIS
23 
24 	Melder_progress (double progress, messageArgs...);
25 
26 		Function:
27 			Show the progress of a time-consuming process.
28 		Arguments:
29 			Any of 'args' may be null.
30 		Batch behaviour:
31 			Does nothing, always returns 1.
32 		Interactive behaviour:
33 			Shows the progress of a time-consuming process:
34 			- if 'progress' <= 0.0, show a window with text and a Cancel button, and return 1;
35 			- if 0.0 < 'progress' < 1.0, show text and a partially filled progress bar,
36 			  and return 0 if user interrupts, else return 1;
37 			- if 'progress' >= 1, hide the window.
38 		Usage:
39 			- call with 'progress' = 0.0 before the process starts:
40 				  (void) Melder_progress (0.0, U"Starting work...");
41 			- at every turn in your loop, call with 'progress' between 0.0 and 1.0:
42 				  Melder_progress (i / (n + 1.0), U"Working on part ", i, U" out of ", n, U"...");
43 			  an exception is thrown if the user clicks Cancel; if you don't want that, catch it:
44 				  try {
45 					  Melder_progress (i / (n + 1.0), U"Working on part ", i, U" out of ", n, U"...");
46 				  } catch (MelderError) {
47 					  Melder_clearError ();
48 					  break;
49 				  }
50 			- after the process has finished, call with 'progress' = 1.0:
51 				  (void) Melder_progress (1.0);
52 			- the first and third steps can be automated by autoMelderProgress:
53 				  autoMelderProgress progress (U"Starting work...");
54 
55 	void* Melder_monitor (double progress, messageArgs...);
56 
57 		Function:
58 			Show the progress of a time-consuming process.
59 		Arguments:
60 			Any of 'args' may be null.
61 		Batch behaviour:
62 			Does nothing, returns null if 'progress' <= 0.0 and a non-null pointer otherwise.
63 		Interactive behaviour:
64 			Shows the progress of a time-consuming process:
65 			- if 'progress' <= 0.0, show a window with text and a Cancel button and
66 			  room for a square drawing, and return a Graphics;
67 			- if 0.0 < 'progress' < 1.0, show text and a partially filled progress bar,
68 			  and return nullptr if user interrupts, else return a non-null pointer;
69 			- if 'progress' >= 1, hide the window.
70 		Usage:
71 			- call with 'progress' = 0.0 before the process starts.
72 			- assign the return value to a Graphics:
73 				  Graphics graphics = Melder_monitor (0.0, U"Starting work...");
74 			- at every turn of your loop, draw something in the Graphics:
75 				  if (graphics) {   // always check; might be batch
76 					  Graphics_beginMovieFrame (graphics, & Melder_WHITE);   // the colour only if you erase all every time
77 					  Graphics_polyline (graphics, ...);
78 					  Graphics_text (graphics, ...);
79 					  Graphics_endMovieFrame (graphics, 0.0);
80 				  }
81 			- immediately after this in your loop, call with 'progress' between 0.0 and 1.0:
82 				  Melder_monitor (i / (n + 1.0), U"Working on part ", i, U" out of ", n, U"...");
83 			  an exception is thrown if the user clicks Cancel; if you don't want that, catch it:
84 				  try {
85 					  Melder_monitor (i / (n + 1.0), U"Working on part ", i, U" out of ", n, U"...");
86 				  } catch (MelderError) {
87 					  Melder_clearError ();
88 					  break;
89 				  }
90 			- after the process has finished, call with 'progress' = 1.0:
91 				  (void) Melder_monitor (1.0, nullptr);
92 			- showing and hiding can be automated by autoMelderMonitor:
93 				  autoMelderMonitor monitor ("Starting work...");
94 				  if (monitor.graphics()) {   // always check; might be batch
95 					  Graphics_beginMovieFrame (graphics, & Melder_WHITE);   // the colour only if you erase all every time
96 					  Graphics_polyline (monitor.graphics(), ...);
97 					  Graphics_text (monitor.graphics(), ...);
98 					  Graphics_endMovieFrame (graphics, 0.0);
99 				  }
100 */
101 
102 namespace MelderProgress {
103 	extern int _depth;
104 	using ProgressProc = void (*) (double progress, conststring32 message);
105 	using MonitorProc = void * (*) (double progress, conststring32 message);
106 	extern ProgressProc _p_progressProc;
107 	extern MonitorProc _p_monitorProc;
108 	void _doProgress (double progress, conststring32 message);
109 	void * _doMonitor (double progress, conststring32 message);
110 	extern MelderString _buffer;
111 }
112 
113 void Melder_progressOff ();
114 void Melder_progressOn ();
115 
Melder_progress(double progress)116 inline void Melder_progress (double progress) {
117 	MelderProgress::_doProgress (progress, U"");
118 }
119 template <typename... Args>
Melder_progress(double progress,const MelderArg & first,Args...rest)120 void Melder_progress (double progress, const MelderArg& first, Args... rest) {
121 	MelderString_copy (& MelderProgress::_buffer, first, rest...);
122 	MelderProgress::_doProgress (progress, MelderProgress::_buffer.string);
123 }
124 class autoMelderProgress {
125 public:
autoMelderProgress(conststring32 message)126 	autoMelderProgress (conststring32 message) {
127 		Melder_progress (0.0, message);
128 	}
~autoMelderProgress()129 	~autoMelderProgress () {
130 		Melder_progress (1.0);
131 	}
132 };
133 
Melder_monitor(double progress)134 inline void * Melder_monitor (double progress) {
135 	return MelderProgress::_doMonitor (progress, U"");
136 }
137 template <typename... Args>
Melder_monitor(double progress,const MelderArg & first,Args...rest)138 void * Melder_monitor (double progress, const MelderArg& first, Args... rest) {
139 	MelderString_copy (& MelderProgress::_buffer, first, rest...);
140 	return MelderProgress::_doMonitor (progress, MelderProgress::_buffer.string);
141 }
142 
143 typedef class structGraphics *Graphics;
144 class autoMelderMonitor {
145 	Graphics _graphics;
146 public:
autoMelderMonitor(conststring32 message)147 	autoMelderMonitor (conststring32 message) {
148 		our _graphics = (Graphics) Melder_monitor (0.0, message);
149 	}
~autoMelderMonitor()150 	~autoMelderMonitor () {
151 		Melder_monitor (1.0);
152 	}
graphics()153 	Graphics graphics () { return _graphics; }
154 };
155 
156 struct autoMelderProgressOff {
autoMelderProgressOffautoMelderProgressOff157 	autoMelderProgressOff () {
158 		Melder_progressOff ();
159 	}
~autoMelderProgressOffautoMelderProgressOff160 	~autoMelderProgressOff () {
161 		Melder_progressOn ();
162 	}
163 };
164 
165 void Melder_setProgressProc (MelderProgress::ProgressProc p_proc);
166 void Melder_setMonitorProc  (MelderProgress::MonitorProc  p_proc);
167 
168 /* End of file melder_progress.h */
169 #endif
170