| 1 | /**************************************************************************/ |
| 2 | /* style_box_editor_plugin.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 | |
| 31 | #include "style_box_editor_plugin.h" |
| 32 | |
| 33 | #include "editor/editor_scale.h" |
| 34 | #include "scene/gui/button.h" |
| 35 | #include "scene/resources/style_box_texture.h" |
| 36 | |
| 37 | bool StyleBoxPreview::grid_preview_enabled = true; |
| 38 | |
| 39 | void StyleBoxPreview::_grid_preview_toggled(bool p_active) { |
| 40 | grid_preview_enabled = p_active; |
| 41 | queue_redraw(); |
| 42 | } |
| 43 | |
| 44 | void StyleBoxPreview::edit(const Ref<StyleBox> &p_stylebox) { |
| 45 | if (stylebox.is_valid()) { |
| 46 | stylebox->disconnect_changed(callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw)); |
| 47 | } |
| 48 | stylebox = p_stylebox; |
| 49 | if (stylebox.is_valid()) { |
| 50 | stylebox->connect_changed(callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw)); |
| 51 | } |
| 52 | Ref<StyleBoxTexture> sbt = stylebox; |
| 53 | grid_preview->set_visible(sbt.is_valid()); |
| 54 | queue_redraw(); |
| 55 | } |
| 56 | |
| 57 | void StyleBoxPreview::_notification(int p_what) { |
| 58 | switch (p_what) { |
| 59 | case NOTIFICATION_THEME_CHANGED: { |
| 60 | set_texture(get_editor_theme_icon(SNAME("Checkerboard" ))); |
| 61 | grid_preview->set_icon(get_editor_theme_icon(SNAME("StyleBoxGrid" ))); |
| 62 | } break; |
| 63 | case NOTIFICATION_DRAW: { |
| 64 | _redraw(); |
| 65 | } break; |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | void StyleBoxPreview::_redraw() { |
| 70 | if (stylebox.is_valid()) { |
| 71 | float grid_button_width = get_editor_theme_icon(SNAME("StyleBoxGrid" ))->get_size().x; |
| 72 | Rect2 preview_rect = get_rect(); |
| 73 | preview_rect = preview_rect.grow(-grid_button_width); |
| 74 | |
| 75 | // Re-adjust preview panel to fit all drawn content. |
| 76 | Rect2 drawing_rect = stylebox->get_draw_rect(preview_rect); |
| 77 | preview_rect.size -= drawing_rect.size - preview_rect.size; |
| 78 | preview_rect.position -= drawing_rect.position - preview_rect.position; |
| 79 | |
| 80 | draw_style_box(stylebox, preview_rect); |
| 81 | |
| 82 | Ref<StyleBoxTexture> sbt = stylebox; |
| 83 | // Draw the "grid". Use white lines, as well as subtle black lines to ensure contrast. |
| 84 | if (sbt.is_valid() && grid_preview->is_pressed()) { |
| 85 | const Color dark_color = Color(0, 0, 0, 0.4); |
| 86 | const Color bright_color = Color(1, 1, 1, 0.8); |
| 87 | int x_left = drawing_rect.position.x + sbt->get_margin(SIDE_LEFT); |
| 88 | int x_right = drawing_rect.position.x + drawing_rect.size.width - sbt->get_margin(SIDE_RIGHT); |
| 89 | int y_top = drawing_rect.position.y + sbt->get_margin(SIDE_TOP); |
| 90 | int y_bottom = drawing_rect.position.y + drawing_rect.size.height - sbt->get_margin(SIDE_BOTTOM); |
| 91 | |
| 92 | draw_line(Point2(x_left + 2, 0), Point2(x_left + 2, get_size().height), dark_color); |
| 93 | draw_line(Point2(x_right + 1, 0), Point2(x_right + 1, get_size().height), dark_color); |
| 94 | draw_line(Point2(0, y_top + 2), Point2(get_size().width, y_top + 2), dark_color); |
| 95 | draw_line(Point2(0, y_bottom + 1), Point2(get_size().width, y_bottom + 1), dark_color); |
| 96 | |
| 97 | draw_line(Point2(x_left + 1, 0), Point2(x_left + 1, get_size().height), bright_color); |
| 98 | draw_line(Point2(x_right, 0), Point2(x_right, get_size().height), bright_color); |
| 99 | draw_line(Point2(0, y_top + 1), Point2(get_size().width, y_top + 1), bright_color); |
| 100 | draw_line(Point2(0, y_bottom), Point2(get_size().width, y_bottom), bright_color); |
| 101 | } |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | StyleBoxPreview::StyleBoxPreview() { |
| 106 | set_clip_contents(true); |
| 107 | set_custom_minimum_size(Size2(0, 150) * EDSCALE); |
| 108 | set_stretch_mode(TextureRect::STRETCH_TILE); |
| 109 | set_texture_repeat(CanvasItem::TEXTURE_REPEAT_ENABLED); |
| 110 | set_anchors_and_offsets_preset(PRESET_FULL_RECT); |
| 111 | |
| 112 | grid_preview = memnew(Button); |
| 113 | // This theme variation works better than the normal theme because there's no focus highlight. |
| 114 | grid_preview->set_theme_type_variation("PreviewLightButton" ); |
| 115 | grid_preview->set_toggle_mode(true); |
| 116 | grid_preview->connect("toggled" , callable_mp(this, &StyleBoxPreview::_grid_preview_toggled)); |
| 117 | grid_preview->set_pressed(grid_preview_enabled); |
| 118 | add_child(grid_preview); |
| 119 | } |
| 120 | |
| 121 | bool EditorInspectorPluginStyleBox::can_handle(Object *p_object) { |
| 122 | return Object::cast_to<StyleBox>(p_object) != nullptr; |
| 123 | } |
| 124 | |
| 125 | void EditorInspectorPluginStyleBox::parse_begin(Object *p_object) { |
| 126 | Ref<StyleBox> sb = Ref<StyleBox>(Object::cast_to<StyleBox>(p_object)); |
| 127 | |
| 128 | StyleBoxPreview *preview = memnew(StyleBoxPreview); |
| 129 | preview->edit(sb); |
| 130 | add_custom_control(preview); |
| 131 | } |
| 132 | |
| 133 | StyleBoxEditorPlugin::StyleBoxEditorPlugin() { |
| 134 | Ref<EditorInspectorPluginStyleBox> inspector_plugin; |
| 135 | inspector_plugin.instantiate(); |
| 136 | add_inspector_plugin(inspector_plugin); |
| 137 | } |
| 138 | |