textbox.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. #include "textbox.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #define ERROR(...) fprintf(stderr, __VA_ARGS__)
  6. TextBox *textBoxNew(const char *text, float x, float y, float textSize,
  7. SDL_Color color, SDL_Texture *background, TTF_Font *font,
  8. const Window *window) {
  9. TextBox *box = malloc(sizeof(TextBox));
  10. if (!box) {
  11. ERROR("error: out of memory\n");
  12. exit(EXIT_FAILURE);
  13. }
  14. box->text = strdup(text);
  15. if (!box->text) {
  16. ERROR("error: out of memory\n");
  17. free(box);
  18. exit(EXIT_FAILURE);
  19. }
  20. box->x = x;
  21. box->y = y;
  22. box->textColor = color;
  23. box->background = background;
  24. box->font = font;
  25. box->textSize = textSize;
  26. textBoxUpdate(box, window);
  27. return box;
  28. }
  29. void textBoxDelete(TextBox *textBox) {
  30. free(textBox->text);
  31. size_t i;
  32. for (i = 0; i < textBox->lineCount; ++i) {
  33. SDL_DestroyTexture(textBox->renderedText[i]);
  34. }
  35. free(textBox->renderedText);
  36. free(textBox);
  37. }
  38. static void getLineSizes(TextBox *textBox, int ww, int wh, int *widths,
  39. int *width, int *height) {
  40. int yInc = textBox->textSize * wh;
  41. *width = 0;
  42. size_t i;
  43. for (i = 0; i < textBox->lineCount; ++i) {
  44. int tw, th;
  45. SDL_QueryTexture(textBox->renderedText[i], NULL, NULL, &tw, &th);
  46. int lw = ((float)tw / (float)th) * (float)yInc;
  47. widths[i] = lw;
  48. if (lw > *width) {
  49. *width = lw;
  50. }
  51. }
  52. *width += ww * TEXT_BOX_PADDING;
  53. *height = yInc * textBox->lineCount;
  54. }
  55. void textBoxDraw(TextBox *textBox, const Window *window) {
  56. int ww, wh;
  57. SDL_GetWindowSize(window->obj, &ww, &wh);
  58. int widths[textBox->lineCount];
  59. int bw, bh;
  60. getLineSizes(textBox, ww, wh, widths, &bw, &bh);
  61. SDL_Rect backArea = {textBox->x * ww, textBox->y * wh, bw, bh};
  62. if (textBox->background != NULL) {
  63. SDL_RenderCopy(window->render, textBox->background, NULL, &backArea);
  64. }
  65. int yInc = textBox->textSize * wh;
  66. size_t i;
  67. for (i = 0; i < textBox->lineCount; ++i) {
  68. int th;
  69. SDL_QueryTexture(textBox->renderedText[i], NULL, NULL, NULL, &th);
  70. SDL_Rect area = {backArea.x * (1.0f + TEXT_BOX_PADDING),
  71. (backArea.y * (1.0f + TEXT_BOX_PADDING)) + (yInc * i),
  72. widths[i] * (1.0f - (2 * TEXT_BOX_PADDING)),
  73. yInc * (1.0f - (2 * TEXT_BOX_PADDING))};
  74. SDL_RenderCopy(window->render, textBox->renderedText[i], NULL, &area);
  75. }
  76. }
  77. static SDL_Texture *renderLine(const char *text, const TextBox *textBox,
  78. const Window *window) {
  79. SDL_Surface *surface =
  80. TTF_RenderText_Blended(textBox->font, text, textBox->textColor);
  81. if (!surface) {
  82. ERROR("error: sdl2: ttf: %s\n", TTF_GetError());
  83. exit(EXIT_FAILURE);
  84. }
  85. SDL_Texture *texture =
  86. SDL_CreateTextureFromSurface(window->render, surface);
  87. SDL_FreeSurface(surface);
  88. if (!texture) {
  89. ERROR("error: sdl2: %s\n", SDL_GetError());
  90. exit(EXIT_FAILURE);
  91. }
  92. return texture;
  93. }
  94. void textBoxUpdate(TextBox *textBox, const Window *window) {
  95. textBox->renderedText = malloc(1);
  96. if (!textBox->renderedText) {
  97. ERROR("error: out of memory\n");
  98. exit(EXIT_FAILURE);
  99. }
  100. char *savePtr;
  101. char *line = strtok_r(textBox->text, "\n", &savePtr);
  102. for (textBox->lineCount = 0; line != NULL; ++textBox->lineCount) {
  103. textBox->renderedText =
  104. realloc(textBox->renderedText,
  105. sizeof(SDL_Texture *) * (textBox->lineCount + 1));
  106. if (!textBox->renderedText) {
  107. ERROR("error: out of memory\n");
  108. exit(EXIT_FAILURE);
  109. }
  110. textBox->renderedText[textBox->lineCount] =
  111. renderLine(line, textBox, window);
  112. line = strtok_r(NULL, "\n", &savePtr);
  113. }
  114. }