gds_text.c 5.9 KB

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