texture_button.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*************************************************************************/
  2. /* texture_button.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
  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 "texture_button.h"
  31. #include "core/typedefs.h"
  32. #include <stdlib.h>
  33. Size2 TextureButton::get_minimum_size() const {
  34. Size2 rscale = Control::get_minimum_size();
  35. if (!expand) {
  36. if (normal.is_null()) {
  37. if (pressed.is_null()) {
  38. if (hover.is_null())
  39. if (click_mask.is_null())
  40. rscale = Size2();
  41. else
  42. rscale = click_mask->get_size();
  43. else
  44. rscale = hover->get_size();
  45. } else
  46. rscale = pressed->get_size();
  47. } else
  48. rscale = normal->get_size();
  49. }
  50. return rscale.abs();
  51. }
  52. bool TextureButton::has_point(const Point2 &p_point) const {
  53. if (click_mask.is_valid()) {
  54. Point2 point = p_point;
  55. Rect2 rect = Rect2();
  56. Size2 mask_size = click_mask->get_size();
  57. if (_tile) {
  58. // if the stretch mode is tile we offset the point to keep it inside the mask size
  59. rect.size = mask_size;
  60. if (_position_rect.has_point(point)) {
  61. int cols = (int)Math::ceil(_position_rect.size.x / mask_size.x);
  62. int rows = (int)Math::ceil(_position_rect.size.y / mask_size.y);
  63. int col = (int)(point.x / mask_size.x) % cols;
  64. int row = (int)(point.y / mask_size.y) % rows;
  65. point.x -= mask_size.x * col;
  66. point.y -= mask_size.y * row;
  67. }
  68. } else {
  69. // we need to transform the point from our scaled / translated image back to our mask image
  70. Point2 ofs = _position_rect.position;
  71. Size2 scale = mask_size / _position_rect.size;
  72. switch (stretch_mode) {
  73. case STRETCH_KEEP_ASPECT_COVERED: {
  74. // if the stretch mode is aspect covered the image uses a texture region so we need to take that into account
  75. float min = MIN(scale.x, scale.y);
  76. scale.x = min;
  77. scale.y = min;
  78. ofs -= _texture_region.position / min;
  79. } break;
  80. default: {
  81. // FIXME: Why a switch if we only handle one enum value?
  82. }
  83. }
  84. // offset and scale the new point position to adjust it to the bitmask size
  85. point -= ofs;
  86. point *= scale;
  87. // finally, we need to check if the point is inside a rectangle with a position >= 0,0 and a size <= mask_size
  88. rect.position = Point2(MAX(0, _texture_region.position.x), MAX(0, _texture_region.position.y));
  89. rect.size = Size2(MIN(mask_size.x, _texture_region.size.x), MIN(mask_size.y, _texture_region.size.y));
  90. }
  91. if (!rect.has_point(point)) {
  92. return false;
  93. }
  94. Point2i p = point;
  95. return click_mask->get_bit(p);
  96. }
  97. return Control::has_point(p_point);
  98. }
  99. void TextureButton::_notification(int p_what) {
  100. switch (p_what) {
  101. case NOTIFICATION_DRAW: {
  102. DrawMode draw_mode = get_draw_mode();
  103. Ref<Texture> texdraw;
  104. switch (draw_mode) {
  105. case DRAW_NORMAL: {
  106. if (normal.is_valid())
  107. texdraw = normal;
  108. } break;
  109. case DRAW_HOVER_PRESSED:
  110. case DRAW_PRESSED: {
  111. if (pressed.is_null()) {
  112. if (hover.is_null()) {
  113. if (normal.is_valid())
  114. texdraw = normal;
  115. } else
  116. texdraw = hover;
  117. } else
  118. texdraw = pressed;
  119. } break;
  120. case DRAW_HOVER: {
  121. if (hover.is_null()) {
  122. if (pressed.is_valid() && is_pressed())
  123. texdraw = pressed;
  124. else if (normal.is_valid())
  125. texdraw = normal;
  126. } else
  127. texdraw = hover;
  128. } break;
  129. case DRAW_DISABLED: {
  130. if (disabled.is_null()) {
  131. if (normal.is_valid())
  132. texdraw = normal;
  133. } else
  134. texdraw = disabled;
  135. } break;
  136. }
  137. if (texdraw.is_valid()) {
  138. Point2 ofs;
  139. Size2 size = texdraw->get_size();
  140. _texture_region = Rect2(Point2(), texdraw->get_size());
  141. _tile = false;
  142. if (expand) {
  143. switch (stretch_mode) {
  144. case STRETCH_KEEP:
  145. size = texdraw->get_size();
  146. break;
  147. case STRETCH_SCALE:
  148. size = get_size();
  149. break;
  150. case STRETCH_TILE:
  151. size = get_size();
  152. _tile = true;
  153. break;
  154. case STRETCH_KEEP_CENTERED:
  155. ofs = (get_size() - texdraw->get_size()) / 2;
  156. size = texdraw->get_size();
  157. break;
  158. case STRETCH_KEEP_ASPECT_CENTERED:
  159. case STRETCH_KEEP_ASPECT: {
  160. Size2 _size = get_size();
  161. float tex_width = texdraw->get_width() * _size.height / texdraw->get_height();
  162. float tex_height = _size.height;
  163. if (tex_width > _size.width) {
  164. tex_width = _size.width;
  165. tex_height = texdraw->get_height() * tex_width / texdraw->get_width();
  166. }
  167. if (stretch_mode == STRETCH_KEEP_ASPECT_CENTERED) {
  168. ofs.x = (_size.width - tex_width) / 2;
  169. ofs.y = (_size.height - tex_height) / 2;
  170. }
  171. size.width = tex_width;
  172. size.height = tex_height;
  173. } break;
  174. case STRETCH_KEEP_ASPECT_COVERED: {
  175. size = get_size();
  176. Size2 tex_size = texdraw->get_size();
  177. Size2 scaleSize(size.width / tex_size.width, size.height / tex_size.height);
  178. float scale = scaleSize.width > scaleSize.height ? scaleSize.width : scaleSize.height;
  179. Size2 scaledTexSize = tex_size * scale;
  180. Point2 ofs = ((scaledTexSize - size) / scale).abs() / 2.0f;
  181. _texture_region = Rect2(ofs, size / scale);
  182. } break;
  183. }
  184. }
  185. _position_rect = Rect2(ofs, size);
  186. if (_tile)
  187. draw_texture_rect(texdraw, _position_rect, _tile);
  188. else
  189. draw_texture_rect_region(texdraw, _position_rect, _texture_region);
  190. }
  191. if (has_focus() && focused.is_valid()) {
  192. Rect2 drect(Point2(), get_size());
  193. draw_texture_rect(focused, drect, false);
  194. };
  195. } break;
  196. }
  197. }
  198. void TextureButton::_bind_methods() {
  199. ClassDB::bind_method(D_METHOD("set_normal_texture", "texture"), &TextureButton::set_normal_texture);
  200. ClassDB::bind_method(D_METHOD("set_pressed_texture", "texture"), &TextureButton::set_pressed_texture);
  201. ClassDB::bind_method(D_METHOD("set_hover_texture", "texture"), &TextureButton::set_hover_texture);
  202. ClassDB::bind_method(D_METHOD("set_disabled_texture", "texture"), &TextureButton::set_disabled_texture);
  203. ClassDB::bind_method(D_METHOD("set_focused_texture", "texture"), &TextureButton::set_focused_texture);
  204. ClassDB::bind_method(D_METHOD("set_click_mask", "mask"), &TextureButton::set_click_mask);
  205. ClassDB::bind_method(D_METHOD("set_expand", "p_expand"), &TextureButton::set_expand);
  206. ClassDB::bind_method(D_METHOD("set_stretch_mode", "p_mode"), &TextureButton::set_stretch_mode);
  207. ClassDB::bind_method(D_METHOD("get_normal_texture"), &TextureButton::get_normal_texture);
  208. ClassDB::bind_method(D_METHOD("get_pressed_texture"), &TextureButton::get_pressed_texture);
  209. ClassDB::bind_method(D_METHOD("get_hover_texture"), &TextureButton::get_hover_texture);
  210. ClassDB::bind_method(D_METHOD("get_disabled_texture"), &TextureButton::get_disabled_texture);
  211. ClassDB::bind_method(D_METHOD("get_focused_texture"), &TextureButton::get_focused_texture);
  212. ClassDB::bind_method(D_METHOD("get_click_mask"), &TextureButton::get_click_mask);
  213. ClassDB::bind_method(D_METHOD("get_expand"), &TextureButton::get_expand);
  214. ClassDB::bind_method(D_METHOD("get_stretch_mode"), &TextureButton::get_stretch_mode);
  215. ADD_GROUP("Textures", "texture_");
  216. ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_texture", "get_normal_texture");
  217. ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_pressed", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_pressed_texture", "get_pressed_texture");
  218. ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_hover", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_hover_texture", "get_hover_texture");
  219. ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_disabled", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_disabled_texture", "get_disabled_texture");
  220. ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_focused", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_focused_texture", "get_focused_texture");
  221. ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_click_mask", PROPERTY_HINT_RESOURCE_TYPE, "BitMap"), "set_click_mask", "get_click_mask");
  222. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand", PROPERTY_HINT_RESOURCE_TYPE, "bool"), "set_expand", "get_expand");
  223. ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_mode", PROPERTY_HINT_ENUM, "Scale,Tile,Keep,Keep Centered,Keep Aspect,Keep Aspect Centered,Keep Aspect Covered"), "set_stretch_mode", "get_stretch_mode");
  224. BIND_ENUM_CONSTANT(STRETCH_SCALE);
  225. BIND_ENUM_CONSTANT(STRETCH_TILE);
  226. BIND_ENUM_CONSTANT(STRETCH_KEEP);
  227. BIND_ENUM_CONSTANT(STRETCH_KEEP_CENTERED);
  228. BIND_ENUM_CONSTANT(STRETCH_KEEP_ASPECT);
  229. BIND_ENUM_CONSTANT(STRETCH_KEEP_ASPECT_CENTERED);
  230. BIND_ENUM_CONSTANT(STRETCH_KEEP_ASPECT_COVERED);
  231. }
  232. void TextureButton::set_normal_texture(const Ref<Texture> &p_normal) {
  233. normal = p_normal;
  234. update();
  235. minimum_size_changed();
  236. }
  237. void TextureButton::set_pressed_texture(const Ref<Texture> &p_pressed) {
  238. pressed = p_pressed;
  239. update();
  240. }
  241. void TextureButton::set_hover_texture(const Ref<Texture> &p_hover) {
  242. hover = p_hover;
  243. update();
  244. }
  245. void TextureButton::set_disabled_texture(const Ref<Texture> &p_disabled) {
  246. disabled = p_disabled;
  247. update();
  248. }
  249. void TextureButton::set_click_mask(const Ref<BitMap> &p_click_mask) {
  250. click_mask = p_click_mask;
  251. update();
  252. }
  253. Ref<Texture> TextureButton::get_normal_texture() const {
  254. return normal;
  255. }
  256. Ref<Texture> TextureButton::get_pressed_texture() const {
  257. return pressed;
  258. }
  259. Ref<Texture> TextureButton::get_hover_texture() const {
  260. return hover;
  261. }
  262. Ref<Texture> TextureButton::get_disabled_texture() const {
  263. return disabled;
  264. }
  265. Ref<BitMap> TextureButton::get_click_mask() const {
  266. return click_mask;
  267. }
  268. Ref<Texture> TextureButton::get_focused_texture() const {
  269. return focused;
  270. };
  271. void TextureButton::set_focused_texture(const Ref<Texture> &p_focused) {
  272. focused = p_focused;
  273. };
  274. bool TextureButton::get_expand() const {
  275. return expand;
  276. }
  277. void TextureButton::set_expand(bool p_expand) {
  278. expand = p_expand;
  279. minimum_size_changed();
  280. update();
  281. }
  282. void TextureButton::set_stretch_mode(StretchMode p_stretch_mode) {
  283. stretch_mode = p_stretch_mode;
  284. update();
  285. }
  286. TextureButton::StretchMode TextureButton::get_stretch_mode() const {
  287. return stretch_mode;
  288. }
  289. TextureButton::TextureButton() {
  290. expand = false;
  291. stretch_mode = STRETCH_SCALE;
  292. _texture_region = Rect2();
  293. _position_rect = Rect2();
  294. _tile = false;
  295. }