tab_swatches.ts 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. let _tab_swatches_empty: image_t;
  2. let tab_swatches_drag_pos: i32 = -1;
  3. function tab_swatches_empty_set(image: image_t) {
  4. _tab_swatches_empty = image;
  5. }
  6. function tab_swatches_empty_get(): image_t {
  7. if (_tab_swatches_empty == null) {
  8. let b: u8_array_t = u8_array_create(4);
  9. b[0] = 255;
  10. b[1] = 255;
  11. b[2] = 255;
  12. b[3] = 255;
  13. _tab_swatches_empty = image_from_bytes(b.buffer, 1, 1);
  14. }
  15. return _tab_swatches_empty;
  16. }
  17. let _tab_swatches_draw_i: i32;
  18. function tab_swatches_draw(htab: zui_handle_t) {
  19. let ui: zui_t = ui_base_ui;
  20. let statush: i32 = config_raw.layout[layout_size_t.STATUS_H];
  21. if (zui_tab(htab, tr("Swatches")) && statush > ui_status_default_status_h * zui_SCALE(ui)) {
  22. zui_begin_sticky();
  23. if (config_raw.touch_ui) {
  24. let row: f32[] = [1 / 5, 1 / 5, 1 / 5, 1 / 5, 1 / 5];
  25. zui_row(row);
  26. }
  27. else {
  28. let row: f32[] = [1 / 14, 1 / 14, 1 / 14, 1 / 14, 1 / 14];
  29. zui_row(row);
  30. }
  31. if (zui_button(tr("New"))) {
  32. context_set_swatch(make_swatch());
  33. array_push(project_raw.swatches, context_raw.swatch);
  34. }
  35. if (ui.is_hovered) {
  36. zui_tooltip(tr("Add new swatch"));
  37. }
  38. if (zui_button(tr("Import"))) {
  39. ui_menu_draw(function (ui: zui_t) {
  40. if (ui_menu_button(ui, tr("Replace Existing"))) {
  41. project_import_swatches(true);
  42. context_set_swatch(project_raw.swatches[0]);
  43. }
  44. if (ui_menu_button(ui, tr("Append"))) {
  45. project_import_swatches(false);
  46. }
  47. }, 2);
  48. }
  49. if (ui.is_hovered) {
  50. zui_tooltip(tr("Import swatches"));
  51. }
  52. if (zui_button(tr("Export"))) {
  53. project_export_swatches();
  54. }
  55. if (ui.is_hovered) {
  56. zui_tooltip(tr("Export swatches"));
  57. }
  58. if (zui_button(tr("Clear"))) {
  59. context_set_swatch(make_swatch());
  60. project_raw.swatches = [context_raw.swatch];
  61. }
  62. if (zui_button(tr("Restore"))) {
  63. project_set_default_swatches();
  64. context_set_swatch(project_raw.swatches[0]);
  65. }
  66. if (ui.is_hovered) {
  67. zui_tooltip(tr("Restore default swatches"));
  68. }
  69. zui_end_sticky();
  70. zui_separator(3, false);
  71. let slotw: i32 = math_floor(26 * zui_SCALE(ui));
  72. let num: i32 = math_floor(ui._w / (slotw + 3));
  73. let drag_pos_set: bool = false;
  74. let uix: f32 = 0.0;
  75. let uiy: f32 = 0.0;
  76. for (let row: i32 = 0; row < math_floor(math_ceil(project_raw.swatches.length / num)); ++row) {
  77. let ar: f32[] = [];
  78. for (let i: i32 = 0; i < num; ++i) {
  79. array_push(ar, 1 / num);
  80. }
  81. zui_row(ar);
  82. ui._x += 2;
  83. if (row > 0) {
  84. ui._y += 6;
  85. }
  86. for (let j: i32 = 0; j < num; ++j) {
  87. let i: i32 = j + row * num;
  88. if (i >= project_raw.swatches.length) {
  89. zui_end_element(slotw);
  90. continue;
  91. }
  92. if (context_raw.swatch == project_raw.swatches[i]) {
  93. let w: i32 = 32;
  94. zui_fill(-2, -2, w, w, ui.ops.theme.HIGHLIGHT_COL);
  95. }
  96. uix = ui._x;
  97. uiy = ui._y;
  98. // Draw the drag position indicator
  99. if (base_drag_swatch != null && tab_swatches_drag_pos == i) {
  100. zui_fill(-1, -2 , 2, 32, ui.ops.theme.HIGHLIGHT_COL);
  101. }
  102. let state: zui_state_t = zui_image(tab_swatches_empty_get(), project_raw.swatches[i].base, slotw);
  103. if (state == zui_state_t.STARTED) {
  104. context_set_swatch(project_raw.swatches[i]);
  105. base_drag_off_x = -(mouse_x - uix - ui._window_x - 2 * slotw);
  106. base_drag_off_y = -(mouse_y - uiy - ui._window_y + 1);
  107. base_drag_swatch = context_raw.swatch;
  108. }
  109. else if (state == zui_state_t.HOVERED) {
  110. tab_swatches_drag_pos = (mouse_x > uix + ui._window_x + slotw / 2) ? i + 1 : i; // Switch to the next position if the mouse crosses the swatch rectangle center
  111. drag_pos_set = true;
  112. }
  113. else if (state == zui_state_t.RELEASED) {
  114. if (time_time() - context_raw.select_time < 0.25) {
  115. _tab_swatches_draw_i = i;
  116. ui_menu_draw(function (ui: zui_t) {
  117. ui.changed = false;
  118. let h: zui_handle_t = zui_handle(__ID__);
  119. h.color = context_raw.swatch.base;
  120. context_raw.swatch.base = zui_color_wheel(h, false, null, 11 * ui.ops.theme.ELEMENT_H * zui_SCALE(ui), true, function () {
  121. context_raw.color_picker_previous_tool = context_raw.tool;
  122. context_select_tool(workspace_tool_t.PICKER);
  123. context_raw.color_picker_callback = function (color: swatch_color_t) {
  124. let i: i32 = _tab_swatches_draw_i;
  125. project_raw.swatches[i] = project_clone_swatch(color);
  126. };
  127. });
  128. let hopacity: zui_handle_t = zui_handle(__ID__);
  129. hopacity.value = context_raw.swatch.opacity;
  130. context_raw.swatch.opacity = zui_slider(hopacity, "Opacity", 0, 1, true);
  131. let hocclusion: zui_handle_t = zui_handle(__ID__);
  132. hocclusion.value = context_raw.swatch.occlusion;
  133. context_raw.swatch.occlusion = zui_slider(hocclusion, "Occlusion", 0, 1, true);
  134. let hroughness: zui_handle_t = zui_handle(__ID__);
  135. hroughness.value = context_raw.swatch.roughness;
  136. context_raw.swatch.roughness = zui_slider(hroughness, "Roughness", 0, 1, true);
  137. let hmetallic: zui_handle_t = zui_handle(__ID__);
  138. hmetallic.value = context_raw.swatch.metallic;
  139. context_raw.swatch.metallic = zui_slider(hmetallic, "Metallic", 0, 1, true);
  140. let hheight: zui_handle_t = zui_handle(__ID__);
  141. hheight.value = context_raw.swatch.height;
  142. context_raw.swatch.height = zui_slider(hheight, "Height", 0, 1, true);
  143. if (ui.changed || ui.is_typing) {
  144. ui_menu_keep_open = true;
  145. }
  146. if (ui.input_released) {
  147. context_set_swatch(context_raw.swatch); // Trigger material preview update
  148. }
  149. }, 16, math_floor(mouse_x - 200 * zui_SCALE(ui)), math_floor(mouse_y - 250 * zui_SCALE(ui)));
  150. }
  151. context_raw.select_time = time_time();
  152. }
  153. if (ui.is_hovered && ui.input_released_r) {
  154. context_set_swatch(project_raw.swatches[i]);
  155. let add: i32 = project_raw.swatches.length > 1 ? 1 : 0;
  156. ///if (krom_windows || krom_linux || krom_darwin)
  157. add += 1; // Copy
  158. ///end
  159. ///if (is_paint || is_sculpt)
  160. add += 3;
  161. ///end
  162. ///if is_lav
  163. add += 1;
  164. ///end
  165. _tab_swatches_draw_i = i;
  166. ui_menu_draw(function (ui: zui_t) {
  167. let i: i32 = _tab_swatches_draw_i;
  168. if (ui_menu_button(ui, tr("Duplicate"))) {
  169. context_set_swatch(project_clone_swatch(context_raw.swatch));
  170. array_push(project_raw.swatches, context_raw.swatch);
  171. }
  172. ///if (krom_windows || krom_linux || krom_darwin)
  173. else if (ui_menu_button(ui, tr("Copy Hex Code"))) {
  174. let color: i32 = context_raw.swatch.base;
  175. color = color_set_ab(color, context_raw.swatch.opacity * 255);
  176. let val: i32 = color;
  177. if (val < 0) {
  178. val += 4294967296;
  179. }
  180. krom_copy_to_clipboard(i32_to_string(val));
  181. }
  182. ///end
  183. else if (project_raw.swatches.length > 1 && ui_menu_button(ui, tr("Delete"), "delete")) {
  184. tab_swatches_delete_swatch(project_raw.swatches[i]);
  185. }
  186. ///if (is_paint || is_sculpt)
  187. else if (ui_menu_button(ui, tr("Create Material"))) {
  188. tab_materials_accept_swatch_drag(project_raw.swatches[i]);
  189. }
  190. else if (ui_menu_button(ui, tr("Create Color Layer"))) {
  191. let color: i32 = project_raw.swatches[i].base;
  192. color = color_set_ab(color, project_raw.swatches[i].opacity * 255);
  193. base_create_color_layer(color, project_raw.swatches[i].occlusion, project_raw.swatches[i].roughness, project_raw.swatches[i].metallic);
  194. }
  195. ///end
  196. }, add);
  197. }
  198. if (ui.is_hovered) {
  199. let color: i32 = project_raw.swatches[i].base;
  200. color = color_set_ab(color, project_raw.swatches[i].opacity * 255);
  201. let val: i32 = color;
  202. if (val < 0) {
  203. val += 4294967296;
  204. }
  205. zui_tooltip("#" + i32_to_string_hex(val));
  206. }
  207. }
  208. }
  209. // Draw the rightmost line next to the last swatch
  210. if (base_drag_swatch != null && tab_swatches_drag_pos == project_raw.swatches.length) {
  211. ui._x = uix; // Reset the position because otherwise it would start in the row below
  212. ui._y = uiy;
  213. zui_fill(28, -2, 2, 32, ui.ops.theme.HIGHLIGHT_COL);
  214. }
  215. // Currently there is no valid dragPosition so reset it
  216. if (!drag_pos_set) {
  217. tab_swatches_drag_pos = -1;
  218. }
  219. let in_focus: bool = ui.input_x > ui._window_x && ui.input_x < ui._window_x + ui._window_w &&
  220. ui.input_y > ui._window_y && ui.input_y < ui._window_y + ui._window_h;
  221. if (in_focus && ui.is_delete_down && project_raw.swatches.length > 1) {
  222. ui.is_delete_down = false;
  223. tab_swatches_delete_swatch(context_raw.swatch);
  224. }
  225. }
  226. }
  227. function tab_swatches_accept_swatch_drag(swatch: swatch_color_t) {
  228. // No valid position available
  229. if (tab_swatches_drag_pos == -1) {
  230. return;
  231. }
  232. let swatch_pos: i32 = array_index_of(project_raw.swatches, swatch);
  233. // A new swatch from color picker
  234. if (swatch_pos == -1) {
  235. array_insert(project_raw.swatches, tab_swatches_drag_pos, swatch);
  236. }
  237. else if (math_abs(swatch_pos - tab_swatches_drag_pos) > 0) { // Existing swatch is reordered
  238. array_remove(project_raw.swatches, swatch);
  239. // If the new position is after the old one, decrease by one because the swatch has been deleted
  240. let new_pos: i32 = tab_swatches_drag_pos - swatch_pos > 0 ? tab_swatches_drag_pos -1 : tab_swatches_drag_pos;
  241. array_insert(project_raw.swatches, new_pos, swatch);
  242. }
  243. }
  244. function tab_swatches_delete_swatch(swatch: swatch_color_t) {
  245. let i: i32 = array_index_of(project_raw.swatches, swatch);
  246. context_set_swatch(project_raw.swatches[i == project_raw.swatches.length - 1 ? i - 1 : i + 1]);
  247. array_splice(project_raw.swatches, i, 1);
  248. ui_base_hwnds[tab_area_t.STATUS].redraws = 2;
  249. }