graph_node.cpp 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180
  1. /**************************************************************************/
  2. /* graph_node.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "graph_node.h"
  31. #include "core/string/translation.h"
  32. #include "graph_edit.h"
  33. struct _MinSizeCache {
  34. int min_size;
  35. bool will_stretch;
  36. int final_size;
  37. };
  38. bool GraphNode::_set(const StringName &p_name, const Variant &p_value) {
  39. String str = p_name;
  40. if (!str.begins_with("slot/")) {
  41. return false;
  42. }
  43. int idx = str.get_slice("/", 1).to_int();
  44. String what = str.get_slice("/", 2);
  45. Slot si;
  46. if (slot_info.has(idx)) {
  47. si = slot_info[idx];
  48. }
  49. if (what == "left_enabled") {
  50. si.enable_left = p_value;
  51. } else if (what == "left_type") {
  52. si.type_left = p_value;
  53. } else if (what == "left_icon") {
  54. si.custom_slot_left = p_value;
  55. } else if (what == "left_color") {
  56. si.color_left = p_value;
  57. } else if (what == "right_enabled") {
  58. si.enable_right = p_value;
  59. } else if (what == "right_type") {
  60. si.type_right = p_value;
  61. } else if (what == "right_color") {
  62. si.color_right = p_value;
  63. } else if (what == "right_icon") {
  64. si.custom_slot_right = p_value;
  65. } else if (what == "draw_stylebox") {
  66. si.draw_stylebox = p_value;
  67. } else {
  68. return false;
  69. }
  70. set_slot(idx, si.enable_left, si.type_left, si.color_left, si.enable_right, si.type_right, si.color_right, si.custom_slot_left, si.custom_slot_right, si.draw_stylebox);
  71. queue_redraw();
  72. return true;
  73. }
  74. bool GraphNode::_get(const StringName &p_name, Variant &r_ret) const {
  75. String str = p_name;
  76. if (!str.begins_with("slot/")) {
  77. return false;
  78. }
  79. int idx = str.get_slice("/", 1).to_int();
  80. String what = str.get_slice("/", 2);
  81. Slot si;
  82. if (slot_info.has(idx)) {
  83. si = slot_info[idx];
  84. }
  85. if (what == "left_enabled") {
  86. r_ret = si.enable_left;
  87. } else if (what == "left_type") {
  88. r_ret = si.type_left;
  89. } else if (what == "left_color") {
  90. r_ret = si.color_left;
  91. } else if (what == "left_icon") {
  92. r_ret = si.custom_slot_left;
  93. } else if (what == "right_enabled") {
  94. r_ret = si.enable_right;
  95. } else if (what == "right_type") {
  96. r_ret = si.type_right;
  97. } else if (what == "right_color") {
  98. r_ret = si.color_right;
  99. } else if (what == "right_icon") {
  100. r_ret = si.custom_slot_right;
  101. } else if (what == "draw_stylebox") {
  102. r_ret = si.draw_stylebox;
  103. } else {
  104. return false;
  105. }
  106. return true;
  107. }
  108. void GraphNode::_get_property_list(List<PropertyInfo> *p_list) const {
  109. int idx = 0;
  110. for (int i = 0; i < get_child_count(); i++) {
  111. Control *c = Object::cast_to<Control>(get_child(i));
  112. if (!c || c->is_set_as_top_level()) {
  113. continue;
  114. }
  115. String base = "slot/" + itos(idx) + "/";
  116. p_list->push_back(PropertyInfo(Variant::BOOL, base + "left_enabled"));
  117. p_list->push_back(PropertyInfo(Variant::INT, base + "left_type"));
  118. p_list->push_back(PropertyInfo(Variant::COLOR, base + "left_color"));
  119. p_list->push_back(PropertyInfo(Variant::OBJECT, base + "left_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL));
  120. p_list->push_back(PropertyInfo(Variant::BOOL, base + "right_enabled"));
  121. p_list->push_back(PropertyInfo(Variant::INT, base + "right_type"));
  122. p_list->push_back(PropertyInfo(Variant::COLOR, base + "right_color"));
  123. p_list->push_back(PropertyInfo(Variant::OBJECT, base + "right_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL));
  124. p_list->push_back(PropertyInfo(Variant::BOOL, base + "draw_stylebox"));
  125. idx++;
  126. }
  127. }
  128. void GraphNode::_resort() {
  129. /** First pass, determine minimum size AND amount of stretchable elements */
  130. Size2i new_size = get_size();
  131. Ref<StyleBox> sb = get_theme_stylebox(SNAME("frame"));
  132. Ref<StyleBox> sb_slot = get_theme_stylebox(SNAME("slot"));
  133. int sep = get_theme_constant(SNAME("separation"));
  134. bool first = true;
  135. int children_count = 0;
  136. int stretch_min = 0;
  137. int stretch_avail = 0;
  138. float stretch_ratio_total = 0;
  139. HashMap<Control *, _MinSizeCache> min_size_cache;
  140. for (int i = 0; i < get_child_count(); i++) {
  141. Control *c = Object::cast_to<Control>(get_child(i));
  142. if (!c || !c->is_visible_in_tree()) {
  143. continue;
  144. }
  145. if (c->is_set_as_top_level()) {
  146. continue;
  147. }
  148. Size2i size = c->get_combined_minimum_size() + (slot_info[i].draw_stylebox ? sb_slot->get_minimum_size() : Size2());
  149. _MinSizeCache msc;
  150. stretch_min += size.height;
  151. msc.min_size = size.height;
  152. msc.will_stretch = c->get_v_size_flags().has_flag(SIZE_EXPAND);
  153. if (msc.will_stretch) {
  154. stretch_avail += msc.min_size;
  155. stretch_ratio_total += c->get_stretch_ratio();
  156. }
  157. msc.final_size = msc.min_size;
  158. min_size_cache[c] = msc;
  159. children_count++;
  160. }
  161. if (children_count == 0) {
  162. return;
  163. }
  164. int stretch_max = new_size.height - (children_count - 1) * sep;
  165. int stretch_diff = stretch_max - stretch_min;
  166. if (stretch_diff < 0) {
  167. //avoid negative stretch space
  168. stretch_diff = 0;
  169. }
  170. stretch_avail += stretch_diff - sb->get_margin(SIDE_BOTTOM) - sb->get_margin(SIDE_TOP); //available stretch space.
  171. /** Second, pass successively to discard elements that can't be stretched, this will run while stretchable
  172. elements exist */
  173. while (stretch_ratio_total > 0) { // first of all, don't even be here if no stretchable objects exist
  174. bool refit_successful = true; //assume refit-test will go well
  175. for (int i = 0; i < get_child_count(); i++) {
  176. Control *c = Object::cast_to<Control>(get_child(i));
  177. if (!c || !c->is_visible_in_tree()) {
  178. continue;
  179. }
  180. if (c->is_set_as_top_level()) {
  181. continue;
  182. }
  183. ERR_FAIL_COND(!min_size_cache.has(c));
  184. _MinSizeCache &msc = min_size_cache[c];
  185. if (msc.will_stretch) { //wants to stretch
  186. //let's see if it can really stretch
  187. int final_pixel_size = stretch_avail * c->get_stretch_ratio() / stretch_ratio_total;
  188. if (final_pixel_size < msc.min_size) {
  189. //if available stretching area is too small for widget,
  190. //then remove it from stretching area
  191. msc.will_stretch = false;
  192. stretch_ratio_total -= c->get_stretch_ratio();
  193. refit_successful = false;
  194. stretch_avail -= msc.min_size;
  195. msc.final_size = msc.min_size;
  196. break;
  197. } else {
  198. msc.final_size = final_pixel_size;
  199. }
  200. }
  201. }
  202. if (refit_successful) { //uf refit went well, break
  203. break;
  204. }
  205. }
  206. /** Final pass, draw and stretch elements **/
  207. int ofs = sb->get_margin(SIDE_TOP);
  208. first = true;
  209. int idx = 0;
  210. cache_y.clear();
  211. int w = new_size.width - sb->get_minimum_size().x;
  212. for (int i = 0; i < get_child_count(); i++) {
  213. Control *c = Object::cast_to<Control>(get_child(i));
  214. if (!c || !c->is_visible_in_tree()) {
  215. continue;
  216. }
  217. if (c->is_set_as_top_level()) {
  218. continue;
  219. }
  220. _MinSizeCache &msc = min_size_cache[c];
  221. if (first) {
  222. first = false;
  223. } else {
  224. ofs += sep;
  225. }
  226. int from = ofs;
  227. int to = ofs + msc.final_size;
  228. if (msc.will_stretch && idx == children_count - 1) {
  229. //adjust so the last one always fits perfect
  230. //compensating for numerical imprecision
  231. to = new_size.height - sb->get_margin(SIDE_BOTTOM);
  232. }
  233. int size = to - from;
  234. float margin = sb->get_margin(SIDE_LEFT) + (slot_info[i].draw_stylebox ? sb_slot->get_margin(SIDE_LEFT) : 0);
  235. float width = w - (slot_info[i].draw_stylebox ? sb_slot->get_minimum_size().x : 0);
  236. Rect2 rect(margin, from, width, size);
  237. fit_child_in_rect(c, rect);
  238. cache_y.push_back(from - sb->get_margin(SIDE_TOP) + size * 0.5);
  239. ofs = to;
  240. idx++;
  241. }
  242. queue_redraw();
  243. connpos_dirty = true;
  244. }
  245. bool GraphNode::has_point(const Point2 &p_point) const {
  246. if (comment) {
  247. Ref<StyleBox> comment_sb = get_theme_stylebox(SNAME("comment"));
  248. Ref<Texture2D> resizer = get_theme_icon(SNAME("resizer"));
  249. if (Rect2(get_size() - resizer->get_size(), resizer->get_size()).has_point(p_point)) {
  250. return true;
  251. }
  252. if (Rect2(0, 0, get_size().width, comment_sb->get_margin(SIDE_TOP)).has_point(p_point)) {
  253. return true;
  254. }
  255. return false;
  256. } else {
  257. return Control::has_point(p_point);
  258. }
  259. }
  260. void GraphNode::_notification(int p_what) {
  261. switch (p_what) {
  262. case NOTIFICATION_DRAW: {
  263. Ref<StyleBox> sb;
  264. if (comment) {
  265. sb = get_theme_stylebox(selected ? SNAME("comment_focus") : SNAME("comment"));
  266. } else {
  267. sb = get_theme_stylebox(selected ? SNAME("selected_frame") : SNAME("frame"));
  268. }
  269. Ref<StyleBox> sb_slot = get_theme_stylebox(SNAME("slot"));
  270. Ref<Texture2D> port = get_theme_icon(SNAME("port"));
  271. Ref<Texture2D> close = get_theme_icon(SNAME("close"));
  272. Ref<Texture2D> resizer = get_theme_icon(SNAME("resizer"));
  273. int close_offset = get_theme_constant(SNAME("close_offset"));
  274. int close_h_offset = get_theme_constant(SNAME("close_h_offset"));
  275. Color close_color = get_theme_color(SNAME("close_color"));
  276. Color resizer_color = get_theme_color(SNAME("resizer_color"));
  277. int title_offset = get_theme_constant(SNAME("title_offset"));
  278. int title_h_offset = get_theme_constant(SNAME("title_h_offset"));
  279. Color title_color = get_theme_color(SNAME("title_color"));
  280. Point2i icofs = -port->get_size() * 0.5;
  281. int edgeofs = get_theme_constant(SNAME("port_offset"));
  282. icofs.y += sb->get_margin(SIDE_TOP);
  283. draw_style_box(sb, Rect2(Point2(), get_size()));
  284. switch (overlay) {
  285. case OVERLAY_DISABLED: {
  286. } break;
  287. case OVERLAY_BREAKPOINT: {
  288. draw_style_box(get_theme_stylebox(SNAME("breakpoint")), Rect2(Point2(), get_size()));
  289. } break;
  290. case OVERLAY_POSITION: {
  291. draw_style_box(get_theme_stylebox(SNAME("position")), Rect2(Point2(), get_size()));
  292. } break;
  293. }
  294. int w = get_size().width - sb->get_minimum_size().x;
  295. title_buf->draw(get_canvas_item(), Point2(sb->get_margin(SIDE_LEFT) + title_h_offset, -title_buf->get_size().y + title_offset), title_color);
  296. if (show_close) {
  297. Vector2 cpos = Point2(w + sb->get_margin(SIDE_LEFT) + close_h_offset - close->get_width(), -close->get_height() + close_offset);
  298. draw_texture(close, cpos, close_color);
  299. close_rect.position = cpos;
  300. close_rect.size = close->get_size();
  301. } else {
  302. close_rect = Rect2();
  303. }
  304. if (get_child_count() > 0) {
  305. for (const KeyValue<int, Slot> &E : slot_info) {
  306. if (E.key < 0 || E.key >= cache_y.size()) {
  307. continue;
  308. }
  309. if (!slot_info.has(E.key)) {
  310. continue;
  311. }
  312. const Slot &s = slot_info[E.key];
  313. // Left port.
  314. if (s.enable_left) {
  315. Ref<Texture2D> p = port;
  316. if (s.custom_slot_left.is_valid()) {
  317. p = s.custom_slot_left;
  318. }
  319. p->draw(get_canvas_item(), icofs + Point2(edgeofs, cache_y[E.key]), s.color_left);
  320. }
  321. // Right port.
  322. if (s.enable_right) {
  323. Ref<Texture2D> p = port;
  324. if (s.custom_slot_right.is_valid()) {
  325. p = s.custom_slot_right;
  326. }
  327. p->draw(get_canvas_item(), icofs + Point2(get_size().x - edgeofs, cache_y[E.key]), s.color_right);
  328. }
  329. // Draw slot stylebox.
  330. if (s.draw_stylebox) {
  331. Control *c = Object::cast_to<Control>(get_child(E.key));
  332. if (!c || !c->is_visible_in_tree()) {
  333. continue;
  334. }
  335. if (c->is_set_as_top_level()) {
  336. continue;
  337. }
  338. Rect2 c_rect = c->get_rect();
  339. c_rect.position.x = sb->get_margin(SIDE_LEFT);
  340. c_rect.size.width = w;
  341. draw_style_box(sb_slot, c_rect);
  342. }
  343. }
  344. }
  345. if (resizable) {
  346. draw_texture(resizer, get_size() - resizer->get_size(), resizer_color);
  347. }
  348. } break;
  349. case NOTIFICATION_SORT_CHILDREN: {
  350. _resort();
  351. } break;
  352. case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
  353. case NOTIFICATION_TRANSLATION_CHANGED:
  354. case NOTIFICATION_THEME_CHANGED: {
  355. _shape();
  356. update_minimum_size();
  357. queue_redraw();
  358. } break;
  359. }
  360. }
  361. void GraphNode::_shape() {
  362. Ref<Font> font = get_theme_font(SNAME("title_font"));
  363. int font_size = get_theme_font_size(SNAME("title_font_size"));
  364. title_buf->clear();
  365. if (text_direction == Control::TEXT_DIRECTION_INHERITED) {
  366. title_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
  367. } else {
  368. title_buf->set_direction((TextServer::Direction)text_direction);
  369. }
  370. title_buf->add_string(title, font, font_size, language);
  371. }
  372. #ifdef TOOLS_ENABLED
  373. void GraphNode::_edit_set_position(const Point2 &p_position) {
  374. GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent());
  375. if (graph) {
  376. Point2 offset = (p_position + graph->get_scroll_ofs()) * graph->get_zoom();
  377. set_position_offset(offset);
  378. }
  379. set_position(p_position);
  380. }
  381. #endif
  382. void GraphNode::_validate_property(PropertyInfo &p_property) const {
  383. GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent());
  384. if (graph) {
  385. if (p_property.name == "position") {
  386. p_property.usage |= PROPERTY_USAGE_READ_ONLY;
  387. }
  388. }
  389. }
  390. void GraphNode::set_slot(int p_idx, bool p_enable_left, int p_type_left, const Color &p_color_left, bool p_enable_right, int p_type_right, const Color &p_color_right, const Ref<Texture2D> &p_custom_left, const Ref<Texture2D> &p_custom_right, bool p_draw_stylebox) {
  391. ERR_FAIL_COND_MSG(p_idx < 0, vformat("Cannot set slot with p_idx (%d) lesser than zero.", p_idx));
  392. if (!p_enable_left && p_type_left == 0 && p_color_left == Color(1, 1, 1, 1) &&
  393. !p_enable_right && p_type_right == 0 && p_color_right == Color(1, 1, 1, 1) &&
  394. !p_custom_left.is_valid() && !p_custom_right.is_valid()) {
  395. slot_info.erase(p_idx);
  396. return;
  397. }
  398. Slot s;
  399. s.enable_left = p_enable_left;
  400. s.type_left = p_type_left;
  401. s.color_left = p_color_left;
  402. s.enable_right = p_enable_right;
  403. s.type_right = p_type_right;
  404. s.color_right = p_color_right;
  405. s.custom_slot_left = p_custom_left;
  406. s.custom_slot_right = p_custom_right;
  407. s.draw_stylebox = p_draw_stylebox;
  408. slot_info[p_idx] = s;
  409. queue_redraw();
  410. connpos_dirty = true;
  411. emit_signal(SNAME("slot_updated"), p_idx);
  412. }
  413. void GraphNode::clear_slot(int p_idx) {
  414. slot_info.erase(p_idx);
  415. queue_redraw();
  416. connpos_dirty = true;
  417. }
  418. void GraphNode::clear_all_slots() {
  419. slot_info.clear();
  420. queue_redraw();
  421. connpos_dirty = true;
  422. }
  423. bool GraphNode::is_slot_enabled_left(int p_idx) const {
  424. if (!slot_info.has(p_idx)) {
  425. return false;
  426. }
  427. return slot_info[p_idx].enable_left;
  428. }
  429. void GraphNode::set_slot_enabled_left(int p_idx, bool p_enable_left) {
  430. ERR_FAIL_COND_MSG(p_idx < 0, vformat("Cannot set enable_left for the slot with p_idx (%d) lesser than zero.", p_idx));
  431. if (slot_info[p_idx].enable_left == p_enable_left) {
  432. return;
  433. }
  434. slot_info[p_idx].enable_left = p_enable_left;
  435. queue_redraw();
  436. connpos_dirty = true;
  437. emit_signal(SNAME("slot_updated"), p_idx);
  438. }
  439. void GraphNode::set_slot_type_left(int p_idx, int p_type_left) {
  440. ERR_FAIL_COND_MSG(!slot_info.has(p_idx), vformat("Cannot set type_left for the slot '%d' because it hasn't been enabled.", p_idx));
  441. if (slot_info[p_idx].type_left == p_type_left) {
  442. return;
  443. }
  444. slot_info[p_idx].type_left = p_type_left;
  445. queue_redraw();
  446. connpos_dirty = true;
  447. emit_signal(SNAME("slot_updated"), p_idx);
  448. }
  449. int GraphNode::get_slot_type_left(int p_idx) const {
  450. if (!slot_info.has(p_idx)) {
  451. return 0;
  452. }
  453. return slot_info[p_idx].type_left;
  454. }
  455. void GraphNode::set_slot_color_left(int p_idx, const Color &p_color_left) {
  456. ERR_FAIL_COND_MSG(!slot_info.has(p_idx), vformat("Cannot set color_left for the slot '%d' because it hasn't been enabled.", p_idx));
  457. if (slot_info[p_idx].color_left == p_color_left) {
  458. return;
  459. }
  460. slot_info[p_idx].color_left = p_color_left;
  461. queue_redraw();
  462. connpos_dirty = true;
  463. emit_signal(SNAME("slot_updated"), p_idx);
  464. }
  465. Color GraphNode::get_slot_color_left(int p_idx) const {
  466. if (!slot_info.has(p_idx)) {
  467. return Color(1, 1, 1, 1);
  468. }
  469. return slot_info[p_idx].color_left;
  470. }
  471. bool GraphNode::is_slot_enabled_right(int p_idx) const {
  472. if (!slot_info.has(p_idx)) {
  473. return false;
  474. }
  475. return slot_info[p_idx].enable_right;
  476. }
  477. void GraphNode::set_slot_enabled_right(int p_idx, bool p_enable_right) {
  478. ERR_FAIL_COND_MSG(p_idx < 0, vformat("Cannot set enable_right for the slot with p_idx (%d) lesser than zero.", p_idx));
  479. if (slot_info[p_idx].enable_right == p_enable_right) {
  480. return;
  481. }
  482. slot_info[p_idx].enable_right = p_enable_right;
  483. queue_redraw();
  484. connpos_dirty = true;
  485. emit_signal(SNAME("slot_updated"), p_idx);
  486. }
  487. void GraphNode::set_slot_type_right(int p_idx, int p_type_right) {
  488. ERR_FAIL_COND_MSG(!slot_info.has(p_idx), vformat("Cannot set type_right for the slot '%d' because it hasn't been enabled.", p_idx));
  489. if (slot_info[p_idx].type_right == p_type_right) {
  490. return;
  491. }
  492. slot_info[p_idx].type_right = p_type_right;
  493. queue_redraw();
  494. connpos_dirty = true;
  495. emit_signal(SNAME("slot_updated"), p_idx);
  496. }
  497. int GraphNode::get_slot_type_right(int p_idx) const {
  498. if (!slot_info.has(p_idx)) {
  499. return 0;
  500. }
  501. return slot_info[p_idx].type_right;
  502. }
  503. void GraphNode::set_slot_color_right(int p_idx, const Color &p_color_right) {
  504. ERR_FAIL_COND_MSG(!slot_info.has(p_idx), vformat("Cannot set color_right for the slot '%d' because it hasn't been enabled.", p_idx));
  505. if (slot_info[p_idx].color_right == p_color_right) {
  506. return;
  507. }
  508. slot_info[p_idx].color_right = p_color_right;
  509. queue_redraw();
  510. connpos_dirty = true;
  511. emit_signal(SNAME("slot_updated"), p_idx);
  512. }
  513. Color GraphNode::get_slot_color_right(int p_idx) const {
  514. if (!slot_info.has(p_idx)) {
  515. return Color(1, 1, 1, 1);
  516. }
  517. return slot_info[p_idx].color_right;
  518. }
  519. bool GraphNode::is_slot_draw_stylebox(int p_idx) const {
  520. if (!slot_info.has(p_idx)) {
  521. return false;
  522. }
  523. return slot_info[p_idx].draw_stylebox;
  524. }
  525. void GraphNode::set_slot_draw_stylebox(int p_idx, bool p_enable) {
  526. ERR_FAIL_COND_MSG(p_idx < 0, vformat("Cannot set draw_stylebox for the slot with p_idx (%d) lesser than zero.", p_idx));
  527. slot_info[p_idx].draw_stylebox = p_enable;
  528. queue_redraw();
  529. connpos_dirty = true;
  530. emit_signal(SNAME("slot_updated"), p_idx);
  531. }
  532. Size2 GraphNode::get_minimum_size() const {
  533. Ref<StyleBox> sb = get_theme_stylebox(SNAME("frame"));
  534. Ref<StyleBox> sb_slot = get_theme_stylebox(SNAME("slot"));
  535. int sep = get_theme_constant(SNAME("separation"));
  536. int title_h_offset = get_theme_constant(SNAME("title_h_offset"));
  537. bool first = true;
  538. Size2 minsize;
  539. minsize.x = title_buf->get_size().x + title_h_offset;
  540. if (show_close) {
  541. int close_h_offset = get_theme_constant(SNAME("close_h_offset"));
  542. Ref<Texture2D> close = get_theme_icon(SNAME("close"));
  543. //TODO: Remove this magic number after GraphNode rework.
  544. minsize.x += 12 + close->get_width() + close_h_offset;
  545. }
  546. for (int i = 0; i < get_child_count(); i++) {
  547. Control *c = Object::cast_to<Control>(get_child(i));
  548. if (!c) {
  549. continue;
  550. }
  551. if (c->is_set_as_top_level()) {
  552. continue;
  553. }
  554. Size2i size = c->get_combined_minimum_size();
  555. if (slot_info.has(i)) {
  556. size += slot_info[i].draw_stylebox ? sb_slot->get_minimum_size() : Size2();
  557. }
  558. minsize.y += size.y;
  559. minsize.x = MAX(minsize.x, size.x);
  560. if (first) {
  561. first = false;
  562. } else {
  563. minsize.y += sep;
  564. }
  565. }
  566. return minsize + sb->get_minimum_size();
  567. }
  568. void GraphNode::set_title(const String &p_title) {
  569. if (title == p_title) {
  570. return;
  571. }
  572. title = p_title;
  573. _shape();
  574. queue_redraw();
  575. update_minimum_size();
  576. }
  577. String GraphNode::get_title() const {
  578. return title;
  579. }
  580. void GraphNode::set_text_direction(Control::TextDirection p_text_direction) {
  581. ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3);
  582. if (text_direction != p_text_direction) {
  583. text_direction = p_text_direction;
  584. _shape();
  585. queue_redraw();
  586. }
  587. }
  588. Control::TextDirection GraphNode::get_text_direction() const {
  589. return text_direction;
  590. }
  591. void GraphNode::set_language(const String &p_language) {
  592. if (language != p_language) {
  593. language = p_language;
  594. _shape();
  595. queue_redraw();
  596. }
  597. }
  598. String GraphNode::get_language() const {
  599. return language;
  600. }
  601. void GraphNode::set_position_offset(const Vector2 &p_offset) {
  602. if (position_offset == p_offset) {
  603. return;
  604. }
  605. position_offset = p_offset;
  606. emit_signal(SNAME("position_offset_changed"));
  607. queue_redraw();
  608. }
  609. Vector2 GraphNode::get_position_offset() const {
  610. return position_offset;
  611. }
  612. void GraphNode::set_selected(bool p_selected) {
  613. if (!is_selectable() || selected == p_selected) {
  614. return;
  615. }
  616. selected = p_selected;
  617. emit_signal(p_selected ? SNAME("node_selected") : SNAME("node_deselected"));
  618. queue_redraw();
  619. }
  620. bool GraphNode::is_selected() {
  621. return selected;
  622. }
  623. void GraphNode::set_drag(bool p_drag) {
  624. if (p_drag) {
  625. drag_from = get_position_offset();
  626. } else {
  627. emit_signal(SNAME("dragged"), drag_from, get_position_offset()); //useful for undo/redo
  628. }
  629. }
  630. Vector2 GraphNode::get_drag_from() {
  631. return drag_from;
  632. }
  633. void GraphNode::set_show_close_button(bool p_enable) {
  634. if (show_close == p_enable) {
  635. return;
  636. }
  637. show_close = p_enable;
  638. queue_redraw();
  639. }
  640. bool GraphNode::is_close_button_visible() const {
  641. return show_close;
  642. }
  643. void GraphNode::_connpos_update() {
  644. int edgeofs = get_theme_constant(SNAME("port_offset"));
  645. int sep = get_theme_constant(SNAME("separation"));
  646. Ref<StyleBox> sb = get_theme_stylebox(SNAME("frame"));
  647. left_port_cache.clear();
  648. right_port_cache.clear();
  649. int vofs = 0;
  650. int idx = 0;
  651. for (int i = 0; i < get_child_count(); i++) {
  652. Control *c = Object::cast_to<Control>(get_child(i));
  653. if (!c) {
  654. continue;
  655. }
  656. if (c->is_set_as_top_level()) {
  657. continue;
  658. }
  659. Size2i size = c->get_rect().size;
  660. int y = sb->get_margin(SIDE_TOP) + vofs;
  661. int h = size.height;
  662. if (slot_info.has(idx)) {
  663. if (slot_info[idx].enable_left) {
  664. PortCache cc;
  665. cc.position = Point2i(edgeofs, y + h / 2);
  666. cc.height = h;
  667. cc.slot_idx = idx;
  668. cc.type = slot_info[idx].type_left;
  669. cc.color = slot_info[idx].color_left;
  670. left_port_cache.push_back(cc);
  671. }
  672. if (slot_info[idx].enable_right) {
  673. PortCache cc;
  674. cc.position = Point2i(get_size().width - edgeofs, y + h / 2);
  675. cc.height = h;
  676. cc.slot_idx = idx;
  677. cc.type = slot_info[idx].type_right;
  678. cc.color = slot_info[idx].color_right;
  679. right_port_cache.push_back(cc);
  680. }
  681. }
  682. vofs += sep;
  683. vofs += h;
  684. idx++;
  685. }
  686. connpos_dirty = false;
  687. }
  688. int GraphNode::get_connection_input_count() {
  689. if (connpos_dirty) {
  690. _connpos_update();
  691. }
  692. return left_port_cache.size();
  693. }
  694. int GraphNode::get_connection_input_height(int p_port) {
  695. if (connpos_dirty) {
  696. _connpos_update();
  697. }
  698. ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), 0);
  699. return left_port_cache[p_port].height;
  700. }
  701. Vector2 GraphNode::get_connection_input_position(int p_port) {
  702. if (connpos_dirty) {
  703. _connpos_update();
  704. }
  705. ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), Vector2());
  706. Vector2 pos = left_port_cache[p_port].position;
  707. pos.x *= get_scale().x;
  708. pos.y *= get_scale().y;
  709. return pos;
  710. }
  711. int GraphNode::get_connection_input_type(int p_port) {
  712. if (connpos_dirty) {
  713. _connpos_update();
  714. }
  715. ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), 0);
  716. return left_port_cache[p_port].type;
  717. }
  718. Color GraphNode::get_connection_input_color(int p_port) {
  719. if (connpos_dirty) {
  720. _connpos_update();
  721. }
  722. ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), Color());
  723. return left_port_cache[p_port].color;
  724. }
  725. int GraphNode::get_connection_input_slot(int p_port) {
  726. if (connpos_dirty) {
  727. _connpos_update();
  728. }
  729. ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), -1);
  730. return left_port_cache[p_port].slot_idx;
  731. }
  732. int GraphNode::get_connection_output_count() {
  733. if (connpos_dirty) {
  734. _connpos_update();
  735. }
  736. return right_port_cache.size();
  737. }
  738. int GraphNode::get_connection_output_height(int p_port) {
  739. if (connpos_dirty) {
  740. _connpos_update();
  741. }
  742. ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), 0);
  743. return right_port_cache[p_port].height;
  744. }
  745. Vector2 GraphNode::get_connection_output_position(int p_port) {
  746. if (connpos_dirty) {
  747. _connpos_update();
  748. }
  749. ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), Vector2());
  750. Vector2 pos = right_port_cache[p_port].position;
  751. pos.x *= get_scale().x;
  752. pos.y *= get_scale().y;
  753. return pos;
  754. }
  755. int GraphNode::get_connection_output_type(int p_port) {
  756. if (connpos_dirty) {
  757. _connpos_update();
  758. }
  759. ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), 0);
  760. return right_port_cache[p_port].type;
  761. }
  762. Color GraphNode::get_connection_output_color(int p_port) {
  763. if (connpos_dirty) {
  764. _connpos_update();
  765. }
  766. ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), Color());
  767. return right_port_cache[p_port].color;
  768. }
  769. int GraphNode::get_connection_output_slot(int p_port) {
  770. if (connpos_dirty) {
  771. _connpos_update();
  772. }
  773. ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), -1);
  774. return right_port_cache[p_port].slot_idx;
  775. }
  776. void GraphNode::gui_input(const Ref<InputEvent> &p_ev) {
  777. ERR_FAIL_COND(p_ev.is_null());
  778. Ref<InputEventMouseButton> mb = p_ev;
  779. if (mb.is_valid()) {
  780. ERR_FAIL_COND_MSG(get_parent_control() == nullptr, "GraphNode must be the child of a GraphEdit node.");
  781. if (mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
  782. Vector2 mpos = mb->get_position();
  783. if (close_rect.size != Size2() && close_rect.has_point(mpos)) {
  784. //send focus to parent
  785. get_parent_control()->grab_focus();
  786. emit_signal(SNAME("close_request"));
  787. accept_event();
  788. return;
  789. }
  790. Ref<Texture2D> resizer = get_theme_icon(SNAME("resizer"));
  791. if (resizable && mpos.x > get_size().x - resizer->get_width() && mpos.y > get_size().y - resizer->get_height()) {
  792. resizing = true;
  793. resizing_from = mpos;
  794. resizing_from_size = get_size();
  795. accept_event();
  796. return;
  797. }
  798. emit_signal(SNAME("raise_request"));
  799. }
  800. if (!mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
  801. resizing = false;
  802. }
  803. }
  804. Ref<InputEventMouseMotion> mm = p_ev;
  805. if (resizing && mm.is_valid()) {
  806. Vector2 mpos = mm->get_position();
  807. Vector2 diff = mpos - resizing_from;
  808. emit_signal(SNAME("resize_request"), resizing_from_size + diff);
  809. }
  810. }
  811. void GraphNode::set_overlay(Overlay p_overlay) {
  812. if (overlay == p_overlay) {
  813. return;
  814. }
  815. overlay = p_overlay;
  816. queue_redraw();
  817. }
  818. GraphNode::Overlay GraphNode::get_overlay() const {
  819. return overlay;
  820. }
  821. void GraphNode::set_comment(bool p_enable) {
  822. if (comment == p_enable) {
  823. return;
  824. }
  825. comment = p_enable;
  826. queue_redraw();
  827. }
  828. bool GraphNode::is_comment() const {
  829. return comment;
  830. }
  831. void GraphNode::set_resizable(bool p_enable) {
  832. if (resizable == p_enable) {
  833. return;
  834. }
  835. resizable = p_enable;
  836. queue_redraw();
  837. }
  838. bool GraphNode::is_resizable() const {
  839. return resizable;
  840. }
  841. void GraphNode::set_draggable(bool p_draggable) {
  842. draggable = p_draggable;
  843. }
  844. bool GraphNode::is_draggable() {
  845. return draggable;
  846. }
  847. void GraphNode::set_selectable(bool p_selectable) {
  848. if (!p_selectable) {
  849. set_selected(false);
  850. }
  851. selectable = p_selectable;
  852. }
  853. bool GraphNode::is_selectable() {
  854. return selectable;
  855. }
  856. Vector<int> GraphNode::get_allowed_size_flags_horizontal() const {
  857. Vector<int> flags;
  858. flags.append(SIZE_FILL);
  859. flags.append(SIZE_SHRINK_BEGIN);
  860. flags.append(SIZE_SHRINK_CENTER);
  861. flags.append(SIZE_SHRINK_END);
  862. return flags;
  863. }
  864. Vector<int> GraphNode::get_allowed_size_flags_vertical() const {
  865. Vector<int> flags;
  866. flags.append(SIZE_FILL);
  867. flags.append(SIZE_EXPAND);
  868. flags.append(SIZE_SHRINK_BEGIN);
  869. flags.append(SIZE_SHRINK_CENTER);
  870. flags.append(SIZE_SHRINK_END);
  871. return flags;
  872. }
  873. void GraphNode::_bind_methods() {
  874. ClassDB::bind_method(D_METHOD("set_title", "title"), &GraphNode::set_title);
  875. ClassDB::bind_method(D_METHOD("get_title"), &GraphNode::get_title);
  876. ClassDB::bind_method(D_METHOD("set_text_direction", "direction"), &GraphNode::set_text_direction);
  877. ClassDB::bind_method(D_METHOD("get_text_direction"), &GraphNode::get_text_direction);
  878. ClassDB::bind_method(D_METHOD("set_language", "language"), &GraphNode::set_language);
  879. ClassDB::bind_method(D_METHOD("get_language"), &GraphNode::get_language);
  880. ClassDB::bind_method(D_METHOD("set_slot", "slot_index", "enable_left_port", "type_left", "color_left", "enable_right_port", "type_right", "color_right", "custom_icon_left", "custom_icon_right", "draw_stylebox"), &GraphNode::set_slot, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(true));
  881. ClassDB::bind_method(D_METHOD("clear_slot", "slot_index"), &GraphNode::clear_slot);
  882. ClassDB::bind_method(D_METHOD("clear_all_slots"), &GraphNode::clear_all_slots);
  883. ClassDB::bind_method(D_METHOD("set_slot_enabled_left", "slot_index", "enable"), &GraphNode::set_slot_enabled_left);
  884. ClassDB::bind_method(D_METHOD("is_slot_enabled_left", "slot_index"), &GraphNode::is_slot_enabled_left);
  885. ClassDB::bind_method(D_METHOD("set_slot_type_left", "slot_index", "type"), &GraphNode::set_slot_type_left);
  886. ClassDB::bind_method(D_METHOD("get_slot_type_left", "slot_index"), &GraphNode::get_slot_type_left);
  887. ClassDB::bind_method(D_METHOD("set_slot_color_left", "slot_index", "color"), &GraphNode::set_slot_color_left);
  888. ClassDB::bind_method(D_METHOD("get_slot_color_left", "slot_index"), &GraphNode::get_slot_color_left);
  889. ClassDB::bind_method(D_METHOD("set_slot_enabled_right", "slot_index", "enable"), &GraphNode::set_slot_enabled_right);
  890. ClassDB::bind_method(D_METHOD("is_slot_enabled_right", "slot_index"), &GraphNode::is_slot_enabled_right);
  891. ClassDB::bind_method(D_METHOD("set_slot_type_right", "slot_index", "type"), &GraphNode::set_slot_type_right);
  892. ClassDB::bind_method(D_METHOD("get_slot_type_right", "slot_index"), &GraphNode::get_slot_type_right);
  893. ClassDB::bind_method(D_METHOD("set_slot_color_right", "slot_index", "color"), &GraphNode::set_slot_color_right);
  894. ClassDB::bind_method(D_METHOD("get_slot_color_right", "slot_index"), &GraphNode::get_slot_color_right);
  895. ClassDB::bind_method(D_METHOD("is_slot_draw_stylebox", "slot_index"), &GraphNode::is_slot_draw_stylebox);
  896. ClassDB::bind_method(D_METHOD("set_slot_draw_stylebox", "slot_index", "enable"), &GraphNode::set_slot_draw_stylebox);
  897. ClassDB::bind_method(D_METHOD("set_position_offset", "offset"), &GraphNode::set_position_offset);
  898. ClassDB::bind_method(D_METHOD("get_position_offset"), &GraphNode::get_position_offset);
  899. ClassDB::bind_method(D_METHOD("set_comment", "comment"), &GraphNode::set_comment);
  900. ClassDB::bind_method(D_METHOD("is_comment"), &GraphNode::is_comment);
  901. ClassDB::bind_method(D_METHOD("set_resizable", "resizable"), &GraphNode::set_resizable);
  902. ClassDB::bind_method(D_METHOD("is_resizable"), &GraphNode::is_resizable);
  903. ClassDB::bind_method(D_METHOD("set_draggable", "draggable"), &GraphNode::set_draggable);
  904. ClassDB::bind_method(D_METHOD("is_draggable"), &GraphNode::is_draggable);
  905. ClassDB::bind_method(D_METHOD("set_selectable", "selectable"), &GraphNode::set_selectable);
  906. ClassDB::bind_method(D_METHOD("is_selectable"), &GraphNode::is_selectable);
  907. ClassDB::bind_method(D_METHOD("set_selected", "selected"), &GraphNode::set_selected);
  908. ClassDB::bind_method(D_METHOD("is_selected"), &GraphNode::is_selected);
  909. ClassDB::bind_method(D_METHOD("get_connection_input_count"), &GraphNode::get_connection_input_count);
  910. ClassDB::bind_method(D_METHOD("get_connection_input_height", "port"), &GraphNode::get_connection_input_height);
  911. ClassDB::bind_method(D_METHOD("get_connection_input_position", "port"), &GraphNode::get_connection_input_position);
  912. ClassDB::bind_method(D_METHOD("get_connection_input_type", "port"), &GraphNode::get_connection_input_type);
  913. ClassDB::bind_method(D_METHOD("get_connection_input_color", "port"), &GraphNode::get_connection_input_color);
  914. ClassDB::bind_method(D_METHOD("get_connection_input_slot", "port"), &GraphNode::get_connection_input_slot);
  915. ClassDB::bind_method(D_METHOD("get_connection_output_count"), &GraphNode::get_connection_output_count);
  916. ClassDB::bind_method(D_METHOD("get_connection_output_height", "port"), &GraphNode::get_connection_output_height);
  917. ClassDB::bind_method(D_METHOD("get_connection_output_position", "port"), &GraphNode::get_connection_output_position);
  918. ClassDB::bind_method(D_METHOD("get_connection_output_type", "port"), &GraphNode::get_connection_output_type);
  919. ClassDB::bind_method(D_METHOD("get_connection_output_color", "port"), &GraphNode::get_connection_output_color);
  920. ClassDB::bind_method(D_METHOD("get_connection_output_slot", "port"), &GraphNode::get_connection_output_slot);
  921. ClassDB::bind_method(D_METHOD("set_show_close_button", "show"), &GraphNode::set_show_close_button);
  922. ClassDB::bind_method(D_METHOD("is_close_button_visible"), &GraphNode::is_close_button_visible);
  923. ClassDB::bind_method(D_METHOD("set_overlay", "overlay"), &GraphNode::set_overlay);
  924. ClassDB::bind_method(D_METHOD("get_overlay"), &GraphNode::get_overlay);
  925. ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title");
  926. ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_position_offset", "get_position_offset");
  927. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_close"), "set_show_close_button", "is_close_button_visible");
  928. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "resizable"), "set_resizable", "is_resizable");
  929. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draggable"), "set_draggable", "is_draggable");
  930. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selectable"), "set_selectable", "is_selectable");
  931. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selected"), "set_selected", "is_selected");
  932. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "comment"), "set_comment", "is_comment");
  933. ADD_PROPERTY(PropertyInfo(Variant::INT, "overlay", PROPERTY_HINT_ENUM, "Disabled,Breakpoint,Position"), "set_overlay", "get_overlay");
  934. ADD_GROUP("BiDi", "");
  935. ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
  936. ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language");
  937. ADD_GROUP("", "");
  938. ADD_SIGNAL(MethodInfo("position_offset_changed"));
  939. ADD_SIGNAL(MethodInfo("node_selected"));
  940. ADD_SIGNAL(MethodInfo("node_deselected"));
  941. ADD_SIGNAL(MethodInfo("slot_updated", PropertyInfo(Variant::INT, "idx")));
  942. ADD_SIGNAL(MethodInfo("dragged", PropertyInfo(Variant::VECTOR2, "from"), PropertyInfo(Variant::VECTOR2, "to")));
  943. ADD_SIGNAL(MethodInfo("raise_request"));
  944. ADD_SIGNAL(MethodInfo("close_request"));
  945. ADD_SIGNAL(MethodInfo("resize_request", PropertyInfo(Variant::VECTOR2, "new_minsize")));
  946. BIND_ENUM_CONSTANT(OVERLAY_DISABLED);
  947. BIND_ENUM_CONSTANT(OVERLAY_BREAKPOINT);
  948. BIND_ENUM_CONSTANT(OVERLAY_POSITION);
  949. }
  950. GraphNode::GraphNode() {
  951. title_buf.instantiate();
  952. set_mouse_filter(MOUSE_FILTER_STOP);
  953. }