g_kern.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. * sfnedit/g_kern.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 kerning tool
  27. *
  28. */
  29. #include <stdint.h>
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include "libsfn.h"
  33. #include "ui.h"
  34. #include "lang.h"
  35. char ksearch[32] = { 0 };
  36. int selkern = 0, scrollkern = 0, pagekern = 0, numk = 0, kres[0x110000], kernn, kernx, kerny;
  37. extern int mousex, mousey, isclick;
  38. void ctrl_zoom_in(int idx, int mx, int my);
  39. void ctrl_zoom_out(int idx, int mx, int my);
  40. void ctrl_move(int idx, int mx, int my);
  41. /**
  42. * Kerning window
  43. */
  44. void view_kern(int idx)
  45. {
  46. ui_win_t *win = &wins[idx];
  47. int i, j, k, l, n, x = win->w - 74, ox = win->zx > 0 ? win->zx : 0, oy = win->zy > 0 ? win->zy : 0;
  48. char st[8];
  49. uint32_t c;
  50. if(x < 0) x = 0;
  51. ssfn_dst.w = x - 6;
  52. ssfn_dst.h = win->h - 24;
  53. pagekern = (win->h - 47 - 29) / 22; if(pagekern < 1) pagekern = 1;
  54. if(!numk) input_refresh = 1;
  55. if(input_refresh && !ksearch[0]) {
  56. ksearch[0] = 0;
  57. for(i = 0; i < ctx.glyphs[win->unicode].numkern; i++) kres[i] = ctx.glyphs[win->unicode].kern[i].n;
  58. numk = ctx.glyphs[win->unicode].numkern;
  59. } else
  60. if(input_refresh) {
  61. numk = scrollkern = 0;
  62. l = strlen(ksearch);
  63. n = (ksearch[0] == 'U' || ksearch[0] == 'u') && ksearch[1] == '+' ? (int)gethex(ksearch + 2, 6) : -1;
  64. /* exact matches first */
  65. for(i = 0; i < UNICODE_NUMNAMES; i++) {
  66. if(ctx.glyphs[i].height && (!strcmp(utf8(uninames[i].unicode), ksearch) || uninames[i].unicode == n))
  67. kres[numk++] = uninames[i].unicode;
  68. }
  69. /* name matches after */
  70. for(i = 0; i < UNICODE_NUMNAMES; i++) {
  71. if(ctx.glyphs[i].height && (strcmp(utf8(uninames[i].unicode), ksearch) && uninames[i].unicode != n)) {
  72. k = strlen(uninames[i].name);
  73. if(k < l) continue;
  74. k -= l;
  75. for(j = 0; j <= k && ui_casecmp(uninames[i].name + j, ksearch, l); j++);
  76. if(j > k) continue;
  77. kres[numk++] = uninames[i].unicode;
  78. }
  79. }
  80. }
  81. if(selkern >= numk) selkern = numk - 1;
  82. if(selkern < 0) selkern = 0;
  83. if(scrollkern + pagekern > numk) scrollkern = numk-pagekern;
  84. if(scrollkern < 0) scrollkern = 0;
  85. input_refresh = 0;
  86. kernn = -1; kernx = 0; kerny = 0;
  87. ui_grid(win, ctx.glyphs[win->unicode].width, ctx.glyphs[win->unicode].height);
  88. if(ctx.glyphs[win->unicode].width && ctx.glyphs[win->unicode].height) {
  89. if(!ctx.glyphs[win->unicode].adv_y) {
  90. ui_gridbg(win, 20 + ox + (ctx.glyphs[win->unicode].rtl ? -win->zoom * ctx.width :
  91. win->zoom * ctx.glyphs[win->unicode].width),
  92. 36 + oy, win->zoom * ctx.width, win->zoom * ctx.height, 0, win->data, -1, -1);
  93. ui_gridbg(win, 20 + ox, 36 + oy, win->zoom * ctx.glyphs[win->unicode].width, win->zoom * ctx.height,
  94. 1, win->data, -1, -1);
  95. } else if(!ctx.glyphs[win->unicode].adv_x) {
  96. i = win->zoom * (ctx.glyphs[win->unicode].width - ctx.width) / 2;
  97. ui_gridbg(win, 20 + ox + i, 36 + oy + win->zoom * ctx.glyphs[win->unicode].height,
  98. win->zoom * ctx.width, win->zoom * ctx.height, 0, win->data, -1, -1);
  99. ui_gridbg(win, 20 + ox + i, 36 + oy, win->zoom * ctx.width, win->zoom * ctx.glyphs[win->unicode].height,
  100. 1, win->data, -1, -1);
  101. }
  102. ui_edit(win, 20 + win->zx, 36 + win->zy, win->unicode, -2);
  103. if(selkern < numk && kres[selkern] > 32) {
  104. kernn = kres[selkern];
  105. for(i = 0; i < ctx.glyphs[win->unicode].numkern && ctx.glyphs[win->unicode].kern[i].n != kres[selkern]; i++);
  106. if(i < ctx.glyphs[win->unicode].numkern) {
  107. kernx = ctx.glyphs[win->unicode].kern[i].x;
  108. kerny = ctx.glyphs[win->unicode].kern[i].y;
  109. }
  110. if(!ctx.glyphs[win->unicode].adv_y) {
  111. ui_edit(win, 20 + win->zx + win->zoom * (ctx.glyphs[win->unicode].rtl ? ctx.glyphs[win->unicode].width -
  112. ctx.glyphs[win->unicode].adv_x - ctx.glyphs[kres[selkern]].width - kernx :
  113. ctx.glyphs[win->unicode].adv_x + kernx), 36 + win->zy + kerny * win->zoom, kres[selkern], -1);
  114. } else if(!ctx.glyphs[win->unicode].adv_x) {
  115. i = win->zoom * ctx.glyphs[kres[selkern]].width / 2;
  116. ui_edit(win, 20 + win->zx, 36 + win->zy + (ctx.glyphs[win->unicode].adv_y+kerny) * win->zoom, kres[selkern], -1);
  117. }
  118. }
  119. }
  120. ssfn_dst.w = win->w - 1;
  121. ssfn_dst.h = win->h - 20;
  122. ui_icon(win, win->w - 130 - 16, 4, ICON_SEARCH, 0);
  123. ui_input(win, win->w - 128, 2, 120, ksearch, win->field == 4, 31, 0);
  124. ui_box(win, x, win->h - 42, 22, 22, theme[win->field == 6 ? THEME_CURSOR : (selfield == 0 ? THEME_DARKER : THEME_LIGHT)],
  125. theme[win->field == 6 ? THEME_LIGHT : THEME_BG],
  126. theme[win->field == 6 ? THEME_CURSOR : (selfield == 0 ? THEME_LIGHT : THEME_DARKER)]);
  127. ui_icon(win, x+3, win->h - 39, ICON_RHORIZ, ctx.glyphs[win->unicode].adv_y > 0);
  128. ui_box(win, x+24, win->h - 42, 22, 22, theme[win->field == 7 ? THEME_CURSOR : (selfield == 1 ? THEME_DARKER : THEME_LIGHT)],
  129. theme[win->field == 7 ? THEME_LIGHT : THEME_BG],
  130. theme[win->field == 7 ? THEME_CURSOR : (selfield == 1 ? THEME_LIGHT : THEME_DARKER)]);
  131. ui_icon(win, x+27, win->h - 39, ICON_HORIZ, ctx.glyphs[win->unicode].adv_y > 0);
  132. ui_box(win, x+48, win->h - 42, 22, 22, theme[win->field == 8 ? THEME_CURSOR : (selfield == 2 ? THEME_DARKER : THEME_LIGHT)],
  133. theme[win->field == 8 ? THEME_LIGHT : THEME_BG],
  134. theme[win->field == 8 ? THEME_CURSOR : (selfield == 2 ? THEME_LIGHT : THEME_DARKER)]);
  135. ui_icon(win, x+51, win->h - 39, ICON_DELETE, ctx.glyphs[win->unicode].numkern < 1);
  136. if(selkern >= ctx.glyphs[win->unicode].numkern) selkern = ctx.glyphs[win->unicode].numkern - 1;
  137. if(selkern < 0) selkern = 0;
  138. ui_box(win, x, 26, 70, win->h - 26 - 46, theme[win->field == 5 ? THEME_CURSOR : THEME_DARKER], theme[THEME_BG],
  139. theme[win->field == 5 ? THEME_CURSOR : THEME_LIGHT]);
  140. ssfn_dst.w = x + 68; ssfn_dst.h = win->h - 49; ssfn_dst.y = 29; x += 3;
  141. for(i = scrollkern, n = 0; i < numk && ssfn_dst.y < ssfn_dst.h; i++, ssfn_dst.y += 11) {
  142. if(i == selkern) {
  143. c = theme[THEME_SELBG];
  144. ssfn_dst.fg = theme[THEME_SELFG];
  145. } else {
  146. c = theme[THEME_DARK];
  147. ssfn_dst.fg = theme[THEME_FG];
  148. }
  149. ui_box(win, x, ssfn_dst.y, 64, 20, c, c, c);
  150. ssfn_dst.x = x + 2; ssfn_dst.y++;
  151. ssfn_putc(kres[i]);
  152. sprintf(st, "%06X", kres[i]);
  153. ssfn_dst.x = x + 22; ssfn_dst.y += 3;
  154. ui_hex(win, st[0]); ui_hex(win, st[1]); ui_hex(win, st[2]);
  155. ssfn_dst.x = x + 22; ssfn_dst.y += 7;
  156. ui_hex(win, st[3]); ui_hex(win, st[4]); ui_hex(win, st[5]);
  157. for(n = 0; n < ctx.glyphs[win->unicode].numkern && ctx.glyphs[win->unicode].kern[n].n != kres[i]; n++);
  158. if(n < ctx.glyphs[win->unicode].numkern && kres[i] == ctx.glyphs[win->unicode].kern[n].n &&
  159. (ctx.glyphs[win->unicode].kern[n].x || ctx.glyphs[win->unicode].kern[n].y)) {
  160. ssfn_dst.x = x + 40; ssfn_dst.y -= 7;
  161. ui_hex(win, 'X'); ui_number(win, x + 46, ssfn_dst.y, ctx.glyphs[win->unicode].kern[n].x, theme[THEME_FG]);
  162. ssfn_dst.x = x + 40; ssfn_dst.y += 7;
  163. ui_hex(win, 'Y'); ui_number(win, x + 46, ssfn_dst.y, ctx.glyphs[win->unicode].kern[n].y, theme[THEME_FG]);
  164. }
  165. }
  166. }
  167. /**
  168. * On enter handler
  169. */
  170. void ctrl_kern_onenter(int idx)
  171. {
  172. ui_win_t *win = &wins[idx];
  173. int n;
  174. switch(win->field) {
  175. case 6: ctx.glyphs[win->unicode].rtl = 1; break;
  176. case 7: ctx.glyphs[win->unicode].rtl = 0; break;
  177. case 8:
  178. for(n = 0; n < ctx.glyphs[win->unicode].numkern && ctx.glyphs[win->unicode].kern[n].n != kres[selkern]; n++);
  179. if(n < ctx.glyphs[win->unicode].numkern) {
  180. memcpy(&ctx.glyphs[win->unicode].kern[n], &ctx.glyphs[win->unicode].kern[n+1],
  181. (ctx.glyphs[win->unicode].numkern - n) * sizeof(sfnkern_t));
  182. ctx.glyphs[win->unicode].numkern--;
  183. }
  184. input_refresh = 1;
  185. break;
  186. }
  187. }
  188. /**
  189. * On key handler
  190. */
  191. void ctrl_kern_onkey(int idx)
  192. {
  193. ui_win_t *win = &wins[idx];
  194. if(win->field == 5) {
  195. switch(event.x) {
  196. case K_UP: if(selkern > 0) selkern--; break;
  197. case K_DOWN: if(selkern < numk - 1) selkern++; break;
  198. }
  199. } else
  200. if(event.x >= ' ') {
  201. strcpy(ksearch, (char*)&event.x);
  202. win->field = 4;
  203. input_refresh = 1;
  204. input_maxlen = 0;
  205. input_str = NULL;
  206. } else {
  207. switch(event.x) {
  208. case K_PGUP: if(selkern > 0) selkern--; break;
  209. case K_PGDN: if(selkern < numk - 1) selkern++; break;
  210. case K_UP: kerny--; break;
  211. case K_DOWN: kerny++; break;
  212. case K_LEFT: kernx--; break;
  213. case K_RIGHT: kernx++; break;
  214. }
  215. sfn_kernadd(win->unicode, kernn, kernx, kerny);
  216. modified++;
  217. }
  218. ui_refreshwin(idx, 20, 29, win->w - 20, win->h - 29 - 24);
  219. }
  220. /**
  221. * On button press handler
  222. */
  223. void ctrl_kern_onbtnpress(int idx)
  224. {
  225. ui_win_t *win = &wins[idx];
  226. int x = win->w - 74, ox = win->zx > 0 ? win->zx : 0, oy = win->zy > 0 ? win->zy : 0;
  227. if(x < 0) x = 0;
  228. selfield = win->field = mousex = mousey = -1;
  229. if(event.y < 26) {
  230. if(event.x > win->w - 130 - 16) win->field = 4;
  231. } else
  232. if(event.x > x) {
  233. if(event.y > 26 && event.y < win->h - 44 && event.x > x && event.x < x + 70) {
  234. if(event.w & 1) selkern = (event.y - 31) / 22 + scrollkern; else
  235. if(event.w & (1 << 3)) scrollkern--; else
  236. if(event.w & (1 << 4)) scrollkern++;
  237. } else
  238. if(event.y > win->h - 42 && event.x > x) {
  239. if(event.x > x && event.x < x + 24 && ctx.glyphs[win->unicode].adv_y < 1) selfield = 0; else
  240. if(event.x > x + 24 && event.x < x + 48 && ctx.glyphs[win->unicode].adv_y < 1) selfield = 1; else
  241. if(event.x > x + 48 && event.x < x + 72 && ctx.glyphs[win->unicode].numkern) selfield = 2;
  242. }
  243. } else
  244. if(event.y < win->h - 22) {
  245. if(event.w & (1 << 3)) ctrl_zoom_in(event.win, event.x, event.y); else
  246. if(event.w & (1 << 4)) ctrl_zoom_out(event.win, event.x, event.y); else
  247. if(event.x >= ox + 20 && event.y >= oy + 36 &&
  248. event.x <= ox + 20 + win->zoom * ctx.glyphs[win->unicode].width &&
  249. event.y <= oy + 36 + win->zoom * ctx.glyphs[win->unicode].height) {
  250. mousex = event.x; mousey = event.y;
  251. isclick = 1;
  252. }
  253. }
  254. }
  255. /**
  256. * On click (button release) handler
  257. */
  258. void ctrl_kern_onclick(int idx)
  259. {
  260. ui_win_t *win = &wins[idx];
  261. int x = win->w - 74, ox = win->zx > 0 ? win->zx : 0, oy = win->zy > 0 ? win->zy : 0;
  262. if(x < 0) x = 0;
  263. if(event.y < 26 && event.x > win->w - 130 - 16) win->field = 4; else
  264. if(event.x > x) {
  265. if(event.y > win->h - 42 && event.x > x) {
  266. if(event.x > x && event.x < x + 24 && selfield == 0) { win->field = 6; ctrl_kern_onenter(idx); } else
  267. if(event.x > x + 24 && event.x < x + 48 && selfield == 1) { win->field = 7; ctrl_kern_onenter(idx); } else
  268. if(event.x > x + 48 && event.x < x + 72 && ctx.glyphs[win->unicode].numkern && selfield == 2) {
  269. win->field = 8; ctrl_kern_onenter(idx);
  270. }
  271. win->field = -1;
  272. }
  273. } else
  274. if(isclick && event.x >= ox + 20 && event.y >= oy + 36 &&
  275. event.x <= ox + 20 + win->zoom * ctx.glyphs[win->unicode].width &&
  276. event.y <= oy + 36 + win->zoom * ctx.glyphs[win->unicode].height && posx != -1 && posy != -1) {
  277. printf("click\n");
  278. }
  279. cursor = CURSOR_PTR; isclick = 0;
  280. selfield = mousex = mousey = -1;
  281. }
  282. /**
  283. * On mouse move handler
  284. */
  285. void ctrl_kern_onmove(int idx)
  286. {
  287. ui_win_t *win = &wins[idx];
  288. int i, x = win->w - 74, ox = win->zx > 0 ? win->zx : 0, oy = win->zy > 0 ? win->zy : 0;
  289. if(x < 0) x = 0;
  290. posx = posy = -1; isclick = 0;
  291. if(event.x > x) {
  292. if(event.y > 26 && event.y < win->h - 44 && event.x > x && event.x < x + 70) {
  293. i = (event.y - 31) / 22 + scrollkern;
  294. if(i < numk) ui_chrinfo(kres[i]);
  295. } else
  296. if(event.y > win->h - 42) {
  297. if(event.x > x && event.x < x + 24) status = lang[COORDS_RTL]; else
  298. if(event.x > x + 24 && event.x < x + 48) status = lang[COORDS_LTR]; else
  299. if(event.x > x + 48 && event.x < x + 72) status = lang[KERN_DELETE];
  300. }
  301. } else
  302. if(event.x >= ox + 20 && event.y >= oy + 36 &&
  303. event.x <= ox + 20 + win->zoom * ctx.glyphs[win->unicode].width &&
  304. event.y <= oy + 36 + win->zoom * ctx.glyphs[win->unicode].height && event.y < win->h - 22) {
  305. if(mousex != -1 && mousey != -1) ctrl_move(event.win, event.x, event.y);
  306. posx = (event.x - ox - 20 - (win->zx < 0 ? win->zx : 0)) / win->zoom;
  307. if(posx >= ctx.glyphs[win->unicode].width) posx = -1;
  308. posy = (event.y - oy - 36 - (win->zy < 0 ? win->zy : 0)) / win->zoom;
  309. if(posy >= ctx.glyphs[win->unicode].height) posy = -1;
  310. }
  311. }