-New inspector.
-Changed UI resizing code, gained huge amount of speed. -Reorganized timer sync to clean up behavior (sorry forgot commit this before) -
This commit is contained in:
parent
3b8bd50b41
commit
005b69cf6e
|
@ -55,7 +55,7 @@ enum PropertyHint {
|
|||
PROPERTY_HINT_RANGE, ///< hint_text = "min,max,step,slider; //slider is optional"
|
||||
PROPERTY_HINT_EXP_RANGE, ///< hint_text = "min,max,step", exponential edit
|
||||
PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
|
||||
PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease)
|
||||
PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout")
|
||||
PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer)
|
||||
PROPERTY_HINT_SPRITE_FRAME,
|
||||
PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer)
|
||||
|
|
|
@ -2969,6 +2969,7 @@ void AnimationKeyEditor::_notification(int p_what) {
|
|||
switch (p_what) {
|
||||
case NOTIFICATION_VISIBILITY_CHANGED: {
|
||||
|
||||
update_keying();
|
||||
EditorNode::get_singleton()->update_keying();
|
||||
emit_signal("keying_changed");
|
||||
} break;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,283 @@
|
|||
#ifndef EDITOR_INSPECTOR_H
|
||||
#define EDITOR_INSPECTOR_H
|
||||
|
||||
#include "editor_data.h"
|
||||
#include "scene/gui/scroll_container.h"
|
||||
|
||||
class EditorProperty : public Container {
|
||||
|
||||
GDCLASS(EditorProperty, Container)
|
||||
public:
|
||||
enum LabelLayout {
|
||||
LABEL_LAYOUT_LEFT,
|
||||
LABEL_LAYOUT_TOP,
|
||||
};
|
||||
|
||||
private:
|
||||
String label;
|
||||
int text_size;
|
||||
friend class EditorInspector;
|
||||
Object *object;
|
||||
StringName property;
|
||||
|
||||
LabelLayout label_layout;
|
||||
|
||||
int property_usage;
|
||||
|
||||
bool read_only;
|
||||
bool checkable;
|
||||
bool checked;
|
||||
bool draw_red;
|
||||
bool keying;
|
||||
|
||||
Rect2 keying_rect;
|
||||
bool keying_hover;
|
||||
Rect2 revert_rect;
|
||||
bool revert_hover;
|
||||
Rect2 check_rect;
|
||||
bool check_hover;
|
||||
|
||||
bool can_revert;
|
||||
|
||||
bool _might_be_in_instance();
|
||||
bool _is_property_different(const Variant &p_current, const Variant &p_orig, int p_usage);
|
||||
bool _is_instanced_node_with_original_property_different();
|
||||
bool _get_instanced_node_original_property(const StringName &p_prop, Variant &value);
|
||||
void _focusable_focused(int p_index);
|
||||
|
||||
bool selected;
|
||||
int selected_focusable;
|
||||
|
||||
Vector<Control *> focusables;
|
||||
Control *label_reference;
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
|
||||
void _gui_input(const Ref<InputEvent> &p_event);
|
||||
|
||||
public:
|
||||
virtual Size2 get_minimum_size() const;
|
||||
|
||||
void set_label(const String &p_label);
|
||||
String get_label() const;
|
||||
|
||||
void set_read_only(bool p_read_only);
|
||||
bool is_read_only() const;
|
||||
|
||||
Object *get_edited_object();
|
||||
StringName get_edited_property();
|
||||
|
||||
virtual void update_property();
|
||||
void update_reload_status();
|
||||
|
||||
virtual bool use_keying_next() const;
|
||||
|
||||
void set_checkable(bool p_checkable);
|
||||
bool is_checkable() const;
|
||||
|
||||
void set_checked(bool p_checked);
|
||||
bool is_checked() const;
|
||||
|
||||
void set_draw_red(bool p_draw_red);
|
||||
bool is_draw_red() const;
|
||||
|
||||
void set_keying(bool p_keying);
|
||||
bool is_keying() const;
|
||||
|
||||
void add_focusable(Control *p_control);
|
||||
void select(int p_focusable = -1);
|
||||
void deselect();
|
||||
bool is_selected() const;
|
||||
|
||||
void set_label_reference(Control *p_control);
|
||||
|
||||
virtual Variant get_drag_data(const Point2 &p_point);
|
||||
|
||||
void set_label_layout(LabelLayout p_layout);
|
||||
EditorProperty();
|
||||
};
|
||||
|
||||
class EditorInspectorPlugin : public Reference {
|
||||
GDCLASS(EditorInspectorPlugin, Reference)
|
||||
|
||||
friend class EditorInspector;
|
||||
struct AddedEditor {
|
||||
Control *property_editor;
|
||||
Vector<String> properties;
|
||||
String label;
|
||||
};
|
||||
|
||||
List<AddedEditor> added_editors;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void add_custom_control(Control *control);
|
||||
void add_property_editor(const String &p_for_property, Control *p_prop);
|
||||
void add_property_editor_for_multiple_properties(const String &p_label, const Vector<String> &p_properties, Control *p_prop);
|
||||
|
||||
virtual bool can_handle(Object *p_object);
|
||||
virtual void parse_begin(Object *p_object);
|
||||
virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage);
|
||||
virtual void parse_end();
|
||||
};
|
||||
|
||||
class EditorInspectorCategory : public Control {
|
||||
GDCLASS(EditorInspectorCategory, Control);
|
||||
|
||||
friend class EditorInspector;
|
||||
Ref<Texture> icon;
|
||||
String label;
|
||||
Color bg_color;
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
virtual Size2 get_minimum_size() const;
|
||||
|
||||
EditorInspectorCategory();
|
||||
};
|
||||
|
||||
class EditorInspectorSection : public Container {
|
||||
GDCLASS(EditorInspectorSection, Container);
|
||||
|
||||
String label;
|
||||
String section;
|
||||
Object *object;
|
||||
VBoxContainer *vbox;
|
||||
Color bg_color;
|
||||
bool foldable;
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
void _gui_input(const Ref<InputEvent> &p_event);
|
||||
|
||||
public:
|
||||
virtual Size2 get_minimum_size() const;
|
||||
|
||||
void setup(const String &p_section, const String &p_label, Object *p_object, const Color &p_bg_color, bool p_foldable);
|
||||
VBoxContainer *get_vbox();
|
||||
void unfold();
|
||||
void fold();
|
||||
|
||||
Object *get_edited_object();
|
||||
|
||||
EditorInspectorSection();
|
||||
};
|
||||
|
||||
class EditorInspector : public ScrollContainer {
|
||||
GDCLASS(EditorInspector, ScrollContainer);
|
||||
|
||||
UndoRedo *undo_redo;
|
||||
enum {
|
||||
MAX_PLUGINS = 1024
|
||||
};
|
||||
static Ref<EditorInspectorPlugin> inspector_plugins[MAX_PLUGINS];
|
||||
static int inspector_plugin_count;
|
||||
|
||||
VBoxContainer *main_vbox;
|
||||
|
||||
//map use to cache the instanced editors
|
||||
Map<StringName, List<EditorProperty *> > editor_property_map;
|
||||
List<EditorInspectorSection *> sections;
|
||||
Set<StringName> pending;
|
||||
|
||||
void _clear();
|
||||
Object *object;
|
||||
|
||||
//
|
||||
|
||||
LineEdit *search_box;
|
||||
bool show_categories;
|
||||
bool hide_script;
|
||||
bool use_doc_hints;
|
||||
bool capitalize_paths;
|
||||
bool use_filter;
|
||||
bool autoclear;
|
||||
bool use_folding;
|
||||
int changing;
|
||||
bool update_all_pending;
|
||||
bool read_only;
|
||||
bool keying;
|
||||
|
||||
int refresh_countdown;
|
||||
bool update_tree_pending;
|
||||
StringName _prop_edited;
|
||||
StringName property_selected;
|
||||
int property_focusable;
|
||||
|
||||
Map<StringName, Map<StringName, String> > descr_cache;
|
||||
Map<StringName, String> class_descr_cache;
|
||||
|
||||
void _edit_set(const String &p_name, const Variant &p_value, bool p_refresh_all, const String &p_changed_field);
|
||||
|
||||
void _property_changed(const String &p_path, const Variant &p_value);
|
||||
void _multiple_properties_changed(Vector<String> p_paths, Array p_values);
|
||||
void _property_keyed(const String &p_path);
|
||||
void _property_checked(const String &p_path, bool p_checked);
|
||||
|
||||
void _resource_selected(const String &p_path, RES p_resource);
|
||||
void _property_selected(const String &p_path, int p_focusable);
|
||||
void _object_id_selected(const String &p_path, ObjectID p_id);
|
||||
|
||||
void _node_removed(Node *p_node);
|
||||
|
||||
void _changed_callback(Object *p_changed, const char *p_prop);
|
||||
void _edit_request_change(Object *p_changed, const String &p_prop);
|
||||
|
||||
void _filter_changed(const String &p_text);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
static void add_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin);
|
||||
static void remove_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin);
|
||||
static void cleanup_plugins();
|
||||
|
||||
void set_undo_redo(UndoRedo *p_undo_redo);
|
||||
|
||||
String get_selected_path() const;
|
||||
|
||||
void update_tree();
|
||||
void update_property(const String &p_prop);
|
||||
|
||||
void refresh();
|
||||
|
||||
void edit(Object *p_object);
|
||||
|
||||
void set_keying(bool p_active);
|
||||
void set_read_only(bool p_read_only);
|
||||
|
||||
bool is_capitalize_paths_enabled() const;
|
||||
void set_enable_capitalize_paths(bool p_capitalize);
|
||||
void set_autoclear(bool p_enable);
|
||||
|
||||
void set_show_categories(bool p_show);
|
||||
void set_use_doc_hints(bool p_enable);
|
||||
void set_hide_script(bool p_hide);
|
||||
|
||||
void set_use_filter(bool p_use);
|
||||
void register_text_enter(Node *p_line_edit);
|
||||
|
||||
void set_subsection_selectable(bool p_selectable);
|
||||
void set_property_selectable(bool p_selectable);
|
||||
|
||||
void set_use_folding(bool p_enable);
|
||||
|
||||
void collapse_all_folding();
|
||||
void expand_all_folding();
|
||||
|
||||
void set_scroll_offset(int p_offset);
|
||||
int get_scroll_offset() const;
|
||||
|
||||
EditorInspector();
|
||||
};
|
||||
|
||||
#endif // INSPECTOR_H
|
|
@ -56,6 +56,7 @@
|
|||
#include "editor/editor_file_system.h"
|
||||
#include "editor/editor_help.h"
|
||||
#include "editor/editor_initialize_ssl.h"
|
||||
#include "editor/editor_properties.h"
|
||||
#include "editor/editor_settings.h"
|
||||
#include "editor/editor_themes.h"
|
||||
#include "editor/import/editor_import_collada.h"
|
||||
|
@ -548,8 +549,8 @@ void EditorNode::_vp_resized() {
|
|||
|
||||
void EditorNode::_node_renamed() {
|
||||
|
||||
if (property_editor)
|
||||
property_editor->update_tree();
|
||||
if (inspector)
|
||||
inspector->update_tree();
|
||||
}
|
||||
|
||||
void EditorNode::_editor_select_next() {
|
||||
|
@ -1351,7 +1352,7 @@ void EditorNode::_dialog_action(String p_file) {
|
|||
void EditorNode::push_item(Object *p_object, const String &p_property) {
|
||||
|
||||
if (!p_object) {
|
||||
property_editor->edit(NULL);
|
||||
inspector->edit(NULL);
|
||||
node_dock->set_node(NULL);
|
||||
scene_tree_dock->set_selected(NULL);
|
||||
return;
|
||||
|
@ -1444,12 +1445,12 @@ void EditorNode::_property_editor_back() {
|
|||
|
||||
void EditorNode::_menu_collapseall() {
|
||||
|
||||
property_editor->collapse_all_folding();
|
||||
inspector->collapse_all_folding();
|
||||
}
|
||||
|
||||
void EditorNode::_menu_expandall() {
|
||||
|
||||
property_editor->expand_all_folding();
|
||||
inspector->expand_all_folding();
|
||||
}
|
||||
|
||||
void EditorNode::_save_default_environment() {
|
||||
|
@ -1515,7 +1516,7 @@ void EditorNode::_edit_current() {
|
|||
if (!current_obj) {
|
||||
|
||||
scene_tree_dock->set_selected(NULL);
|
||||
property_editor->edit(NULL);
|
||||
inspector->edit(NULL);
|
||||
node_dock->set_node(NULL);
|
||||
object_menu->set_disabled(true);
|
||||
|
||||
|
@ -1536,7 +1537,7 @@ void EditorNode::_edit_current() {
|
|||
Resource *current_res = Object::cast_to<Resource>(current_obj);
|
||||
ERR_FAIL_COND(!current_res);
|
||||
scene_tree_dock->set_selected(NULL);
|
||||
property_editor->edit(current_res);
|
||||
inspector->edit(current_res);
|
||||
node_dock->set_node(NULL);
|
||||
object_menu->set_disabled(false);
|
||||
EditorNode::get_singleton()->get_import_dock()->set_edit_path(current_res->get_path());
|
||||
|
@ -1561,7 +1562,7 @@ void EditorNode::_edit_current() {
|
|||
Node *current_node = Object::cast_to<Node>(current_obj);
|
||||
ERR_FAIL_COND(!current_node);
|
||||
|
||||
property_editor->edit(current_node);
|
||||
inspector->edit(current_node);
|
||||
if (current_node->is_inside_tree()) {
|
||||
node_dock->set_node(current_node);
|
||||
scene_tree_dock->set_selected(current_node);
|
||||
|
@ -1585,7 +1586,7 @@ void EditorNode::_edit_current() {
|
|||
capitalize = false;
|
||||
}
|
||||
|
||||
property_editor->edit(current_obj);
|
||||
inspector->edit(current_obj);
|
||||
node_dock->set_node(NULL);
|
||||
}
|
||||
|
||||
|
@ -1594,8 +1595,8 @@ void EditorNode::_edit_current() {
|
|||
property_editable_warning_dialog->set_text(editable_warning);
|
||||
}
|
||||
|
||||
if (property_editor->is_capitalize_paths_enabled() != capitalize) {
|
||||
property_editor->set_enable_capitalize_paths(capitalize);
|
||||
if (inspector->is_capitalize_paths_enabled() != capitalize) {
|
||||
inspector->set_enable_capitalize_paths(capitalize);
|
||||
}
|
||||
|
||||
/* Take care of PLUGIN EDITOR */
|
||||
|
@ -2939,7 +2940,7 @@ Dictionary EditorNode::_get_main_scene_state() {
|
|||
Dictionary state;
|
||||
state["main_tab"] = _get_current_main_editor();
|
||||
state["scene_tree_offset"] = scene_tree_dock->get_tree_editor()->get_scene_tree()->get_vscroll_bar()->get_value();
|
||||
state["property_edit_offset"] = get_property_editor()->get_scene_tree()->get_vscroll_bar()->get_value();
|
||||
state["property_edit_offset"] = get_inspector()->get_scroll_offset();
|
||||
state["saved_version"] = saved_version;
|
||||
state["node_filter"] = scene_tree_dock->get_filter();
|
||||
return state;
|
||||
|
@ -2985,7 +2986,7 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) {
|
|||
if (p_state.has("scene_tree_offset"))
|
||||
scene_tree_dock->get_tree_editor()->get_scene_tree()->get_vscroll_bar()->set_value(p_state["scene_tree_offset"]);
|
||||
if (p_state.has("property_edit_offset"))
|
||||
get_property_editor()->get_scene_tree()->get_vscroll_bar()->set_value(p_state["property_edit_offset"]);
|
||||
get_inspector()->set_scroll_offset(p_state["property_edit_offset"]);
|
||||
|
||||
if (p_state.has("node_filter"))
|
||||
scene_tree_dock->set_filter(p_state["node_filter"]);
|
||||
|
@ -3278,9 +3279,7 @@ void EditorNode::update_keying() {
|
|||
}
|
||||
}
|
||||
|
||||
property_editor->set_keying(valid);
|
||||
|
||||
AnimationPlayerEditor::singleton->get_key_editor()->update_keying();
|
||||
inspector->set_keying(valid);
|
||||
}
|
||||
|
||||
void EditorNode::_close_messages() {
|
||||
|
@ -3425,6 +3424,9 @@ void EditorNode::register_editor_types() {
|
|||
ClassDB::register_class<EditorExportPlugin>();
|
||||
ClassDB::register_class<EditorResourceConversionPlugin>();
|
||||
ClassDB::register_class<EditorSceneImporter>();
|
||||
ClassDB::register_class<EditorInspector>();
|
||||
ClassDB::register_class<EditorInspectorPlugin>();
|
||||
ClassDB::register_class<EditorProperty>();
|
||||
|
||||
// FIXME: Is this stuff obsolete, or should it be ported to new APIs?
|
||||
ClassDB::register_class<EditorScenePostImport>();
|
||||
|
@ -4236,7 +4238,7 @@ void EditorNode::_scene_tab_changed(int p_tab) {
|
|||
|
||||
void EditorNode::_toggle_search_bar(bool p_pressed) {
|
||||
|
||||
property_editor->set_use_filter(p_pressed);
|
||||
inspector->set_use_filter(p_pressed);
|
||||
|
||||
if (p_pressed) {
|
||||
|
||||
|
@ -4255,7 +4257,7 @@ void EditorNode::_clear_search_box() {
|
|||
return;
|
||||
|
||||
search_box->clear();
|
||||
property_editor->update_tree();
|
||||
inspector->update_tree();
|
||||
}
|
||||
|
||||
ToolButton *EditorNode::add_bottom_panel_item(String p_text, Control *p_item) {
|
||||
|
@ -5007,6 +5009,12 @@ EditorNode::EditorNode() {
|
|||
ResourceFormatImporter::get_singleton()->add_importer(import_bitmap);
|
||||
}
|
||||
|
||||
{
|
||||
Ref<EditorInspectorDefaultPlugin> eidp;
|
||||
eidp.instance();
|
||||
EditorInspector::add_inspector_plugin(eidp);
|
||||
}
|
||||
|
||||
_pvrtc_register_compressors();
|
||||
|
||||
editor_selection = memnew(EditorSelection);
|
||||
|
@ -5665,21 +5673,21 @@ EditorNode::EditorNode() {
|
|||
property_editable_warning->hide();
|
||||
property_editable_warning->connect("pressed", this, "_property_editable_warning_pressed");
|
||||
|
||||
property_editor = memnew(PropertyEditor);
|
||||
property_editor->set_autoclear(true);
|
||||
property_editor->set_show_categories(true);
|
||||
property_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
property_editor->set_use_doc_hints(true);
|
||||
property_editor->set_hide_script(false);
|
||||
property_editor->set_enable_capitalize_paths(bool(EDITOR_DEF("interface/editor/capitalize_properties", true)));
|
||||
property_editor->set_use_folding(!bool(EDITOR_DEF("interface/editor/disable_inspector_folding", false)));
|
||||
inspector = memnew(EditorInspector);
|
||||
inspector->set_autoclear(true);
|
||||
inspector->set_show_categories(true);
|
||||
inspector->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
inspector->set_use_doc_hints(true);
|
||||
inspector->set_hide_script(false);
|
||||
inspector->set_enable_capitalize_paths(bool(EDITOR_DEF("interface/editor/capitalize_properties", true)));
|
||||
inspector->set_use_folding(!bool(EDITOR_DEF("interface/editor/disable_inspector_folding", false)));
|
||||
|
||||
property_editor->hide_top_label();
|
||||
property_editor->register_text_enter(search_box);
|
||||
// inspector->hide_top_label();
|
||||
inspector->register_text_enter(search_box);
|
||||
|
||||
Button *property_editable_warning;
|
||||
prop_editor_base->add_child(property_editor);
|
||||
property_editor->set_undo_redo(&editor_data.get_undo_redo());
|
||||
prop_editor_base->add_child(inspector);
|
||||
inspector->set_undo_redo(&editor_data.get_undo_redo());
|
||||
|
||||
import_dock = memnew(ImportDock);
|
||||
dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(import_dock);
|
||||
|
@ -5815,8 +5823,8 @@ EditorNode::EditorNode() {
|
|||
|
||||
file->connect("file_selected", this, "_dialog_action");
|
||||
file_templates->connect("file_selected", this, "_dialog_action");
|
||||
property_editor->connect("resource_selected", this, "_resource_selected");
|
||||
property_editor->connect("property_keyed", this, "_property_keyed");
|
||||
inspector->connect("resource_selected", this, "_resource_selected");
|
||||
inspector->connect("property_keyed", this, "_property_keyed");
|
||||
|
||||
//plugin stuff
|
||||
|
||||
|
@ -6039,6 +6047,8 @@ EditorNode::EditorNode() {
|
|||
|
||||
EditorNode::~EditorNode() {
|
||||
|
||||
EditorInspector::cleanup_plugins();
|
||||
|
||||
remove_print_handler(&print_handler);
|
||||
memdelete(EditorHelp::get_doc_data());
|
||||
memdelete(editor_selection);
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "editor/editor_about.h"
|
||||
#include "editor/editor_data.h"
|
||||
#include "editor/editor_export.h"
|
||||
#include "editor/editor_inspector.h"
|
||||
#include "editor/editor_log.h"
|
||||
#include "editor/editor_name_dialog.h"
|
||||
#include "editor/editor_path.h"
|
||||
|
@ -80,7 +81,6 @@
|
|||
#include "scene/gui/tool_button.h"
|
||||
#include "scene/gui/tree.h"
|
||||
#include "scene/gui/viewport_container.h"
|
||||
|
||||
/**
|
||||
@author Juan Linietsky <reduzio@gmail.com>
|
||||
*/
|
||||
|
@ -267,7 +267,7 @@ private:
|
|||
Button *property_back;
|
||||
Button *property_forward;
|
||||
SceneTreeDock *scene_tree_dock;
|
||||
PropertyEditor *property_editor;
|
||||
EditorInspector *inspector;
|
||||
Button *property_editable_warning;
|
||||
AcceptDialog *property_editable_warning_dialog;
|
||||
void _property_editable_warning_pressed();
|
||||
|
@ -640,7 +640,7 @@ public:
|
|||
EditorPluginList *get_editor_plugins_over() { return editor_plugins_over; }
|
||||
EditorPluginList *get_editor_plugins_force_over() { return editor_plugins_force_over; }
|
||||
EditorPluginList *get_editor_plugins_force_input_forwarding() { return editor_plugins_force_input_forwarding; }
|
||||
PropertyEditor *get_property_editor() { return property_editor; }
|
||||
EditorInspector *get_inspector() { return inspector; }
|
||||
VBoxContainer *get_property_editor_vb() { return prop_editor_vb; }
|
||||
|
||||
ProjectSettingsEditor *get_project_settings() { return project_settings; }
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,490 @@
|
|||
#ifndef EDITOR_PROPERTIES_H
|
||||
#define EDITOR_PROPERTIES_H
|
||||
|
||||
#include "editor/create_dialog.h"
|
||||
#include "editor/editor_file_system.h"
|
||||
#include "editor/editor_inspector.h"
|
||||
#include "editor/editor_spin_slider.h"
|
||||
#include "editor/property_selector.h"
|
||||
#include "editor/scene_tree_editor.h"
|
||||
#include "scene/gui/color_picker.h"
|
||||
|
||||
class EditorPropertyText : public EditorProperty {
|
||||
GDCLASS(EditorPropertyText, EditorProperty)
|
||||
LineEdit *text;
|
||||
|
||||
bool updating;
|
||||
void _text_changed(const String &p_string);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
EditorPropertyText();
|
||||
};
|
||||
|
||||
class EditorPropertyMultilineText : public EditorProperty {
|
||||
GDCLASS(EditorPropertyMultilineText, EditorProperty)
|
||||
TextEdit *text;
|
||||
|
||||
AcceptDialog *big_text_dialog;
|
||||
TextEdit *big_text;
|
||||
Button *open_big_text;
|
||||
|
||||
void _big_text_changed();
|
||||
void _text_changed();
|
||||
void _open_big_text();
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
EditorPropertyMultilineText();
|
||||
};
|
||||
|
||||
class EditorPropertyTextEnum : public EditorProperty {
|
||||
GDCLASS(EditorPropertyTextEnum, EditorProperty)
|
||||
OptionButton *options;
|
||||
|
||||
void _option_selected(int p_which);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void setup(const Vector<String> &p_options);
|
||||
virtual void update_property();
|
||||
EditorPropertyTextEnum();
|
||||
};
|
||||
|
||||
class EditorPropertyPath : public EditorProperty {
|
||||
GDCLASS(EditorPropertyPath, EditorProperty)
|
||||
Vector<String> extensions;
|
||||
bool folder;
|
||||
bool global;
|
||||
EditorFileDialog *dialog;
|
||||
Button *path;
|
||||
|
||||
void _path_selected(const String &p_path);
|
||||
void _path_pressed();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void setup(const Vector<String> &p_extensions, bool p_folder, bool p_global);
|
||||
virtual void update_property();
|
||||
EditorPropertyPath();
|
||||
};
|
||||
|
||||
class EditorPropertyMember : public EditorProperty {
|
||||
GDCLASS(EditorPropertyMember, EditorProperty)
|
||||
public:
|
||||
enum Type {
|
||||
MEMBER_METHOD_OF_VARIANT_TYPE, ///< a method of a type
|
||||
MEMBER_METHOD_OF_BASE_TYPE, ///< a method of a base type
|
||||
MEMBER_METHOD_OF_INSTANCE, ///< a method of an instance
|
||||
MEMBER_METHOD_OF_SCRIPT, ///< a method of a script & base
|
||||
MEMBER_PROPERTY_OF_VARIANT_TYPE, ///< a property of a type
|
||||
MEMBER_PROPERTY_OF_BASE_TYPE, ///< a property of a base type
|
||||
MEMBER_PROPERTY_OF_INSTANCE, ///< a property of an instance
|
||||
MEMBER_PROPERTY_OF_SCRIPT, ///< a property of a script & base
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
Type hint;
|
||||
PropertySelector *selector;
|
||||
Button *property;
|
||||
String hint_text;
|
||||
|
||||
void _property_selected(const String &p_selected);
|
||||
void _property_select();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void setup(Type p_hint, const String &p_hint_text);
|
||||
virtual void update_property();
|
||||
EditorPropertyMember();
|
||||
};
|
||||
|
||||
class EditorPropertyCheck : public EditorProperty {
|
||||
GDCLASS(EditorPropertyCheck, EditorProperty)
|
||||
CheckBox *checkbox;
|
||||
|
||||
void _checkbox_pressed();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
EditorPropertyCheck();
|
||||
};
|
||||
|
||||
class EditorPropertyEnum : public EditorProperty {
|
||||
GDCLASS(EditorPropertyEnum, EditorProperty)
|
||||
OptionButton *options;
|
||||
|
||||
void _option_selected(int p_which);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void setup(const Vector<String> &p_options);
|
||||
virtual void update_property();
|
||||
EditorPropertyEnum();
|
||||
};
|
||||
|
||||
class EditorPropertyFlags : public EditorProperty {
|
||||
GDCLASS(EditorPropertyFlags, EditorProperty)
|
||||
VBoxContainer *vbox;
|
||||
Vector<CheckBox *> flags;
|
||||
Vector<int> flag_indices;
|
||||
|
||||
void _flag_toggled();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void setup(const Vector<String> &p_options);
|
||||
virtual void update_property();
|
||||
EditorPropertyFlags();
|
||||
};
|
||||
|
||||
class EditorPropertyLayersGrid;
|
||||
|
||||
class EditorPropertyLayers : public EditorProperty {
|
||||
GDCLASS(EditorPropertyLayers, EditorProperty)
|
||||
public:
|
||||
enum LayerType {
|
||||
LAYER_PHYSICS_2D,
|
||||
LAYER_RENDER_2D,
|
||||
LAYER_PHYSICS_3D,
|
||||
LAYER_RENDER_3D,
|
||||
};
|
||||
|
||||
private:
|
||||
EditorPropertyLayersGrid *grid;
|
||||
void _grid_changed(uint32_t p_grid);
|
||||
LayerType layer_type;
|
||||
PopupMenu *layers;
|
||||
Button *button;
|
||||
|
||||
void _button_pressed();
|
||||
void _menu_pressed(int p_menu);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void setup(LayerType p_layer_type);
|
||||
virtual void update_property();
|
||||
EditorPropertyLayers();
|
||||
};
|
||||
|
||||
class EditorPropertyInteger : public EditorProperty {
|
||||
GDCLASS(EditorPropertyInteger, EditorProperty)
|
||||
EditorSpinSlider *spin;
|
||||
bool setting;
|
||||
void _value_changed(double p_val);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
void setup(int p_min, int p_max);
|
||||
EditorPropertyInteger();
|
||||
};
|
||||
|
||||
class EditorPropertyObjectID : public EditorProperty {
|
||||
GDCLASS(EditorPropertyObjectID, EditorProperty)
|
||||
Button *edit;
|
||||
String base_type;
|
||||
void _edit_pressed();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
void setup(const String &p_base_type);
|
||||
EditorPropertyObjectID();
|
||||
};
|
||||
|
||||
class EditorPropertyFloat : public EditorProperty {
|
||||
GDCLASS(EditorPropertyFloat, EditorProperty)
|
||||
EditorSpinSlider *spin;
|
||||
bool setting;
|
||||
void _value_changed(double p_val);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
void setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_exp_range);
|
||||
EditorPropertyFloat();
|
||||
};
|
||||
|
||||
class EditorPropertyEasing : public EditorProperty {
|
||||
GDCLASS(EditorPropertyEasing, EditorProperty)
|
||||
Control *easing_draw;
|
||||
ToolButton *button_out, *button_in, *button_linear, *button_constant;
|
||||
ToolButton *button_in_out, *button_out_in;
|
||||
VBoxContainer *vb;
|
||||
|
||||
bool flip;
|
||||
|
||||
void _drag_easing(const Ref<InputEvent> &p_ev);
|
||||
void _draw_easing();
|
||||
void _notification(int p_what);
|
||||
void _set_preset(float p_val);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
void setup(bool p_full, bool p_flip);
|
||||
EditorPropertyEasing();
|
||||
};
|
||||
|
||||
class EditorPropertyVector2 : public EditorProperty {
|
||||
GDCLASS(EditorPropertyVector2, EditorProperty)
|
||||
EditorSpinSlider *spin[2];
|
||||
bool setting;
|
||||
void _value_changed(double p_val);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
void setup(double p_min, double p_max, double p_step, bool p_no_slider);
|
||||
EditorPropertyVector2();
|
||||
};
|
||||
|
||||
class EditorPropertyRect2 : public EditorProperty {
|
||||
GDCLASS(EditorPropertyRect2, EditorProperty)
|
||||
EditorSpinSlider *spin[4];
|
||||
bool setting;
|
||||
void _value_changed(double p_val);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
void setup(double p_min, double p_max, double p_step, bool p_no_slider);
|
||||
EditorPropertyRect2();
|
||||
};
|
||||
|
||||
class EditorPropertyVector3 : public EditorProperty {
|
||||
GDCLASS(EditorPropertyVector3, EditorProperty)
|
||||
EditorSpinSlider *spin[3];
|
||||
bool setting;
|
||||
void _value_changed(double p_val);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
void setup(double p_min, double p_max, double p_step, bool p_no_slider);
|
||||
EditorPropertyVector3();
|
||||
};
|
||||
|
||||
class EditorPropertyPlane : public EditorProperty {
|
||||
GDCLASS(EditorPropertyPlane, EditorProperty)
|
||||
EditorSpinSlider *spin[4];
|
||||
bool setting;
|
||||
void _value_changed(double p_val);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
void setup(double p_min, double p_max, double p_step, bool p_no_slider);
|
||||
EditorPropertyPlane();
|
||||
};
|
||||
|
||||
class EditorPropertyQuat : public EditorProperty {
|
||||
GDCLASS(EditorPropertyQuat, EditorProperty)
|
||||
EditorSpinSlider *spin[4];
|
||||
bool setting;
|
||||
void _value_changed(double p_val);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
void setup(double p_min, double p_max, double p_step, bool p_no_slider);
|
||||
EditorPropertyQuat();
|
||||
};
|
||||
|
||||
class EditorPropertyAABB : public EditorProperty {
|
||||
GDCLASS(EditorPropertyAABB, EditorProperty)
|
||||
EditorSpinSlider *spin[6];
|
||||
bool setting;
|
||||
void _value_changed(double p_val);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
void setup(double p_min, double p_max, double p_step, bool p_no_slider);
|
||||
EditorPropertyAABB();
|
||||
};
|
||||
|
||||
class EditorPropertyTransform2D : public EditorProperty {
|
||||
GDCLASS(EditorPropertyTransform2D, EditorProperty)
|
||||
EditorSpinSlider *spin[6];
|
||||
bool setting;
|
||||
void _value_changed(double p_val);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
void setup(double p_min, double p_max, double p_step, bool p_no_slider);
|
||||
EditorPropertyTransform2D();
|
||||
};
|
||||
|
||||
class EditorPropertyBasis : public EditorProperty {
|
||||
GDCLASS(EditorPropertyBasis, EditorProperty)
|
||||
EditorSpinSlider *spin[9];
|
||||
bool setting;
|
||||
void _value_changed(double p_val);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
void setup(double p_min, double p_max, double p_step, bool p_no_slider);
|
||||
EditorPropertyBasis();
|
||||
};
|
||||
|
||||
class EditorPropertyTransform : public EditorProperty {
|
||||
GDCLASS(EditorPropertyTransform, EditorProperty)
|
||||
EditorSpinSlider *spin[12];
|
||||
bool setting;
|
||||
void _value_changed(double p_val);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
void setup(double p_min, double p_max, double p_step, bool p_no_slider);
|
||||
EditorPropertyTransform();
|
||||
};
|
||||
|
||||
class EditorPropertyColor : public EditorProperty {
|
||||
GDCLASS(EditorPropertyColor, EditorProperty)
|
||||
ColorPickerButton *picker;
|
||||
void _color_changed(const Color &p_color);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
void setup(bool p_show_alpha);
|
||||
EditorPropertyColor();
|
||||
};
|
||||
|
||||
class EditorPropertyNodePath : public EditorProperty {
|
||||
GDCLASS(EditorPropertyNodePath, EditorProperty)
|
||||
Button *assign;
|
||||
Button *clear;
|
||||
SceneTreeDialog *scene_tree;
|
||||
NodePath base_hint;
|
||||
|
||||
void _node_selected(const NodePath &p_path);
|
||||
void _node_assign();
|
||||
void _node_clear();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
void setup(const NodePath &p_base_hint);
|
||||
EditorPropertyNodePath();
|
||||
};
|
||||
|
||||
class EditorPropertyResource : public EditorProperty {
|
||||
GDCLASS(EditorPropertyResource, EditorProperty)
|
||||
|
||||
enum MenuOption {
|
||||
|
||||
OBJ_MENU_LOAD = 0,
|
||||
OBJ_MENU_EDIT = 1,
|
||||
OBJ_MENU_CLEAR = 2,
|
||||
OBJ_MENU_MAKE_UNIQUE = 3,
|
||||
OBJ_MENU_COPY = 4,
|
||||
OBJ_MENU_PASTE = 5,
|
||||
OBJ_MENU_NEW_SCRIPT = 6,
|
||||
OBJ_MENU_SHOW_IN_FILE_SYSTEM = 7,
|
||||
TYPE_BASE_ID = 100,
|
||||
CONVERT_BASE_ID = 1000
|
||||
|
||||
};
|
||||
|
||||
Button *assign;
|
||||
Button *edit;
|
||||
PopupMenu *menu;
|
||||
EditorFileDialog *file;
|
||||
Vector<String> inheritors_array;
|
||||
|
||||
String base_type;
|
||||
|
||||
SceneTreeDialog *scene_tree;
|
||||
|
||||
void _file_selected(const String &p_path);
|
||||
void _menu_option(int p_which);
|
||||
void _resource_preview(const String &p_path, const Ref<Texture> &p_preview, ObjectID p_obj);
|
||||
void _resource_selected();
|
||||
void _viewport_selected(const NodePath &p_path);
|
||||
|
||||
void _update_menu();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
virtual void update_property();
|
||||
void setup(const String &p_base_type);
|
||||
EditorPropertyResource();
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
/// \brief The EditorInspectorDefaultPlugin class
|
||||
///
|
||||
class EditorInspectorDefaultPlugin : public EditorInspectorPlugin {
|
||||
GDCLASS(EditorInspectorDefaultPlugin, EditorInspectorPlugin)
|
||||
|
||||
public:
|
||||
virtual bool can_handle(Object *p_object);
|
||||
virtual void parse_begin(Object *p_object);
|
||||
virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage);
|
||||
virtual void parse_end();
|
||||
};
|
||||
|
||||
#endif // EDITOR_PROPERTIES_H
|
|
@ -0,0 +1,315 @@
|
|||
#include "editor_spin_slider.h"
|
||||
#include "editor_scale.h"
|
||||
#include "os/input.h"
|
||||
String EditorSpinSlider::get_text_value() const {
|
||||
int zeros = Math::step_decimals(get_step());
|
||||
return String::num(get_value(), zeros);
|
||||
}
|
||||
void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) {
|
||||
|
||||
Ref<InputEventMouseButton> mb = p_event;
|
||||
if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
|
||||
|
||||
if (mb->is_pressed()) {
|
||||
|
||||
if (updown_offset != -1 && mb->get_position().x > updown_offset) {
|
||||
//there is an updown, so use it.
|
||||
if (mb->get_position().y < get_size().height / 2) {
|
||||
set_value(get_value() + get_step());
|
||||
} else {
|
||||
set_value(get_value() - get_step());
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
|
||||
grabbing_spinner_attempt = true;
|
||||
grabbing_spinner = false;
|
||||
grabbing_spinner_mouse_pos = Input::get_singleton()->get_mouse_position();
|
||||
}
|
||||
} else {
|
||||
|
||||
if (grabbing_spinner_attempt) {
|
||||
|
||||
if (grabbing_spinner) {
|
||||
|
||||
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
|
||||
Input::get_singleton()->warp_mouse_position(grabbing_spinner_mouse_pos);
|
||||
update();
|
||||
} else {
|
||||
Rect2 gr = get_global_rect();
|
||||
value_input->set_text(get_text_value());
|
||||
value_input->set_position(gr.position);
|
||||
value_input->set_size(gr.size);
|
||||
value_input->call_deferred("show_modal");
|
||||
value_input->call_deferred("grab_focus");
|
||||
value_input->call_deferred("select_all");
|
||||
}
|
||||
|
||||
grabbing_spinner = false;
|
||||
grabbing_spinner_attempt = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ref<InputEventMouseMotion> mm = p_event;
|
||||
if (mm.is_valid()) {
|
||||
|
||||
if (grabbing_spinner_attempt) {
|
||||
|
||||
if (!grabbing_spinner) {
|
||||
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
|
||||
grabbing_spinner = true;
|
||||
}
|
||||
|
||||
double v = get_value();
|
||||
|
||||
double diff_x = mm->get_relative().x;
|
||||
diff_x = Math::pow(ABS(diff_x), 1.8f) * SGN(diff_x);
|
||||
diff_x *= 0.1;
|
||||
|
||||
v += diff_x * get_step();
|
||||
|
||||
set_value(v);
|
||||
|
||||
} else if (updown_offset != -1) {
|
||||
bool new_hover = (mm->get_position().x > updown_offset);
|
||||
if (new_hover != hover_updown) {
|
||||
hover_updown = new_hover;
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ref<InputEventKey> k = p_event;
|
||||
if (k.is_valid() && k->is_pressed() && k->is_action("ui_accept")) {
|
||||
Rect2 gr = get_global_rect();
|
||||
value_input->set_text(get_text_value());
|
||||
value_input->set_position(gr.position);
|
||||
value_input->set_size(gr.size);
|
||||
value_input->call_deferred("show_modal");
|
||||
value_input->call_deferred("grab_focus");
|
||||
value_input->call_deferred("select_all");
|
||||
}
|
||||
}
|
||||
|
||||
void EditorSpinSlider::_value_input_closed() {
|
||||
set_value(value_input->get_text().to_double());
|
||||
}
|
||||
|
||||
void EditorSpinSlider::_value_input_entered(const String &p_text) {
|
||||
set_value(p_text.to_double());
|
||||
value_input->hide();
|
||||
}
|
||||
|
||||
void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
|
||||
|
||||
Ref<InputEventMouseButton> mb = p_event;
|
||||
if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
|
||||
|
||||
if (mb->is_pressed()) {
|
||||
|
||||
grabbing_grabber = true;
|
||||
grabbing_ratio = get_as_ratio();
|
||||
grabbing_from = grabber->get_transform().xform(mb->get_position()).x;
|
||||
} else {
|
||||
grabbing_grabber = false;
|
||||
}
|
||||
}
|
||||
|
||||
Ref<InputEventMouseMotion> mm = p_event;
|
||||
if (mm.is_valid() && grabbing_grabber) {
|
||||
|
||||
float grabbing_ofs = (grabber->get_transform().xform(mm->get_position()).x - grabbing_from) / float(grabber_range);
|
||||
set_as_ratio(grabbing_ratio + grabbing_ofs);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void EditorSpinSlider::_notification(int p_what) {
|
||||
|
||||
if (p_what == MainLoop::NOTIFICATION_WM_FOCUS_OUT || p_what == MainLoop::NOTIFICATION_WM_FOCUS_OUT) {
|
||||
if (grabbing_spinner) {
|
||||
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
|
||||
grabbing_spinner = false;
|
||||
grabbing_spinner_attempt = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_what == NOTIFICATION_DRAW) {
|
||||
|
||||
updown_offset = -1;
|
||||
|
||||
Ref<StyleBox> sb = get_stylebox("normal", "LineEdit");
|
||||
draw_style_box(sb, Rect2(Vector2(), get_size()));
|
||||
Ref<Font> font = get_font("font", "LineEdit");
|
||||
|
||||
int avail_width = get_size().width - sb->get_minimum_size().width - sb->get_minimum_size().width;
|
||||
avail_width -= font->get_string_size(label).width;
|
||||
Ref<Texture> updown = get_icon("updown", "SpinBox");
|
||||
|
||||
if (get_step() == 1) {
|
||||
avail_width -= updown->get_width();
|
||||
}
|
||||
|
||||
if (has_focus()) {
|
||||
Ref<StyleBox> focus = get_stylebox("focus", "LineEdit");
|
||||
draw_style_box(focus, Rect2(Vector2(), get_size()));
|
||||
}
|
||||
|
||||
String numstr = get_text_value();
|
||||
|
||||
int vofs = (get_size().height - font->get_height()) / 2 + font->get_ascent();
|
||||
|
||||
Color fc = get_color("font_color", "LineEdit");
|
||||
|
||||
int label_ofs = sb->get_offset().x + avail_width;
|
||||
draw_string(font, Vector2(label_ofs, vofs), label, fc * Color(1, 1, 1, 0.5));
|
||||
draw_string(font, Vector2(sb->get_offset().x, vofs), numstr, fc, avail_width);
|
||||
|
||||
if (get_step() == 1) {
|
||||
Ref<Texture> updown = get_icon("updown", "SpinBox");
|
||||
int updown_vofs = (get_size().height - updown->get_height()) / 2;
|
||||
updown_offset = get_size().width - sb->get_margin(MARGIN_RIGHT) - updown->get_width();
|
||||
Color c(1, 1, 1);
|
||||
if (hover_updown) {
|
||||
c *= Color(1.2, 1.2, 1.2);
|
||||
}
|
||||
draw_texture(updown, Vector2(updown_offset, updown_vofs), c);
|
||||
if (grabber->is_visible()) {
|
||||
grabber->hide();
|
||||
}
|
||||
} else if (!hide_slider) {
|
||||
int grabber_w = 4 * EDSCALE;
|
||||
int width = get_size().width - sb->get_minimum_size().width - grabber_w;
|
||||
int ofs = sb->get_offset().x;
|
||||
int svofs = (get_size().height + vofs) / 2 - 1;
|
||||
Color c = fc;
|
||||
c.a = 0.2;
|
||||
|
||||
draw_rect(Rect2(ofs, svofs + 1, width, 2 * EDSCALE), c);
|
||||
int gofs = get_as_ratio() * width;
|
||||
c.a = 0.9;
|
||||
Rect2 grabber_rect = Rect2(ofs + gofs, svofs + 1, grabber_w, 2 * EDSCALE);
|
||||
draw_rect(grabber_rect, c);
|
||||
|
||||
bool display_grabber = (mouse_over_spin || mouse_over_grabber) && !grabbing_spinner;
|
||||
if (grabber->is_visible() != display_grabber) {
|
||||
if (display_grabber) {
|
||||
grabber->show();
|
||||
} else {
|
||||
grabber->hide();
|
||||
}
|
||||
}
|
||||
|
||||
if (display_grabber) {
|
||||
Ref<Texture> grabber_tex;
|
||||
if (mouse_over_grabber) {
|
||||
grabber_tex = get_icon("grabber_highlight", "HSlider");
|
||||
} else {
|
||||
grabber_tex = get_icon("grabber", "HSlider");
|
||||
}
|
||||
|
||||
if (grabber->get_texture() != grabber_tex) {
|
||||
grabber->set_texture(grabber_tex);
|
||||
}
|
||||
|
||||
grabber->set_size(Size2(0, 0));
|
||||
grabber->set_position(get_global_position() + grabber_rect.position + grabber_rect.size * 0.5 - grabber->get_size() * 0.5);
|
||||
grabber_range = width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p_what == NOTIFICATION_MOUSE_ENTER) {
|
||||
|
||||
mouse_over_spin = true;
|
||||
update();
|
||||
}
|
||||
if (p_what == NOTIFICATION_MOUSE_EXIT) {
|
||||
|
||||
mouse_over_spin = false;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
Size2 EditorSpinSlider::get_minimum_size() const {
|
||||
|
||||
Ref<StyleBox> sb = get_stylebox("normal", "LineEdit");
|
||||
Ref<Font> font = get_font("font", "LineEdit");
|
||||
|
||||
Size2 ms = sb->get_minimum_size();
|
||||
ms.height += font->get_height();
|
||||
|
||||
return ms;
|
||||
}
|
||||
|
||||
void EditorSpinSlider::set_hide_slider(bool p_hide) {
|
||||
hide_slider = p_hide;
|
||||
update();
|
||||
}
|
||||
|
||||
bool EditorSpinSlider::is_hiding_slider() const {
|
||||
return hide_slider;
|
||||
}
|
||||
|
||||
void EditorSpinSlider::set_label(const String &p_label) {
|
||||
label = p_label;
|
||||
update();
|
||||
}
|
||||
|
||||
String EditorSpinSlider::get_label() const {
|
||||
return label;
|
||||
}
|
||||
|
||||
void EditorSpinSlider::_grabber_mouse_entered() {
|
||||
mouse_over_grabber = true;
|
||||
update();
|
||||
}
|
||||
|
||||
void EditorSpinSlider::_grabber_mouse_exited() {
|
||||
mouse_over_grabber = false;
|
||||
update();
|
||||
}
|
||||
|
||||
void EditorSpinSlider::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_label", "label"), &EditorSpinSlider::set_label);
|
||||
ClassDB::bind_method(D_METHOD("get_label"), &EditorSpinSlider::get_label);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_gui_input"), &EditorSpinSlider::_gui_input);
|
||||
ClassDB::bind_method(D_METHOD("_grabber_mouse_entered"), &EditorSpinSlider::_grabber_mouse_entered);
|
||||
ClassDB::bind_method(D_METHOD("_grabber_mouse_exited"), &EditorSpinSlider::_grabber_mouse_exited);
|
||||
ClassDB::bind_method(D_METHOD("_grabber_gui_input"), &EditorSpinSlider::_grabber_gui_input);
|
||||
ClassDB::bind_method(D_METHOD("_value_input_closed"), &EditorSpinSlider::_value_input_closed);
|
||||
ClassDB::bind_method(D_METHOD("_value_input_entered"), &EditorSpinSlider::_value_input_entered);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "label"), "set_label", "get_label");
|
||||
}
|
||||
|
||||
EditorSpinSlider::EditorSpinSlider() {
|
||||
|
||||
grabbing_spinner_attempt = false;
|
||||
grabbing_spinner = false;
|
||||
|
||||
set_focus_mode(FOCUS_ALL);
|
||||
updown_offset = -1;
|
||||
hover_updown = false;
|
||||
grabber = memnew(TextureRect);
|
||||
add_child(grabber);
|
||||
grabber->hide();
|
||||
grabber->set_as_toplevel(true);
|
||||
grabber->set_mouse_filter(MOUSE_FILTER_STOP);
|
||||
grabber->connect("mouse_entered", this, "_grabber_mouse_entered");
|
||||
grabber->connect("mouse_exited", this, "_grabber_mouse_exited");
|
||||
grabber->connect("gui_input", this, "_grabber_gui_input");
|
||||
mouse_over_spin = false;
|
||||
mouse_over_grabber = false;
|
||||
grabbing_grabber = false;
|
||||
grabber_range = 1;
|
||||
value_input = memnew(LineEdit);
|
||||
add_child(value_input);
|
||||
value_input->set_as_toplevel(true);
|
||||
value_input->hide();
|
||||
value_input->connect("modal_closed", this, "_value_input_closed");
|
||||
value_input->connect("text_entered", this, "_value_input_entered");
|
||||
hide_slider = false;
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef EDITOR_SPIN_SLIDER_H
|
||||
#define EDITOR_SPIN_SLIDER_H
|
||||
|
||||
#include "scene/gui/line_edit.h"
|
||||
#include "scene/gui/range.h"
|
||||
#include "scene/gui/texture_rect.h"
|
||||
|
||||
class EditorSpinSlider : public Range {
|
||||
GDCLASS(EditorSpinSlider, Range)
|
||||
|
||||
String label;
|
||||
int updown_offset;
|
||||
bool hover_updown;
|
||||
bool mouse_hover;
|
||||
|
||||
TextureRect *grabber;
|
||||
int grabber_range;
|
||||
|
||||
bool mouse_over_spin;
|
||||
bool mouse_over_grabber;
|
||||
|
||||
bool grabbing_grabber;
|
||||
int grabbing_from;
|
||||
float grabbing_ratio;
|
||||
|
||||
bool grabbing_spinner_attempt;
|
||||
bool grabbing_spinner;
|
||||
Vector2 grabbing_spinner_mouse_pos;
|
||||
|
||||
LineEdit *value_input;
|
||||
|
||||
void _grabber_gui_input(const Ref<InputEvent> &p_event);
|
||||
void _value_input_closed();
|
||||
void _value_input_entered(const String &);
|
||||
|
||||
bool hide_slider;
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
void _gui_input(const Ref<InputEvent> &p_event);
|
||||
static void _bind_methods();
|
||||
void _grabber_mouse_entered();
|
||||
void _grabber_mouse_exited();
|
||||
|
||||
public:
|
||||
String get_text_value() const;
|
||||
void set_label(const String &p_label);
|
||||
String get_label() const;
|
||||
|
||||
void set_hide_slider(bool p_hide);
|
||||
bool is_hiding_slider() const;
|
||||
|
||||
virtual Size2 get_minimum_size() const;
|
||||
EditorSpinSlider();
|
||||
};
|
||||
|
||||
#endif // EDITOR_SPIN_SLIDER_H
|
|
@ -1,5 +1,82 @@
|
|||
<svg width="16" height="16" version="1.1" viewBox="0 0 16 15.999999" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(0 -1036.4)">
|
||||
<circle cx="8" cy="1044.4" r="3" fill="#fff" fill-opacity=".78431" stroke-linejoin="round" stroke-opacity=".39216" stroke-width="3"/>
|
||||
</g>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16"
|
||||
height="16"
|
||||
version="1.1"
|
||||
viewBox="0 0 16 15.999999"
|
||||
id="svg8"
|
||||
sodipodi:docname="icon_GUI_slider_grabber.svg"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)">
|
||||
<metadata
|
||||
id="metadata14">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs12" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1211"
|
||||
inkscape:window-height="644"
|
||||
id="namedview10"
|
||||
showgrid="false"
|
||||
inkscape:zoom="14.75"
|
||||
inkscape:cx="-5.7627119"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-x="67"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="g6" />
|
||||
<g
|
||||
transform="translate(0 -1036.4)"
|
||||
id="g6">
|
||||
<path
|
||||
transform="translate(0 1036.4)"
|
||||
d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7 -7 7 7 0 0 0 -7 -7zm0 2a5 5 0 0 1 0.5 0.025391 5 5 0 0 1 0.49414 0.074219 5 5 0 0 1 0.48438 0.12305 5 5 0 0 1 0.46875 0.17188 5 5 0 0 1 0.44922 0.2168 5 5 0 0 1 0.42578 0.26172 5 5 0 0 1 0.39844 0.30273 5 5 0 0 1 0.36524 0.33984 5 5 0 0 1 0.33008 0.37695 5 5 0 0 1 0.29102 0.40625 5 5 0 0 1 0.24805 0.43359 5 5 0 0 1 0.20508 0.45508 5 5 0 0 1 0.1582 0.47461 5 5 0 0 1 0.10938 0.48828 5 5 0 0 1 0.060547 0.49609 5 5 0 0 1 0.011719 0.35352 5 5 0 0 1 -0.025391 0.5 5 5 0 0 1 -0.074218 0.49414 5 5 0 0 1 -0.12305 0.48438 5 5 0 0 1 -0.17188 0.46875 5 5 0 0 1 -0.2168 0.44922 5 5 0 0 1 -0.26172 0.42578 5 5 0 0 1 -0.30273 0.39844 5 5 0 0 1 -0.33984 0.36524 5 5 0 0 1 -0.37695 0.33008 5 5 0 0 1 -0.40625 0.29102 5 5 0 0 1 -0.43359 0.24805 5 5 0 0 1 -0.45508 0.20508 5 5 0 0 1 -0.47461 0.1582 5 5 0 0 1 -0.48828 0.10938 5 5 0 0 1 -0.49609 0.060547 5 5 0 0 1 -0.35352 0.011719 5 5 0 0 1 -0.5 -0.025391 5 5 0 0 1 -0.49414 -0.074218 5 5 0 0 1 -0.48438 -0.12305 5 5 0 0 1 -0.46875 -0.17188 5 5 0 0 1 -0.44922 -0.2168 5 5 0 0 1 -0.42578 -0.26172 5 5 0 0 1 -0.39844 -0.30273 5 5 0 0 1 -0.36523 -0.33984 5 5 0 0 1 -0.33008 -0.37695 5 5 0 0 1 -0.29102 -0.40625 5 5 0 0 1 -0.24805 -0.43359 5 5 0 0 1 -0.20508 -0.45508 5 5 0 0 1 -0.1582 -0.47461 5 5 0 0 1 -0.10938 -0.48828 5 5 0 0 1 -0.060547 -0.49609 5 5 0 0 1 -0.011719 -0.35352 5 5 0 0 1 0.025391 -0.5 5 5 0 0 1 0.074219 -0.49414 5 5 0 0 1 0.12305 -0.48438 5 5 0 0 1 0.17188 -0.46875 5 5 0 0 1 0.2168 -0.44922 5 5 0 0 1 0.26172 -0.42578 5 5 0 0 1 0.30273 -0.39844 5 5 0 0 1 0.33984 -0.36523 5 5 0 0 1 0.37695 -0.33008 5 5 0 0 1 0.40625 -0.29102 5 5 0 0 1 0.43359 -0.24805 5 5 0 0 1 0.45508 -0.20508 5 5 0 0 1 0.47461 -0.1582 5 5 0 0 1 0.48828 -0.10938 5 5 0 0 1 0.49609 -0.060547 5 5 0 0 1 0.35352 -0.011719z"
|
||||
fill="#e0e0e0"
|
||||
id="path2"
|
||||
style="fill:#e0e0e0;fill-opacity:0.28925619" />
|
||||
<circle
|
||||
cx="8"
|
||||
cy="1044.4"
|
||||
r="3"
|
||||
fill="#fff"
|
||||
fill-opacity=".58824"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-opacity=".32549"
|
||||
stroke-width="3"
|
||||
id="circle4" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(-0.06779632,-1036.4)"
|
||||
id="g18">
|
||||
<circle
|
||||
style="fill:#ffffff;fill-opacity:0.78430996;stroke-width:3;stroke-linejoin:round;stroke-opacity:0.39216003"
|
||||
cx="8"
|
||||
cy="1044.4"
|
||||
r="3"
|
||||
id="circle16" />
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 288 B After Width: | Height: | Size: 3.9 KiB |
|
@ -1,6 +1,80 @@
|
|||
<svg width="16" height="16" version="1.1" viewBox="0 0 16 15.999999" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(0 -1036.4)">
|
||||
<path transform="translate(0 1036.4)" d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7 -7 7 7 0 0 0 -7 -7zm0 2a5 5 0 0 1 0.5 0.025391 5 5 0 0 1 0.49414 0.074219 5 5 0 0 1 0.48438 0.12305 5 5 0 0 1 0.46875 0.17188 5 5 0 0 1 0.44922 0.2168 5 5 0 0 1 0.42578 0.26172 5 5 0 0 1 0.39844 0.30273 5 5 0 0 1 0.36524 0.33984 5 5 0 0 1 0.33008 0.37695 5 5 0 0 1 0.29102 0.40625 5 5 0 0 1 0.24805 0.43359 5 5 0 0 1 0.20508 0.45508 5 5 0 0 1 0.1582 0.47461 5 5 0 0 1 0.10938 0.48828 5 5 0 0 1 0.060547 0.49609 5 5 0 0 1 0.011719 0.35352 5 5 0 0 1 -0.025391 0.5 5 5 0 0 1 -0.074218 0.49414 5 5 0 0 1 -0.12305 0.48438 5 5 0 0 1 -0.17188 0.46875 5 5 0 0 1 -0.2168 0.44922 5 5 0 0 1 -0.26172 0.42578 5 5 0 0 1 -0.30273 0.39844 5 5 0 0 1 -0.33984 0.36524 5 5 0 0 1 -0.37695 0.33008 5 5 0 0 1 -0.40625 0.29102 5 5 0 0 1 -0.43359 0.24805 5 5 0 0 1 -0.45508 0.20508 5 5 0 0 1 -0.47461 0.1582 5 5 0 0 1 -0.48828 0.10938 5 5 0 0 1 -0.49609 0.060547 5 5 0 0 1 -0.35352 0.011719 5 5 0 0 1 -0.5 -0.025391 5 5 0 0 1 -0.49414 -0.074218 5 5 0 0 1 -0.48438 -0.12305 5 5 0 0 1 -0.46875 -0.17188 5 5 0 0 1 -0.44922 -0.2168 5 5 0 0 1 -0.42578 -0.26172 5 5 0 0 1 -0.39844 -0.30273 5 5 0 0 1 -0.36523 -0.33984 5 5 0 0 1 -0.33008 -0.37695 5 5 0 0 1 -0.29102 -0.40625 5 5 0 0 1 -0.24805 -0.43359 5 5 0 0 1 -0.20508 -0.45508 5 5 0 0 1 -0.1582 -0.47461 5 5 0 0 1 -0.10938 -0.48828 5 5 0 0 1 -0.060547 -0.49609 5 5 0 0 1 -0.011719 -0.35352 5 5 0 0 1 0.025391 -0.5 5 5 0 0 1 0.074219 -0.49414 5 5 0 0 1 0.12305 -0.48438 5 5 0 0 1 0.17188 -0.46875 5 5 0 0 1 0.2168 -0.44922 5 5 0 0 1 0.26172 -0.42578 5 5 0 0 1 0.30273 -0.39844 5 5 0 0 1 0.33984 -0.36523 5 5 0 0 1 0.37695 -0.33008 5 5 0 0 1 0.40625 -0.29102 5 5 0 0 1 0.43359 -0.24805 5 5 0 0 1 0.45508 -0.20508 5 5 0 0 1 0.47461 -0.1582 5 5 0 0 1 0.48828 -0.10938 5 5 0 0 1 0.49609 -0.060547 5 5 0 0 1 0.35352 -0.011719z" fill="#e0e0e0"/>
|
||||
<circle cx="8" cy="1044.4" r="3" fill="#fff" fill-opacity=".58824" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".32549" stroke-width="3"/>
|
||||
</g>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16"
|
||||
height="16"
|
||||
version="1.1"
|
||||
viewBox="0 0 16 15.999999"
|
||||
id="svg8"
|
||||
sodipodi:docname="icon_GUI_slider_grabber_hl.svg"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)">
|
||||
<metadata
|
||||
id="metadata14">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs12" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="944"
|
||||
inkscape:window-height="480"
|
||||
id="namedview10"
|
||||
showgrid="false"
|
||||
inkscape:zoom="14.75"
|
||||
inkscape:cx="8"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-x="67"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg8" />
|
||||
<g
|
||||
transform="translate(0 -1036.4)"
|
||||
id="g6">
|
||||
<path
|
||||
transform="translate(0 1036.4)"
|
||||
d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7 -7 7 7 0 0 0 -7 -7zm0 2a5 5 0 0 1 0.5 0.025391 5 5 0 0 1 0.49414 0.074219 5 5 0 0 1 0.48438 0.12305 5 5 0 0 1 0.46875 0.17188 5 5 0 0 1 0.44922 0.2168 5 5 0 0 1 0.42578 0.26172 5 5 0 0 1 0.39844 0.30273 5 5 0 0 1 0.36524 0.33984 5 5 0 0 1 0.33008 0.37695 5 5 0 0 1 0.29102 0.40625 5 5 0 0 1 0.24805 0.43359 5 5 0 0 1 0.20508 0.45508 5 5 0 0 1 0.1582 0.47461 5 5 0 0 1 0.10938 0.48828 5 5 0 0 1 0.060547 0.49609 5 5 0 0 1 0.011719 0.35352 5 5 0 0 1 -0.025391 0.5 5 5 0 0 1 -0.074218 0.49414 5 5 0 0 1 -0.12305 0.48438 5 5 0 0 1 -0.17188 0.46875 5 5 0 0 1 -0.2168 0.44922 5 5 0 0 1 -0.26172 0.42578 5 5 0 0 1 -0.30273 0.39844 5 5 0 0 1 -0.33984 0.36524 5 5 0 0 1 -0.37695 0.33008 5 5 0 0 1 -0.40625 0.29102 5 5 0 0 1 -0.43359 0.24805 5 5 0 0 1 -0.45508 0.20508 5 5 0 0 1 -0.47461 0.1582 5 5 0 0 1 -0.48828 0.10938 5 5 0 0 1 -0.49609 0.060547 5 5 0 0 1 -0.35352 0.011719 5 5 0 0 1 -0.5 -0.025391 5 5 0 0 1 -0.49414 -0.074218 5 5 0 0 1 -0.48438 -0.12305 5 5 0 0 1 -0.46875 -0.17188 5 5 0 0 1 -0.44922 -0.2168 5 5 0 0 1 -0.42578 -0.26172 5 5 0 0 1 -0.39844 -0.30273 5 5 0 0 1 -0.36523 -0.33984 5 5 0 0 1 -0.33008 -0.37695 5 5 0 0 1 -0.29102 -0.40625 5 5 0 0 1 -0.24805 -0.43359 5 5 0 0 1 -0.20508 -0.45508 5 5 0 0 1 -0.1582 -0.47461 5 5 0 0 1 -0.10938 -0.48828 5 5 0 0 1 -0.060547 -0.49609 5 5 0 0 1 -0.011719 -0.35352 5 5 0 0 1 0.025391 -0.5 5 5 0 0 1 0.074219 -0.49414 5 5 0 0 1 0.12305 -0.48438 5 5 0 0 1 0.17188 -0.46875 5 5 0 0 1 0.2168 -0.44922 5 5 0 0 1 0.26172 -0.42578 5 5 0 0 1 0.30273 -0.39844 5 5 0 0 1 0.33984 -0.36523 5 5 0 0 1 0.37695 -0.33008 5 5 0 0 1 0.40625 -0.29102 5 5 0 0 1 0.43359 -0.24805 5 5 0 0 1 0.45508 -0.20508 5 5 0 0 1 0.47461 -0.1582 5 5 0 0 1 0.48828 -0.10938 5 5 0 0 1 0.49609 -0.060547 5 5 0 0 1 0.35352 -0.011719z"
|
||||
fill="#e0e0e0"
|
||||
id="path2" />
|
||||
<circle
|
||||
cx="8"
|
||||
cy="1044.4"
|
||||
r="3"
|
||||
fill="#fff"
|
||||
fill-opacity=".58824"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-opacity=".32549"
|
||||
stroke-width="3"
|
||||
id="circle4" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(-0.06779632,-1036.4)"
|
||||
id="g18">
|
||||
<circle
|
||||
style="fill:#ffffff;fill-opacity:0.78430996;stroke-width:3;stroke-linejoin:round;stroke-opacity:0.39216003"
|
||||
cx="8"
|
||||
cy="1044.4"
|
||||
r="3"
|
||||
id="circle16" />
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 3.8 KiB |
|
@ -80,8 +80,8 @@ bool MultiNodeEdit::_set_impl(const StringName &p_name, const Variant &p_value,
|
|||
|
||||
ur->add_undo_property(n, name, n->get(name));
|
||||
}
|
||||
ur->add_do_method(EditorNode::get_singleton()->get_property_editor(), "refresh");
|
||||
ur->add_undo_method(EditorNode::get_singleton()->get_property_editor(), "refresh");
|
||||
ur->add_do_method(EditorNode::get_singleton()->get_inspector(), "refresh");
|
||||
ur->add_undo_method(EditorNode::get_singleton()->get_inspector(), "refresh");
|
||||
|
||||
ur->commit_action();
|
||||
return true;
|
||||
|
|
|
@ -85,7 +85,7 @@ void AnimationPlayerEditor::_notification(int p_what) {
|
|||
}
|
||||
frame->set_value(player->get_current_animation_position());
|
||||
key_editor->set_anim_pos(player->get_current_animation_position());
|
||||
EditorNode::get_singleton()->get_property_editor()->refresh();
|
||||
EditorNode::get_singleton()->get_inspector()->refresh();
|
||||
|
||||
} else if (last_active) {
|
||||
//need the last frame after it stopped
|
||||
|
@ -1073,7 +1073,7 @@ void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos, bool p_drag)
|
|||
updating = false;
|
||||
_seek_value_changed(p_pos, !p_drag);
|
||||
|
||||
EditorNode::get_singleton()->get_property_editor()->refresh();
|
||||
EditorNode::get_singleton()->get_inspector()->refresh();
|
||||
|
||||
//seekit
|
||||
}
|
||||
|
|
|
@ -198,7 +198,7 @@ void MeshLibraryEditor::_menu_cbk(int p_option) {
|
|||
} break;
|
||||
case MENU_OPTION_REMOVE_ITEM: {
|
||||
|
||||
String p = editor->get_property_editor()->get_selected_path();
|
||||
String p = editor->get_inspector()->get_selected_path();
|
||||
if (p.begins_with("/MeshLibrary/item") && p.get_slice_count("/") >= 3) {
|
||||
|
||||
to_erase = p.get_slice("/", 3).to_int();
|
||||
|
|
|
@ -388,7 +388,7 @@ ItemListEditor::ItemListEditor() {
|
|||
vbc->add_child(property_editor);
|
||||
property_editor->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
|
||||
tree = property_editor->get_scene_tree();
|
||||
tree = property_editor->get_property_tree();
|
||||
}
|
||||
|
||||
ItemListEditor::~ItemListEditor() {
|
||||
|
|
|
@ -785,7 +785,7 @@ void ProjectSettingsEditor::popup_project_settings() {
|
|||
|
||||
void ProjectSettingsEditor::_item_selected() {
|
||||
|
||||
TreeItem *ti = globals_editor->get_property_editor()->get_scene_tree()->get_selected();
|
||||
TreeItem *ti = globals_editor->get_property_editor()->get_property_tree()->get_selected();
|
||||
if (!ti)
|
||||
return;
|
||||
if (!ti->get_parent())
|
||||
|
@ -1727,7 +1727,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
|
|||
//globals_editor->hide_top_label();
|
||||
globals_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||
globals_editor->register_search_box(search_box);
|
||||
globals_editor->get_property_editor()->get_scene_tree()->connect("cell_selected", this, "_item_selected");
|
||||
globals_editor->get_property_editor()->get_property_tree()->connect("cell_selected", this, "_item_selected");
|
||||
globals_editor->get_property_editor()->connect("property_toggled", this, "_item_checked", varray(), CONNECT_DEFERRED);
|
||||
globals_editor->get_property_editor()->connect("property_edited", this, "_settings_prop_edited");
|
||||
|
||||
|
|
|
@ -4212,7 +4212,7 @@ void PropertyEditor::_bind_methods() {
|
|||
ADD_SIGNAL(MethodInfo("property_edited", PropertyInfo(Variant::STRING, "property")));
|
||||
}
|
||||
|
||||
Tree *PropertyEditor::get_scene_tree() {
|
||||
Tree *PropertyEditor::get_property_tree() {
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
@ -4695,7 +4695,7 @@ SectionedPropertyEditor::SectionedPropertyEditor() {
|
|||
editor->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||
right_vb->add_child(editor, true);
|
||||
|
||||
editor->get_scene_tree()->set_column_titles_visible(false);
|
||||
editor->get_property_tree()->set_column_titles_visible(false);
|
||||
|
||||
editor->hide_top_label();
|
||||
|
||||
|
|
|
@ -275,7 +275,7 @@ public:
|
|||
|
||||
String get_selected_path() const;
|
||||
|
||||
Tree *get_scene_tree();
|
||||
Tree *get_property_tree();
|
||||
Label *get_top_label();
|
||||
void hide_top_label();
|
||||
void update_tree();
|
||||
|
@ -309,6 +309,7 @@ public:
|
|||
|
||||
void collapse_all_folding();
|
||||
void expand_all_folding();
|
||||
|
||||
PropertyEditor();
|
||||
~PropertyEditor();
|
||||
};
|
||||
|
|
|
@ -732,7 +732,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
|
|||
if (node) {
|
||||
node->set_scene_inherited_state(Ref<SceneState>());
|
||||
scene_tree->update_tree();
|
||||
EditorNode::get_singleton()->get_property_editor()->update_tree();
|
||||
EditorNode::get_singleton()->get_inspector()->update_tree();
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
|
|
@ -1851,7 +1851,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
|
|||
ppeer = Ref<PacketPeerStream>(memnew(PacketPeerStream));
|
||||
ppeer->set_input_buffer_max_size(1024 * 1024 * 8); //8mb should be enough
|
||||
editor = p_editor;
|
||||
editor->get_property_editor()->connect("object_id_selected", this, "_scene_tree_property_select_object");
|
||||
editor->get_inspector()->connect("object_id_selected", this, "_scene_tree_property_select_object");
|
||||
|
||||
tabs = memnew(TabContainer);
|
||||
tabs->set_tab_align(TabContainer::ALIGN_LEFT);
|
||||
|
@ -1936,7 +1936,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
|
|||
inspector = memnew(PropertyEditor);
|
||||
inspector->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
inspector->hide_top_label();
|
||||
inspector->get_scene_tree()->set_column_title(0, TTR("Variable"));
|
||||
inspector->get_property_tree()->set_column_title(0, TTR("Variable"));
|
||||
inspector->set_enable_capitalize_paths(false);
|
||||
inspector->set_read_only(true);
|
||||
inspector->connect("object_id_selected", this, "_scene_tree_property_select_object");
|
||||
|
|
234
main/main.cpp
234
main/main.cpp
|
@ -82,6 +82,8 @@
|
|||
#include "version.h"
|
||||
#include "version_hash.gen.h"
|
||||
|
||||
#include "main/timer_sync.h"
|
||||
|
||||
static ProjectSettings *globals = NULL;
|
||||
static Engine *engine = NULL;
|
||||
static InputMap *input_map = NULL;
|
||||
|
@ -1221,227 +1223,8 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
|
|||
}
|
||||
|
||||
// everything the main loop needs to know about frame timings
|
||||
struct _FrameTime {
|
||||
float animation_step; // time to advance animations for (argument to process())
|
||||
int physics_steps; // number of times to iterate the physics engine
|
||||
|
||||
void clamp_animation(float min_animation_step, float max_animation_step) {
|
||||
if (animation_step < min_animation_step) {
|
||||
animation_step = min_animation_step;
|
||||
} else if (animation_step > max_animation_step) {
|
||||
animation_step = max_animation_step;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class _TimerSync {
|
||||
// wall clock time measured on the main thread
|
||||
uint64_t last_cpu_ticks_usec;
|
||||
uint64_t current_cpu_ticks_usec;
|
||||
|
||||
// logical game time since last physics timestep
|
||||
float time_accum;
|
||||
|
||||
// current difference between wall clock time and reported sum of animation_steps
|
||||
float time_deficit;
|
||||
|
||||
// number of frames back for keeping accumulated physics steps roughly constant.
|
||||
// value of 12 chosen because that is what is required to make 144 Hz monitors
|
||||
// behave well with 60 Hz physics updates. The only worse commonly available refresh
|
||||
// would be 85, requiring CONTROL_STEPS = 17.
|
||||
static const int CONTROL_STEPS = 12;
|
||||
|
||||
// sum of physics steps done over the last (i+1) frames
|
||||
int accumulated_physics_steps[CONTROL_STEPS];
|
||||
|
||||
// typical value for accumulated_physics_steps[i] is either this or this plus one
|
||||
int typical_physics_steps[CONTROL_STEPS];
|
||||
|
||||
protected:
|
||||
// returns the fraction of p_frame_slice required for the timer to overshoot
|
||||
// before advance_core considers changing the physics_steps return from
|
||||
// the typical values as defined by typical_physics_steps
|
||||
float get_physics_jitter_fix() {
|
||||
return Engine::get_singleton()->get_physics_jitter_fix();
|
||||
}
|
||||
|
||||
// gets our best bet for the average number of physics steps per render frame
|
||||
// return value: number of frames back this data is consistent
|
||||
int get_average_physics_steps(float &p_min, float &p_max) {
|
||||
p_min = typical_physics_steps[0];
|
||||
p_max = p_min + 1;
|
||||
|
||||
for (int i = 1; i < CONTROL_STEPS; ++i) {
|
||||
const float typical_lower = typical_physics_steps[i];
|
||||
const float current_min = typical_lower / (i + 1);
|
||||
if (current_min > p_max)
|
||||
return i; // bail out of further restrictions would void the interval
|
||||
else if (current_min > p_min)
|
||||
p_min = current_min;
|
||||
const float current_max = (typical_lower + 1) / (i + 1);
|
||||
if (current_max < p_min)
|
||||
return i;
|
||||
else if (current_max < p_max)
|
||||
p_max = current_max;
|
||||
}
|
||||
|
||||
return CONTROL_STEPS;
|
||||
}
|
||||
|
||||
// advance physics clock by p_animation_step, return appropriate number of steps to simulate
|
||||
_FrameTime advance_core(float p_frame_slice, int p_iterations_per_second, float p_animation_step) {
|
||||
_FrameTime ret;
|
||||
|
||||
ret.animation_step = p_animation_step;
|
||||
|
||||
// simple determination of number of physics iteration
|
||||
time_accum += ret.animation_step;
|
||||
ret.physics_steps = floor(time_accum * p_iterations_per_second);
|
||||
|
||||
int min_typical_steps = typical_physics_steps[0];
|
||||
int max_typical_steps = min_typical_steps + 1;
|
||||
|
||||
// given the past recorded steps and typcial steps to match, calculate bounds for this
|
||||
// step to be typical
|
||||
bool update_typical = false;
|
||||
|
||||
for (int i = 0; i < CONTROL_STEPS - 1; ++i) {
|
||||
int steps_left_to_match_typical = typical_physics_steps[i + 1] - accumulated_physics_steps[i];
|
||||
if (steps_left_to_match_typical > max_typical_steps ||
|
||||
steps_left_to_match_typical + 1 < min_typical_steps) {
|
||||
update_typical = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (steps_left_to_match_typical > min_typical_steps)
|
||||
min_typical_steps = steps_left_to_match_typical;
|
||||
if (steps_left_to_match_typical + 1 < max_typical_steps)
|
||||
max_typical_steps = steps_left_to_match_typical + 1;
|
||||
}
|
||||
|
||||
// try to keep it consistent with previous iterations
|
||||
if (ret.physics_steps < min_typical_steps) {
|
||||
const int max_possible_steps = floor((time_accum)*p_iterations_per_second + get_physics_jitter_fix());
|
||||
if (max_possible_steps < min_typical_steps) {
|
||||
ret.physics_steps = max_possible_steps;
|
||||
update_typical = true;
|
||||
} else {
|
||||
ret.physics_steps = min_typical_steps;
|
||||
}
|
||||
} else if (ret.physics_steps > max_typical_steps) {
|
||||
const int min_possible_steps = floor((time_accum)*p_iterations_per_second - get_physics_jitter_fix());
|
||||
if (min_possible_steps > max_typical_steps) {
|
||||
ret.physics_steps = min_possible_steps;
|
||||
update_typical = true;
|
||||
} else {
|
||||
ret.physics_steps = max_typical_steps;
|
||||
}
|
||||
}
|
||||
|
||||
time_accum -= ret.physics_steps * p_frame_slice;
|
||||
|
||||
// keep track of accumulated step counts
|
||||
for (int i = CONTROL_STEPS - 2; i >= 0; --i) {
|
||||
accumulated_physics_steps[i + 1] = accumulated_physics_steps[i] + ret.physics_steps;
|
||||
}
|
||||
accumulated_physics_steps[0] = ret.physics_steps;
|
||||
|
||||
if (update_typical) {
|
||||
for (int i = CONTROL_STEPS - 1; i >= 0; --i) {
|
||||
if (typical_physics_steps[i] > accumulated_physics_steps[i]) {
|
||||
typical_physics_steps[i] = accumulated_physics_steps[i];
|
||||
} else if (typical_physics_steps[i] < accumulated_physics_steps[i] - 1) {
|
||||
typical_physics_steps[i] = accumulated_physics_steps[i] - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// calls advance_core, keeps track of deficit it adds to animaption_step, make sure the deficit sum stays close to zero
|
||||
_FrameTime advance_checked(float p_frame_slice, int p_iterations_per_second, float p_animation_step) {
|
||||
if (fixed_fps != -1)
|
||||
p_animation_step = 1.0 / fixed_fps;
|
||||
|
||||
// compensate for last deficit
|
||||
p_animation_step += time_deficit;
|
||||
|
||||
_FrameTime ret = advance_core(p_frame_slice, p_iterations_per_second, p_animation_step);
|
||||
|
||||
// we will do some clamping on ret.animation_step and need to sync those changes to time_accum,
|
||||
// that's easiest if we just remember their fixed difference now
|
||||
const double animation_minus_accum = ret.animation_step - time_accum;
|
||||
|
||||
// first, least important clamping: keep ret.animation_step consistent with typical_physics_steps.
|
||||
// this smoothes out the animation steps and culls small but quick variations.
|
||||
{
|
||||
float min_average_physics_steps, max_average_physics_steps;
|
||||
int consistent_steps = get_average_physics_steps(min_average_physics_steps, max_average_physics_steps);
|
||||
if (consistent_steps > 3) {
|
||||
ret.clamp_animation(min_average_physics_steps * p_frame_slice, max_average_physics_steps * p_frame_slice);
|
||||
}
|
||||
}
|
||||
|
||||
// second clamping: keep abs(time_deficit) < jitter_fix * frame_slise
|
||||
float max_clock_deviation = get_physics_jitter_fix() * p_frame_slice;
|
||||
ret.clamp_animation(p_animation_step - max_clock_deviation, p_animation_step + max_clock_deviation);
|
||||
|
||||
// last clamping: make sure time_accum is between 0 and p_frame_slice for consistency between physics and animation
|
||||
ret.clamp_animation(animation_minus_accum, animation_minus_accum + p_frame_slice);
|
||||
|
||||
// restore time_accum
|
||||
time_accum = ret.animation_step - animation_minus_accum;
|
||||
|
||||
// track deficit
|
||||
time_deficit = p_animation_step - ret.animation_step;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// determine wall clock step since last iteration
|
||||
float get_cpu_animation_step() {
|
||||
uint64_t cpu_ticks_elapsed = current_cpu_ticks_usec - last_cpu_ticks_usec;
|
||||
last_cpu_ticks_usec = current_cpu_ticks_usec;
|
||||
|
||||
return cpu_ticks_elapsed / 1000000.0;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit _TimerSync() :
|
||||
last_cpu_ticks_usec(0),
|
||||
current_cpu_ticks_usec(0),
|
||||
time_accum(0),
|
||||
time_deficit(0) {
|
||||
for (int i = CONTROL_STEPS - 1; i >= 0; --i) {
|
||||
typical_physics_steps[i] = i;
|
||||
accumulated_physics_steps[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// start the clock
|
||||
void init(uint64_t p_cpu_ticks_usec) {
|
||||
current_cpu_ticks_usec = last_cpu_ticks_usec = p_cpu_ticks_usec;
|
||||
}
|
||||
|
||||
// set measured wall clock time
|
||||
void set_cpu_ticks_usec(uint64_t p_cpu_ticks_usec) {
|
||||
current_cpu_ticks_usec = p_cpu_ticks_usec;
|
||||
}
|
||||
|
||||
// advance one frame, return timesteps to take
|
||||
_FrameTime advance(float p_frame_slice, int p_iterations_per_second) {
|
||||
float cpu_animation_step = get_cpu_animation_step();
|
||||
|
||||
return advance_checked(p_frame_slice, p_iterations_per_second, cpu_animation_step);
|
||||
}
|
||||
|
||||
void before_start_render() {
|
||||
VisualServer::get_singleton()->sync();
|
||||
}
|
||||
};
|
||||
|
||||
static _TimerSync _timer_sync;
|
||||
static MainTimerSync main_timer_sync;
|
||||
|
||||
bool Main::start() {
|
||||
|
||||
|
@ -1457,7 +1240,7 @@ bool Main::start() {
|
|||
String _export_preset;
|
||||
bool export_debug = false;
|
||||
|
||||
_timer_sync.init(OS::get_singleton()->get_ticks_usec());
|
||||
main_timer_sync.init(OS::get_singleton()->get_ticks_usec());
|
||||
|
||||
List<String> args = OS::get_singleton()->get_cmdline_args();
|
||||
for (int i = 0; i < args.size(); i++) {
|
||||
|
@ -1958,15 +1741,16 @@ bool Main::iteration() {
|
|||
|
||||
uint64_t ticks = OS::get_singleton()->get_ticks_usec();
|
||||
Engine::get_singleton()->_frame_ticks = ticks;
|
||||
_timer_sync.set_cpu_ticks_usec(ticks);
|
||||
main_timer_sync.set_cpu_ticks_usec(ticks);
|
||||
main_timer_sync.set_fixed_fps(fixed_fps);
|
||||
|
||||
uint64_t ticks_elapsed = ticks - last_ticks;
|
||||
|
||||
int physics_fps = Engine::get_singleton()->get_iterations_per_second();
|
||||
float frame_slice = 1.0 / physics_fps;
|
||||
|
||||
_FrameTime advance = _timer_sync.advance(frame_slice, physics_fps);
|
||||
double step = advance.animation_step;
|
||||
MainFrameTime advance = main_timer_sync.advance(frame_slice, physics_fps);
|
||||
double step = advance.idle_step;
|
||||
|
||||
Engine::get_singleton()->_frame_step = step;
|
||||
|
||||
|
@ -2030,7 +1814,7 @@ bool Main::iteration() {
|
|||
OS::get_singleton()->get_main_loop()->idle(step * time_scale);
|
||||
message_queue->flush();
|
||||
|
||||
_timer_sync.before_start_render(); //sync if still drawing from previous frames.
|
||||
VisualServer::get_singleton()->sync(); //sync if still drawing from previous frames.
|
||||
|
||||
if (OS::get_singleton()->can_draw() && !disable_render_loop) {
|
||||
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
#include "timer_sync.h"
|
||||
|
||||
void MainFrameTime::clamp_idle(float min_idle_step, float max_idle_step) {
|
||||
if (idle_step < min_idle_step) {
|
||||
idle_step = min_idle_step;
|
||||
} else if (idle_step > max_idle_step) {
|
||||
idle_step = max_idle_step;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////
|
||||
|
||||
// returns the fraction of p_frame_slice required for the timer to overshoot
|
||||
// before advance_core considers changing the physics_steps return from
|
||||
// the typical values as defined by typical_physics_steps
|
||||
float MainTimerSync::get_physics_jitter_fix() {
|
||||
return Engine::get_singleton()->get_physics_jitter_fix();
|
||||
}
|
||||
|
||||
// gets our best bet for the average number of physics steps per render frame
|
||||
// return value: number of frames back this data is consistent
|
||||
int MainTimerSync::get_average_physics_steps(float &p_min, float &p_max) {
|
||||
p_min = typical_physics_steps[0];
|
||||
p_max = p_min + 1;
|
||||
|
||||
for (int i = 1; i < CONTROL_STEPS; ++i) {
|
||||
const float typical_lower = typical_physics_steps[i];
|
||||
const float current_min = typical_lower / (i + 1);
|
||||
if (current_min > p_max)
|
||||
return i; // bail out of further restrictions would void the interval
|
||||
else if (current_min > p_min)
|
||||
p_min = current_min;
|
||||
const float current_max = (typical_lower + 1) / (i + 1);
|
||||
if (current_max < p_min)
|
||||
return i;
|
||||
else if (current_max < p_max)
|
||||
p_max = current_max;
|
||||
}
|
||||
|
||||
return CONTROL_STEPS;
|
||||
}
|
||||
|
||||
// advance physics clock by p_idle_step, return appropriate number of steps to simulate
|
||||
MainFrameTime MainTimerSync::advance_core(float p_frame_slice, int p_iterations_per_second, float p_idle_step) {
|
||||
MainFrameTime ret;
|
||||
|
||||
ret.idle_step = p_idle_step;
|
||||
|
||||
// simple determination of number of physics iteration
|
||||
time_accum += ret.idle_step;
|
||||
ret.physics_steps = floor(time_accum * p_iterations_per_second);
|
||||
|
||||
int min_typical_steps = typical_physics_steps[0];
|
||||
int max_typical_steps = min_typical_steps + 1;
|
||||
|
||||
// given the past recorded steps and typcial steps to match, calculate bounds for this
|
||||
// step to be typical
|
||||
bool update_typical = false;
|
||||
|
||||
for (int i = 0; i < CONTROL_STEPS - 1; ++i) {
|
||||
int steps_left_to_match_typical = typical_physics_steps[i + 1] - accumulated_physics_steps[i];
|
||||
if (steps_left_to_match_typical > max_typical_steps ||
|
||||
steps_left_to_match_typical + 1 < min_typical_steps) {
|
||||
update_typical = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (steps_left_to_match_typical > min_typical_steps)
|
||||
min_typical_steps = steps_left_to_match_typical;
|
||||
if (steps_left_to_match_typical + 1 < max_typical_steps)
|
||||
max_typical_steps = steps_left_to_match_typical + 1;
|
||||
}
|
||||
|
||||
// try to keep it consistent with previous iterations
|
||||
if (ret.physics_steps < min_typical_steps) {
|
||||
const int max_possible_steps = floor((time_accum)*p_iterations_per_second + get_physics_jitter_fix());
|
||||
if (max_possible_steps < min_typical_steps) {
|
||||
ret.physics_steps = max_possible_steps;
|
||||
update_typical = true;
|
||||
} else {
|
||||
ret.physics_steps = min_typical_steps;
|
||||
}
|
||||
} else if (ret.physics_steps > max_typical_steps) {
|
||||
const int min_possible_steps = floor((time_accum)*p_iterations_per_second - get_physics_jitter_fix());
|
||||
if (min_possible_steps > max_typical_steps) {
|
||||
ret.physics_steps = min_possible_steps;
|
||||
update_typical = true;
|
||||
} else {
|
||||
ret.physics_steps = max_typical_steps;
|
||||
}
|
||||
}
|
||||
|
||||
time_accum -= ret.physics_steps * p_frame_slice;
|
||||
|
||||
// keep track of accumulated step counts
|
||||
for (int i = CONTROL_STEPS - 2; i >= 0; --i) {
|
||||
accumulated_physics_steps[i + 1] = accumulated_physics_steps[i] + ret.physics_steps;
|
||||
}
|
||||
accumulated_physics_steps[0] = ret.physics_steps;
|
||||
|
||||
if (update_typical) {
|
||||
for (int i = CONTROL_STEPS - 1; i >= 0; --i) {
|
||||
if (typical_physics_steps[i] > accumulated_physics_steps[i]) {
|
||||
typical_physics_steps[i] = accumulated_physics_steps[i];
|
||||
} else if (typical_physics_steps[i] < accumulated_physics_steps[i] - 1) {
|
||||
typical_physics_steps[i] = accumulated_physics_steps[i] - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// calls advance_core, keeps track of deficit it adds to animaption_step, make sure the deficit sum stays close to zero
|
||||
MainFrameTime MainTimerSync::advance_checked(float p_frame_slice, int p_iterations_per_second, float p_idle_step) {
|
||||
if (fixed_fps != -1)
|
||||
p_idle_step = 1.0 / fixed_fps;
|
||||
|
||||
// compensate for last deficit
|
||||
p_idle_step += time_deficit;
|
||||
|
||||
MainFrameTime ret = advance_core(p_frame_slice, p_iterations_per_second, p_idle_step);
|
||||
|
||||
// we will do some clamping on ret.idle_step and need to sync those changes to time_accum,
|
||||
// that's easiest if we just remember their fixed difference now
|
||||
const double idle_minus_accum = ret.idle_step - time_accum;
|
||||
|
||||
// first, least important clamping: keep ret.idle_step consistent with typical_physics_steps.
|
||||
// this smoothes out the idle steps and culls small but quick variations.
|
||||
{
|
||||
float min_average_physics_steps, max_average_physics_steps;
|
||||
int consistent_steps = get_average_physics_steps(min_average_physics_steps, max_average_physics_steps);
|
||||
if (consistent_steps > 3) {
|
||||
ret.clamp_idle(min_average_physics_steps * p_frame_slice, max_average_physics_steps * p_frame_slice);
|
||||
}
|
||||
}
|
||||
|
||||
// second clamping: keep abs(time_deficit) < jitter_fix * frame_slise
|
||||
float max_clock_deviation = get_physics_jitter_fix() * p_frame_slice;
|
||||
ret.clamp_idle(p_idle_step - max_clock_deviation, p_idle_step + max_clock_deviation);
|
||||
|
||||
// last clamping: make sure time_accum is between 0 and p_frame_slice for consistency between physics and idle
|
||||
ret.clamp_idle(idle_minus_accum, idle_minus_accum + p_frame_slice);
|
||||
|
||||
// restore time_accum
|
||||
time_accum = ret.idle_step - idle_minus_accum;
|
||||
|
||||
// track deficit
|
||||
time_deficit = p_idle_step - ret.idle_step;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// determine wall clock step since last iteration
|
||||
float MainTimerSync::get_cpu_idle_step() {
|
||||
uint64_t cpu_ticks_elapsed = current_cpu_ticks_usec - last_cpu_ticks_usec;
|
||||
last_cpu_ticks_usec = current_cpu_ticks_usec;
|
||||
|
||||
return cpu_ticks_elapsed / 1000000.0;
|
||||
}
|
||||
|
||||
MainTimerSync::MainTimerSync() :
|
||||
last_cpu_ticks_usec(0),
|
||||
current_cpu_ticks_usec(0),
|
||||
time_accum(0),
|
||||
time_deficit(0),
|
||||
fixed_fps(0) {
|
||||
for (int i = CONTROL_STEPS - 1; i >= 0; --i) {
|
||||
typical_physics_steps[i] = i;
|
||||
accumulated_physics_steps[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
// start the clock
|
||||
void MainTimerSync::init(uint64_t p_cpu_ticks_usec) {
|
||||
current_cpu_ticks_usec = last_cpu_ticks_usec = p_cpu_ticks_usec;
|
||||
}
|
||||
|
||||
// set measured wall clock time
|
||||
void MainTimerSync::set_cpu_ticks_usec(uint64_t p_cpu_ticks_usec) {
|
||||
current_cpu_ticks_usec = p_cpu_ticks_usec;
|
||||
}
|
||||
|
||||
void MainTimerSync::set_fixed_fps(int p_fixed_fps) {
|
||||
fixed_fps = p_fixed_fps;
|
||||
}
|
||||
|
||||
// advance one frame, return timesteps to take
|
||||
MainFrameTime MainTimerSync::advance(float p_frame_slice, int p_iterations_per_second) {
|
||||
float cpu_idle_step = get_cpu_idle_step();
|
||||
|
||||
return advance_checked(p_frame_slice, p_iterations_per_second, cpu_idle_step);
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
#ifndef TIMER_SYNC_H
|
||||
#define TIMER_SYNC_H
|
||||
|
||||
#include "core/engine.h"
|
||||
|
||||
struct MainFrameTime {
|
||||
float idle_step; // time to advance idles for (argument to process())
|
||||
int physics_steps; // number of times to iterate the physics engine
|
||||
|
||||
void clamp_idle(float min_idle_step, float max_idle_step);
|
||||
};
|
||||
|
||||
class MainTimerSync {
|
||||
// wall clock time measured on the main thread
|
||||
uint64_t last_cpu_ticks_usec;
|
||||
uint64_t current_cpu_ticks_usec;
|
||||
|
||||
// logical game time since last physics timestep
|
||||
float time_accum;
|
||||
|
||||
// current difference between wall clock time and reported sum of idle_steps
|
||||
float time_deficit;
|
||||
|
||||
// number of frames back for keeping accumulated physics steps roughly constant.
|
||||
// value of 12 chosen because that is what is required to make 144 Hz monitors
|
||||
// behave well with 60 Hz physics updates. The only worse commonly available refresh
|
||||
// would be 85, requiring CONTROL_STEPS = 17.
|
||||
static const int CONTROL_STEPS = 12;
|
||||
|
||||
// sum of physics steps done over the last (i+1) frames
|
||||
int accumulated_physics_steps[CONTROL_STEPS];
|
||||
|
||||
// typical value for accumulated_physics_steps[i] is either this or this plus one
|
||||
int typical_physics_steps[CONTROL_STEPS];
|
||||
|
||||
int fixed_fps;
|
||||
|
||||
protected:
|
||||
// returns the fraction of p_frame_slice required for the timer to overshoot
|
||||
// before advance_core considers changing the physics_steps return from
|
||||
// the typical values as defined by typical_physics_steps
|
||||
float get_physics_jitter_fix();
|
||||
|
||||
// gets our best bet for the average number of physics steps per render frame
|
||||
// return value: number of frames back this data is consistent
|
||||
int get_average_physics_steps(float &p_min, float &p_max);
|
||||
|
||||
// advance physics clock by p_idle_step, return appropriate number of steps to simulate
|
||||
MainFrameTime advance_core(float p_frame_slice, int p_iterations_per_second, float p_idle_step);
|
||||
|
||||
// calls advance_core, keeps track of deficit it adds to animaption_step, make sure the deficit sum stays close to zero
|
||||
MainFrameTime advance_checked(float p_frame_slice, int p_iterations_per_second, float p_idle_step);
|
||||
|
||||
// determine wall clock step since last iteration
|
||||
float get_cpu_idle_step();
|
||||
|
||||
public:
|
||||
MainTimerSync();
|
||||
|
||||
// start the clock
|
||||
void init(uint64_t p_cpu_ticks_usec);
|
||||
// set measured wall clock time
|
||||
void set_cpu_ticks_usec(uint64_t p_cpu_ticks_usec);
|
||||
//set fixed fps
|
||||
void set_fixed_fps(int p_fixed_fps);
|
||||
|
||||
// advance one frame, return timesteps to take
|
||||
MainFrameTime advance(float p_frame_slice, int p_iterations_per_second);
|
||||
};
|
||||
|
||||
#endif // TIMER_SYNC_H
|
|
@ -782,7 +782,7 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) {
|
|||
}
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
EditorNode::get_singleton()->get_property_editor()->update_tree();
|
||||
EditorNode::get_singleton()->get_inspector()->update_tree();
|
||||
NodeDock::singleton->update_lists();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -268,7 +268,7 @@ protected:
|
|||
|
||||
if (String(p_name) == "export") {
|
||||
script->set_variable_export(var, p_value);
|
||||
EditorNode::get_singleton()->get_property_editor()->update_tree();
|
||||
EditorNode::get_singleton()->get_inspector()->update_tree();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -462,7 +462,7 @@ void AudioStreamPlayer2D::_bind_methods() {
|
|||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_RANGE, "1,65536,1"), "set_max_distance", "get_max_distance");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "attenuation", PROPERTY_HINT_EXP_EASING), "set_attenuation", "get_attenuation");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_attenuation", "get_attenuation");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask");
|
||||
|
||||
|
|
|
@ -375,7 +375,7 @@ void DirectionalLight::_bind_methods() {
|
|||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_normal_bias", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_bias_split_scale", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_BIAS_SPLIT_SCALE);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_depth_range", PROPERTY_HINT_ENUM, "Stable,Optimized"), "set_shadow_depth_range", "get_shadow_depth_range");
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_max_distance", PROPERTY_HINT_RANGE, "0,65536,0.1"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_max_distance", PROPERTY_HINT_EXP_RANGE, "0,65536,0.1"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE);
|
||||
|
||||
BIND_ENUM_CONSTANT(SHADOW_ORTHOGONAL);
|
||||
BIND_ENUM_CONSTANT(SHADOW_PARALLEL_2_SPLITS);
|
||||
|
@ -428,8 +428,8 @@ void OmniLight::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_shadow_detail"), &OmniLight::get_shadow_detail);
|
||||
|
||||
ADD_GROUP("Omni", "omni_");
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_range", PROPERTY_HINT_RANGE, "0,65536,0.1"), "set_param", "get_param", PARAM_RANGE);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_attenuation", PROPERTY_HINT_EXP_EASING), "set_param", "get_param", PARAM_ATTENUATION);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1"), "set_param", "get_param", PARAM_RANGE);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "omni_shadow_mode", PROPERTY_HINT_ENUM, "Dual Paraboloid,Cube"), "set_shadow_mode", "get_shadow_mode");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "omni_shadow_detail", PROPERTY_HINT_ENUM, "Vertical,Horizontal"), "set_shadow_detail", "get_shadow_detail");
|
||||
|
||||
|
@ -450,8 +450,8 @@ OmniLight::OmniLight() :
|
|||
void SpotLight::_bind_methods() {
|
||||
|
||||
ADD_GROUP("Spot", "spot_");
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_range", PROPERTY_HINT_RANGE, "0,65536,0.1"), "set_param", "get_param", PARAM_RANGE);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_attenuation", PROPERTY_HINT_EXP_EASING), "set_param", "get_param", PARAM_ATTENUATION);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1"), "set_param", "get_param", PARAM_RANGE);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_angle", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_param", "get_param", PARAM_SPOT_ANGLE);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_angle_attenuation", PROPERTY_HINT_EXP_EASING), "set_param", "get_param", PARAM_SPOT_ATTENUATION);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_angle_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_SPOT_ATTENUATION);
|
||||
}
|
||||
|
|
|
@ -656,8 +656,9 @@ ColorPicker::ColorPicker() :
|
|||
|
||||
void ColorPickerButton::_color_changed(const Color &p_color) {
|
||||
|
||||
color = p_color;
|
||||
update();
|
||||
emit_signal("color_changed", p_color);
|
||||
emit_signal("color_changed", color);
|
||||
}
|
||||
|
||||
void ColorPickerButton::_modal_closed() {
|
||||
|
@ -667,6 +668,7 @@ void ColorPickerButton::_modal_closed() {
|
|||
|
||||
void ColorPickerButton::pressed() {
|
||||
|
||||
_update_picker();
|
||||
popup->set_position(get_global_position() - picker->get_combined_minimum_size());
|
||||
popup->popup();
|
||||
picker->set_focus_on_line_edit();
|
||||
|
@ -679,7 +681,7 @@ void ColorPickerButton::_notification(int p_what) {
|
|||
Ref<StyleBox> normal = get_stylebox("normal");
|
||||
Rect2 r = Rect2(normal->get_offset(), get_size() - normal->get_minimum_size());
|
||||
draw_texture_rect(Control::get_icon("bg", "ColorPickerButton"), r, true);
|
||||
draw_rect(r, picker->get_pick_color());
|
||||
draw_rect(r, color);
|
||||
}
|
||||
|
||||
if (p_what == MainLoop::NOTIFICATION_WM_QUIT_REQUEST) {
|
||||
|
@ -689,27 +691,34 @@ void ColorPickerButton::_notification(int p_what) {
|
|||
|
||||
void ColorPickerButton::set_pick_color(const Color &p_color) {
|
||||
|
||||
picker->set_pick_color(p_color);
|
||||
color = p_color;
|
||||
if (picker) {
|
||||
picker->set_pick_color(p_color);
|
||||
}
|
||||
|
||||
update();
|
||||
emit_signal("color_changed", p_color);
|
||||
}
|
||||
Color ColorPickerButton::get_pick_color() const {
|
||||
|
||||
return picker->get_pick_color();
|
||||
return color;
|
||||
}
|
||||
|
||||
void ColorPickerButton::set_edit_alpha(bool p_show) {
|
||||
|
||||
picker->set_edit_alpha(p_show);
|
||||
edit_alpha = p_show;
|
||||
if (picker) {
|
||||
picker->set_edit_alpha(p_show);
|
||||
}
|
||||
}
|
||||
|
||||
bool ColorPickerButton::is_editing_alpha() const {
|
||||
|
||||
return picker->is_editing_alpha();
|
||||
return edit_alpha;
|
||||
}
|
||||
|
||||
ColorPicker *ColorPickerButton::get_picker() const {
|
||||
ColorPicker *ColorPickerButton::get_picker() {
|
||||
|
||||
_update_picker();
|
||||
return picker;
|
||||
}
|
||||
|
||||
|
@ -718,6 +727,19 @@ PopupPanel *ColorPickerButton::get_popup() const {
|
|||
return popup;
|
||||
}
|
||||
|
||||
void ColorPickerButton::_update_picker() {
|
||||
if (!picker) {
|
||||
popup = memnew(PopupPanel);
|
||||
picker = memnew(ColorPicker);
|
||||
popup->add_child(picker);
|
||||
add_child(popup);
|
||||
picker->connect("color_changed", this, "_color_changed");
|
||||
popup->connect("modal_closed", this, "_modal_closed");
|
||||
picker->set_pick_color(color);
|
||||
picker->set_edit_alpha(edit_alpha);
|
||||
}
|
||||
}
|
||||
|
||||
void ColorPickerButton::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_pick_color", "color"), &ColorPickerButton::set_pick_color);
|
||||
|
@ -737,12 +759,7 @@ void ColorPickerButton::_bind_methods() {
|
|||
|
||||
ColorPickerButton::ColorPickerButton() {
|
||||
|
||||
popup = memnew(PopupPanel);
|
||||
picker = memnew(ColorPicker);
|
||||
popup->add_child(picker);
|
||||
|
||||
picker->connect("color_changed", this, "_color_changed");
|
||||
popup->connect("modal_closed", this, "_modal_closed");
|
||||
|
||||
add_child(popup);
|
||||
picker = NULL;
|
||||
popup = NULL;
|
||||
edit_alpha = true;
|
||||
}
|
||||
|
|
|
@ -118,12 +118,16 @@ class ColorPickerButton : public Button {
|
|||
|
||||
PopupPanel *popup;
|
||||
ColorPicker *picker;
|
||||
Color color;
|
||||
bool edit_alpha;
|
||||
|
||||
void _color_changed(const Color &p_color);
|
||||
void _modal_closed();
|
||||
|
||||
virtual void pressed();
|
||||
|
||||
void _update_picker();
|
||||
|
||||
protected:
|
||||
void _notification(int);
|
||||
static void _bind_methods();
|
||||
|
@ -135,7 +139,7 @@ public:
|
|||
void set_edit_alpha(bool p_show);
|
||||
bool is_editing_alpha() const;
|
||||
|
||||
ColorPicker *get_picker() const;
|
||||
ColorPicker *get_picker();
|
||||
PopupPanel *get_popup() const;
|
||||
|
||||
ColorPickerButton();
|
||||
|
|
|
@ -34,9 +34,9 @@
|
|||
|
||||
void Container::_child_minsize_changed() {
|
||||
|
||||
Size2 ms = get_combined_minimum_size();
|
||||
if (ms.width > get_size().width || ms.height > get_size().height)
|
||||
minimum_size_changed();
|
||||
//Size2 ms = get_combined_minimum_size();
|
||||
//if (ms.width > get_size().width || ms.height > get_size().height) {
|
||||
minimum_size_changed();
|
||||
queue_sort();
|
||||
}
|
||||
|
||||
|
|
|
@ -155,12 +155,21 @@ Size2 Control::get_custom_minimum_size() const {
|
|||
return data.custom_minimum_size;
|
||||
}
|
||||
|
||||
Size2 Control::get_combined_minimum_size() const {
|
||||
void Control::_update_minimum_size_cache() {
|
||||
|
||||
Size2 minsize = get_minimum_size();
|
||||
minsize.x = MAX(minsize.x, data.custom_minimum_size.x);
|
||||
minsize.y = MAX(minsize.y, data.custom_minimum_size.y);
|
||||
return minsize;
|
||||
data.minimum_size_cache = minsize;
|
||||
data.minimum_size_valid = true;
|
||||
}
|
||||
|
||||
Size2 Control::get_combined_minimum_size() const {
|
||||
|
||||
if (!data.minimum_size_valid) {
|
||||
const_cast<Control *>(this)->_update_minimum_size_cache();
|
||||
}
|
||||
return data.minimum_size_cache;
|
||||
}
|
||||
|
||||
Size2 Control::_edit_get_minimum_size() const {
|
||||
|
@ -259,14 +268,17 @@ void Control::_update_minimum_size() {
|
|||
if (!is_inside_tree())
|
||||
return;
|
||||
|
||||
data.pending_min_size_update = false;
|
||||
Size2 minsize = get_combined_minimum_size();
|
||||
if (minsize.x > data.size_cache.x ||
|
||||
minsize.y > data.size_cache.y) {
|
||||
_size_changed();
|
||||
}
|
||||
|
||||
emit_signal(SceneStringNames::get_singleton()->minimum_size_changed);
|
||||
data.updating_last_minimum_size = false;
|
||||
|
||||
if (minsize != data.last_minimum_size) {
|
||||
emit_signal(SceneStringNames::get_singleton()->minimum_size_changed);
|
||||
}
|
||||
}
|
||||
|
||||
bool Control::_get(const StringName &p_name, Variant &r_ret) const {
|
||||
|
@ -437,8 +449,12 @@ void Control::_notification(int p_notification) {
|
|||
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
|
||||
_size_changed();
|
||||
|
||||
} break;
|
||||
case NOTIFICATION_POST_ENTER_TREE: {
|
||||
if (is_visible_in_tree()) {
|
||||
data.minimum_size_valid = false;
|
||||
_size_changed();
|
||||
}
|
||||
} break;
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
|
||||
|
@ -620,13 +636,12 @@ void Control::_notification(int p_notification) {
|
|||
|
||||
if (is_inside_tree()) {
|
||||
_modal_stack_remove();
|
||||
minimum_size_changed();
|
||||
}
|
||||
|
||||
//remove key focus
|
||||
//remove modalness
|
||||
} else {
|
||||
|
||||
data.minimum_size_valid = false;
|
||||
_size_changed();
|
||||
}
|
||||
|
||||
|
@ -2464,17 +2479,25 @@ void Control::minimum_size_changed() {
|
|||
if (!is_inside_tree() || data.block_minimum_size_adjust)
|
||||
return;
|
||||
|
||||
if (data.pending_min_size_update)
|
||||
Control *invalidate = this;
|
||||
|
||||
//invalidate cache upwards
|
||||
while (invalidate && invalidate->data.minimum_size_valid) {
|
||||
invalidate->data.minimum_size_valid = false;
|
||||
if (invalidate->is_set_as_toplevel())
|
||||
break; // do not go further up
|
||||
invalidate = invalidate->data.parent;
|
||||
}
|
||||
|
||||
if (!is_visible_in_tree())
|
||||
return;
|
||||
|
||||
data.pending_min_size_update = true;
|
||||
MessageQueue::get_singleton()->push_call(this, "_update_minimum_size");
|
||||
if (data.updating_last_minimum_size)
|
||||
return;
|
||||
|
||||
if (!is_toplevel_control()) {
|
||||
Control *pc = get_parent_control();
|
||||
if (pc)
|
||||
pc->minimum_size_changed();
|
||||
}
|
||||
data.updating_last_minimum_size = true;
|
||||
|
||||
MessageQueue::get_singleton()->push_call(this, "_update_minimum_size");
|
||||
}
|
||||
|
||||
int Control::get_v_size_flags() const {
|
||||
|
@ -2985,7 +3008,6 @@ Control::Control() {
|
|||
data.h_size_flags = SIZE_FILL;
|
||||
data.v_size_flags = SIZE_FILL;
|
||||
data.expand = 1;
|
||||
data.pending_min_size_update = false;
|
||||
data.rotation = 0;
|
||||
data.parent_canvas_item = NULL;
|
||||
data.scale = Vector2(1, 1);
|
||||
|
@ -2995,6 +3017,8 @@ Control::Control() {
|
|||
data.disable_visibility_clip = false;
|
||||
data.h_grow = GROW_DIRECTION_END;
|
||||
data.v_grow = GROW_DIRECTION_END;
|
||||
data.minimum_size_valid = false;
|
||||
data.updating_last_minimum_size = false;
|
||||
|
||||
data.clip_contents = false;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
|
|
@ -148,6 +148,11 @@ private:
|
|||
|
||||
Point2 pos_cache;
|
||||
Size2 size_cache;
|
||||
Size2 minimum_size_cache;
|
||||
bool minimum_size_valid;
|
||||
|
||||
Size2 last_minimum_size;
|
||||
bool updating_last_minimum_size;
|
||||
|
||||
float margin[4];
|
||||
float anchor[4];
|
||||
|
@ -164,7 +169,6 @@ private:
|
|||
int h_size_flags;
|
||||
int v_size_flags;
|
||||
float expand;
|
||||
bool pending_min_size_update;
|
||||
Point2 custom_minimum_size;
|
||||
|
||||
bool pass_on_modal_close_click;
|
||||
|
@ -244,6 +248,8 @@ private:
|
|||
void _modal_stack_remove();
|
||||
void _modal_set_prev_focus_owner(ObjectID p_prev);
|
||||
|
||||
void _update_minimum_size_cache();
|
||||
|
||||
protected:
|
||||
virtual void add_child_notify(Node *p_child);
|
||||
virtual void remove_child_notify(Node *p_child);
|
||||
|
|
|
@ -136,9 +136,9 @@ void Range::set_as_ratio(double p_value) {
|
|||
|
||||
double v;
|
||||
|
||||
if (shared->exp_ratio && get_min() > 0) {
|
||||
if (shared->exp_ratio && get_min() >= 0) {
|
||||
|
||||
double exp_min = Math::log(get_min()) / Math::log((double)2);
|
||||
double exp_min = get_min() == 0 ? 0.0 : Math::log(get_min()) / Math::log((double)2);
|
||||
double exp_max = Math::log(get_max()) / Math::log((double)2);
|
||||
v = Math::pow(2, exp_min + (exp_max - exp_min) * p_value);
|
||||
} else {
|
||||
|
@ -155,9 +155,9 @@ void Range::set_as_ratio(double p_value) {
|
|||
}
|
||||
double Range::get_as_ratio() const {
|
||||
|
||||
if (shared->exp_ratio && get_min() > 0) {
|
||||
if (shared->exp_ratio && get_min() >= 0) {
|
||||
|
||||
double exp_min = Math::log(get_min()) / Math::log((double)2);
|
||||
double exp_min = get_min() == 0 ? 0.0 : Math::log(get_min()) / Math::log((double)2);
|
||||
double exp_max = Math::log(get_max()) / Math::log((double)2);
|
||||
double v = Math::log(get_value()) / Math::log((double)2);
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ bool ScrollContainer::clips_input() const {
|
|||
|
||||
Size2 ScrollContainer::get_minimum_size() const {
|
||||
|
||||
Ref<StyleBox> sb = get_stylebox("bg");
|
||||
Size2 min_size;
|
||||
|
||||
for (int i = 0; i < get_child_count(); i++) {
|
||||
|
@ -64,8 +65,9 @@ Size2 ScrollContainer::get_minimum_size() const {
|
|||
if (v_scroll->is_visible_in_tree()) {
|
||||
min_size.x += v_scroll->get_minimum_size().x;
|
||||
}
|
||||
min_size += sb->get_minimum_size();
|
||||
return min_size;
|
||||
};
|
||||
}
|
||||
|
||||
void ScrollContainer::_cancel_drag() {
|
||||
set_physics_process_internal(false);
|
||||
|
@ -233,6 +235,12 @@ void ScrollContainer::_notification(int p_what) {
|
|||
|
||||
child_max_size = Size2(0, 0);
|
||||
Size2 size = get_size();
|
||||
Point2 ofs;
|
||||
|
||||
Ref<StyleBox> sb = get_stylebox("bg");
|
||||
size -= sb->get_minimum_size();
|
||||
ofs += sb->get_offset();
|
||||
|
||||
if (h_scroll->is_visible_in_tree())
|
||||
size.y -= h_scroll->get_minimum_size().y;
|
||||
|
||||
|
@ -268,6 +276,7 @@ void ScrollContainer::_notification(int p_what) {
|
|||
else
|
||||
r.size.height = minsize.height;
|
||||
}
|
||||
r.position += ofs;
|
||||
fit_child_in_rect(c, r);
|
||||
}
|
||||
update();
|
||||
|
@ -275,6 +284,9 @@ void ScrollContainer::_notification(int p_what) {
|
|||
|
||||
if (p_what == NOTIFICATION_DRAW) {
|
||||
|
||||
Ref<StyleBox> sb = get_stylebox("bg");
|
||||
draw_style_box(sb, Rect2(Vector2(), get_size()));
|
||||
|
||||
update_scrollbars();
|
||||
}
|
||||
|
||||
|
@ -353,6 +365,8 @@ void ScrollContainer::_notification(int p_what) {
|
|||
void ScrollContainer::update_scrollbars() {
|
||||
|
||||
Size2 size = get_size();
|
||||
Ref<StyleBox> sb = get_stylebox("bg");
|
||||
size -= sb->get_minimum_size();
|
||||
|
||||
Size2 hmin = h_scroll->get_combined_minimum_size();
|
||||
Size2 vmin = v_scroll->get_combined_minimum_size();
|
||||
|
|
|
@ -176,6 +176,9 @@ void Node::_propagate_ready() {
|
|||
data.children[i]->_propagate_ready();
|
||||
}
|
||||
data.blocked--;
|
||||
|
||||
notification(NOTIFICATION_POST_ENTER_TREE);
|
||||
|
||||
if (data.ready_first) {
|
||||
data.ready_first = false;
|
||||
notification(NOTIFICATION_READY);
|
||||
|
|
|
@ -237,6 +237,7 @@ public:
|
|||
NOTIFICATION_TRANSLATION_CHANGED = 24,
|
||||
NOTIFICATION_INTERNAL_PROCESS = 25,
|
||||
NOTIFICATION_INTERNAL_PHYSICS_PROCESS = 26,
|
||||
NOTIFICATION_POST_ENTER_TREE = 27,
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -1345,7 +1345,7 @@ void Viewport::_gui_show_tooltip() {
|
|||
gui.tooltip_label->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -ttp->get_margin(MARGIN_RIGHT));
|
||||
gui.tooltip_label->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -ttp->get_margin(MARGIN_BOTTOM));
|
||||
gui.tooltip_label->set_text(tooltip.strip_edges());
|
||||
Rect2 r(gui.tooltip_pos + Point2(10, 10), gui.tooltip_label->get_combined_minimum_size() + ttp->get_minimum_size());
|
||||
Rect2 r(gui.tooltip_pos + Point2(10, 10), gui.tooltip_label->get_minimum_size() + ttp->get_minimum_size());
|
||||
Rect2 vr = gui.tooltip_label->get_viewport_rect();
|
||||
if (r.size.x + r.position.x > vr.size.x)
|
||||
r.position.x = vr.size.x - r.size.x;
|
||||
|
|
|
@ -544,6 +544,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
|
|||
|
||||
theme->set_icon("updown", "SpinBox", make_icon(spinbox_updown_png));
|
||||
|
||||
//scroll container
|
||||
Ref<StyleBoxEmpty> empty;
|
||||
empty.instance();
|
||||
theme->set_stylebox("bg", "ScrollContainer", empty);
|
||||
|
||||
// WindowDialog
|
||||
|
||||
theme->set_stylebox("panel", "WindowDialog", sb_expand(make_stylebox(popup_window_png, 10, 26, 10, 8), 8, 24, 8, 6));
|
||||
|
|
Loading…
Reference in New Issue