Update changelog
[Ale.git] / ui / ui_tty.h
blob84313a081bd07d31ee96f24a9b035c67f7178fda
1 // Copyright 2004 David Hilvert <dhilvert@auricle.dyndns.org>,
2 // <dhilvert@ugcs.caltech.edu>
4 /* This file is part of the Anti-Lamenessing Engine.
6 The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 The Anti-Lamenessing Engine is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with the Anti-Lamenessing Engine; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #ifndef __ui_tty_h__
22 #define __ui_tty_h__
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
29 #include "../d2.h"
30 #include "ui.h"
31 #include "util.h"
34 * TTY user interface
37 class ui_tty : public ui {
38 private:
39 int terminal_width;
40 char *buffer;
41 int buffer_index;
42 int status_index;
44 void clear_buffer() {
45 buffer[0] = '\0';
46 buffer_index = 0;
49 void write_buffer() {
50 if (buffer_index < 0)
51 return;
52 fputc('\r', ui_stream);
53 fputs(buffer, ui_stream);
54 status_index = buffer_index;
57 void status_clear() {
58 while (status_index < terminal_width) {
59 status_index++;
60 fprintf(ui_stream, " ");
64 void line_clear() {
65 fputc('\r', ui_stream);
66 for (int i = 0; i < terminal_width; i++) {
67 fprintf(ui_stream, " ");
72 void status_printf(int count, ...) {
74 if (buffer_index < 0)
75 return;
77 int n;
79 char *local_buffer = (char *) calloc(terminal_width - status_index, sizeof(char));
81 assert(local_buffer);
83 if (!local_buffer)
84 return;
86 for (int i = 0; i < count; i++) {
87 char *format = NULL;
88 va_list ap;
90 va_start(ap, count);
92 for (int arg = 0; arg < i + 1; arg++)
93 format = va_arg(ap, char *);
94 for (int arg = i + 1; arg < count; arg++)
95 va_arg(ap, char *);
97 assert (format);
99 n = vsnprintf(local_buffer, terminal_width - status_index, format, ap);
100 va_end(ap);
102 if (n < 0 || n > terminal_width - status_index - 1)
103 continue;
105 fputs(local_buffer, ui_stream);
107 status_index += n;
109 free(local_buffer);
111 return;
115 * If we reach this point, then there was no valid string produced.
118 status_clear();
120 free(local_buffer);
123 void pad_align_status() {
124 for (int i = 0; i < status.steps - status.steps_completed; i++) {
125 status_printf(1, " ");
128 void pad_match_status() {
129 status_printf(1, " ");
132 void write_match_status() {
133 status_printf(1, format_string_working(), status.match_value);
136 void write_status() {
138 if (status.code == status.UNDEFINED
139 || status.code == status.FRAME_DONE
140 || status.code == status.SET_DONE
141 || status.code == status.IP_STEP_DONE) {
142 status_clear();
143 return;
146 if (status.code == status.ALIGN
147 || status.code == status.POSTMATCH
148 || status.code == status.EXPOSURE_PASS_2) {
149 pad_align_status();
150 write_match_status();
153 status_printf(1, " | ");
155 switch (status.code) {
156 case status_type::LOAD_FILE:
157 status_printf(3, "Loading Image", "Loading", "load");
158 break;
159 case status_type::EXPOSURE_PASS_1:
160 status_printf(3, "Registering exposure (first pass)", "Registering exposure", "regexp1");
161 break;
162 case status_type::LODCLUSTER_CREATE:
163 status_printf(3, "Creating LOD cluster, scale %f", "Creating LOD clusters", "lodcluster",
164 pow(2, -status.align_lod));
165 break;
166 case status_type::PREMATCH:
167 status_printf(3, "Calculating pre-alignment match", "Calculating match", "prematch");
168 break;
169 case status_type::ALIGN:
170 status_printf(5, "Aligning [perturb=%f] [lod=%f] [mc=%f] [exp_mult=%f %f %f]",
171 "Aligning [perturb=%f] [lod=%f] [mc=%f]",
172 "Aligning [perturb=%f] [lod=%f]",
173 "Aligning...",
174 "align",
175 status.perturb_size,
176 pow(2, -status.align_lod),
177 status.mc,
178 status.exp_multiplier[0],
179 status.exp_multiplier[1],
180 status.exp_multiplier[2]);
181 break;
182 case status_type::POSTMATCH:
183 status_printf(3, "Calculating post-alignment match", "Calculating match", "postmatch");
184 break;
185 case status_type::EXPOSURE_PASS_2:
186 status_printf(3, "Registering exposure (second pass)", "Registering exposure", "regexp2");
187 break;
188 case status_type::RENDERA:
189 status_printf(3, "Rendering alignment reference image", "Rendering", "render-a");
190 break;
191 case status_type::RENDERD:
192 status_printf(3, "Rendering default chain", "Rendering", "render-d");
193 break;
194 case status_type::RENDERO:
195 status_printf(3, "Rendering chain %d", "Rendering", "render-o%d", status.onum);
196 break;
197 case status_type::WRITED:
198 status_printf(4, "Writing default chain to '%s'",
199 "Writing '%s'", "Writing", "write-d", d2::image_rw::output_name());
200 break;
201 case status_type::WRITEO:
202 status_printf(3, "Writing image for chain %d", "Writing", "write-o%d", status.onum);
203 break;
204 case status_type::IP_RENDER:
205 status_printf(2, /* "Processing frame '%s'%s", */ "Processing frame '%s'", "Processing",
206 d2::image_rw::name(status.frame_num), status.irani_peleg_stage
207 ? ((status.irani_peleg_stage == 1) ? " [simulate]" : " [backproject]")
208 : "");
209 break;
210 case status_type::IP_UPDATE:
211 status_printf(3, "Updating approximation", "Updating", "update");
212 break;
213 case status_type::IP_WRITE:
214 status_printf(3, "Writing '%s'", "Writing", "write", d2::image_rw::output_name());
215 break;
216 case status_type::D3_CONTROL_POINT_SOLVE:
217 status_printf(1, "Aligning control points, %f%% done, error=%f",
218 log(status.cp_cur_perturb / status.cp_max_perturb)
219 / log(status.cp_min_perturb / status.cp_max_perturb),
220 status.cp_cur_error);
221 break;
222 case status_type::D3_SUBDIVIDING_SPACE:
223 status_printf(2, "Subdividing space, frame pair (%u, %u), y=%u, x=%u, spaces=%u",
224 "Subdividing space", status.frame_num,
225 status.secondary_frame_num, status.y_coordinate, status.x_coordinate,
226 status.total_spaces);
227 break;
228 case status_type::D3_UPDATING_OCCUPANCY:
229 status_printf(2, "Updating occupancy, step %u/%u, frame %u, space %u/%u",
230 "Updating occupancy", status.steps_completed,
231 status.steps, status.frame_num,
232 status.space_num, status.total_spaces);
233 break;
234 case status_type::D3_RENDER:
235 if (status.filtering == 0 && status.focusing == 0) {
236 status_printf(1, "space %u/%u",
237 status.space_num, status.total_spaces);
238 } else if (status.filtering == 1 && status.focusing == 0) {
239 status_printf(1, "frame %u, y=%u, x=%u",
240 status.frame_num, status.y_coordinate, status.x_coordinate);
241 } else if (status.filtering == 0 && status.focusing == 1) {
242 status_printf(1, "y=%u, x=%u, view=%u", status.y_coordinate, status.x_coordinate,
243 status.view_num);
244 } else if (status.filtering == 1 && status.focusing == 1) {
245 status_printf(1, "view=%u, y=%u, x=%u, frame=%u",
246 status.view_num, status.y_coordinate, status.x_coordinate,
247 status.frame_num);
249 break;
251 default:
252 break;
255 status_clear();
258 void write_all() {
259 write_buffer();
260 write_status();
264 void printf(char *format, ...) {
265 va_list ap;
266 int n = -1;
268 if (buffer_index >= 0 && buffer_index < terminal_width /* && format[strlen(format) - 1] != '\n' */) {
269 va_start(ap, format);
270 n = vsnprintf(buffer + buffer_index, terminal_width - buffer_index, format, ap);
271 va_end(ap);
274 if (n >= 0 && n < terminal_width - buffer_index) {
276 * The message fits in the buffer, so update the index
277 * and write buffer and status information.
280 buffer_index += n;
282 if (format[strlen(format) - 1] == '\n') {
283 line_clear();
284 write_buffer();
285 } else
286 write_all();
288 } else {
290 * The message does not fit in the buffer, so write any
291 * existing buffer and append the new text to the stream.
293 if (buffer_index >= 0) {
294 assert(buffer_index < terminal_width);
295 buffer[buffer_index] = '\0';
296 write_buffer();
298 buffer_index = -1;
299 va_start(ap, format);
300 vfprintf(ui_stream, format, ap);
301 va_end(ap);
305 * This is not the only case that produces a newline,
306 * but ignoring other cases should be safe.
308 if (format[strlen(format) - 1] == '\n') {
309 buffer_index = 0;
310 buffer[0] = '\0';
314 void update() {
315 static time_t last_update = 0;
316 time_t now = time(NULL);
319 * Handle DONE status.
322 if (status.code == status_type::FRAME_DONE) {
323 printf(".");
324 fputc('\n', ui_stream);
325 buffer_index = 0;
326 buffer[0] = '\0';
327 return;
330 if (status.code == status_type::SET_DONE) {
331 fputc('\n', ui_stream);
332 buffer_index = 0;
333 buffer[0] = '\0';
334 return;
338 * Handle optional output.
341 if (now == last_update)
342 return;
343 else
344 last_update = now;
346 write_all();
349 public:
351 * Constructor may throw an exception to signal that using ui_wo would
352 * be more appropriate.
354 ui_tty() {
355 int exception_value = 1;
357 if (!isatty(fileno(ui_stream)))
358 throw exception_value;
361 * Don't use the last column, as this may cause
362 * wrapping in some environments (BSD, Hurd).
365 terminal_width = get_terminal_width(ui_stream) - 1;
367 if (terminal_width < 0)
368 throw exception_value;
370 buffer = (char *) calloc(terminal_width + 1, sizeof(char));
372 assert (buffer);
374 if (!buffer)
375 throw exception_value;
377 buffer[0] = '\0';
378 buffer_index = 0;
381 ~ui_tty() {
382 free(buffer);
386 #endif