texture_region_editor_plugin.cpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967
  1. /*************************************************************************/
  2. /* texture_region_editor_plugin.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
  10. /* */
  11. /* Author: Mariano Suligoy */
  12. /* */
  13. /* Permission is hereby granted, free of charge, to any person obtaining */
  14. /* a copy of this software and associated documentation files (the */
  15. /* "Software"), to deal in the Software without restriction, including */
  16. /* without limitation the rights to use, copy, modify, merge, publish, */
  17. /* distribute, sublicense, and/or sell copies of the Software, and to */
  18. /* permit persons to whom the Software is furnished to do so, subject to */
  19. /* the following conditions: */
  20. /* */
  21. /* The above copyright notice and this permission notice shall be */
  22. /* included in all copies or substantial portions of the Software. */
  23. /* */
  24. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  25. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  26. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  27. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  28. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  29. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  30. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  31. /*************************************************************************/
  32. #include "texture_region_editor_plugin.h"
  33. #include "core/core_string_names.h"
  34. #include "os/input.h"
  35. #include "os/keyboard.h"
  36. #include "scene/gui/check_box.h"
  37. void draw_margin_line(Control *edit_draw, Vector2 from, Vector2 to) {
  38. Vector2 line = (to - from).normalized() * 10;
  39. while ((to - from).length_squared() > 200) {
  40. edit_draw->draw_line(from, from + line, EditorNode::get_singleton()->get_theme_base()->get_color("mono_color", "Editor"), 2);
  41. from += line * 2;
  42. }
  43. }
  44. void TextureRegionEditor::_region_draw() {
  45. Ref<Texture> base_tex = NULL;
  46. if (node_sprite)
  47. base_tex = node_sprite->get_texture();
  48. else if (node_ninepatch)
  49. base_tex = node_ninepatch->get_texture();
  50. else if (obj_styleBox.is_valid())
  51. base_tex = obj_styleBox->get_texture();
  52. else if (atlas_tex.is_valid())
  53. base_tex = atlas_tex->get_atlas();
  54. if (base_tex.is_null())
  55. return;
  56. Transform2D mtx;
  57. mtx.elements[2] = -draw_ofs;
  58. mtx.scale_basis(Vector2(draw_zoom, draw_zoom));
  59. VS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), mtx);
  60. edit_draw->draw_texture(base_tex, Point2());
  61. VS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(), Transform2D());
  62. if (snap_mode == SNAP_GRID) {
  63. Color grid_color = get_color("grid_major_color", "Editor");
  64. Size2 s = edit_draw->get_size();
  65. int last_cell = 0;
  66. if (snap_step.x != 0) {
  67. if (snap_separation.x == 0)
  68. for (int i = 0; i < s.width; i++) {
  69. int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(i, 0)).x - snap_offset.x) / snap_step.x));
  70. if (i == 0)
  71. last_cell = cell;
  72. if (last_cell != cell)
  73. edit_draw->draw_line(Point2(i, 0), Point2(i, s.height), grid_color);
  74. last_cell = cell;
  75. }
  76. else
  77. for (int i = 0; i < s.width; i++) {
  78. int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(i, 0)).x - snap_offset.x) / (snap_step.x + snap_separation.x)));
  79. if (i == 0)
  80. last_cell = cell;
  81. if (last_cell != cell)
  82. edit_draw->draw_rect(Rect2(i - snap_separation.x * draw_zoom, 0, snap_separation.x * draw_zoom, s.height), grid_color);
  83. last_cell = cell;
  84. }
  85. }
  86. if (snap_step.y != 0) {
  87. if (snap_separation.y == 0)
  88. for (int i = 0; i < s.height; i++) {
  89. int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(0, i)).y - snap_offset.y) / snap_step.y));
  90. if (i == 0)
  91. last_cell = cell;
  92. if (last_cell != cell)
  93. edit_draw->draw_line(Point2(0, i), Point2(s.width, i), grid_color);
  94. last_cell = cell;
  95. }
  96. else
  97. for (int i = 0; i < s.height; i++) {
  98. int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(0, i)).y - snap_offset.y) / (snap_step.y + snap_separation.y)));
  99. if (i == 0)
  100. last_cell = cell;
  101. if (last_cell != cell)
  102. edit_draw->draw_rect(Rect2(0, i - snap_separation.y * draw_zoom, s.width, snap_separation.y * draw_zoom), grid_color);
  103. last_cell = cell;
  104. }
  105. }
  106. } else if (snap_mode == SNAP_AUTOSLICE) {
  107. for (List<Rect2>::Element *E = autoslice_cache.front(); E; E = E->next()) {
  108. Rect2 r = E->get();
  109. Vector2 endpoints[4] = {
  110. mtx.basis_xform(r.position),
  111. mtx.basis_xform(r.position + Vector2(r.size.x, 0)),
  112. mtx.basis_xform(r.position + r.size),
  113. mtx.basis_xform(r.position + Vector2(0, r.size.y))
  114. };
  115. for (int i = 0; i < 4; i++) {
  116. int next = (i + 1) % 4;
  117. edit_draw->draw_line(endpoints[i] - draw_ofs, endpoints[next] - draw_ofs, Color(0.3, 0.7, 1, 1), 2);
  118. }
  119. }
  120. }
  121. Ref<Texture> select_handle = get_icon("EditorHandle", "EditorIcons");
  122. Rect2 scroll_rect(Point2(), mtx.basis_xform(base_tex->get_size()));
  123. scroll_rect.expand_to(mtx.basis_xform(edit_draw->get_size()));
  124. Vector2 endpoints[4] = {
  125. mtx.basis_xform(rect.position),
  126. mtx.basis_xform(rect.position + Vector2(rect.size.x, 0)),
  127. mtx.basis_xform(rect.position + rect.size),
  128. mtx.basis_xform(rect.position + Vector2(0, rect.size.y))
  129. };
  130. Color color = get_color("mono_color", "Editor");
  131. for (int i = 0; i < 4; i++) {
  132. int prev = (i + 3) % 4;
  133. int next = (i + 1) % 4;
  134. Vector2 ofs = ((endpoints[i] - endpoints[prev]).normalized() + ((endpoints[i] - endpoints[next]).normalized())).normalized();
  135. ofs *= 1.4144 * (select_handle->get_size().width / 2);
  136. edit_draw->draw_line(endpoints[i] - draw_ofs, endpoints[next] - draw_ofs, color, 2);
  137. if (snap_mode != SNAP_AUTOSLICE)
  138. edit_draw->draw_texture(select_handle, (endpoints[i] + ofs - (select_handle->get_size() / 2)).floor() - draw_ofs);
  139. ofs = (endpoints[next] - endpoints[i]) / 2;
  140. ofs += (endpoints[next] - endpoints[i]).tangent().normalized() * (select_handle->get_size().width / 2);
  141. if (snap_mode != SNAP_AUTOSLICE)
  142. edit_draw->draw_texture(select_handle, (endpoints[i] + ofs - (select_handle->get_size() / 2)).floor() - draw_ofs);
  143. scroll_rect.expand_to(endpoints[i]);
  144. }
  145. scroll_rect = scroll_rect.grow(200);
  146. updating_scroll = true;
  147. hscroll->set_min(scroll_rect.position.x);
  148. hscroll->set_max(scroll_rect.position.x + scroll_rect.size.x);
  149. hscroll->set_page(edit_draw->get_size().x);
  150. hscroll->set_value(draw_ofs.x);
  151. hscroll->set_step(0.001);
  152. vscroll->set_min(scroll_rect.position.y);
  153. vscroll->set_max(scroll_rect.position.y + scroll_rect.size.y);
  154. vscroll->set_page(edit_draw->get_size().y);
  155. vscroll->set_value(draw_ofs.y);
  156. vscroll->set_step(0.001);
  157. updating_scroll = false;
  158. float margins[4];
  159. if (node_ninepatch || obj_styleBox.is_valid()) {
  160. if (node_ninepatch) {
  161. margins[0] = node_ninepatch->get_patch_margin(MARGIN_TOP);
  162. margins[1] = node_ninepatch->get_patch_margin(MARGIN_BOTTOM);
  163. margins[2] = node_ninepatch->get_patch_margin(MARGIN_LEFT);
  164. margins[3] = node_ninepatch->get_patch_margin(MARGIN_RIGHT);
  165. } else if (obj_styleBox.is_valid()) {
  166. margins[0] = obj_styleBox->get_margin_size(MARGIN_TOP);
  167. margins[1] = obj_styleBox->get_margin_size(MARGIN_BOTTOM);
  168. margins[2] = obj_styleBox->get_margin_size(MARGIN_LEFT);
  169. margins[3] = obj_styleBox->get_margin_size(MARGIN_RIGHT);
  170. }
  171. Vector2 pos[4] = {
  172. mtx.basis_xform(Vector2(0, margins[0])) + Vector2(0, endpoints[0].y - draw_ofs.y),
  173. -mtx.basis_xform(Vector2(0, margins[1])) + Vector2(0, endpoints[2].y - draw_ofs.y),
  174. mtx.basis_xform(Vector2(margins[2], 0)) + Vector2(endpoints[0].x - draw_ofs.x, 0),
  175. -mtx.basis_xform(Vector2(margins[3], 0)) + Vector2(endpoints[2].x - draw_ofs.x, 0)
  176. };
  177. draw_margin_line(edit_draw, pos[0], pos[0] + Vector2(edit_draw->get_size().x, 0));
  178. draw_margin_line(edit_draw, pos[1], pos[1] + Vector2(edit_draw->get_size().x, 0));
  179. draw_margin_line(edit_draw, pos[2], pos[2] + Vector2(0, edit_draw->get_size().y));
  180. draw_margin_line(edit_draw, pos[3], pos[3] + Vector2(0, edit_draw->get_size().y));
  181. }
  182. }
  183. void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
  184. Transform2D mtx;
  185. mtx.elements[2] = -draw_ofs;
  186. mtx.scale_basis(Vector2(draw_zoom, draw_zoom));
  187. Vector2 endpoints[8] = {
  188. mtx.xform(rect.position) + Vector2(-4, -4),
  189. mtx.xform(rect.position + Vector2(rect.size.x / 2, 0)) + Vector2(0, -4),
  190. mtx.xform(rect.position + Vector2(rect.size.x, 0)) + Vector2(4, -4),
  191. mtx.xform(rect.position + Vector2(rect.size.x, rect.size.y / 2)) + Vector2(4, 0),
  192. mtx.xform(rect.position + rect.size) + Vector2(4, 4),
  193. mtx.xform(rect.position + Vector2(rect.size.x / 2, rect.size.y)) + Vector2(0, 4),
  194. mtx.xform(rect.position + Vector2(0, rect.size.y)) + Vector2(-4, 4),
  195. mtx.xform(rect.position + Vector2(0, rect.size.y / 2)) + Vector2(-4, 0)
  196. };
  197. Ref<InputEventMouseButton> mb = p_input;
  198. if (mb.is_valid()) {
  199. if (mb->get_button_index() == BUTTON_LEFT) {
  200. if (mb->is_pressed()) {
  201. if (node_ninepatch || obj_styleBox.is_valid()) {
  202. edited_margin = -1;
  203. float margins[4];
  204. if (node_ninepatch) {
  205. margins[0] = node_ninepatch->get_patch_margin(MARGIN_TOP);
  206. margins[1] = node_ninepatch->get_patch_margin(MARGIN_BOTTOM);
  207. margins[2] = node_ninepatch->get_patch_margin(MARGIN_LEFT);
  208. margins[3] = node_ninepatch->get_patch_margin(MARGIN_RIGHT);
  209. } else if (obj_styleBox.is_valid()) {
  210. margins[0] = obj_styleBox->get_margin_size(MARGIN_TOP);
  211. margins[1] = obj_styleBox->get_margin_size(MARGIN_BOTTOM);
  212. margins[2] = obj_styleBox->get_margin_size(MARGIN_LEFT);
  213. margins[3] = obj_styleBox->get_margin_size(MARGIN_RIGHT);
  214. }
  215. Vector2 pos[4] = {
  216. mtx.basis_xform(rect.position + Vector2(0, margins[0])) - draw_ofs,
  217. mtx.basis_xform(rect.position + rect.size - Vector2(0, margins[1])) - draw_ofs,
  218. mtx.basis_xform(rect.position + Vector2(margins[2], 0)) - draw_ofs,
  219. mtx.basis_xform(rect.position + rect.size - Vector2(margins[3], 0)) - draw_ofs
  220. };
  221. if (Math::abs(mb->get_position().y - pos[0].y) < 8) {
  222. edited_margin = 0;
  223. prev_margin = margins[0];
  224. } else if (Math::abs(mb->get_position().y - pos[1].y) < 8) {
  225. edited_margin = 1;
  226. prev_margin = margins[1];
  227. } else if (Math::abs(mb->get_position().x - pos[2].x) < 8) {
  228. edited_margin = 2;
  229. prev_margin = margins[2];
  230. } else if (Math::abs(mb->get_position().x - pos[3].x) < 8) {
  231. edited_margin = 3;
  232. prev_margin = margins[3];
  233. }
  234. if (edited_margin >= 0) {
  235. drag_from = Vector2(mb->get_position().x, mb->get_position().y);
  236. drag = true;
  237. }
  238. }
  239. if (edited_margin < 0 && snap_mode == SNAP_AUTOSLICE) {
  240. Vector2 point = mtx.affine_inverse().xform(Vector2(mb->get_position().x, mb->get_position().y));
  241. for (List<Rect2>::Element *E = autoslice_cache.front(); E; E = E->next()) {
  242. if (E->get().has_point(point)) {
  243. rect = E->get();
  244. if (Input::get_singleton()->is_key_pressed(KEY_CONTROL) && !(Input::get_singleton()->is_key_pressed(KEY_SHIFT | KEY_ALT))) {
  245. Rect2 r;
  246. if (node_sprite)
  247. r = node_sprite->get_region_rect();
  248. else if (node_ninepatch)
  249. r = node_ninepatch->get_region_rect();
  250. else if (obj_styleBox.is_valid())
  251. r = obj_styleBox->get_region_rect();
  252. else if (atlas_tex.is_valid())
  253. r = atlas_tex->get_region();
  254. rect.expand_to(r.position);
  255. rect.expand_to(r.position + r.size);
  256. }
  257. undo_redo->create_action(TTR("Set Region Rect"));
  258. if (node_sprite) {
  259. undo_redo->add_do_method(node_sprite, "set_region_rect", rect);
  260. undo_redo->add_undo_method(node_sprite, "set_region_rect", node_sprite->get_region_rect());
  261. } else if (node_ninepatch) {
  262. undo_redo->add_do_method(node_ninepatch, "set_region_rect", rect);
  263. undo_redo->add_undo_method(node_ninepatch, "set_region_rect", node_ninepatch->get_region_rect());
  264. } else if (obj_styleBox.is_valid()) {
  265. undo_redo->add_do_method(obj_styleBox.ptr(), "set_region_rect", rect);
  266. undo_redo->add_undo_method(obj_styleBox.ptr(), "set_region_rect", obj_styleBox->get_region_rect());
  267. } else if (atlas_tex.is_valid()) {
  268. undo_redo->add_do_method(atlas_tex.ptr(), "set_region", rect);
  269. undo_redo->add_undo_method(atlas_tex.ptr(), "set_region", atlas_tex->get_region());
  270. }
  271. undo_redo->add_do_method(edit_draw, "update");
  272. undo_redo->add_undo_method(edit_draw, "update");
  273. undo_redo->commit_action();
  274. break;
  275. }
  276. }
  277. } else if (edited_margin < 0) {
  278. drag_from = mtx.affine_inverse().xform(Vector2(mb->get_position().x, mb->get_position().y));
  279. if (snap_mode == SNAP_PIXEL)
  280. drag_from = drag_from.snapped(Vector2(1, 1));
  281. else if (snap_mode == SNAP_GRID)
  282. drag_from = snap_point(drag_from);
  283. drag = true;
  284. if (node_sprite)
  285. rect_prev = node_sprite->get_region_rect();
  286. else if (node_ninepatch)
  287. rect_prev = node_ninepatch->get_region_rect();
  288. else if (obj_styleBox.is_valid())
  289. rect_prev = obj_styleBox->get_region_rect();
  290. else if (atlas_tex.is_valid())
  291. rect_prev = atlas_tex->get_region();
  292. for (int i = 0; i < 8; i++) {
  293. Vector2 tuv = endpoints[i];
  294. if (tuv.distance_to(Vector2(mb->get_position().x, mb->get_position().y)) < 8) {
  295. drag_index = i;
  296. }
  297. }
  298. if (drag_index == -1) {
  299. creating = true;
  300. rect = Rect2(drag_from, Size2());
  301. }
  302. }
  303. } else if (drag) {
  304. if (edited_margin >= 0) {
  305. undo_redo->create_action("Set Margin");
  306. static Margin m[4] = { MARGIN_TOP, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT };
  307. if (node_ninepatch) {
  308. undo_redo->add_do_method(node_ninepatch, "set_patch_margin", m[edited_margin], node_ninepatch->get_patch_margin(m[edited_margin]));
  309. undo_redo->add_undo_method(node_ninepatch, "set_patch_margin", m[edited_margin], prev_margin);
  310. } else if (obj_styleBox.is_valid()) {
  311. undo_redo->add_do_method(obj_styleBox.ptr(), "set_margin_size", m[edited_margin], obj_styleBox->get_margin_size(m[edited_margin]));
  312. undo_redo->add_undo_method(obj_styleBox.ptr(), "set_margin_size", m[edited_margin], prev_margin);
  313. obj_styleBox->emit_signal(CoreStringNames::get_singleton()->changed);
  314. }
  315. edited_margin = -1;
  316. } else {
  317. undo_redo->create_action("Set Region Rect");
  318. if (node_sprite) {
  319. undo_redo->add_do_method(node_sprite, "set_region_rect", node_sprite->get_region_rect());
  320. undo_redo->add_undo_method(node_sprite, "set_region_rect", rect_prev);
  321. } else if (atlas_tex.is_valid()) {
  322. undo_redo->add_do_method(atlas_tex.ptr(), "set_region", atlas_tex->get_region());
  323. undo_redo->add_undo_method(atlas_tex.ptr(), "set_region", rect_prev);
  324. } else if (node_ninepatch) {
  325. // FIXME: Is this intentional?
  326. } else if (node_ninepatch) {
  327. undo_redo->add_do_method(node_ninepatch, "set_region_rect", node_ninepatch->get_region_rect());
  328. undo_redo->add_undo_method(node_ninepatch, "set_region_rect", rect_prev);
  329. } else if (obj_styleBox.is_valid()) {
  330. undo_redo->add_do_method(obj_styleBox.ptr(), "set_region_rect", obj_styleBox->get_region_rect());
  331. undo_redo->add_undo_method(obj_styleBox.ptr(), "set_region_rect", rect_prev);
  332. }
  333. drag_index = -1;
  334. }
  335. undo_redo->add_do_method(edit_draw, "update");
  336. undo_redo->add_undo_method(edit_draw, "update");
  337. undo_redo->commit_action();
  338. drag = false;
  339. creating = false;
  340. }
  341. } else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
  342. if (drag) {
  343. drag = false;
  344. if (edited_margin >= 0) {
  345. static Margin m[4] = { MARGIN_TOP, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT };
  346. if (node_ninepatch)
  347. node_ninepatch->set_patch_margin(m[edited_margin], prev_margin);
  348. if (obj_styleBox.is_valid())
  349. obj_styleBox->set_margin_size(m[edited_margin], prev_margin);
  350. edited_margin = -1;
  351. } else {
  352. apply_rect(rect_prev);
  353. rect = rect_prev;
  354. edit_draw->update();
  355. drag_index = -1;
  356. }
  357. }
  358. } else if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) {
  359. _zoom_in();
  360. } else if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) {
  361. _zoom_out();
  362. }
  363. }
  364. Ref<InputEventMouseMotion> mm = p_input;
  365. if (mm.is_valid()) {
  366. if (mm->get_button_mask() & BUTTON_MASK_MIDDLE || Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
  367. Vector2 draged(mm->get_relative().x, mm->get_relative().y);
  368. hscroll->set_value(hscroll->get_value() - draged.x);
  369. vscroll->set_value(vscroll->get_value() - draged.y);
  370. } else if (drag) {
  371. if (edited_margin >= 0) {
  372. float new_margin = 0;
  373. if (edited_margin == 0)
  374. new_margin = prev_margin + (mm->get_position().y - drag_from.y) / draw_zoom;
  375. else if (edited_margin == 1)
  376. new_margin = prev_margin - (mm->get_position().y - drag_from.y) / draw_zoom;
  377. else if (edited_margin == 2)
  378. new_margin = prev_margin + (mm->get_position().x - drag_from.x) / draw_zoom;
  379. else if (edited_margin == 3)
  380. new_margin = prev_margin - (mm->get_position().x - drag_from.x) / draw_zoom;
  381. else
  382. ERR_PRINT("Unexpected edited_margin");
  383. if (new_margin < 0)
  384. new_margin = 0;
  385. static Margin m[4] = { MARGIN_TOP, MARGIN_BOTTOM, MARGIN_LEFT, MARGIN_RIGHT };
  386. if (node_ninepatch)
  387. node_ninepatch->set_patch_margin(m[edited_margin], new_margin);
  388. if (obj_styleBox.is_valid())
  389. obj_styleBox->set_margin_size(m[edited_margin], new_margin);
  390. } else {
  391. Vector2 new_pos = mtx.affine_inverse().xform(mm->get_position());
  392. if (snap_mode == SNAP_PIXEL)
  393. new_pos = new_pos.snapped(Vector2(1, 1));
  394. else if (snap_mode == SNAP_GRID)
  395. new_pos = snap_point(new_pos);
  396. if (creating) {
  397. rect = Rect2(drag_from, Size2());
  398. rect.expand_to(new_pos);
  399. apply_rect(rect);
  400. edit_draw->update();
  401. return;
  402. }
  403. switch (drag_index) {
  404. case 0: {
  405. Vector2 p = rect_prev.position + rect_prev.size;
  406. rect = Rect2(p, Size2());
  407. rect.expand_to(new_pos);
  408. apply_rect(rect);
  409. } break;
  410. case 1: {
  411. Vector2 p = rect_prev.position + Vector2(0, rect_prev.size.y);
  412. rect = Rect2(p, Size2(rect_prev.size.x, 0));
  413. rect.expand_to(new_pos);
  414. apply_rect(rect);
  415. } break;
  416. case 2: {
  417. Vector2 p = rect_prev.position + Vector2(0, rect_prev.size.y);
  418. rect = Rect2(p, Size2());
  419. rect.expand_to(new_pos);
  420. apply_rect(rect);
  421. } break;
  422. case 3: {
  423. Vector2 p = rect_prev.position;
  424. rect = Rect2(p, Size2(0, rect_prev.size.y));
  425. rect.expand_to(new_pos);
  426. apply_rect(rect);
  427. } break;
  428. case 4: {
  429. Vector2 p = rect_prev.position;
  430. rect = Rect2(p, Size2());
  431. rect.expand_to(new_pos);
  432. apply_rect(rect);
  433. } break;
  434. case 5: {
  435. Vector2 p = rect_prev.position;
  436. rect = Rect2(p, Size2(rect_prev.size.x, 0));
  437. rect.expand_to(new_pos);
  438. apply_rect(rect);
  439. } break;
  440. case 6: {
  441. Vector2 p = rect_prev.position + Vector2(rect_prev.size.x, 0);
  442. rect = Rect2(p, Size2());
  443. rect.expand_to(new_pos);
  444. apply_rect(rect);
  445. } break;
  446. case 7: {
  447. Vector2 p = rect_prev.position + Vector2(rect_prev.size.x, 0);
  448. rect = Rect2(p, Size2(0, rect_prev.size.y));
  449. rect.expand_to(new_pos);
  450. apply_rect(rect);
  451. } break;
  452. }
  453. }
  454. edit_draw->update();
  455. }
  456. }
  457. }
  458. void TextureRegionEditor::_scroll_changed(float) {
  459. if (updating_scroll)
  460. return;
  461. draw_ofs.x = hscroll->get_value();
  462. draw_ofs.y = vscroll->get_value();
  463. edit_draw->update();
  464. }
  465. void TextureRegionEditor::_set_snap_mode(int p_mode) {
  466. snap_mode_button->get_popup()->set_item_checked(snap_mode, false);
  467. snap_mode = p_mode;
  468. snap_mode_button->set_text(snap_mode_button->get_popup()->get_item_text(p_mode));
  469. snap_mode_button->get_popup()->set_item_checked(snap_mode, true);
  470. if (snap_mode == SNAP_GRID)
  471. hb_grid->show();
  472. else
  473. hb_grid->hide();
  474. edit_draw->update();
  475. }
  476. void TextureRegionEditor::_set_snap_off_x(float p_val) {
  477. snap_offset.x = p_val;
  478. edit_draw->update();
  479. }
  480. void TextureRegionEditor::_set_snap_off_y(float p_val) {
  481. snap_offset.y = p_val;
  482. edit_draw->update();
  483. }
  484. void TextureRegionEditor::_set_snap_step_x(float p_val) {
  485. snap_step.x = p_val;
  486. edit_draw->update();
  487. }
  488. void TextureRegionEditor::_set_snap_step_y(float p_val) {
  489. snap_step.y = p_val;
  490. edit_draw->update();
  491. }
  492. void TextureRegionEditor::_set_snap_sep_x(float p_val) {
  493. snap_separation.x = p_val;
  494. edit_draw->update();
  495. }
  496. void TextureRegionEditor::_set_snap_sep_y(float p_val) {
  497. snap_separation.y = p_val;
  498. edit_draw->update();
  499. }
  500. void TextureRegionEditor::_zoom_in() {
  501. if (draw_zoom < 8) {
  502. draw_zoom *= 2;
  503. edit_draw->update();
  504. }
  505. }
  506. void TextureRegionEditor::_zoom_reset() {
  507. if (draw_zoom == 1) return;
  508. draw_zoom = 1;
  509. edit_draw->update();
  510. }
  511. void TextureRegionEditor::_zoom_out() {
  512. if (draw_zoom > 0.25) {
  513. draw_zoom /= 2;
  514. edit_draw->update();
  515. }
  516. }
  517. void TextureRegionEditor::apply_rect(const Rect2 &rect) {
  518. if (node_sprite)
  519. node_sprite->set_region_rect(rect);
  520. else if (node_ninepatch)
  521. node_ninepatch->set_region_rect(rect);
  522. else if (obj_styleBox.is_valid())
  523. obj_styleBox->set_region_rect(rect);
  524. else if (atlas_tex.is_valid())
  525. atlas_tex->set_region(rect);
  526. }
  527. void TextureRegionEditor::_notification(int p_what) {
  528. switch (p_what) {
  529. case NOTIFICATION_READY: {
  530. zoom_out->set_icon(get_icon("ZoomLess", "EditorIcons"));
  531. zoom_reset->set_icon(get_icon("ZoomReset", "EditorIcons"));
  532. zoom_in->set_icon(get_icon("ZoomMore", "EditorIcons"));
  533. icon_zoom->set_texture(get_icon("Zoom", "EditorIcons"));
  534. } break;
  535. }
  536. }
  537. void TextureRegionEditor::_node_removed(Object *p_obj) {
  538. if (p_obj == node_sprite || p_obj == node_ninepatch || p_obj == obj_styleBox.ptr() || p_obj == atlas_tex.ptr()) {
  539. node_ninepatch = NULL;
  540. node_sprite = NULL;
  541. obj_styleBox = Ref<StyleBox>(NULL);
  542. atlas_tex = Ref<AtlasTexture>(NULL);
  543. hide();
  544. }
  545. }
  546. void TextureRegionEditor::_bind_methods() {
  547. ClassDB::bind_method(D_METHOD("_edit_region"), &TextureRegionEditor::_edit_region);
  548. ClassDB::bind_method(D_METHOD("_region_draw"), &TextureRegionEditor::_region_draw);
  549. ClassDB::bind_method(D_METHOD("_region_input"), &TextureRegionEditor::_region_input);
  550. ClassDB::bind_method(D_METHOD("_scroll_changed"), &TextureRegionEditor::_scroll_changed);
  551. ClassDB::bind_method(D_METHOD("_node_removed"), &TextureRegionEditor::_node_removed);
  552. ClassDB::bind_method(D_METHOD("_set_snap_mode"), &TextureRegionEditor::_set_snap_mode);
  553. ClassDB::bind_method(D_METHOD("_set_snap_off_x"), &TextureRegionEditor::_set_snap_off_x);
  554. ClassDB::bind_method(D_METHOD("_set_snap_off_y"), &TextureRegionEditor::_set_snap_off_y);
  555. ClassDB::bind_method(D_METHOD("_set_snap_step_x"), &TextureRegionEditor::_set_snap_step_x);
  556. ClassDB::bind_method(D_METHOD("_set_snap_step_y"), &TextureRegionEditor::_set_snap_step_y);
  557. ClassDB::bind_method(D_METHOD("_set_snap_sep_x"), &TextureRegionEditor::_set_snap_sep_x);
  558. ClassDB::bind_method(D_METHOD("_set_snap_sep_y"), &TextureRegionEditor::_set_snap_sep_y);
  559. ClassDB::bind_method(D_METHOD("_zoom_in"), &TextureRegionEditor::_zoom_in);
  560. ClassDB::bind_method(D_METHOD("_zoom_reset"), &TextureRegionEditor::_zoom_reset);
  561. ClassDB::bind_method(D_METHOD("_zoom_out"), &TextureRegionEditor::_zoom_out);
  562. }
  563. void TextureRegionEditor::edit(Object *p_obj) {
  564. if (node_sprite)
  565. node_sprite->remove_change_receptor(this);
  566. if (node_ninepatch)
  567. node_ninepatch->remove_change_receptor(this);
  568. if (obj_styleBox.is_valid())
  569. obj_styleBox->remove_change_receptor(this);
  570. if (atlas_tex.is_valid())
  571. atlas_tex->remove_change_receptor(this);
  572. if (p_obj) {
  573. node_sprite = Object::cast_to<Sprite>(p_obj);
  574. node_ninepatch = Object::cast_to<NinePatchRect>(p_obj);
  575. if (Object::cast_to<StyleBoxTexture>(p_obj))
  576. obj_styleBox = Ref<StyleBoxTexture>(Object::cast_to<StyleBoxTexture>(p_obj));
  577. if (Object::cast_to<AtlasTexture>(p_obj))
  578. atlas_tex = Ref<AtlasTexture>(Object::cast_to<AtlasTexture>(p_obj));
  579. p_obj->add_change_receptor(this);
  580. _edit_region();
  581. } else {
  582. node_sprite = NULL;
  583. node_ninepatch = NULL;
  584. obj_styleBox = Ref<StyleBoxTexture>(NULL);
  585. atlas_tex = Ref<AtlasTexture>(NULL);
  586. }
  587. edit_draw->update();
  588. }
  589. void TextureRegionEditor::_changed_callback(Object *p_changed, const char *p_prop) {
  590. if (!is_visible())
  591. return;
  592. if (p_prop == StringName("atlas") || p_prop == StringName("texture"))
  593. _edit_region();
  594. }
  595. void TextureRegionEditor::_edit_region() {
  596. Ref<Texture> texture = NULL;
  597. if (node_sprite)
  598. texture = node_sprite->get_texture();
  599. else if (node_ninepatch)
  600. texture = node_ninepatch->get_texture();
  601. else if (obj_styleBox.is_valid())
  602. texture = obj_styleBox->get_texture();
  603. else if (atlas_tex.is_valid())
  604. texture = atlas_tex->get_atlas();
  605. if (texture.is_null()) {
  606. return;
  607. }
  608. autoslice_cache.clear();
  609. Ref<Image> i;
  610. i.instance();
  611. if (i->load(texture->get_path()) == OK) {
  612. BitMap bm;
  613. bm.create_from_image_alpha(i);
  614. for (int y = 0; y < i->get_height(); y++) {
  615. for (int x = 0; x < i->get_width(); x++) {
  616. if (bm.get_bit(Point2(x, y))) {
  617. bool found = false;
  618. for (List<Rect2>::Element *E = autoslice_cache.front(); E; E = E->next()) {
  619. Rect2 grown = E->get().grow(1.5);
  620. if (grown.has_point(Point2(x, y))) {
  621. E->get().expand_to(Point2(x, y));
  622. E->get().expand_to(Point2(x + 1, y + 1));
  623. x = E->get().position.x + E->get().size.x - 1;
  624. bool merged = true;
  625. while (merged) {
  626. merged = false;
  627. bool queue_erase = false;
  628. for (List<Rect2>::Element *F = autoslice_cache.front(); F; F = F->next()) {
  629. if (queue_erase) {
  630. autoslice_cache.erase(F->prev());
  631. queue_erase = false;
  632. }
  633. if (F == E)
  634. continue;
  635. if (E->get().grow(1).intersects(F->get())) {
  636. E->get().expand_to(F->get().position);
  637. E->get().expand_to(F->get().position + F->get().size);
  638. if (F->prev()) {
  639. F = F->prev();
  640. autoslice_cache.erase(F->next());
  641. } else {
  642. queue_erase = true;
  643. //Can't delete the first rect in the list.
  644. }
  645. merged = true;
  646. }
  647. }
  648. }
  649. found = true;
  650. break;
  651. }
  652. }
  653. if (!found) {
  654. Rect2 new_rect(x, y, 1, 1);
  655. autoslice_cache.push_back(new_rect);
  656. }
  657. }
  658. }
  659. }
  660. }
  661. if (node_sprite)
  662. rect = node_sprite->get_region_rect();
  663. else if (node_ninepatch)
  664. rect = node_ninepatch->get_region_rect();
  665. else if (obj_styleBox.is_valid())
  666. rect = obj_styleBox->get_region_rect();
  667. else if (atlas_tex.is_valid())
  668. rect = atlas_tex->get_region();
  669. edit_draw->update();
  670. }
  671. Vector2 TextureRegionEditor::snap_point(Vector2 p_target) const {
  672. if (snap_mode == SNAP_GRID) {
  673. p_target.x = Math::snap_scalar_seperation(snap_offset.x, snap_step.x, p_target.x, snap_separation.x);
  674. p_target.y = Math::snap_scalar_seperation(snap_offset.y, snap_step.y, p_target.y, snap_separation.y);
  675. }
  676. return p_target;
  677. }
  678. TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) {
  679. node_sprite = NULL;
  680. node_ninepatch = NULL;
  681. obj_styleBox = Ref<StyleBoxTexture>(NULL);
  682. atlas_tex = Ref<AtlasTexture>(NULL);
  683. editor = p_editor;
  684. undo_redo = editor->get_undo_redo();
  685. snap_step = Vector2(10, 10);
  686. snap_separation = Vector2(0, 0);
  687. edited_margin = -1;
  688. drag_index = -1;
  689. drag = false;
  690. VBoxContainer *main_vb = memnew(VBoxContainer);
  691. add_child(main_vb);
  692. main_vb->set_anchors_and_margins_preset(Control::PRESET_WIDE);
  693. HBoxContainer *hb_tools = memnew(HBoxContainer);
  694. main_vb->add_child(hb_tools);
  695. hb_tools->add_child(memnew(Label(TTR("Snap Mode:"))));
  696. snap_mode_button = memnew(MenuButton);
  697. hb_tools->add_child(snap_mode_button);
  698. snap_mode_button->set_text(TTR("<None>"));
  699. PopupMenu *p = snap_mode_button->get_popup();
  700. p->set_hide_on_checkable_item_selection(false);
  701. p->add_item(TTR("<None>"), 0);
  702. p->add_item(TTR("Pixel Snap"), 1);
  703. p->add_item(TTR("Grid Snap"), 2);
  704. p->add_item(TTR("Auto Slice"), 3);
  705. for (int i = 0; i < 4; i++)
  706. p->set_item_as_checkable(i, true);
  707. p->set_item_checked(0, true);
  708. p->connect("id_pressed", this, "_set_snap_mode");
  709. hb_grid = memnew(HBoxContainer);
  710. hb_tools->add_child(hb_grid);
  711. hb_grid->add_child(memnew(VSeparator));
  712. hb_grid->add_child(memnew(Label(TTR("Offset:"))));
  713. sb_off_x = memnew(SpinBox);
  714. sb_off_x->set_min(-256);
  715. sb_off_x->set_max(256);
  716. sb_off_x->set_step(1);
  717. sb_off_x->set_value(snap_offset.x);
  718. sb_off_x->set_suffix("px");
  719. sb_off_x->connect("value_changed", this, "_set_snap_off_x");
  720. hb_grid->add_child(sb_off_x);
  721. sb_off_y = memnew(SpinBox);
  722. sb_off_y->set_min(-256);
  723. sb_off_y->set_max(256);
  724. sb_off_y->set_step(1);
  725. sb_off_y->set_value(snap_offset.y);
  726. sb_off_y->set_suffix("px");
  727. sb_off_y->connect("value_changed", this, "_set_snap_off_y");
  728. hb_grid->add_child(sb_off_y);
  729. hb_grid->add_child(memnew(VSeparator));
  730. hb_grid->add_child(memnew(Label(TTR("Step:"))));
  731. sb_step_x = memnew(SpinBox);
  732. sb_step_x->set_min(-256);
  733. sb_step_x->set_max(256);
  734. sb_step_x->set_step(1);
  735. sb_step_x->set_value(snap_step.x);
  736. sb_step_x->set_suffix("px");
  737. sb_step_x->connect("value_changed", this, "_set_snap_step_x");
  738. hb_grid->add_child(sb_step_x);
  739. sb_step_y = memnew(SpinBox);
  740. sb_step_y->set_min(-256);
  741. sb_step_y->set_max(256);
  742. sb_step_y->set_step(1);
  743. sb_step_y->set_value(snap_step.y);
  744. sb_step_y->set_suffix("px");
  745. sb_step_y->connect("value_changed", this, "_set_snap_step_y");
  746. hb_grid->add_child(sb_step_y);
  747. hb_grid->add_child(memnew(VSeparator));
  748. hb_grid->add_child(memnew(Label(TTR("Separation:"))));
  749. sb_sep_x = memnew(SpinBox);
  750. sb_sep_x->set_min(0);
  751. sb_sep_x->set_max(256);
  752. sb_sep_x->set_step(1);
  753. sb_sep_x->set_value(snap_separation.x);
  754. sb_sep_x->set_suffix("px");
  755. sb_sep_x->connect("value_changed", this, "_set_snap_sep_x");
  756. hb_grid->add_child(sb_sep_x);
  757. sb_sep_y = memnew(SpinBox);
  758. sb_sep_y->set_min(0);
  759. sb_sep_y->set_max(256);
  760. sb_sep_y->set_step(1);
  761. sb_sep_y->set_value(snap_separation.y);
  762. sb_sep_y->set_suffix("px");
  763. sb_sep_y->connect("value_changed", this, "_set_snap_sep_y");
  764. hb_grid->add_child(sb_sep_y);
  765. hb_grid->hide();
  766. HBoxContainer *main_hb = memnew(HBoxContainer);
  767. main_vb->add_child(main_hb);
  768. edit_draw = memnew(Control);
  769. main_hb->add_child(edit_draw);
  770. main_hb->set_v_size_flags(SIZE_EXPAND_FILL);
  771. edit_draw->set_h_size_flags(SIZE_EXPAND_FILL);
  772. Control *separator = memnew(Control);
  773. separator->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  774. hb_tools->add_child(separator);
  775. icon_zoom = memnew(TextureRect);
  776. hb_tools->add_child(icon_zoom);
  777. zoom_out = memnew(ToolButton);
  778. zoom_out->connect("pressed", this, "_zoom_out");
  779. hb_tools->add_child(zoom_out);
  780. zoom_reset = memnew(ToolButton);
  781. zoom_reset->connect("pressed", this, "_zoom_reset");
  782. hb_tools->add_child(zoom_reset);
  783. zoom_in = memnew(ToolButton);
  784. zoom_in->connect("pressed", this, "_zoom_in");
  785. hb_tools->add_child(zoom_in);
  786. vscroll = memnew(VScrollBar);
  787. main_hb->add_child(vscroll);
  788. vscroll->connect("value_changed", this, "_scroll_changed");
  789. hscroll = memnew(HScrollBar);
  790. main_vb->add_child(hscroll);
  791. hscroll->connect("value_changed", this, "_scroll_changed");
  792. edit_draw->connect("draw", this, "_region_draw");
  793. edit_draw->connect("gui_input", this, "_region_input");
  794. draw_zoom = 1.0;
  795. updating_scroll = false;
  796. edit_draw->set_clip_contents(true);
  797. }
  798. void TextureRegionEditorPlugin::edit(Object *p_object) {
  799. region_editor->edit(p_object);
  800. }
  801. bool TextureRegionEditorPlugin::handles(Object *p_object) const {
  802. return p_object->is_class("Sprite") || p_object->is_class("NinePatchRect") || p_object->is_class("StyleBoxTexture") || p_object->is_class("AtlasTexture");
  803. }
  804. void TextureRegionEditorPlugin::make_visible(bool p_visible) {
  805. if (p_visible) {
  806. region_button->show();
  807. if (region_button->is_pressed())
  808. region_editor->show();
  809. } else {
  810. region_button->hide();
  811. region_editor->edit(NULL);
  812. region_editor->hide();
  813. }
  814. }
  815. Dictionary TextureRegionEditorPlugin::get_state() const {
  816. Dictionary state;
  817. state["zoom"] = region_editor->draw_zoom;
  818. state["snap_offset"] = region_editor->snap_offset;
  819. state["snap_step"] = region_editor->snap_step;
  820. state["snap_separation"] = region_editor->snap_separation;
  821. state["snap_mode"] = region_editor->snap_mode;
  822. return state;
  823. }
  824. void TextureRegionEditorPlugin::set_state(const Dictionary &p_state) {
  825. Dictionary state = p_state;
  826. if (state.has("zoom")) {
  827. region_editor->draw_zoom = p_state["zoom"];
  828. }
  829. if (state.has("snap_step")) {
  830. Vector2 s = state["snap_step"];
  831. region_editor->sb_step_x->set_value(s.x);
  832. region_editor->sb_step_y->set_value(s.y);
  833. region_editor->snap_step = s;
  834. }
  835. if (state.has("snap_offset")) {
  836. Vector2 ofs = state["snap_offset"];
  837. region_editor->sb_off_x->set_value(ofs.x);
  838. region_editor->sb_off_y->set_value(ofs.y);
  839. region_editor->snap_offset = ofs;
  840. }
  841. if (state.has("snap_separation")) {
  842. Vector2 sep = state["snap_separation"];
  843. region_editor->sb_sep_x->set_value(sep.x);
  844. region_editor->sb_sep_y->set_value(sep.y);
  845. region_editor->snap_separation = sep;
  846. }
  847. if (state.has("snap_mode")) {
  848. region_editor->_set_snap_mode(state["snap_mode"]);
  849. }
  850. }
  851. TextureRegionEditorPlugin::TextureRegionEditorPlugin(EditorNode *p_node) {
  852. editor = p_node;
  853. region_editor = memnew(TextureRegionEditor(p_node));
  854. region_button = p_node->add_bottom_panel_item(TTR("Texture Region"), region_editor);
  855. region_button->set_tooltip(TTR("Texture Region Editor"));
  856. region_editor->set_custom_minimum_size(Size2(0, 200));
  857. region_editor->hide();
  858. region_button->hide();
  859. }