g_color.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /*
  2. * sfnedit/g_color.c
  3. *
  4. * Copyright (C) 2020 bzt (bztsrc@gitlab)
  5. *
  6. * Permission is hereby granted, free of charge, to any person
  7. * obtaining a copy of this software and associated documentation
  8. * files (the "Software"), to deal in the Software without
  9. * restriction, including without limitation the rights to use, copy,
  10. * modify, merge, publish, distribute, sublicense, and/or sell copies
  11. * of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. *
  26. * @brief Glyph window color picker tool
  27. *
  28. */
  29. #include <stdint.h>
  30. #include <stdio.h>
  31. #include "libsfn.h"
  32. #include "ui.h"
  33. #include "lang.h"
  34. int hue = 0, sat = 0, val = 0, colorsel = 0;
  35. extern int sellayers;
  36. /**
  37. * Color conversion RGB to HSV
  38. */
  39. void rgb2hsv(uint32_t c)
  40. {
  41. int r = (int)(((uint8_t*)&c)[2]), g = (int)(((uint8_t*)&c)[1]), b = (int)(((uint8_t*)&c)[0]), m, d;
  42. m = r < g? r : g; if(b < m) m = b;
  43. val = r > g? r : g; if(b > val) val = b;
  44. d = val - m;
  45. if(!val) { sat = 0; return; }
  46. sat = d * 255 / val;
  47. if(!sat) { return; }
  48. if(r == val) hue = 43*(g - b) / d;
  49. else if(g == val) hue = 85 + 43*(b - r) / d;
  50. else hue = 171 + 43*(r - g) / d;
  51. if(hue < 0) hue += 256;
  52. }
  53. /**
  54. * Color conversion HSV to RGB
  55. */
  56. uint32_t hsv2rgb(int a, int h, int s, int v)
  57. {
  58. int i, f, p, q, t;
  59. uint32_t c = (a & 255) << 24;
  60. if(!s) { ((uint8_t*)&c)[2] = ((uint8_t*)&c)[1] = ((uint8_t*)&c)[0] = v; }
  61. else {
  62. if(h > 255) i = 0; else i = h / 43;
  63. f = (h - i * 43) * 6;
  64. p = (v * (255 - s) + 127) >> 8;
  65. q = (v * (255 - ((s * f + 127) >> 8)) + 127) >> 8;
  66. t = (v * (255 - ((s * (255 - f) + 127) >> 8)) + 127) >> 8;
  67. switch(i) {
  68. case 0: ((uint8_t*)&c)[2] = v; ((uint8_t*)&c)[1] = t; ((uint8_t*)&c)[0] = p; break;
  69. case 1: ((uint8_t*)&c)[2] = q; ((uint8_t*)&c)[1] = v; ((uint8_t*)&c)[0] = p; break;
  70. case 2: ((uint8_t*)&c)[2] = p; ((uint8_t*)&c)[1] = v; ((uint8_t*)&c)[0] = t; break;
  71. case 3: ((uint8_t*)&c)[2] = p; ((uint8_t*)&c)[1] = q; ((uint8_t*)&c)[0] = v; break;
  72. case 4: ((uint8_t*)&c)[2] = t; ((uint8_t*)&c)[1] = p; ((uint8_t*)&c)[0] = v; break;
  73. default: ((uint8_t*)&c)[2] = v; ((uint8_t*)&c)[1] = p; ((uint8_t*)&c)[0] = q; break;
  74. }
  75. }
  76. return c;
  77. }
  78. /**
  79. * View for color picker
  80. */
  81. void view_color(int idx)
  82. {
  83. ui_win_t *win = &wins[idx];
  84. char tmp[10];
  85. int i, j, p, x = win->w - 74, w = (win->w - 16) / 32;
  86. uint32_t h, c, s, *uc = (uint32_t*)&ctx.cpal;
  87. uint8_t *d, *a = (uint8_t*)&theme[THEME_LIGHT], *b = (uint8_t*)&theme[THEME_DARK], *C = (uint8_t*)&c;
  88. if(x < 0) x = 0;
  89. if(w > (win->h - 50) / 8) w = (win->h - 50) / 8;
  90. if(w < 5) w = 5;
  91. ssfn_dst.w = win->w - 1;
  92. c = theme[THEME_BG];
  93. s = ((C[2] + C[1] + C[0]) / 3 > 0x7F) ? 0 : 0xFFFFFF;
  94. for(ctx.numcpal = 0; ctx.numcpal < 0xFE && ctx.cpal[(ctx.numcpal << 2) + 3]; ctx.numcpal++);
  95. c = colorsel <= ctx.numcpal ? uc[colorsel] : 0;
  96. if(hue > 254) hue = 254;
  97. ssfn_dst.w = win->w - 4;
  98. for(j = p = 0; j < 8; j++)
  99. for(i = 0; i < 32; i++, p += 4) {
  100. ui_rect(win, 8+i*w, j*w + 30, w-2, w-2, colorsel == j*32+i ? s : theme[THEME_DARKER],
  101. colorsel == j*32+i ? s : theme[THEME_LIGHTER]);
  102. ui_argb(win, 8+i*w+1, j*w + 30+1, w - 4, w - 4, p == 1016 ? theme[THEME_FG] : (p == 1020 ?
  103. theme[THEME_BG] : uc[p >> 2]));
  104. }
  105. if(colorsel >= 0xFE) {
  106. ui_box(win, 4, win->h - 260 - 20, 32 + 256 + 8 + 16, 260, theme[THEME_BG], theme[THEME_BG], theme[THEME_BG]);
  107. if(selfield >= 0 && selfield < 8) selfield = 8;
  108. } else {
  109. if(!c) c = 0xFF000000;
  110. ssfn_dst.x = x; ssfn_dst.y = win->h - 180;
  111. ssfn_putc('A'); ui_num(win, x+18, ssfn_dst.y, C[3], win->field == 4, selfield);
  112. ssfn_dst.x = x; ssfn_dst.y += 24;
  113. ssfn_putc('R'); ui_num(win, x+18, ssfn_dst.y, C[2], win->field == 5, selfield - 2);
  114. ssfn_dst.x = x; ssfn_dst.y += 24;
  115. ssfn_putc('G'); ui_num(win, x+18, ssfn_dst.y, C[1], win->field == 6, selfield - 4);
  116. ssfn_dst.x = x; ssfn_dst.y += 24;
  117. ssfn_putc('B'); ui_num(win, x+18, ssfn_dst.y, C[0], win->field == 7, selfield - 6);
  118. sprintf(tmp, "%02X%02X%02X%02X", C[3], C[2], C[1], C[0]);
  119. ui_box(win, x, ssfn_dst.y + 24, 72, 16, theme[THEME_BG], theme[THEME_BG], theme[THEME_BG]);
  120. ui_text(win, x, ssfn_dst.y + 24, tmp);
  121. ui_box(win, 4, win->h - 264 - 20, 4, 264, theme[THEME_BG], theme[THEME_BG], theme[THEME_BG]);
  122. ui_box(win, 32 + 256 + 8 + 16, win->h - 264 - 20, 4, 264, theme[THEME_BG], theme[THEME_BG], theme[THEME_BG]);
  123. for(p = (win->h - 260 - 20) * win->p + 8, j = 0; j < 256; j++, p += win->p) {
  124. if(C[3] == 255-j) {
  125. win->data[p - 4] = s; win->data[p - 3] = s; win->data[p - 2] = s; win->data[p - 3 - win->p] = s;
  126. win->data[p - 3 + win->p] = s; win->data[p - 4 - 2*win->p] = s;
  127. win->data[p - 4 - win->p] = s; win->data[p - 4 + win->p] = s; win->data[p - 4 + 2*win->p] = s;
  128. for(i = 0; i < 15 && 8 + i < win->w; i++)
  129. win->data[p + i] = s;
  130. } else
  131. for(i = 0; i < 15 && 8 + i < win->w; i++) {
  132. d = (j & 8) ^ (i & 8) ? a : b;
  133. ((uint8_t*)&win->data[p+i])[0] = (d[0]*j + (256 - j)*C[0])>>8;
  134. ((uint8_t*)&win->data[p+i])[1] = (d[1]*j + (256 - j)*C[1])>>8;
  135. ((uint8_t*)&win->data[p+i])[2] = (d[2]*j + (256 - j)*C[2])>>8;
  136. }
  137. }
  138. rgb2hsv(0xFF000000 | c);
  139. for(p = (win->h - 260 - 20) * win->p + 32, j = 0; j < 256; j++, p += win->p) {
  140. for(i = 0; i < 256 && 32 + i < win->w; i++) {
  141. h = 255-j == val ? j+(((val * i) >> 8) & 0xFF) : j; h |= 0xFF000000 | (h << 16) | (h << 8);
  142. win->data[p + i] = sat == i || 255-j == val ? h : hsv2rgb(255, hue,i,255-j);
  143. }
  144. }
  145. for(p = (win->h - 260 - 20) * win->p + 32 + 256 + 8, j = 0; j < 256; j++, p += win->p) {
  146. h = hsv2rgb(255, j, 255, 255);
  147. if(hue == j && 32 + 256 + 8 < win->w) {
  148. h = s;
  149. win->data[p + 19] = h; win->data[p + 18] = h; win->data[p + 17] = h; win->data[p + 18 - win->p] = h;
  150. win->data[p + 18 + win->p] = h; win->data[p + 19 - 2*win->p] = h;
  151. win->data[p + 19 - win->p] = h; win->data[p + 19 + win->p] = h;
  152. win->data[p + 19 + 2*win->p] = h;
  153. }
  154. for(i = 0; i < 15 && 32 + 256 + 8 + i < win->w; i++)
  155. win->data[p + i] = h;
  156. }
  157. }
  158. ui_button(win, x, win->h - 42, 68, lang[COLORS_SET], selfield == 8, win->field == 8);
  159. posx = posy = -1;
  160. }
  161. /**
  162. * On enter handler
  163. */
  164. void ctrl_colors_onenter(int idx)
  165. {
  166. ui_win_t *win = &wins[idx];
  167. win->field = selfield = -1; win->tool = GLYPH_TOOL_LAYER;
  168. if(sellayers < ctx.glyphs[win->unicode].numlayer && ctx.glyphs[win->unicode].layers[sellayers].color != colorsel) {
  169. ctx.glyphs[win->unicode].layers[sellayers].color = colorsel;
  170. if(ctx.glyphs[win->unicode].layers[sellayers].type != SSFN_FRAG_PIXMAP) modified++;
  171. }
  172. }
  173. /**
  174. * On button press handler
  175. */
  176. void ctrl_colors_onbtnpress(int idx)
  177. {
  178. ui_win_t *win = &wins[idx];
  179. int i, x = win->w - 74, w = (win->w - 16) / 32;
  180. uint32_t c;
  181. uint8_t *C = (uint8_t*)&c;
  182. if(x < 0) x = 0;
  183. if(w > (win->h - 50) / 8) w = (win->h - 50) / 8;
  184. if(w < 5) w = 5;
  185. win->field = selfield = -1;
  186. if(event.y >= 30 && event.y < 30 + 8*w && event.x >= 8 && event.x < 8 + 32*w) {
  187. i = (event.y - 30) / w * 32 + (event.x - 8) / w;
  188. while(i > 0 && i < 0xFE && !ctx.cpal[(i << 2) - 1]) i--;
  189. if(colorsel == i) selfield = -2;
  190. else colorsel = i;
  191. } else
  192. if(event.x > x && event.x < x + 72) {
  193. if(colorsel < 0xFE) {
  194. i = colorsel << 2;
  195. if(event.y > win->h - 180 && event.y < win->h - 158) {
  196. if(event.w & (1 << 3)) ctx.cpal[i + 3]++; else
  197. if(event.w & (1 << 4)) ctx.cpal[i + 3]--; else
  198. if(event.x >= x + 58) selfield = 0 + (event.y - (win->h - 180) > 12 ? 1 : 0);
  199. } else
  200. if(event.y > win->h - 156 && event.y < win->h - 132) {
  201. if(event.w & (1 << 3)) ctx.cpal[i + 2]++; else
  202. if(event.w & (1 << 4)) ctx.cpal[i + 2]--; else
  203. if(event.x >= x + 58) selfield = 2 + (event.y - (win->h - 156) > 12 ? 1 : 0);
  204. } else
  205. if(event.y > win->h - 132 && event.y < win->h - 108) {
  206. if(event.w & (1 << 3)) ctx.cpal[i + 1]++; else
  207. if(event.w & (1 << 4)) ctx.cpal[i + 1]--; else
  208. if(event.x >= x + 58) selfield = 4 + (event.y - (win->h - 132) > 12 ? 1 : 0);
  209. } else
  210. if(event.y > win->h - 108 && event.y < win->h - 84) {
  211. if(event.w & (1 << 3)) ctx.cpal[i + 0]++; else
  212. if(event.w & (1 << 4)) ctx.cpal[i + 0]--; else
  213. if(event.x >= x + 58) selfield = 6 + (event.y - (win->h - 108) > 12 ? 1 : 0);
  214. }
  215. }
  216. if(event.y > win->h - 42) selfield = 8;
  217. } else
  218. if(colorsel < 0xFE && event.y >= win->h - 280 && event.y < win->h - 24) {
  219. if(event.x >= 8 && event.x < 24) ctx.cpal[(colorsel << 2) + 3] = 255 - (event.y - (win->h - 260 - 20)); else
  220. if(event.x >= 32 && event.x < 32+256) { sat = event.x - 32; val = 255 - (event.y - (win->h - 260 - 20)); goto set; } else
  221. if(event.x >= 32 + 256 + 8 && event.x < 32 + 256 + 8 + 16) {
  222. hue = (event.y - (win->h - 260 - 20));
  223. set: c = hsv2rgb(255, hue, sat, val);
  224. i = colorsel << 2;
  225. ctx.cpal[i + 0] = C[0];
  226. ctx.cpal[i + 1] = C[1];
  227. ctx.cpal[i + 2] = C[2];
  228. if(!ctx.cpal[i + 3]) ctx.cpal[i + 3] = 255;
  229. }
  230. }
  231. }
  232. /**
  233. * On click (button release) handler
  234. */
  235. void ctrl_colors_onclick(int idx)
  236. {
  237. ui_win_t *win = &wins[idx];
  238. int i, x = win->w - 74, w = (win->w - 16) / 32;
  239. if(x < 0) x = 0;
  240. if(w > (win->h - 50) / 8) w = (win->h - 50) / 8;
  241. if(w < 5) w = 5;
  242. if(event.y >= 30 && event.y < 30 + 8*w && event.x >= 8 && event.x < 8 + 32*w) {
  243. /* double click on palette entry */
  244. if(colorsel == ((event.y - 30) / w * 32 + (event.x - 8) / w) && selfield == -2) ctrl_colors_onenter(idx);
  245. } else
  246. if(event.x > x + 58 && event.x < x + 72 && colorsel < 0xFE) {
  247. i = colorsel << 2;
  248. if(event.y > win->h - 180 && event.y < win->h - 155) {
  249. if(selfield == 0) ctx.cpal[i + 3]++; else
  250. if(selfield == 1) ctx.cpal[i + 3]--;
  251. } else
  252. if(event.y > win->h - 156 && event.y < win->h - 132) {
  253. if(selfield == 2) ctx.cpal[i + 2]++; else
  254. if(selfield == 3) ctx.cpal[i + 2]--;
  255. } else
  256. if(event.y > win->h - 132 && event.y < win->h - 108) {
  257. if(selfield == 4) ctx.cpal[i + 1]++; else
  258. if(selfield == 5) ctx.cpal[i + 1]--;
  259. } else
  260. if(event.y > win->h - 108 && event.y < win->h - 84) {
  261. if(selfield == 6) ctx.cpal[i + 0]++; else
  262. if(selfield == 7) ctx.cpal[i + 0]--;
  263. }
  264. }
  265. if(event.y > win->h - 42 && event.x > x && event.x < x + 72 && selfield == 8) ctrl_colors_onenter(idx);
  266. selfield = -1;
  267. }
  268. /**
  269. * On mouse move handler
  270. */
  271. void ctrl_colors_onmove(int idx)
  272. {
  273. ui_win_t *win = &wins[idx];
  274. int x = win->w - 74;
  275. if(x < 0) x = 0;
  276. if(colorsel < 0xFE && (event.w & 1) && event.x >= 8 && event.x < 32 + 256 + 8 + 16 && event.y >= win->h - 280 &&
  277. event.y < win->h - 24) {
  278. ctrl_colors_onbtnpress(idx);
  279. view_color(idx);
  280. ui_flushwin(win, 0, 0, win->w, win->h);
  281. }
  282. }