button.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. #include "button.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #define ERROR(...) fprintf(stderr, __VA_ARGS__)
  5. Button *buttonNew(const char *text, float x, float y, float w, float h,
  6. SDL_Texture *inactive, SDL_Texture *active,
  7. SDL_Color textColor, TTF_Font *font, ButtonSoundSet sounds,
  8. const Window *window) {
  9. Button *button = malloc(sizeof(Button));
  10. if (!button) {
  11. ERROR("error: out of memory\n");
  12. exit(EXIT_FAILURE);
  13. }
  14. if (text) {
  15. button->text = strdup(text);
  16. if (!text) {
  17. ERROR("error: out of memory\n");
  18. free(button);
  19. exit(EXIT_FAILURE);
  20. }
  21. } else {
  22. button->text = NULL;
  23. }
  24. button->x = x;
  25. button->y = y;
  26. button->w = w;
  27. button->h = h;
  28. button->inactive = inactive;
  29. button->active = active;
  30. button->current = inactive;
  31. button->font = font;
  32. button->textColor = textColor;
  33. button->sounds = sounds;
  34. button->action = NULL;
  35. button->renderedText = NULL;
  36. button->down = 0;
  37. buttonUpdate(button, window);
  38. return button;
  39. }
  40. void buttonDelete(Button *button) {
  41. if (button->text && strlen(button->text)) {
  42. free(button->text);
  43. SDL_DestroyTexture(button->renderedText);
  44. }
  45. free(button);
  46. }
  47. void buttonDraw(const Button *button, const Window *window) {
  48. float bw = button->w;
  49. float bh = button->h;
  50. int ww, wh;
  51. SDL_GetWindowSize(window->obj, &ww, &wh);
  52. if (button->w == 0 && button->h == 0) {
  53. bh = (float)button->textW / ww;
  54. bw = (float)button->textH / wh;
  55. } else if (button->w == 0) {
  56. bw = (((wh * button->h) * button->textH) / button->textW) / ww;
  57. } else if (button->h == 0) {
  58. bh = (((ww * button->w) * button->textH) / button->textW) / wh;
  59. }
  60. SDL_Rect backArea = {ww * button->x, wh * button->y, ww * bw, wh * bh};
  61. SDL_RenderCopy(window->render, button->current, NULL, &backArea);
  62. if (button->text && strlen(button->text)) {
  63. SDL_Rect textArea = {backArea.x * (1.0f + BUTTON_PADDING),
  64. backArea.y * (1.0f + BUTTON_PADDING),
  65. backArea.w * (1.0f - (2 * BUTTON_PADDING)),
  66. backArea.h * (1.0f - (2 * BUTTON_PADDING))};
  67. SDL_RenderCopy(window->render, button->renderedText, NULL, &textArea);
  68. }
  69. }
  70. void buttonUpdate(Button *button, const Window *window) {
  71. if (button->renderedText) {
  72. SDL_DestroyTexture(button->renderedText);
  73. }
  74. if (button->text && strlen(button->text)) {
  75. SDL_Surface *surface = TTF_RenderText_Blended(
  76. button->font, button->text, button->textColor);
  77. if (!surface) {
  78. ERROR("error: sdl2: ttf: %s\n", TTF_GetError());
  79. exit(EXIT_FAILURE);
  80. }
  81. button->textW = surface->w;
  82. button->textH = surface->h;
  83. button->renderedText =
  84. SDL_CreateTextureFromSurface(window->render, surface);
  85. SDL_FreeSurface(surface);
  86. if (!button->renderedText) {
  87. ERROR("error: sdl2: %s\n", SDL_GetError());
  88. exit(EXIT_FAILURE);
  89. }
  90. }
  91. }
  92. static int intersectsButton(const Button *button, float bw, float bh, float x,
  93. float y) {
  94. return x >= button->x && y >= button->y && x <= button->x + bw &&
  95. y <= button->y + bh;
  96. }
  97. void buttonProcessInput(Button *button, Window *window,
  98. const SDL_Event *event) {
  99. int ww, wh;
  100. SDL_GetWindowSize(window->obj, &ww, &wh);
  101. float bw = button->w;
  102. float bh = button->h;
  103. if (button->w == 0 && button->h == 0) {
  104. bh = (float)button->textW / ww;
  105. bw = (float)button->textH / wh;
  106. } else if (button->w == 0) {
  107. bw = (((wh * button->h) * button->textH) / button->textW) / ww;
  108. } else if (button->h == 0) {
  109. bh = (((ww * button->w) * button->textH) / button->textW) / wh;
  110. }
  111. if (event->type == SDL_MOUSEMOTION) {
  112. float x = (float)event->motion.x / ww;
  113. float y = (float)event->motion.y / wh;
  114. if (intersectsButton(button, bw, bh, x, y)) {
  115. if (button->active && button->current != button->active) {
  116. if (button->sounds.hover) {
  117. Mix_PlayChannel(-1, button->sounds.hover, 0);
  118. }
  119. button->current = button->active;
  120. }
  121. } else {
  122. if (button->current != button->inactive) {
  123. if (button->sounds.hover) {
  124. Mix_PlayChannel(-1, button->sounds.hover, 0);
  125. }
  126. button->current = button->inactive;
  127. }
  128. if (button->down) {
  129. button->down = 0;
  130. }
  131. }
  132. } else if (event->type == SDL_MOUSEBUTTONDOWN &&
  133. event->button.button == SDL_BUTTON_LEFT) {
  134. float x = (float)event->button.x / ww;
  135. float y = (float)event->button.y / wh;
  136. if (intersectsButton(button, bw, bh, x, y)) {
  137. button->down = 1;
  138. if (button->sounds.down) {
  139. Mix_PlayChannel(-1, button->sounds.down, 0);
  140. }
  141. }
  142. } else if (event->type == SDL_MOUSEBUTTONUP &&
  143. event->button.button == SDL_BUTTON_LEFT) {
  144. float x = (float)event->button.x / ww;
  145. float y = (float)event->button.y / wh;
  146. if (intersectsButton(button, bw, bh, x, y) && button->down) {
  147. button->down = 0;
  148. if (button->sounds.up) {
  149. Mix_PlayChannel(-1, button->sounds.up, 0);
  150. }
  151. if (button->action) {
  152. button->action(button, window, x - button->x, y - button->y);
  153. }
  154. button->current = button->inactive;
  155. }
  156. }
  157. }
  158. void buttonGetCenter(const Button *button, Point *point) {
  159. point->x = button->x + (button->w / 2);
  160. point->y = button->y + (button->w / 2);
  161. }