Tscope5
textio.c
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // __ ______
4 // / /_______________ ____ ___ / ____/
5 // / __/ ___/ ___/ __ \/ __ \/ _ \ /___ )
6 // / /_(__ ) /__/ /_/ / /_/ / __/ ____/ /
7 // \__/____/\___/\____/ .___/\___/ /_____/
8 // /_/
9 //
10 /// \file textio.c
11 /// Definitions of text input/output functions.
12 /// \example textio01.c
13 /// \example textio02.c
14 /// \example textio03.c
15 /// \example textio04.c
16 /// \example textio05.c
17 ////////////////////////////////////////////////////////////////////////////////
18 
19 
20 #include "../include/tscope5/textio.h"
21 #include "../include/tscope5/display.h"
22 #include "../include/tscope5/graphics.h"
23 #include "../include/tscope5/textio_internal.h"
24 #include "../include/tscope5/system_internal.h"
25 #include "../include/tscope5/keyboard_internal.h"
26 #include "../include/tscope5/graphics_internal.h"
27 
28 
29 #include <allegro5/allegro_font.h>
30 #include <allegro5/allegro_ttf.h>
31 
32 
33 ////////////////////////////////////////////////////////////////////////////////
34 /// @name Text input/output functions
35 /// The text input-output functions all take the smallest possible number of
36 /// parameters to put something on the screen:
37 /// two coordinates and a format string.
38 ///
39 /// The vertical coordinates are interpreted differently by
40 /// the two coordinate systems.
41 /// - When using the Cartesian coordinate system,
42 /// text is vertically centered around the y coordinate.
43 /// - When using the Display coordinate system,
44 /// the y coordinate corresponds to the top of the text
45 /// (like in other libraries).
46 ///
47 /// The format string is the same as the standard C
48 /// printf and scanf function families.
49 ///
50 /// Both standard C strings and Unicode strings can be used.
51 ///
52 /// Drawing parameters are set with the graphics parameter functions.
53 //@{
54 ////////////////////////////////////////////////////////////////////////////////
55 
56 
57 ////////////////////////////////////////////////////////////////////////////////
58 /// Write text to the active bitmap.
59 ///
60 /// \param x Horizontal position of the text.
61 /// \param y Vertical position of the text.
62 /// \param format Printf style format string.
63 ///
64 /// \return Length of the string on the display (in pixels).
65 ////////////////////////////////////////////////////////////////////////////////
66 double ts5_printf(double x, double y, const char *format, ...)
67 {
68  ts5_check_textio("ts5_printf");
69  ts5_log(TS5_LOGLEVEL_5, "ts5_printf(%f,%f,...)\n", x, y);
70 
71  if (_ts5_status.graphics.coordinate_scale
72  == TS5_RELATIVE_COORDINATES) {
75  }
76 
77  if (_ts5_status.graphics.coordinate_system
78  == TS5_CARTESIAN_COORDINATES) {
81  + _ts5_status.graphics.font_size / 2.0);
82  }
83 
84  x *= _ts5_status.display[_ts5_status.active_display].sampling_factor;
85  y *= _ts5_status.display[_ts5_status.active_display].sampling_factor;
86 
87  TS5_USTR *buf;
88  va_list ap;
89  double width;
90 
91  va_start(ap, format);
92  buf = al_ustr_new("");
93  al_ustr_vappendf(buf, format, ap);
94  va_end(ap);
95 
96  ALLEGRO_FONT *font;
97  if (!_ts5_status.display[_ts5_status.active_display].multisampling) {
98  font = _ts5_status.graphics.font->aliased_font;
99  }
100  else {
101  font = _ts5_status.graphics.font->multisampled_font;
102  }
103 
104  al_draw_ustr(font,
105  _ts5_status.graphics.foreground_color,
106  x, y, _ts5_status.graphics.text_alignment, buf);
107 
108  width = al_get_ustr_width(_ts5_status.graphics.font->aliased_font, buf);
109  al_ustr_free(buf);
110 
111  if (_ts5_status.graphics.coordinate_scale
112  == TS5_RELATIVE_COORDINATES) {
113  width/=_ts5_status.graphics.target_width;
114  }
115 
116  return width;
117 }
118 
119 
120 ////////////////////////////////////////////////////////////////////////////////
121 /// Write justified text to the active bitmap.
122 ///
123 /// \param x1 Horizontal start position of the text.
124 /// \param x2 Horizontal end position of the text.
125 /// \param y Vertical position of the text.
126 /// \param diff Maximum amount of space. If the amount of space in a line
127 /// of text is greater than the diff value, left justified text will be written.
128 /// \param format Printf style format string.
129 ////////////////////////////////////////////////////////////////////////////////
130 void ts5_printf_justify(double x1, double x2, double y, double diff,
131  const char *format, ...)
132 {
133  ts5_check_textio("ts5_printf_justify");
134  ts5_log(TS5_LOGLEVEL_5, "ts5_printf_justify(%f,%f,%f,%f,...)\n",
135  x1, x2, y, diff);
136 
137  if (_ts5_status.graphics.coordinate_scale
138  == TS5_RELATIVE_COORDINATES) {
142  }
143 
144  if (_ts5_status.graphics.coordinate_system
145  == TS5_CARTESIAN_COORDINATES) {
149  + _ts5_status.graphics.font_size / 2.0);
150  }
151 
152  x1 *= _ts5_status.display[_ts5_status.active_display].sampling_factor;
153  x2 *= _ts5_status.display[_ts5_status.active_display].sampling_factor;
154  y *= _ts5_status.display[_ts5_status.active_display].sampling_factor;
155  diff *= _ts5_status.display[_ts5_status.active_display].sampling_factor;
156 
157  TS5_USTR *buf;
158  va_list ap;
159 
160  va_start(ap, format);
161  buf = al_ustr_new("");
162  al_ustr_vappendf(buf, format, ap);
163  va_end(ap);
164 
165  ALLEGRO_FONT *font;
166  if (!_ts5_status.display[_ts5_status.active_display].multisampling) {
167  font = _ts5_status.graphics.font->aliased_font;
168  }
169  else {
170  font = _ts5_status.graphics.font->multisampled_font;
171  }
172 
173  al_draw_justified_ustr(font,
174  _ts5_status.graphics.foreground_color,
175  x1, x2, y, diff,
176  _ts5_status.graphics.text_alignment, buf);
177 }
178 
179 
180 ////////////////////////////////////////////////////////////////////////////////
181 /// Write UTF-8 encoded text to the active bitmap.
182 ///
183 /// \param x Horizontal position of the text.
184 /// \param y Vertical position of the text.
185 /// \param ustr Unicode string.
186 ///
187 /// \return Length of the string on the display (in pixels).
188 ////////////////////////////////////////////////////////////////////////////////
189 double ts5_printf_ustr(double x, double y, const TS5_USTR *ustr)
190 {
191  ts5_check_textio("ts5_printf_ustr");
192  ts5_log(TS5_LOGLEVEL_5, "ts5_printf_ustr(%f,%f,...)\n", x, y);
193 
194  if (_ts5_status.graphics.coordinate_scale
195  == TS5_RELATIVE_COORDINATES) {
198  }
199 
200  if (_ts5_status.graphics.coordinate_system
201  == TS5_CARTESIAN_COORDINATES) {
204  + _ts5_status.graphics.font_size / 2.0);
205  }
206 
207  x *= _ts5_status.display[_ts5_status.active_display].sampling_factor;
208  y *= _ts5_status.display[_ts5_status.active_display].sampling_factor;
209 
210  ALLEGRO_FONT *font;
211  if (!_ts5_status.display[_ts5_status.active_display].multisampling) {
212  font = _ts5_status.graphics.font->aliased_font;
213  }
214  else {
215  font = _ts5_status.graphics.font->multisampled_font;
216  }
217 
218  al_draw_ustr(font,
219  _ts5_status.graphics.foreground_color,
220  x, y, _ts5_status.graphics.text_alignment, ustr);
221 
222  double width;
223  width = al_get_ustr_width(_ts5_status.graphics.font->aliased_font, ustr);
224 
225  if (_ts5_status.graphics.coordinate_scale
226  == TS5_RELATIVE_COORDINATES) {
227  width/=_ts5_status.graphics.target_width;
228  }
229 
230  width /= _ts5_status.display[_ts5_status.active_display].sampling_factor;
231 
232  return width;
233 }
234 
235 
236 ////////////////////////////////////////////////////////////////////////////////
237 /// Write justified UTF-8 encoded text to the active bitmap.
238 ///
239 /// \param x1 Horizontal start position of the text.
240 /// \param x2 Horizontal end position of the text.
241 /// \param y Vertical position of the text.
242 /// \param diff Maximum amount of space. If the amount of space in a line
243 /// of text is greater than the diff value, left justified text will be written.
244 /// \param ustr Unicode string.
245 ////////////////////////////////////////////////////////////////////////////////
246 void ts5_printf_justify_ustr(double x1, double x2, double y, double diff,
247  const TS5_USTR *ustr)
248 {
249  ts5_check_textio("ts5_printf_justify_ustr");
250  ts5_log(TS5_LOGLEVEL_5, "ts5_printf_justify_ustr(%f,%f,%f,%f,...)\n",
251  x1, x2, y, diff);
252 
253  if (_ts5_status.graphics.coordinate_scale
254  == TS5_RELATIVE_COORDINATES) {
258  }
259 
260  if (_ts5_status.graphics.coordinate_system
261  == TS5_CARTESIAN_COORDINATES) {
265  + _ts5_status.graphics.font_size / 2.0);
266  }
267 
268  x1 *= _ts5_status.display[_ts5_status.active_display].sampling_factor;
269  x2 *= _ts5_status.display[_ts5_status.active_display].sampling_factor;
270  y *= _ts5_status.display[_ts5_status.active_display].sampling_factor;
271  diff *= _ts5_status.display[_ts5_status.active_display].sampling_factor;
272 
273  ALLEGRO_FONT *font;
274  if (!_ts5_status.display[_ts5_status.active_display].multisampling) {
275  font = _ts5_status.graphics.font->aliased_font;
276  }
277  else {
278  font = _ts5_status.graphics.font->multisampled_font;
279  }
280 
281  al_draw_justified_ustr(font,
282  _ts5_status.graphics.foreground_color,
283  x1, x2, y, diff,
284  _ts5_status.graphics.text_alignment, ustr);
285 }
286 
287 
288 ////////////////////////////////////////////////////////////////////////////////
289 /// Read text from the keyboard.
290 ///
291 /// \param x Horizontal position where the input will be echoed.
292 /// \param y Vertical position where the input will be echoed.
293 /// \param format Printf style format string.
294 ///
295 /// \return The number of arguments that were processed.
296 ////////////////////////////////////////////////////////////////////////////////
297 int ts5_scanf(double x, double y, const char *format, ...)
298 {
299  ts5_check_textio("ts5_scanf");
300  ts5_check_keyboard("ts5_scanf");
301  ts5_log(TS5_LOGLEVEL_5, "ts5_scanf(%f,%f,...)\n", x, y);
302 
303  char str[TS5_MAX_CHAR];
304  int done = 0, pos = 0;
305  int ascii;
306  TS5_COLOR fg = _ts5_status.graphics.foreground_color;
307  TS5_COLOR bg = _ts5_status.graphics.background_color;
308 
309  ALLEGRO_EVENT_QUEUE *event_queue;
310  event_queue = al_create_event_queue();
311 
312  if (!event_queue) {
313  ts5_fatal("ts5_scanf: could not create event cue for keyboard\n");
314  return 1;
315  }
316 
317  al_register_event_source(event_queue, al_get_keyboard_event_source());
318 
319  ALLEGRO_EVENT event;
320 
321  do {
322  al_wait_for_event(event_queue, &event);
323 
324  if (event.type == ALLEGRO_EVENT_KEY_CHAR) {
325 
327  ts5_printf(x, y, "%s", str);
328 
329  ascii = event.keyboard.unichar;
330  if (ascii == 3 || ascii == 13) {
331  done = 1;
332  }
333  else if (ascii == 8 || ascii == 127) {
334  if (pos > 0)
335  pos--;
336  }
337  else if (ascii == 0) {
338 
339  }
340  else {
341  str[pos] = ascii;
342  pos++;
343  }
344 
345  if (pos > TS5_MAX_CHAR) {
346  pos = TS5_MAX_CHAR;
347  }
348  str[pos] = '\0';
350  ts5_printf(x, y, "%s", str);
352  }
353  } while (!done);
354 
355  al_unregister_event_source(event_queue, al_get_keyboard_event_source());
356  al_destroy_event_queue(event_queue);
357 
358  int i;
359  va_list args;
360  va_start(args, format);
361  i = vsscanf(str, format, args);
362  va_end(args);
363 
364  return i;
365 }
366 
367 
368 ////////////////////////////////////////////////////////////////////////////////
369 /// Get the width of a string without printing it.
370 ///
371 /// \param format Printf style format string.
372 ///
373 /// \return The width of the string on the display (in pixels).
374 ////////////////////////////////////////////////////////////////////////////////
375 double ts5_get_text_width(const char *format, ...)
376 {
377  ts5_check_textio("ts5_get_text_width");
378  ts5_log(TS5_LOGLEVEL_5, "ts5_get_text_width(...)\n");
379 
380  TS5_USTR *buf;
381  va_list ap;
382  int width;
383 
384  va_start(ap, format);
385  buf = al_ustr_new("");
386  al_ustr_vappendf(buf, format, ap);
387  va_end(ap);
388 
389  width = al_get_ustr_width(_ts5_status.graphics.font->aliased_font, buf);
390  al_ustr_free(buf);
391 
392  if (_ts5_status.graphics.coordinate_scale
393  == TS5_RELATIVE_COORDINATES) {
394  width/=_ts5_status.graphics.target_width;
395  }
396 
397  return width;
398 }
399 
400 
401 ////////////////////////////////////////////////////////////////////////////////
402 /// Get the width of a UTF-8 string without printing it.
403 ///
404 /// \param ustr Unicode string.
405 ///
406 /// \return The width of the string on the display (in pixels).
407 ////////////////////////////////////////////////////////////////////////////////
408 double ts5_get_text_width_ustr(TS5_USTR *ustr)
409 {
410  ts5_check_textio("ts5_get_text_width_ustr");
411  ts5_log(TS5_LOGLEVEL_5, "ts5_get_text_width_ustr(...)\n");
412 
413  double width;
414  width = al_get_ustr_width(_ts5_status.graphics.font->aliased_font, ustr);
415 
416  if (_ts5_status.graphics.coordinate_scale
417  == TS5_RELATIVE_COORDINATES) {
418  width/=_ts5_status.graphics.target_width;
419  }
420 
421  return width;
422 }
423 
424 
425 ////////////////////////////////////////////////////////////////////////////////
426 //@}
427 ////////////////////////////////////////////////////////////////////////////////
428 
429 
430 ////////////////////////////////////////////////////////////////////////////////
431 /// @name Loading custom fonts
432 /// In Tscope5 three fonts are available as standard (courier, arial and times).
433 /// If these do not suit your needs any TrueType font that is installed
434 /// on your computer can be loaded manually.
435 //@{
436 ////////////////////////////////////////////////////////////////////////////////
437 
438 
439 ////////////////////////////////////////////////////////////////////////////////
440 /// Load a user defined font.
441 ///
442 /// \param fontfile Path to the file that describes the 1 type font.
443 /// \param size Size the font will be rendered in.
444 ///
445 /// \return A pointer to the TS5_FONT font structure.
446 ///
447 /// True type fonts can be found in /Library/fonts on Mac OS X.
448 ////////////////////////////////////////////////////////////////////////////////
449 TS5_FONT *ts5_read_font(const char *fontfile, double size)
450 {
451  ts5_check_textio("ts5_read_font");
452  ts5_log(TS5_LOGLEVEL_4, "ts5_read_font(%s,%f)\n", fontfile, size);
453 
454  ts5_log(TS5_LOGLEVEL_2, "ts5_read_font: loading font %s %f\n",
455  fontfile, size);
456 
457  TS5_FONT *font;
458  font = (TS5_FONT *)al_malloc(sizeof(TS5_FONT));
459  font->aliased_font = al_load_ttf_font(fontfile, -size, 0);
460  font->multisampled_font = al_load_ttf_font(fontfile,
461  -size * _ts5_status.display[_ts5_status.active_display].sampling_factor, 0);
462 
463  if (!font->aliased_font) {
464  ts5_fatal("ts5_read_font: could not load font %s %d\n", fontfile,
465  _ts5_status.graphics.font_size);
466  }
467 
468  return font;
469 }
470 
471 
472 ////////////////////////////////////////////////////////////////////////////////
473 /// Set a user defined font.
474 ///
475 /// \param font The new font.
476 ///
477 /// \return A pointer to the previous font.
478 ////////////////////////////////////////////////////////////////////////////////
479 TS5_FONT *ts5_set_font(TS5_FONT *font)
480 {
481  ts5_check_textio("ts5_set_font");
482  ts5_log(TS5_LOGLEVEL_4, "ts5_set_font(%p)\n", font);
483 
484  if (font == NULL) {
485  ts5_fatal("ts5_set_font: font is a NULL pointer\n");
486  }
487 
488  TS5_FONT *retval = _ts5_status.graphics.font;
489  _ts5_status.graphics.font = font;
490  _ts5_status.graphics.font_index = TS5_USERFONT;
491 
492  _ts5_status.graphics.font_size =
493  al_get_font_line_height(_ts5_status.graphics.font->aliased_font);
494 
495  return retval;
496 }
497 
498 
499 ////////////////////////////////////////////////////////////////////////////////
500 /// Free the memory used by a user defined font.
501 ///
502 /// \param font pointer to the font that will be freed.
503 ///
504 /// This function should be called at the end of the program for
505 /// each font read by the user.
506 ////////////////////////////////////////////////////////////////////////////////
507 void ts5_free_font(TS5_FONT *font)
508 {
509  ts5_check_textio("ts5_free_font");
510  ts5_log(TS5_LOGLEVEL_2, "ts5_free_font(%p)\n", font);
511 
512  if (font) {
513  al_destroy_font(font->aliased_font);
514  al_destroy_font(font->multisampled_font);
515  al_free(font);
516  ts5_log(TS5_LOGLEVEL_2, "ts5_free_font: removed font\n");
517  font = NULL;
518  }
519 }
520 
521 
522 ////////////////////////////////////////////////////////////////////////////////
523 //@}
524 ////////////////////////////////////////////////////////////////////////////////
void ts5_printf_justify(double x1, double x2, double y, double diff, const char *format,...)
Write justified text to the active bitmap.
Definition: textio.c:130
TS5_FONT * ts5_set_font(TS5_FONT *font)
Set a user defined font.
Definition: textio.c:479
int ts5_scanf(double x, double y, const char *format,...)
Read text from the keyboard.
Definition: textio.c:297
void ts5_printf_justify_ustr(double x1, double x2, double y, double diff, const TS5_USTR *ustr)
Write justified UTF-8 encoded text to the active bitmap.
Definition: textio.c:246
void ts5_check_textio(char *calling_function)
Do some checks at the start of each textio function.
double ts5_get_text_width_ustr(TS5_USTR *ustr)
Get the width of a UTF-8 string without printing it.
Definition: textio.c:408
double ts5_flip_display()
Make what has been drawn visible on the screen.
Definition: display.c:539
double ts5_printf(double x, double y, const char *format,...)
Write text to the active bitmap.
Definition: textio.c:66
TS5_COLOR ts5_set_foreground_color(const TS5_COLOR foreground_color)
Set the foreground color.
Definition: graphics.c:607
TS5_FONT * ts5_read_font(const char *fontfile, double size)
Load a user defined font.
Definition: textio.c:449
double ts5_printf_ustr(double x, double y, const TS5_USTR *ustr)
Write UTF-8 encoded text to the active bitmap.
Definition: textio.c:189
double ts5_relative_to_absolute_coordinate_x(const double x)
Convert a relative horizontal coordinate into an absolute horizontal coordinate.
Definition: graphics.c:208
void ts5_log(const unsigned int level, const char *format,...)
Send info to a logging window.
Definition: system.c:45
double ts5_cartesian_to_display_coordinate_x(const double x)
Convert a horizontal Cartesian coordinate into a horizontal display coordinate.
Definition: graphics.c:333
double ts5_cartesian_to_display_coordinate_y(const double y)
Convert a vertical Cartesian coordinate into a vertical display coordinate.
Definition: graphics.c:354
void ts5_check_keyboard(char *calling_function)
Do some checks at the start of each keyboard function.
void ts5_fatal(const char *format,...)
Exit safely with an error message.
Definition: system.c:533
double ts5_relative_to_absolute_coordinate_y(const double y)
Convert a relative vertical coordinate into an absolute vertical coordinate.
Definition: graphics.c:240
double ts5_get_text_width(const char *format,...)
Get the width of a string without printing it.
Definition: textio.c:375
void ts5_free_font(TS5_FONT *font)
Free the memory used by a user defined font.
Definition: textio.c:507