gds_text.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. * (c) Philippe G. 2019, philippe_44@outlook.com
  3. *
  4. * This software is released under the MIT License.
  5. * https://opensource.org/licenses/MIT
  6. *
  7. */
  8. #include <string.h>
  9. #include <ctype.h>
  10. #include <stdint.h>
  11. #include <arpa/inet.h>
  12. #include "esp_log.h"
  13. #include "gds_private.h"
  14. #include "gds.h"
  15. #include "gds_draw.h"
  16. #include "gds_text.h"
  17. #define max(a,b) (((a) > (b)) ? (a) : (b))
  18. static char TAG[] = "gds";
  19. /****************************************************************************************
  20. * Set fonts for each line in text mode
  21. */
  22. static const struct GDS_FontDef *GuessFont( struct GDS_Device *Device, int FontType) {
  23. switch(FontType) {
  24. case GDS_FONT_LINE_1:
  25. return &Font_line_1;
  26. case GDS_FONT_LINE_2:
  27. return &Font_line_2;
  28. case GDS_FONT_MEDIUM:
  29. //return &Font_droid_sans_fallback_15x17;
  30. case GDS_FONT_SMALL:
  31. default:
  32. return &Font_droid_sans_fallback_11x13;
  33. #ifdef USE_LARGE_FONTS
  34. case GDS_FONT_LARGE:
  35. return &Font_droid_sans_fallback_24x28;
  36. case GDS_FONT_SEGMENT:
  37. if (Device->Height == 32) return &Font_Tarable7Seg_16x32;
  38. else return &Font_Tarable7Seg_32x64;
  39. #else
  40. case GDS_FONT_LARGE:
  41. case GDS_FONT_SEGMENT:
  42. ESP_LOGW(TAG, "large fonts disabled");
  43. //return &Font_droid_sans_fallback_15x17;
  44. return &Font_droid_sans_fallback_11x13;
  45. #endif
  46. }
  47. }
  48. /****************************************************************************************
  49. * Set fonts for each line in text mode
  50. */
  51. bool GDS_TextSetFontAuto(struct GDS_Device* Device, int N, int FontType, int Space) {
  52. const struct GDS_FontDef *Font = GuessFont( Device, FontType );
  53. return GDS_TextSetFont( Device, N, Font, Space );
  54. }
  55. /****************************************************************************************
  56. * Set fonts for each line in text mode
  57. */
  58. bool GDS_TextSetFont(struct GDS_Device* Device, int N, const struct GDS_FontDef *Font, int Space) {
  59. if (--N >= MAX_LINES) return false;
  60. Device->Lines[N].Font = Font;
  61. // re-calculate lines absolute position
  62. Device->Lines[N].Space = Space;
  63. Device->Lines[0].Y = Device->Lines[0].Space;
  64. for (int i = 1; i <= N; i++) Device->Lines[i].Y = Device->Lines[i-1].Y + Device->Lines[i-1].Font->Height + Device->Lines[i].Space;
  65. ESP_LOGI(TAG, "Adding line %u at %d (height:%u)", N + 1, Device->Lines[N].Y, Device->Lines[N].Font->Height);
  66. if (Device->Lines[N].Y + Device->Lines[N].Font->Height > Device->Height) {
  67. ESP_LOGW(TAG, "line does not fit display");
  68. return false;
  69. }
  70. return true;
  71. }
  72. /****************************************************************************************
  73. *
  74. */
  75. bool GDS_TextLine(struct GDS_Device* Device, int N, int Pos, int Attr, char *Text) {
  76. int Width, X = Pos;
  77. // counting 1..n
  78. N--;
  79. GDS_SetFont( Device, Device->Lines[N].Font );
  80. if (Attr & GDS_TEXT_MONOSPACE) GDS_FontForceMonospace( Device, true );
  81. Width = GDS_FontMeasureString( Device, Text );
  82. // adjusting position, erase only EoL for rigth-justified
  83. if (Pos == GDS_TEXT_RIGHT) X = Device->Width - Width - 1;
  84. else if (Pos == GDS_TEXT_CENTER) X = (Device->Width - Width) / 2;
  85. // erase if requested
  86. if (Attr & GDS_TEXT_CLEAR) {
  87. int Y_min = max(0, Device->Lines[N].Y), Y_max = max(0, Device->Lines[N].Y + Device->Lines[N].Font->Height);
  88. for (int c = (Attr & GDS_TEXT_CLEAR_EOL) ? X : 0; c < Device->Width; c++)
  89. for (int y = Y_min; y < Y_max; y++)
  90. DrawPixelFast( Device, c, y, GDS_COLOR_BLACK );
  91. }
  92. GDS_FontDrawString( Device, X, Device->Lines[N].Y, Text, GDS_COLOR_WHITE );
  93. ESP_LOGD(TAG, "displaying %s line %u (x:%d, attr:%u)", Text, N+1, X, Attr);
  94. // update whole display if requested
  95. Device->Dirty = true;
  96. if (Attr & GDS_TEXT_UPDATE) GDS_Update( Device );
  97. return Width + X < Device->Width;
  98. }
  99. /****************************************************************************************
  100. *
  101. */
  102. int GDS_GetTextWidth(struct GDS_Device* Device, int N, int Attr, char *Text) {
  103. const struct GDS_FontDef *Font = GDS_SetFont( Device, Device->Lines[N-1].Font );
  104. if (Attr & GDS_TEXT_MONOSPACE) GDS_FontForceMonospace( Device, true );
  105. int Width = GDS_FontMeasureString( Device, Text );
  106. GDS_SetFont( Device, Font );
  107. return Width;
  108. }
  109. /****************************************************************************************
  110. * Try to align string for better scrolling visual. there is probably much better to do
  111. */
  112. int GDS_TextStretch(struct GDS_Device* Device, int N, char *String, int Max) {
  113. char Space[] = " ";
  114. int Len = strlen(String), Extra = 0, Boundary;
  115. N--;
  116. // we might already fit
  117. GDS_SetFont( Device, Device->Lines[N].Font );
  118. if (GDS_FontMeasureString( Device, String ) <= Device->Width) return 0;
  119. // add some space for better visual
  120. strncat(String, Space, Max-Len);
  121. String[Max] = '\0';
  122. Len = strlen(String);
  123. // mark the end of the extended string
  124. Boundary = GDS_FontMeasureString( Device, String );
  125. // add a full display width
  126. while (Len < Max && GDS_FontMeasureString( Device, String ) - Boundary < Device->Width) {
  127. String[Len++] = String[Extra++];
  128. String[Len] = '\0';
  129. }
  130. return Boundary;
  131. }
  132. /****************************************************************************************
  133. *
  134. */
  135. void GDS_TextPos(struct GDS_Device* Device, int FontType, int Where, int Attr, char *Text, ...) {
  136. va_list args;
  137. TextAnchor Anchor = TextAnchor_Center;
  138. if (Attr & GDS_TEXT_CLEAR) GDS_Clear( Device, GDS_COLOR_BLACK );
  139. if (!Text) return;
  140. va_start(args, Text);
  141. switch(Where) {
  142. case GDS_TEXT_TOP_LEFT:
  143. default:
  144. Anchor = TextAnchor_NorthWest;
  145. break;
  146. case GDS_TEXT_MIDDLE_LEFT:
  147. Anchor = TextAnchor_West;
  148. break;
  149. case GDS_TEXT_BOTTOM_LEFT:
  150. Anchor = TextAnchor_SouthWest;
  151. break;
  152. case GDS_TEXT_CENTERED:
  153. Anchor = TextAnchor_Center;
  154. break;
  155. }
  156. ESP_LOGD(TAG, "Displaying %s at %u with attribute %u", Text, Anchor, Attr);
  157. GDS_SetFont( Device, GuessFont( Device, FontType ) );
  158. GDS_FontDrawAnchoredString( Device, Anchor, Text, GDS_COLOR_WHITE );
  159. Device->Dirty = true;
  160. if (Attr & GDS_TEXT_UPDATE) GDS_Update( Device );
  161. va_end(args);
  162. }