decor-fancy.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2016-2018 K. Lange
  5. *
  6. * The default "fancy" decorations theme.
  7. *
  8. * Based on an old gtk-window-decorator theme I used to use many,
  9. * many years ago.
  10. */
  11. #include <stdint.h>
  12. #include <dlfcn.h>
  13. #include <toaru/yutani.h>
  14. #include <toaru/graphics.h>
  15. #include <toaru/decorations.h>
  16. #include <toaru/sdf.h>
  17. #define INACTIVE 10
  18. #define TTK_FANCY_PATH "/usr/share/ttk/"
  19. static int u_height = 33;
  20. static int ul_width = 10;
  21. static int ur_width = 10;
  22. static int mr_width = 6;
  23. static int l_height = 9;
  24. static int ll_width = 9;
  25. static int lr_width = 9;
  26. static sprite_t * sprites[20];
  27. #define TEXT_OFFSET ((window->decorator_flags & DECOR_FLAG_TILED) ? 5 : 10)
  28. #define BUTTON_OFFSET ((window->decorator_flags & DECOR_FLAG_TILED) ? 5 : 0)
  29. static int _have_freetype = 0;
  30. static void (*freetype_set_font_face)(int face) = NULL;
  31. static void (*freetype_set_font_size)(int size) = NULL;
  32. static int (*freetype_draw_string)(gfx_context_t * ctx, int x, int y, uint32_t fg, const char * s) = NULL;
  33. static int (*freetype_draw_string_width)(char * s) = NULL;
  34. static void init_sprite(int id, char * path) {
  35. sprites[id] = malloc(sizeof(sprite_t));
  36. load_sprite(sprites[id], path);
  37. sprites[id]->alpha = ALPHA_EMBEDDED;
  38. }
  39. static int get_bounds_fancy(yutani_window_t * window, struct decor_bounds * bounds) {
  40. if (window == NULL || !(window->decorator_flags & DECOR_FLAG_TILED)) {
  41. bounds->top_height = 33;
  42. bounds->bottom_height = 6;
  43. bounds->left_width = 6;
  44. bounds->right_width = 6;
  45. } else {
  46. /* Any "exposed" edge gets an extra pixel. */
  47. bounds->top_height = 27 + !(window->decorator_flags & DECOR_FLAG_TILE_UP);
  48. bounds->bottom_height = !(window->decorator_flags & DECOR_FLAG_TILE_DOWN);
  49. bounds->left_width = !(window->decorator_flags & DECOR_FLAG_TILE_LEFT);
  50. bounds->right_width = !(window->decorator_flags & DECOR_FLAG_TILE_RIGHT);
  51. }
  52. bounds->width = bounds->left_width + bounds->right_width;
  53. bounds->height = bounds->top_height + bounds->bottom_height;
  54. return 0;
  55. }
  56. static void render_decorations_fancy(yutani_window_t * window, gfx_context_t * ctx, char * title, int decors_active) {
  57. int width = window->width;
  58. int height = window->height;
  59. struct decor_bounds bounds;
  60. get_bounds_fancy(window, &bounds);
  61. for (int j = 0; j < (int)bounds.top_height; ++j) {
  62. for (int i = 0; i < width; ++i) {
  63. GFX(ctx,i,j) = 0;
  64. }
  65. }
  66. if (decors_active == DECOR_INACTIVE) decors_active = INACTIVE;
  67. if ((window->decorator_flags & DECOR_FLAG_TILED)) {
  68. for (int i = 0; i < width; ++i) {
  69. draw_sprite(ctx, sprites[decors_active + 1], i, -6 + !(window->decorator_flags & DECOR_FLAG_TILE_UP));
  70. }
  71. uint32_t clear_color = rgb(62,62,62);
  72. if (!(window->decorator_flags & DECOR_FLAG_TILE_DOWN)) {
  73. /* Draw bottom line */
  74. for (int i = 0; i < (int)window->width; ++i) {
  75. GFX(ctx,i,window->height-1) = clear_color;
  76. }
  77. }
  78. if (!(window->decorator_flags & DECOR_FLAG_TILE_LEFT)) {
  79. /* Draw left line */
  80. for (int i = 0; i < (int)window->height; ++i) {
  81. GFX(ctx,0,i) = clear_color;
  82. }
  83. }
  84. if (!(window->decorator_flags & DECOR_FLAG_TILE_RIGHT)) {
  85. /* Draw right line */
  86. for (int i = 0; i < (int)window->height; ++i) {
  87. GFX(ctx,window->width-1,i) = clear_color;
  88. }
  89. }
  90. } else {
  91. uint32_t clear_color = 0x000000;
  92. for (int j = (int)bounds.top_height; j < height - (int)bounds.bottom_height; ++j) {
  93. for (int i = 0; i < (int)bounds.left_width; ++i) {
  94. GFX(ctx,i,j) = clear_color;
  95. }
  96. for (int i = width - (int)bounds.right_width; i < width; ++i) {
  97. GFX(ctx,i,j) = clear_color;
  98. }
  99. }
  100. for (int j = height - (int)bounds.bottom_height; j < height; ++j) {
  101. for (int i = 0; i < width; ++i) {
  102. GFX(ctx,i,j) = clear_color;
  103. }
  104. }
  105. draw_sprite(ctx, sprites[decors_active + 0], 0, 0);
  106. for (int i = 0; i < width - (ul_width + ur_width); ++i) {
  107. draw_sprite(ctx, sprites[decors_active + 1], i + ul_width, 0);
  108. }
  109. draw_sprite(ctx, sprites[decors_active + 2], width - ur_width, 0);
  110. for (int i = 0; i < height - (u_height + l_height); ++i) {
  111. draw_sprite(ctx, sprites[decors_active + 3], 0, i + u_height);
  112. draw_sprite(ctx, sprites[decors_active + 4], width - mr_width, i + u_height);
  113. }
  114. draw_sprite(ctx, sprites[decors_active + 5], 0, height - l_height);
  115. for (int i = 0; i < width - (ll_width + lr_width); ++i) {
  116. draw_sprite(ctx, sprites[decors_active + 6], i + ll_width, height - l_height);
  117. }
  118. draw_sprite(ctx, sprites[decors_active + 7], width - lr_width, height - l_height);
  119. }
  120. char * tmp_title = strdup(title);
  121. int t_l = strlen(tmp_title);
  122. #define EXTRA_SPACE 120
  123. uint32_t title_color = (decors_active == 0) ? rgb(226,226,226) : rgb(147,147,147);
  124. if (_have_freetype) {
  125. freetype_set_font_face(1); /* regular non-monospace */
  126. freetype_set_font_size(12);
  127. if (freetype_draw_string_width(tmp_title) + EXTRA_SPACE > width) {
  128. while (t_l >= 0 && (freetype_draw_string_width(tmp_title) + EXTRA_SPACE > width)) {
  129. tmp_title[t_l] = '\0';
  130. t_l--;
  131. }
  132. }
  133. if (*tmp_title) {
  134. int title_offset = (width / 2) - (freetype_draw_string_width(tmp_title) / 2);
  135. freetype_draw_string(ctx, title_offset, TEXT_OFFSET + 14, title_color, tmp_title);
  136. }
  137. } else {
  138. if (draw_sdf_string_width(tmp_title, 18, SDF_FONT_BOLD) + EXTRA_SPACE > width) {
  139. while (t_l >= 0 && (draw_sdf_string_width(tmp_title, 18, SDF_FONT_BOLD) + EXTRA_SPACE > width)) {
  140. tmp_title[t_l] = '\0';
  141. t_l--;
  142. }
  143. }
  144. if (*tmp_title) {
  145. int title_offset = (width / 2) - (draw_sdf_string_width(tmp_title, 18, SDF_FONT_BOLD) / 2);
  146. draw_sdf_string(ctx, title_offset, TEXT_OFFSET, tmp_title, 18, title_color, SDF_FONT_BOLD);
  147. }
  148. }
  149. free(tmp_title);
  150. /* Buttons */
  151. draw_sprite(ctx, sprites[decors_active + 8], width - 28 + BUTTON_OFFSET, 16 - BUTTON_OFFSET);
  152. if (!(window->decorator_flags & DECOR_FLAG_NO_MAXIMIZE)) {
  153. draw_sprite(ctx, sprites[decors_active + 9], width - 50 + BUTTON_OFFSET, 16 - BUTTON_OFFSET);
  154. }
  155. }
  156. static int check_button_press_fancy(yutani_window_t * window, int x, int y) {
  157. if (x >= (int)window->width - 28 + BUTTON_OFFSET && x <= (int)window->width - 18 + BUTTON_OFFSET &&
  158. y >= 16 && y <= 26) {
  159. return DECOR_CLOSE;
  160. }
  161. if (!(window->decorator_flags & DECOR_FLAG_NO_MAXIMIZE)) {
  162. if (x >= (int)window->width - 50 + BUTTON_OFFSET && x <= (int)window->width - 40 + BUTTON_OFFSET &&
  163. y >= 16 && y <= 26) {
  164. return DECOR_MAXIMIZE;
  165. }
  166. }
  167. return 0;
  168. }
  169. void decor_init() {
  170. init_sprite(0, TTK_FANCY_PATH "active/ul.bmp");
  171. init_sprite(1, TTK_FANCY_PATH "active/um.bmp");
  172. init_sprite(2, TTK_FANCY_PATH "active/ur.bmp");
  173. init_sprite(3, TTK_FANCY_PATH "active/ml.bmp");
  174. init_sprite(4, TTK_FANCY_PATH "active/mr.bmp");
  175. init_sprite(5, TTK_FANCY_PATH "active/ll.bmp");
  176. init_sprite(6, TTK_FANCY_PATH "active/lm.bmp");
  177. init_sprite(7, TTK_FANCY_PATH "active/lr.bmp");
  178. init_sprite(8, TTK_FANCY_PATH "active/button-close.bmp");
  179. init_sprite(9, TTK_FANCY_PATH "active/button-maximize.bmp");
  180. init_sprite(INACTIVE + 0, TTK_FANCY_PATH "inactive/ul.bmp");
  181. init_sprite(INACTIVE + 1, TTK_FANCY_PATH "inactive/um.bmp");
  182. init_sprite(INACTIVE + 2, TTK_FANCY_PATH "inactive/ur.bmp");
  183. init_sprite(INACTIVE + 3, TTK_FANCY_PATH "inactive/ml.bmp");
  184. init_sprite(INACTIVE + 4, TTK_FANCY_PATH "inactive/mr.bmp");
  185. init_sprite(INACTIVE + 5, TTK_FANCY_PATH "inactive/ll.bmp");
  186. init_sprite(INACTIVE + 6, TTK_FANCY_PATH "inactive/lm.bmp");
  187. init_sprite(INACTIVE + 7, TTK_FANCY_PATH "inactive/lr.bmp");
  188. init_sprite(INACTIVE + 8, TTK_FANCY_PATH "inactive/button-close.bmp");
  189. init_sprite(INACTIVE + 9, TTK_FANCY_PATH "inactive/button-maximize.bmp");
  190. decor_render_decorations = render_decorations_fancy;
  191. decor_check_button_press = check_button_press_fancy;
  192. decor_get_bounds = get_bounds_fancy;
  193. void * freetype = dlopen("libtoaru_ext_freetype_fonts.so", 0);
  194. if (freetype) {
  195. _have_freetype = 1;
  196. freetype_set_font_face = dlsym(freetype, "freetype_set_font_face");
  197. freetype_set_font_size = dlsym(freetype, "freetype_set_font_size");
  198. freetype_draw_string = dlsym(freetype, "freetype_draw_string");
  199. freetype_draw_string_width = dlsym(freetype, "freetype_draw_string_width");
  200. }
  201. }