|
1 <?php |
|
2 |
|
3 /** |
|
4 * Class for drawing progress bars in a vt100 console. |
|
5 * @author Dan Fuhry |
|
6 * @license Public domain |
|
7 */ |
|
8 |
|
9 class ProgressBar |
|
10 { |
|
11 /** |
|
12 * Shell escape character. |
|
13 * @const string |
|
14 */ |
|
15 |
|
16 const SHELL_ESCAPE = "\x1B"; |
|
17 |
|
18 /** |
|
19 * Carriage return (0x0D) |
|
20 * @const string |
|
21 */ |
|
22 |
|
23 const CARRIAGE_RETURN = "\r"; |
|
24 |
|
25 /** |
|
26 * Colors of the foreground, background, foreground text, and background text, respectively |
|
27 * @var int |
|
28 * @var int |
|
29 * @var int |
|
30 * @var int |
|
31 */ |
|
32 |
|
33 private $color_bar, $color_empty, $color_text, $color_emptytext; |
|
34 |
|
35 /** |
|
36 * Text to the left of the bar. |
|
37 * @var string |
|
38 */ |
|
39 |
|
40 private $bar_left; |
|
41 |
|
42 /** |
|
43 * Text to the right of the bar. |
|
44 * @var string |
|
45 */ |
|
46 |
|
47 private $bar_right; |
|
48 |
|
49 /** |
|
50 * Text in the middle of the bar. |
|
51 * @var string |
|
52 */ |
|
53 |
|
54 private $bar_text; |
|
55 |
|
56 /** |
|
57 * The current location of the bar in %. |
|
58 * @var int |
|
59 */ |
|
60 |
|
61 private $bar_pos = 0; |
|
62 |
|
63 /** |
|
64 * Position where the text should start. |
|
65 * @var int |
|
66 */ |
|
67 |
|
68 private $text_pos = 0; |
|
69 |
|
70 /** |
|
71 * Width of the current terminal. |
|
72 * @var int |
|
73 */ |
|
74 |
|
75 private $term_width = 80; |
|
76 |
|
77 /** |
|
78 * Width of the actual bar. |
|
79 * @var int |
|
80 */ |
|
81 |
|
82 private $bar_width = 0; |
|
83 |
|
84 /** |
|
85 * State of the bar's color. Used to avoid echoing tons of color codes. |
|
86 * @var int |
|
87 */ |
|
88 |
|
89 private $color_state = 0; |
|
90 |
|
91 /** |
|
92 * Color state constants |
|
93 * @const int |
|
94 * @const int |
|
95 * @const int |
|
96 * @const int |
|
97 * @const int |
|
98 */ |
|
99 |
|
100 const COLOR_STATE_RESET = 0; |
|
101 const COLOR_STATE_FULL_HIDE = 1; |
|
102 const COLOR_STATE_FULL_SHOW = 2; |
|
103 const COLOR_STATE_EMPTY_HIDE = 3; |
|
104 const COLOR_STATE_EMPTY_SHOW = 4; |
|
105 |
|
106 /** |
|
107 * Constructor. All parameters are optional. Color choices are defined in color_to_code. |
|
108 * @param string $bar_left |
|
109 * @param string $bar_right |
|
110 * @param string $bar_text |
|
111 * @param string $color_bar |
|
112 * @param string $color_empty |
|
113 * @param string $color_text |
|
114 * @param string $color_emptytext |
|
115 */ |
|
116 |
|
117 public function __construct($bar_left = '[', $bar_right = ']', $bar_text = '', $color_bar = 'red', $color_empty = 'black', $color_text = 'white', $color_emptytext = 'cyan') |
|
118 { |
|
119 $this->bar_left = $bar_left; |
|
120 $this->bar_right = $bar_right; |
|
121 $this->color_bar = $this->color_to_code($color_bar); |
|
122 $this->color_empty = $this->color_to_code($color_empty); |
|
123 $this->color_text = $this->color_to_code($color_text); |
|
124 $this->color_emptytext = $this->color_to_code($color_emptytext); |
|
125 |
|
126 if ( isset($_SERVER['COLUMNS']) ) |
|
127 { |
|
128 $this->term_width = intval($_SERVER['COLUMNS']); |
|
129 } |
|
130 $this->bar_width = $this->term_width - strlen($this->bar_left) - strlen($this->bar_right); |
|
131 |
|
132 $this->update_text_quiet($bar_text); |
|
133 } |
|
134 |
|
135 /** |
|
136 * Updates the text on the progress bar and recalculates the position without redrawing. |
|
137 * @param string Text in the bar. If omitted, blanked. |
|
138 */ |
|
139 |
|
140 public function update_text_quiet($bar_text = '') |
|
141 { |
|
142 $this->bar_text = strval($bar_text); |
|
143 |
|
144 if ( !empty($this->bar_text) ) |
|
145 { |
|
146 $this->text_pos = round(( $this->bar_width / 2 ) - ( strlen($this->bar_text) / 2 )); |
|
147 } |
|
148 } |
|
149 |
|
150 /** |
|
151 * Updates the text on the progress bar, recalculates the position, and redraws. |
|
152 * @param string Text in the bar. If omitted, blanked. |
|
153 */ |
|
154 |
|
155 function update_text($bar_text = '') |
|
156 { |
|
157 $this->update_text_quiet($bar_text); |
|
158 $this->set($this->bar_pos); |
|
159 } |
|
160 |
|
161 /** |
|
162 * Starts output of the bar. |
|
163 */ |
|
164 |
|
165 function start() |
|
166 { |
|
167 echo self::CARRIAGE_RETURN; |
|
168 echo $this->bar_left; |
|
169 } |
|
170 |
|
171 /** |
|
172 * Closes the bar. |
|
173 */ |
|
174 |
|
175 function end() |
|
176 { |
|
177 $this->set($this->bar_pos, $this->bar_width); |
|
178 echo "\n"; |
|
179 } |
|
180 |
|
181 /** |
|
182 * Sets the position of the bar. |
|
183 * @param int Position in %. If a second parameter is set, this is treated as a numerator with the second parameter being the denominator and that is used to calculate position. |
|
184 * @param int Optional. Total number of units to allow fraction usage instead of percentage. |
|
185 */ |
|
186 |
|
187 function set($pos, $max = 100) |
|
188 { |
|
189 // if our pos is higher than 100%, reduce it |
|
190 if ( $pos > $max ) |
|
191 $pos = $max; |
|
192 |
|
193 // arithmetic one-liner |
|
194 // this is where we should stop showing the "full" color and instead use "empty" |
|
195 $bar_pos = round($this->bar_width * ( $pos / $max )); |
|
196 $this->bar_pos = 100 * ( $pos / $max ); |
|
197 |
|
198 // reset the cursor |
|
199 echo self::CARRIAGE_RETURN . $this->bar_left; |
|
200 |
|
201 // print everything out |
|
202 for ( $i = 0; $i < $this->bar_width; $i++ ) |
|
203 { |
|
204 $char = ' '; |
|
205 $hide = true; |
|
206 if ( !empty($this->bar_text) ) |
|
207 { |
|
208 // we have some text to display in the middle; see where we are. |
|
209 $show_text = ( $i >= $this->text_pos && $i < ( $this->text_pos + strlen($this->bar_text) ) ); |
|
210 if ( $show_text ) |
|
211 { |
|
212 $char = substr($this->bar_text, $i - $this->text_pos, 1); |
|
213 if ( strlen($char) < 1 ) |
|
214 $char = ' '; |
|
215 else |
|
216 $hide = false; |
|
217 } |
|
218 } |
|
219 // determine color |
|
220 if ( $i > $bar_pos ) |
|
221 { |
|
222 $hide ? $this->set_color_empty_hide() : $this->set_color_empty_show(); |
|
223 } |
|
224 else |
|
225 { |
|
226 $hide ? $this->set_color_full_hide() : $this->set_color_full_show(); |
|
227 } |
|
228 echo $char; |
|
229 } |
|
230 $this->set_color_reset(); |
|
231 echo $this->bar_right; |
|
232 } |
|
233 |
|
234 # |
|
235 # PRIVATE METHODS |
|
236 # |
|
237 |
|
238 function set_color_full_hide() |
|
239 { |
|
240 if ( $this->color_state == self::COLOR_STATE_FULL_HIDE ) |
|
241 return; |
|
242 $this->color_state = self::COLOR_STATE_FULL_HIDE; |
|
243 |
|
244 $fgcolor = 30 + $this->color_bar; |
|
245 $bgcolor = $fgcolor + 10; |
|
246 echo self::SHELL_ESCAPE . "[0;{$fgcolor};{$bgcolor};8m"; |
|
247 } |
|
248 |
|
249 function set_color_full_show() |
|
250 { |
|
251 if ( $this->color_state == self::COLOR_STATE_FULL_SHOW ) |
|
252 return; |
|
253 $this->color_state = self::COLOR_STATE_FULL_SHOW; |
|
254 |
|
255 $fgcolor = 30 + $this->color_text; |
|
256 $bgcolor = 40 + $this->color_bar; |
|
257 echo self::SHELL_ESCAPE . "[0;1;{$fgcolor};{$bgcolor}m"; |
|
258 } |
|
259 |
|
260 function set_color_empty_hide() |
|
261 { |
|
262 if ( $this->color_state == self::COLOR_STATE_EMPTY_HIDE ) |
|
263 return; |
|
264 $this->color_state = self::COLOR_STATE_EMPTY_HIDE; |
|
265 |
|
266 $fgcolor = 30 + $this->color_empty; |
|
267 $bgcolor = $fgcolor + 10; |
|
268 echo self::SHELL_ESCAPE . "[0;{$fgcolor};{$bgcolor};8m"; |
|
269 } |
|
270 |
|
271 function set_color_empty_show() |
|
272 { |
|
273 if ( $this->color_state == self::COLOR_STATE_EMPTY_SHOW ) |
|
274 return; |
|
275 $this->color_state = self::COLOR_STATE_EMPTY_SHOW; |
|
276 |
|
277 $fgcolor = 30 + $this->color_emptytext; |
|
278 $bgcolor = 40 + $this->color_empty; |
|
279 echo self::SHELL_ESCAPE . "[0;1;{$fgcolor};{$bgcolor}m"; |
|
280 } |
|
281 |
|
282 function set_color_reset() |
|
283 { |
|
284 if ( $this->color_state == self::COLOR_STATE_RESET ) |
|
285 return; |
|
286 $this->color_state = self::COLOR_STATE_RESET; |
|
287 |
|
288 echo self::SHELL_ESCAPE . "[0m"; |
|
289 } |
|
290 |
|
291 /** |
|
292 * Converts a color name to an ASCII color code. Valid color names are black, red, green, yellow, blue, magenta, cyan, and white. |
|
293 * @param string Color name |
|
294 * @return int |
|
295 */ |
|
296 |
|
297 private function color_to_code($color) |
|
298 { |
|
299 static $colors = array( |
|
300 'black' => 0, |
|
301 'red' => 1, |
|
302 'green' => 2, |
|
303 'yellow' => 3, |
|
304 'blue' => 4, |
|
305 'magenta' => 5, |
|
306 'cyan' => 6, |
|
307 'white' => 7 |
|
308 ); |
|
309 return ( isset($colors[$color]) ) ? $colors[$color] : $colors['white']; |
|
310 } |
|
311 } |