S&B Volcano vaporizer remote control with Pi Pico W
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

text.c 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /*
  2. * text.c
  3. *
  4. * Copyright (c) 2023 Thomas Buck (thomas@xythobuz.de)
  5. *
  6. * This program 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 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program 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.
  15. *
  16. * See <http://www.gnu.org/licenses/>.
  17. */
  18. #include "config.h"
  19. #include "log.h"
  20. #include "lcd.h"
  21. #include "text.h"
  22. typedef struct {
  23. struct text_conf *options;
  24. uint16_t anchor;
  25. } state_t;
  26. static uint32_t blend(uint32_t fg_c, uint32_t bg_c, uint8_t alpha) {
  27. float bg[4] = { RGB_565_REV(bg_c), 1.0f };
  28. float fg[4] = { RGB_565_REV(fg_c), alpha / 255.0f };
  29. float r[4];
  30. r[3] = 1.0f - (1.0f - fg[3]) * (1.0f - bg[3]);
  31. if (r[3] < 1.0e-6f) {
  32. r[0] = 0.0f;
  33. r[1] = 0.0f;
  34. r[2] = 0.0f;
  35. } else {
  36. r[0] = fg[0] * fg[3] / r[3] + bg[0] * bg[3] * (1.0f - fg[3]) / r[3];
  37. r[1] = fg[1] * fg[3] / r[3] + bg[1] * bg[3] * (1.0f - fg[3]) / r[3];
  38. r[2] = fg[2] * fg[3] / r[3] + bg[2] * bg[3] * (1.0f - fg[3]) / r[3];
  39. }
  40. return RGB_565((uint32_t)(r[0] * 255.0f),
  41. (uint32_t)(r[1] * 255.0f),
  42. (uint32_t)(r[2] * 255.0f));
  43. }
  44. static void pixel_callback(int16_t x, int16_t y, uint8_t count, uint8_t alpha,
  45. void *state) {
  46. state_t *s = (state_t*)state;
  47. if (y < 0 || y >= s->options->height) return;
  48. if (x < 0 || x + count >= s->options->width) return;
  49. while (count--) {
  50. lcd_write_point(240 - y - 1, x,
  51. blend(s->options->fg, s->options->bg, alpha));
  52. x++;
  53. }
  54. }
  55. static uint8_t character_callback(int16_t x, int16_t y, mf_char character,
  56. void *state) {
  57. state_t *s = (state_t*)state;
  58. uint8_t w = mf_render_character(s->options->font->font, x, y, character, pixel_callback, state);
  59. return w;
  60. }
  61. static bool line_callback(const char *line, uint16_t count, void *state) {
  62. state_t *s = (state_t*)state;
  63. if (s->options->bg != TEXT_BG_NONE) {
  64. int16_t width = mf_get_string_width(s->options->font->font, line, count, false) + 2 * s->options->margin;
  65. int16_t line_height = s->options->font->font->line_height;
  66. if (s->options->alignment == MF_ALIGN_LEFT) {
  67. lcd_write_rect(240 - s->options->y - 1 - line_height,
  68. s->options->x,
  69. 240 - s->options->y - 1,
  70. s->options->x + width,
  71. s->options->bg);
  72. } else if (s->options->alignment == MF_ALIGN_CENTER) {
  73. lcd_write_rect(240 - s->options->y - 1 - line_height,
  74. s->options->x + s->options->width / 2 - width / 2,
  75. 240 - s->options->y - 1,
  76. s->options->x + s->options->width / 2 + width / 2,
  77. s->options->bg);
  78. } else if (s->options->alignment == MF_ALIGN_RIGHT) {
  79. lcd_write_rect(240 - s->options->y - 1 - line_height,
  80. s->options->x + s->options->width - width,
  81. 240 - s->options->y - 1,
  82. s->options->x + s->options->width,
  83. s->options->bg);
  84. }
  85. }
  86. if (s->options->justify) {
  87. mf_render_justified(s->options->font->font, s->anchor + s->options->x, s->options->y,
  88. s->options->width - s->options->margin * 2,
  89. line, count, character_callback, state);
  90. } else {
  91. mf_render_aligned(s->options->font->font, s->anchor + s->options->x, s->options->y,
  92. s->options->alignment, line, count,
  93. character_callback, state);
  94. }
  95. s->options->y += s->options->font->font->line_height;
  96. return true;
  97. }
  98. void text_prepare_font(struct text_font *tf) {
  99. if (!tf) {
  100. debug("invalid param");
  101. return;
  102. }
  103. const struct mf_font_s *font = mf_find_font(tf->fontname);
  104. if (!font) {
  105. debug("No such font: %s", tf->fontname);
  106. return;
  107. }
  108. tf->font = font;
  109. // TODO
  110. //struct mf_scaledfont_s scaledfont;
  111. //if (tf->scale > 1) {
  112. // mf_scale_font(&scaledfont, font, tf->scale, tf->scale);
  113. // tf->font = scaledfont.font;
  114. //}
  115. }
  116. void text_draw(struct text_conf *tc) {
  117. if ((!tc) || (!tc->font) || (!tc->font->font)) {
  118. debug("invalid param");
  119. return;
  120. }
  121. state_t state;
  122. state.options = tc;
  123. if (tc->alignment == MF_ALIGN_LEFT) {
  124. state.anchor = tc->margin;
  125. } else if (tc->alignment == MF_ALIGN_CENTER) {
  126. state.anchor = tc->width / 2;
  127. } else if (tc->alignment == MF_ALIGN_RIGHT) {
  128. state.anchor = tc->width - tc->margin;
  129. }
  130. mf_wordwrap(tc->font->font, tc->width - 2 * tc->margin,
  131. tc->text, line_callback, &state);
  132. }
  133. void text_box(const char *s) {
  134. static struct text_font font = {
  135. .fontname = "fixed_10x20",
  136. .font = NULL,
  137. };
  138. if (font.font == NULL) {
  139. text_prepare_font(&font);
  140. }
  141. struct text_conf text = {
  142. .text = "",
  143. .x = 0,
  144. .y = 50,
  145. .justify = false,
  146. .alignment = MF_ALIGN_CENTER,
  147. .width = 240,
  148. .height = 240 - 80,
  149. .margin = 2,
  150. .fg = RGB_565(0xFF, 0xFF, 0xFF),
  151. .bg = RGB_565(0x00, 0x00, 0x00),
  152. .font = &font,
  153. };
  154. // TODO clear background?!
  155. text.text = s;
  156. text_draw(&text);
  157. }