Editor: Display deprecated/experimental messages in tooltips
This commit is contained in:
parent
3b1806182a
commit
a714cb9f65
|
@ -47,6 +47,7 @@
|
||||||
#include "scene/gui/check_box.h"
|
#include "scene/gui/check_box.h"
|
||||||
#include "scene/gui/label.h"
|
#include "scene/gui/label.h"
|
||||||
#include "scene/gui/line_edit.h"
|
#include "scene/gui/line_edit.h"
|
||||||
|
#include "scene/gui/margin_container.h"
|
||||||
#include "scene/gui/option_button.h"
|
#include "scene/gui/option_button.h"
|
||||||
#include "scene/gui/popup_menu.h"
|
#include "scene/gui/popup_menu.h"
|
||||||
#include "scene/gui/spin_box.h"
|
#include "scene/gui/spin_box.h"
|
||||||
|
@ -872,7 +873,13 @@ ConnectDialog::~ConnectDialog() {
|
||||||
|
|
||||||
Control *ConnectionsDockTree::make_custom_tooltip(const String &p_text) const {
|
Control *ConnectionsDockTree::make_custom_tooltip(const String &p_text) const {
|
||||||
// If it's not a doc tooltip, fallback to the default one.
|
// If it's not a doc tooltip, fallback to the default one.
|
||||||
return p_text.contains("::") ? nullptr : memnew(EditorHelpTooltip(p_text));
|
if (p_text.contains("::")) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorHelpBit *help_bit = memnew(EditorHelpBit(p_text));
|
||||||
|
EditorHelpBitTooltip::show_tooltip(help_bit, const_cast<ConnectionsDockTree *>(this));
|
||||||
|
return memnew(Control); // Make the standard tooltip invisible.
|
||||||
}
|
}
|
||||||
|
|
||||||
struct _ConnectionsDockMethodInfoSort {
|
struct _ConnectionsDockMethodInfoSort {
|
||||||
|
@ -1458,8 +1465,8 @@ void ConnectionsDock::update_tree() {
|
||||||
|
|
||||||
section_item = tree->create_item(root);
|
section_item = tree->create_item(root);
|
||||||
section_item->set_text(0, class_name);
|
section_item->set_text(0, class_name);
|
||||||
// `|` separators used in `EditorHelpTooltip` for formatting.
|
// `|` separators used in `EditorHelpBit`.
|
||||||
section_item->set_tooltip_text(0, "class|" + doc_class_name + "||");
|
section_item->set_tooltip_text(0, "class|" + doc_class_name + "|");
|
||||||
section_item->set_icon(0, class_icon);
|
section_item->set_icon(0, class_icon);
|
||||||
section_item->set_selectable(0, false);
|
section_item->set_selectable(0, false);
|
||||||
section_item->set_editable(0, false);
|
section_item->set_editable(0, false);
|
||||||
|
@ -1490,8 +1497,8 @@ void ConnectionsDock::update_tree() {
|
||||||
sinfo["args"] = argnames;
|
sinfo["args"] = argnames;
|
||||||
signal_item->set_metadata(0, sinfo);
|
signal_item->set_metadata(0, sinfo);
|
||||||
signal_item->set_icon(0, get_editor_theme_icon(SNAME("Signal")));
|
signal_item->set_icon(0, get_editor_theme_icon(SNAME("Signal")));
|
||||||
// `|` separators used in `EditorHelpTooltip` for formatting.
|
// `|` separators used in `EditorHelpBit`.
|
||||||
signal_item->set_tooltip_text(0, "signal|" + doc_class_name + "|" + String(signal_name) + "|" + signame.trim_prefix(mi.name));
|
signal_item->set_tooltip_text(0, "signal|" + doc_class_name + "|" + String(signal_name));
|
||||||
|
|
||||||
// List existing connections.
|
// List existing connections.
|
||||||
List<Object::Connection> existing_connections;
|
List<Object::Connection> existing_connections;
|
||||||
|
|
|
@ -191,7 +191,7 @@ public:
|
||||||
|
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
|
|
||||||
// Custom `Tree` needed to use `EditorHelpTooltip` to display signal documentation.
|
// Custom `Tree` needed to use `EditorHelpBit` to display signal documentation.
|
||||||
class ConnectionsDockTree : public Tree {
|
class ConnectionsDockTree : public Tree {
|
||||||
virtual Control *make_custom_tooltip(const String &p_text) const;
|
virtual Control *make_custom_tooltip(const String &p_text) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -202,8 +202,7 @@ void CreateDialog::_update_search() {
|
||||||
select_type(_top_result(candidates, search_text));
|
select_type(_top_result(candidates, search_text));
|
||||||
} else {
|
} else {
|
||||||
favorite->set_disabled(true);
|
favorite->set_disabled(true);
|
||||||
help_bit->set_text(vformat(TTR("No results for \"%s\"."), search_text));
|
help_bit->set_custom_text(String(), String(), vformat(TTR("No results for \"%s\"."), search_text.replace("[", "[lb]")));
|
||||||
help_bit->get_rich_text()->set_self_modulate(Color(1, 1, 1, 0.5));
|
|
||||||
get_ok_button()->set_disabled(true);
|
get_ok_button()->set_disabled(true);
|
||||||
search_options->deselect_all();
|
search_options->deselect_all();
|
||||||
}
|
}
|
||||||
|
@ -502,17 +501,7 @@ void CreateDialog::select_type(const String &p_type, bool p_center_on_item) {
|
||||||
to_select->select(0);
|
to_select->select(0);
|
||||||
search_options->scroll_to_item(to_select, p_center_on_item);
|
search_options->scroll_to_item(to_select, p_center_on_item);
|
||||||
|
|
||||||
String text = help_bit->get_class_description(p_type);
|
help_bit->parse_symbol("class|" + p_type + "|");
|
||||||
if (!text.is_empty()) {
|
|
||||||
// Display both class name and description, since the help bit may be displayed
|
|
||||||
// far away from the location (especially if the dialog was resized to be taller).
|
|
||||||
help_bit->set_text(vformat("[b]%s[/b]: %s", p_type, text));
|
|
||||||
help_bit->get_rich_text()->set_self_modulate(Color(1, 1, 1, 1));
|
|
||||||
} else {
|
|
||||||
// Use nested `vformat()` as translators shouldn't interfere with BBCode tags.
|
|
||||||
help_bit->set_text(vformat(TTR("No description available for %s."), vformat("[b]%s[/b]", p_type)));
|
|
||||||
help_bit->get_rich_text()->set_self_modulate(Color(1, 1, 1, 0.5));
|
|
||||||
}
|
|
||||||
|
|
||||||
favorite->set_disabled(false);
|
favorite->set_disabled(false);
|
||||||
favorite->set_pressed(favorite_list.has(p_type));
|
favorite->set_pressed(favorite_list.has(p_type));
|
||||||
|
@ -837,6 +826,7 @@ CreateDialog::CreateDialog() {
|
||||||
vbc->add_margin_child(TTR("Matches:"), search_options, true);
|
vbc->add_margin_child(TTR("Matches:"), search_options, true);
|
||||||
|
|
||||||
help_bit = memnew(EditorHelpBit);
|
help_bit = memnew(EditorHelpBit);
|
||||||
|
help_bit->set_content_height_limits(64 * EDSCALE, 64 * EDSCALE);
|
||||||
help_bit->connect("request_hide", callable_mp(this, &CreateDialog::_hide_requested));
|
help_bit->connect("request_hide", callable_mp(this, &CreateDialog::_hide_requested));
|
||||||
vbc->add_margin_child(TTR("Description:"), help_bit);
|
vbc->add_margin_child(TTR("Description:"), help_bit);
|
||||||
|
|
||||||
|
|
|
@ -593,6 +593,10 @@ void EditorBuildProfileManager::_action_confirm() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditorBuildProfileManager::_hide_requested() {
|
||||||
|
_cancel_pressed(); // From AcceptDialog.
|
||||||
|
}
|
||||||
|
|
||||||
void EditorBuildProfileManager::_fill_classes_from(TreeItem *p_parent, const String &p_class, const String &p_selected) {
|
void EditorBuildProfileManager::_fill_classes_from(TreeItem *p_parent, const String &p_class, const String &p_selected) {
|
||||||
TreeItem *class_item = class_list->create_item(p_parent);
|
TreeItem *class_item = class_list->create_item(p_parent);
|
||||||
class_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
|
class_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
|
||||||
|
@ -646,21 +650,10 @@ void EditorBuildProfileManager::_class_list_item_selected() {
|
||||||
|
|
||||||
Variant md = item->get_metadata(0);
|
Variant md = item->get_metadata(0);
|
||||||
if (md.get_type() == Variant::STRING || md.get_type() == Variant::STRING_NAME) {
|
if (md.get_type() == Variant::STRING || md.get_type() == Variant::STRING_NAME) {
|
||||||
String text = description_bit->get_class_description(md);
|
description_bit->parse_symbol("class|" + md.operator String() + "|");
|
||||||
if (!text.is_empty()) {
|
|
||||||
// Display both class name and description, since the help bit may be displayed
|
|
||||||
// far away from the location (especially if the dialog was resized to be taller).
|
|
||||||
description_bit->set_text(vformat("[b]%s[/b]: %s", md, text));
|
|
||||||
description_bit->get_rich_text()->set_self_modulate(Color(1, 1, 1, 1));
|
|
||||||
} else {
|
|
||||||
// Use nested `vformat()` as translators shouldn't interfere with BBCode tags.
|
|
||||||
description_bit->set_text(vformat(TTR("No description available for %s."), vformat("[b]%s[/b]", md)));
|
|
||||||
description_bit->get_rich_text()->set_self_modulate(Color(1, 1, 1, 0.5));
|
|
||||||
}
|
|
||||||
} else if (md.get_type() == Variant::INT) {
|
} else if (md.get_type() == Variant::INT) {
|
||||||
String build_option_description = EditorBuildProfile::get_build_option_description(EditorBuildProfile::BuildOption((int)md));
|
String build_option_description = EditorBuildProfile::get_build_option_description(EditorBuildProfile::BuildOption((int)md));
|
||||||
description_bit->set_text(vformat("[b]%s[/b]: %s", TTR(item->get_text(0)), TTRGET(build_option_description)));
|
description_bit->set_custom_text(TTR(item->get_text(0)), String(), TTRGET(build_option_description));
|
||||||
description_bit->get_rich_text()->set_self_modulate(Color(1, 1, 1, 1));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -864,7 +857,8 @@ EditorBuildProfileManager::EditorBuildProfileManager() {
|
||||||
main_vbc->add_margin_child(TTR("Configure Engine Compilation Profile:"), class_list, true);
|
main_vbc->add_margin_child(TTR("Configure Engine Compilation Profile:"), class_list, true);
|
||||||
|
|
||||||
description_bit = memnew(EditorHelpBit);
|
description_bit = memnew(EditorHelpBit);
|
||||||
description_bit->set_custom_minimum_size(Size2(0, 80) * EDSCALE);
|
description_bit->set_content_height_limits(80 * EDSCALE, 80 * EDSCALE);
|
||||||
|
description_bit->connect("request_hide", callable_mp(this, &EditorBuildProfileManager::_hide_requested));
|
||||||
main_vbc->add_margin_child(TTR("Description:"), description_bit, false);
|
main_vbc->add_margin_child(TTR("Description:"), description_bit, false);
|
||||||
|
|
||||||
confirm_dialog = memnew(ConfirmationDialog);
|
confirm_dialog = memnew(ConfirmationDialog);
|
||||||
|
|
|
@ -150,6 +150,7 @@ class EditorBuildProfileManager : public AcceptDialog {
|
||||||
|
|
||||||
void _profile_action(int p_action);
|
void _profile_action(int p_action);
|
||||||
void _action_confirm();
|
void _action_confirm();
|
||||||
|
void _hide_requested();
|
||||||
|
|
||||||
void _update_edited_profile();
|
void _update_edited_profile();
|
||||||
void _fill_classes_from(TreeItem *p_parent, const String &p_class, const String &p_selected);
|
void _fill_classes_from(TreeItem *p_parent, const String &p_class, const String &p_selected);
|
||||||
|
|
|
@ -493,6 +493,10 @@ void EditorFeatureProfileManager::_profile_selected(int p_what) {
|
||||||
_update_selected_profile();
|
_update_selected_profile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditorFeatureProfileManager::_hide_requested() {
|
||||||
|
_cancel_pressed(); // From AcceptDialog.
|
||||||
|
}
|
||||||
|
|
||||||
void EditorFeatureProfileManager::_fill_classes_from(TreeItem *p_parent, const String &p_class, const String &p_selected) {
|
void EditorFeatureProfileManager::_fill_classes_from(TreeItem *p_parent, const String &p_class, const String &p_selected) {
|
||||||
TreeItem *class_item = class_list->create_item(p_parent);
|
TreeItem *class_item = class_list->create_item(p_parent);
|
||||||
class_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
|
class_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
|
||||||
|
@ -555,22 +559,10 @@ void EditorFeatureProfileManager::_class_list_item_selected() {
|
||||||
|
|
||||||
Variant md = item->get_metadata(0);
|
Variant md = item->get_metadata(0);
|
||||||
if (md.get_type() == Variant::STRING || md.get_type() == Variant::STRING_NAME) {
|
if (md.get_type() == Variant::STRING || md.get_type() == Variant::STRING_NAME) {
|
||||||
String text = description_bit->get_class_description(md);
|
description_bit->parse_symbol("class|" + md.operator String() + "|");
|
||||||
if (!text.is_empty()) {
|
|
||||||
// Display both class name and description, since the help bit may be displayed
|
|
||||||
// far away from the location (especially if the dialog was resized to be taller).
|
|
||||||
description_bit->set_text(vformat("[b]%s[/b]: %s", md, text));
|
|
||||||
description_bit->get_rich_text()->set_self_modulate(Color(1, 1, 1, 1));
|
|
||||||
} else {
|
|
||||||
// Use nested `vformat()` as translators shouldn't interfere with BBCode tags.
|
|
||||||
description_bit->set_text(vformat(TTR("No description available for %s."), vformat("[b]%s[/b]", md)));
|
|
||||||
description_bit->get_rich_text()->set_self_modulate(Color(1, 1, 1, 0.5));
|
|
||||||
}
|
|
||||||
} else if (md.get_type() == Variant::INT) {
|
} else if (md.get_type() == Variant::INT) {
|
||||||
String feature_description = EditorFeatureProfile::get_feature_description(EditorFeatureProfile::Feature((int)md));
|
String feature_description = EditorFeatureProfile::get_feature_description(EditorFeatureProfile::Feature((int)md));
|
||||||
description_bit->set_text(vformat("[b]%s[/b]: %s", TTR(item->get_text(0)), TTRGET(feature_description)));
|
description_bit->set_custom_text(TTR(item->get_text(0)), String(), TTRGET(feature_description));
|
||||||
description_bit->get_rich_text()->set_self_modulate(Color(1, 1, 1, 1));
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
|
@ -991,8 +983,9 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() {
|
||||||
property_list_vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
property_list_vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
|
|
||||||
description_bit = memnew(EditorHelpBit);
|
description_bit = memnew(EditorHelpBit);
|
||||||
|
description_bit->set_content_height_limits(80 * EDSCALE, 80 * EDSCALE);
|
||||||
|
description_bit->connect("request_hide", callable_mp(this, &EditorFeatureProfileManager::_hide_requested));
|
||||||
property_list_vbc->add_margin_child(TTR("Description:"), description_bit, false);
|
property_list_vbc->add_margin_child(TTR("Description:"), description_bit, false);
|
||||||
description_bit->set_custom_minimum_size(Size2(0, 80) * EDSCALE);
|
|
||||||
|
|
||||||
property_list = memnew(Tree);
|
property_list = memnew(Tree);
|
||||||
property_list_vbc->add_margin_child(TTR("Extra Options:"), property_list, true);
|
property_list_vbc->add_margin_child(TTR("Extra Options:"), property_list, true);
|
||||||
|
|
|
@ -142,6 +142,7 @@ class EditorFeatureProfileManager : public AcceptDialog {
|
||||||
|
|
||||||
void _profile_action(int p_action);
|
void _profile_action(int p_action);
|
||||||
void _profile_selected(int p_what);
|
void _profile_selected(int p_what);
|
||||||
|
void _hide_requested();
|
||||||
|
|
||||||
String current_profile;
|
String current_profile;
|
||||||
void _update_profile_list(const String &p_select_profile = String());
|
void _update_profile_list(const String &p_select_profile = String());
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -35,9 +35,9 @@
|
||||||
#include "editor/code_editor.h"
|
#include "editor/code_editor.h"
|
||||||
#include "editor/doc_tools.h"
|
#include "editor/doc_tools.h"
|
||||||
#include "editor/editor_plugin.h"
|
#include "editor/editor_plugin.h"
|
||||||
#include "scene/gui/margin_container.h"
|
|
||||||
#include "scene/gui/menu_button.h"
|
#include "scene/gui/menu_button.h"
|
||||||
#include "scene/gui/panel_container.h"
|
#include "scene/gui/panel_container.h"
|
||||||
|
#include "scene/gui/popup.h"
|
||||||
#include "scene/gui/rich_text_label.h"
|
#include "scene/gui/rich_text_label.h"
|
||||||
#include "scene/gui/split_container.h"
|
#include "scene/gui/split_container.h"
|
||||||
#include "scene/gui/tab_container.h"
|
#include "scene/gui/tab_container.h"
|
||||||
|
@ -251,53 +251,91 @@ public:
|
||||||
~EditorHelp();
|
~EditorHelp();
|
||||||
};
|
};
|
||||||
|
|
||||||
class EditorHelpBit : public MarginContainer {
|
class EditorHelpBit : public VBoxContainer {
|
||||||
GDCLASS(EditorHelpBit, MarginContainer);
|
GDCLASS(EditorHelpBit, VBoxContainer);
|
||||||
|
|
||||||
inline static HashMap<StringName, String> doc_class_cache;
|
struct DocType {
|
||||||
inline static HashMap<StringName, HashMap<StringName, String>> doc_property_cache;
|
String type;
|
||||||
inline static HashMap<StringName, HashMap<StringName, String>> doc_method_cache;
|
String enumeration;
|
||||||
inline static HashMap<StringName, HashMap<StringName, String>> doc_signal_cache;
|
bool is_bitfield = false;
|
||||||
inline static HashMap<StringName, HashMap<StringName, String>> doc_theme_item_cache;
|
};
|
||||||
|
|
||||||
RichTextLabel *rich_text = nullptr;
|
struct ArgumentData {
|
||||||
|
String name;
|
||||||
|
DocType doc_type;
|
||||||
|
String default_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HelpData {
|
||||||
|
String description;
|
||||||
|
String deprecated_message;
|
||||||
|
String experimental_message;
|
||||||
|
DocType doc_type; // For method return type.
|
||||||
|
Vector<ArgumentData> arguments; // For methods and signals.
|
||||||
|
};
|
||||||
|
|
||||||
|
inline static HashMap<StringName, HelpData> doc_class_cache;
|
||||||
|
inline static HashMap<StringName, HashMap<StringName, HelpData>> doc_property_cache;
|
||||||
|
inline static HashMap<StringName, HashMap<StringName, HelpData>> doc_method_cache;
|
||||||
|
inline static HashMap<StringName, HashMap<StringName, HelpData>> doc_signal_cache;
|
||||||
|
inline static HashMap<StringName, HashMap<StringName, HelpData>> doc_theme_item_cache;
|
||||||
|
|
||||||
|
RichTextLabel *title = nullptr;
|
||||||
|
RichTextLabel *content = nullptr;
|
||||||
|
|
||||||
|
String symbol_class_name;
|
||||||
|
String symbol_type;
|
||||||
|
String symbol_visible_type;
|
||||||
|
String symbol_name;
|
||||||
|
|
||||||
|
HelpData help_data;
|
||||||
|
|
||||||
|
float content_min_height = 0.0;
|
||||||
|
float content_max_height = 0.0;
|
||||||
|
|
||||||
|
static HelpData _get_class_help_data(const StringName &p_class_name);
|
||||||
|
static HelpData _get_property_help_data(const StringName &p_class_name, const StringName &p_property_name);
|
||||||
|
static HelpData _get_method_help_data(const StringName &p_class_name, const StringName &p_method_name);
|
||||||
|
static HelpData _get_signal_help_data(const StringName &p_class_name, const StringName &p_signal_name);
|
||||||
|
static HelpData _get_theme_item_help_data(const StringName &p_class_name, const StringName &p_theme_item_name);
|
||||||
|
|
||||||
|
void _add_type_to_title(const DocType &p_doc_type);
|
||||||
|
void _update_labels();
|
||||||
void _go_to_help(const String &p_what);
|
void _go_to_help(const String &p_what);
|
||||||
void _meta_clicked(const String &p_select);
|
void _meta_clicked(const String &p_select);
|
||||||
|
|
||||||
String text;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
String doc_class_name;
|
|
||||||
String custom_description;
|
|
||||||
|
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
String get_class_description(const StringName &p_class_name) const;
|
void parse_symbol(const String &p_symbol);
|
||||||
String get_property_description(const StringName &p_class_name, const StringName &p_property_name) const;
|
void set_custom_text(const String &p_type, const String &p_name, const String &p_description);
|
||||||
String get_method_description(const StringName &p_class_name, const StringName &p_method_name) const;
|
void prepend_description(const String &p_text);
|
||||||
String get_signal_description(const StringName &p_class_name, const StringName &p_signal_name) const;
|
|
||||||
String get_theme_item_description(const StringName &p_class_name, const StringName &p_theme_item_name) const;
|
|
||||||
|
|
||||||
RichTextLabel *get_rich_text() { return rich_text; }
|
void set_content_height_limits(float p_min, float p_max);
|
||||||
void set_text(const String &p_text);
|
void update_content_height();
|
||||||
|
|
||||||
EditorHelpBit();
|
EditorHelpBit(const String &p_symbol = String());
|
||||||
};
|
};
|
||||||
|
|
||||||
class EditorHelpTooltip : public EditorHelpBit {
|
// Standard tooltips do not allow you to hover over them.
|
||||||
GDCLASS(EditorHelpTooltip, EditorHelpBit);
|
// This class is intended as a temporary workaround.
|
||||||
|
class EditorHelpBitTooltip : public PopupPanel {
|
||||||
|
GDCLASS(EditorHelpBitTooltip, PopupPanel);
|
||||||
|
|
||||||
String tooltip_text;
|
Timer *timer = nullptr;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
|
virtual void _input_from_window(const Ref<InputEvent> &p_event) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void parse_tooltip(const String &p_text);
|
static void show_tooltip(EditorHelpBit *p_help_bit, Control *p_target);
|
||||||
|
|
||||||
EditorHelpTooltip(const String &p_text = String(), const String &p_custom_description = String());
|
void popup_under_cursor();
|
||||||
|
|
||||||
|
EditorHelpBitTooltip(Control *p_target);
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(MODULE_GDSCRIPT_ENABLED) || defined(MODULE_MONO_ENABLED)
|
#if defined(MODULE_GDSCRIPT_ENABLED) || defined(MODULE_MONO_ENABLED)
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "editor/plugins/script_editor_plugin.h"
|
#include "editor/plugins/script_editor_plugin.h"
|
||||||
#include "editor/themes/editor_scale.h"
|
#include "editor/themes/editor_scale.h"
|
||||||
#include "editor/themes/editor_theme_manager.h"
|
#include "editor/themes/editor_theme_manager.h"
|
||||||
|
#include "scene/gui/margin_container.h"
|
||||||
#include "scene/gui/spin_box.h"
|
#include "scene/gui/spin_box.h"
|
||||||
#include "scene/gui/texture_rect.h"
|
#include "scene/gui/texture_rect.h"
|
||||||
#include "scene/property_utils.h"
|
#include "scene/property_utils.h"
|
||||||
|
@ -916,34 +917,35 @@ void EditorProperty::_update_pin_flags() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Control *EditorProperty::make_custom_tooltip(const String &p_text) const {
|
Control *EditorProperty::make_custom_tooltip(const String &p_text) const {
|
||||||
EditorHelpBit *tooltip = nullptr;
|
String custom_warning;
|
||||||
|
|
||||||
if (has_doc_tooltip) {
|
|
||||||
String custom_description;
|
|
||||||
|
|
||||||
const EditorInspector *inspector = get_parent_inspector();
|
|
||||||
if (inspector) {
|
|
||||||
custom_description = inspector->get_custom_property_description(p_text);
|
|
||||||
}
|
|
||||||
tooltip = memnew(EditorHelpTooltip(p_text, custom_description));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (object->has_method("_get_property_warning")) {
|
if (object->has_method("_get_property_warning")) {
|
||||||
String warn = object->call("_get_property_warning", property);
|
custom_warning = object->call("_get_property_warning", property);
|
||||||
if (!warn.is_empty()) {
|
|
||||||
String prev_text;
|
|
||||||
if (tooltip == nullptr) {
|
|
||||||
tooltip = memnew(EditorHelpBit());
|
|
||||||
tooltip->set_text(p_text);
|
|
||||||
tooltip->get_rich_text()->set_custom_minimum_size(Size2(360 * EDSCALE, 0));
|
|
||||||
} else {
|
|
||||||
prev_text = tooltip->get_rich_text()->get_text() + "\n";
|
|
||||||
}
|
|
||||||
tooltip->set_text(prev_text + "[b][color=" + get_theme_color(SNAME("warning_color")).to_html(false) + "]" + warn + "[/color][/b]");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return tooltip;
|
if (has_doc_tooltip || !custom_warning.is_empty()) {
|
||||||
|
EditorHelpBit *help_bit = memnew(EditorHelpBit);
|
||||||
|
|
||||||
|
if (has_doc_tooltip) {
|
||||||
|
help_bit->parse_symbol(p_text);
|
||||||
|
|
||||||
|
const EditorInspector *inspector = get_parent_inspector();
|
||||||
|
if (inspector) {
|
||||||
|
const String custom_description = inspector->get_custom_property_description(p_text);
|
||||||
|
if (!custom_description.is_empty()) {
|
||||||
|
help_bit->prepend_description(custom_description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!custom_warning.is_empty()) {
|
||||||
|
help_bit->prepend_description("[b][color=" + get_theme_color(SNAME("warning_color")).to_html(false) + "]" + custom_warning + "[/color][/b]");
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorHelpBitTooltip::show_tooltip(help_bit, const_cast<EditorProperty *>(this));
|
||||||
|
return memnew(Control); // Make the standard tooltip invisible.
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorProperty::menu_option(int p_option) {
|
void EditorProperty::menu_option(int p_option) {
|
||||||
|
@ -1178,7 +1180,14 @@ void EditorInspectorCategory::_notification(int p_what) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) const {
|
Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) const {
|
||||||
return doc_class_name.is_empty() ? nullptr : memnew(EditorHelpTooltip(p_text));
|
// If it's not a doc tooltip, fallback to the default one.
|
||||||
|
if (doc_class_name.is_empty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorHelpBit *help_bit = memnew(EditorHelpBit(p_text));
|
||||||
|
EditorHelpBitTooltip::show_tooltip(help_bit, const_cast<EditorInspectorCategory *>(this));
|
||||||
|
return memnew(Control); // Make the standard tooltip invisible.
|
||||||
}
|
}
|
||||||
|
|
||||||
Size2 EditorInspectorCategory::get_minimum_size() const {
|
Size2 EditorInspectorCategory::get_minimum_size() const {
|
||||||
|
@ -2887,8 +2896,8 @@ void EditorInspector::update_tree() {
|
||||||
category->doc_class_name = doc_name;
|
category->doc_class_name = doc_name;
|
||||||
|
|
||||||
if (use_doc_hints) {
|
if (use_doc_hints) {
|
||||||
// `|` separator used in `EditorHelpTooltip` for formatting.
|
// `|` separators used in `EditorHelpBit`.
|
||||||
category->set_tooltip_text("class|" + doc_name + "||");
|
category->set_tooltip_text("class|" + doc_name + "|");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3368,15 +3377,15 @@ void EditorInspector::update_tree() {
|
||||||
ep->connect("object_id_selected", callable_mp(this, &EditorInspector::_object_id_selected), CONNECT_DEFERRED);
|
ep->connect("object_id_selected", callable_mp(this, &EditorInspector::_object_id_selected), CONNECT_DEFERRED);
|
||||||
|
|
||||||
if (use_doc_hints) {
|
if (use_doc_hints) {
|
||||||
// `|` separator used in `EditorHelpTooltip` for formatting.
|
// `|` separators used in `EditorHelpBit`.
|
||||||
if (theme_item_name.is_empty()) {
|
if (theme_item_name.is_empty()) {
|
||||||
if (p.usage & PROPERTY_USAGE_INTERNAL) {
|
if (p.usage & PROPERTY_USAGE_INTERNAL) {
|
||||||
ep->set_tooltip_text("internal_property|" + classname + "|" + property_prefix + p.name + "|");
|
ep->set_tooltip_text("internal_property|" + classname + "|" + property_prefix + p.name);
|
||||||
} else {
|
} else {
|
||||||
ep->set_tooltip_text("property|" + classname + "|" + property_prefix + p.name + "|");
|
ep->set_tooltip_text("property|" + classname + "|" + property_prefix + p.name);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ep->set_tooltip_text("theme_item|" + classname + "|" + theme_item_name + "|");
|
ep->set_tooltip_text("theme_item|" + classname + "|" + theme_item_name);
|
||||||
}
|
}
|
||||||
ep->has_doc_tooltip = true;
|
ep->has_doc_tooltip = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ class ConfirmationDialog;
|
||||||
class EditorInspector;
|
class EditorInspector;
|
||||||
class EditorValidationPanel;
|
class EditorValidationPanel;
|
||||||
class LineEdit;
|
class LineEdit;
|
||||||
|
class MarginContainer;
|
||||||
class OptionButton;
|
class OptionButton;
|
||||||
class PanelContainer;
|
class PanelContainer;
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "editor/inspector_dock.h"
|
#include "editor/inspector_dock.h"
|
||||||
#include "editor/themes/editor_scale.h"
|
#include "editor/themes/editor_scale.h"
|
||||||
#include "scene/gui/button.h"
|
#include "scene/gui/button.h"
|
||||||
|
#include "scene/gui/margin_container.h"
|
||||||
#include "scene/resources/packed_scene.h"
|
#include "scene/resources/packed_scene.h"
|
||||||
|
|
||||||
bool EditorPropertyArrayObject::_set(const StringName &p_name, const Variant &p_value) {
|
bool EditorPropertyArrayObject::_set(const StringName &p_name, const Variant &p_value) {
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
|
|
||||||
class Button;
|
class Button;
|
||||||
class EditorSpinSlider;
|
class EditorSpinSlider;
|
||||||
|
class MarginContainer;
|
||||||
|
|
||||||
class EditorPropertyArrayObject : public RefCounted {
|
class EditorPropertyArrayObject : public RefCounted {
|
||||||
GDCLASS(EditorPropertyArrayObject, RefCounted);
|
GDCLASS(EditorPropertyArrayObject, RefCounted);
|
||||||
|
|
|
@ -2267,7 +2267,9 @@ ThemeTypeDialog::ThemeTypeDialog() {
|
||||||
///////////////////////
|
///////////////////////
|
||||||
|
|
||||||
Control *ThemeItemLabel::make_custom_tooltip(const String &p_text) const {
|
Control *ThemeItemLabel::make_custom_tooltip(const String &p_text) const {
|
||||||
return memnew(EditorHelpTooltip(p_text));
|
EditorHelpBit *help_bit = memnew(EditorHelpBit(p_text));
|
||||||
|
EditorHelpBitTooltip::show_tooltip(help_bit, const_cast<ThemeItemLabel *>(this));
|
||||||
|
return memnew(Control); // Make the standard tooltip invisible.
|
||||||
}
|
}
|
||||||
|
|
||||||
VBoxContainer *ThemeTypeEditor::_create_item_list(Theme::DataType p_data_type) {
|
VBoxContainer *ThemeTypeEditor::_create_item_list(Theme::DataType p_data_type) {
|
||||||
|
@ -2436,8 +2438,8 @@ HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_
|
||||||
item_name->set_h_size_flags(SIZE_EXPAND_FILL);
|
item_name->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||||
item_name->set_clip_text(true);
|
item_name->set_clip_text(true);
|
||||||
item_name->set_text(p_item_name);
|
item_name->set_text(p_item_name);
|
||||||
// `|` separators used in `EditorHelpTooltip` for formatting.
|
// `|` separators used in `EditorHelpBit`.
|
||||||
item_name->set_tooltip_text("theme_item|" + edited_type + "|" + p_item_name + "|");
|
item_name->set_tooltip_text("theme_item|" + edited_type + "|" + p_item_name);
|
||||||
item_name->set_mouse_filter(Control::MOUSE_FILTER_STOP);
|
item_name->set_mouse_filter(Control::MOUSE_FILTER_STOP);
|
||||||
item_name_container->add_child(item_name);
|
item_name_container->add_child(item_name);
|
||||||
|
|
||||||
|
|
|
@ -321,7 +321,7 @@ public:
|
||||||
ThemeTypeDialog();
|
ThemeTypeDialog();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Custom `Label` needed to use `EditorHelpTooltip` to display theme item documentation.
|
// Custom `Label` needed to use `EditorHelpBit` to display theme item documentation.
|
||||||
class ThemeItemLabel : public Label {
|
class ThemeItemLabel : public Label {
|
||||||
virtual Control *make_custom_tooltip(const String &p_text) const;
|
virtual Control *make_custom_tooltip(const String &p_text) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -87,7 +87,7 @@ void PropertySelector::_update_search() {
|
||||||
}
|
}
|
||||||
|
|
||||||
search_options->clear();
|
search_options->clear();
|
||||||
help_bit->set_text("");
|
help_bit->set_custom_text(String(), String(), String());
|
||||||
|
|
||||||
TreeItem *root = search_options->create_item();
|
TreeItem *root = search_options->create_item();
|
||||||
|
|
||||||
|
@ -353,7 +353,7 @@ void PropertySelector::_confirmed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PropertySelector::_item_selected() {
|
void PropertySelector::_item_selected() {
|
||||||
help_bit->set_text("");
|
help_bit->set_custom_text(String(), String(), String());
|
||||||
|
|
||||||
TreeItem *item = search_options->get_selected();
|
TreeItem *item = search_options->get_selected();
|
||||||
if (!item) {
|
if (!item) {
|
||||||
|
@ -372,25 +372,21 @@ void PropertySelector::_item_selected() {
|
||||||
|
|
||||||
String text;
|
String text;
|
||||||
while (!class_type.is_empty()) {
|
while (!class_type.is_empty()) {
|
||||||
text = properties ? help_bit->get_property_description(class_type, name) : help_bit->get_method_description(class_type, name);
|
if (properties) {
|
||||||
if (!text.is_empty()) {
|
if (ClassDB::has_property(class_type, name, true)) {
|
||||||
break;
|
help_bit->parse_symbol("property|" + class_type + "|" + name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ClassDB::has_method(class_type, name, true)) {
|
||||||
|
help_bit->parse_symbol("method|" + class_type + "|" + name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// It may be from a parent class, keep looking.
|
// It may be from a parent class, keep looking.
|
||||||
class_type = ClassDB::get_parent_class(class_type);
|
class_type = ClassDB::get_parent_class(class_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!text.is_empty()) {
|
|
||||||
// Display both property name and description, since the help bit may be displayed
|
|
||||||
// far away from the location (especially if the dialog was resized to be taller).
|
|
||||||
help_bit->set_text(vformat("[b]%s[/b]: %s", name, text));
|
|
||||||
help_bit->get_rich_text()->set_self_modulate(Color(1, 1, 1, 1));
|
|
||||||
} else {
|
|
||||||
// Use nested `vformat()` as translators shouldn't interfere with BBCode tags.
|
|
||||||
help_bit->set_text(vformat(TTR("No description available for %s."), vformat("[b]%s[/b]", name)));
|
|
||||||
help_bit->get_rich_text()->set_self_modulate(Color(1, 1, 1, 0.5));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PropertySelector::_hide_requested() {
|
void PropertySelector::_hide_requested() {
|
||||||
|
@ -569,8 +565,7 @@ PropertySelector::PropertySelector() {
|
||||||
search_options->set_hide_folding(true);
|
search_options->set_hide_folding(true);
|
||||||
|
|
||||||
help_bit = memnew(EditorHelpBit);
|
help_bit = memnew(EditorHelpBit);
|
||||||
vbc->add_margin_child(TTR("Description:"), help_bit);
|
help_bit->set_content_height_limits(80 * EDSCALE, 80 * EDSCALE);
|
||||||
help_bit->get_rich_text()->set_fit_content(false);
|
|
||||||
help_bit->get_rich_text()->set_custom_minimum_size(Size2(help_bit->get_rich_text()->get_minimum_size().x, 135 * EDSCALE));
|
|
||||||
help_bit->connect("request_hide", callable_mp(this, &PropertySelector::_hide_requested));
|
help_bit->connect("request_hide", callable_mp(this, &PropertySelector::_hide_requested));
|
||||||
|
vbc->add_margin_child(TTR("Description:"), help_bit);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2158,6 +2158,28 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme
|
||||||
p_theme->set_constant("text_highlight_v_padding", "EditorHelp", 2 * EDSCALE);
|
p_theme->set_constant("text_highlight_v_padding", "EditorHelp", 2 * EDSCALE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EditorHelpBitTitle.
|
||||||
|
{
|
||||||
|
Ref<StyleBoxFlat> style = p_config.tree_panel_style->duplicate();
|
||||||
|
style->set_bg_color(p_config.dark_theme ? style->get_bg_color().lightened(0.04) : style->get_bg_color().darkened(0.04));
|
||||||
|
style->set_border_color(p_config.dark_theme ? style->get_border_color().lightened(0.04) : style->get_border_color().darkened(0.04));
|
||||||
|
style->set_corner_radius(CORNER_BOTTOM_LEFT, 0);
|
||||||
|
style->set_corner_radius(CORNER_BOTTOM_RIGHT, 0);
|
||||||
|
|
||||||
|
p_theme->set_type_variation("EditorHelpBitTitle", "RichTextLabel");
|
||||||
|
p_theme->set_stylebox("normal", "EditorHelpBitTitle", style);
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditorHelpBitContent.
|
||||||
|
{
|
||||||
|
Ref<StyleBoxFlat> style = p_config.tree_panel_style->duplicate();
|
||||||
|
style->set_corner_radius(CORNER_TOP_LEFT, 0);
|
||||||
|
style->set_corner_radius(CORNER_TOP_RIGHT, 0);
|
||||||
|
|
||||||
|
p_theme->set_type_variation("EditorHelpBitContent", "RichTextLabel");
|
||||||
|
p_theme->set_stylebox("normal", "EditorHelpBitContent", style);
|
||||||
|
}
|
||||||
|
|
||||||
// Asset Library.
|
// Asset Library.
|
||||||
p_theme->set_stylebox("bg", "AssetLib", p_config.base_empty_style);
|
p_theme->set_stylebox("bg", "AssetLib", p_config.base_empty_style);
|
||||||
p_theme->set_stylebox("panel", "AssetLib", p_config.content_panel_style);
|
p_theme->set_stylebox("panel", "AssetLib", p_config.content_panel_style);
|
||||||
|
|
Loading…
Reference in New Issue