-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:
Juan Linietsky 2018-05-15 17:12:35 -03:00
parent 3b8bd50b41
commit 005b69cf6e
39 changed files with 5975 additions and 337 deletions

View File

@ -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)

View File

@ -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;

1797
editor/editor_inspector.cpp Normal file

File diff suppressed because it is too large Load Diff

283
editor/editor_inspector.h Normal file
View File

@ -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

View File

@ -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);

View File

@ -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; }

2411
editor/editor_properties.cpp Normal file

File diff suppressed because it is too large Load Diff

490
editor/editor_properties.h Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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
}

View File

@ -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();

View File

@ -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() {

View File

@ -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");

View File

@ -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();

View File

@ -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();
};

View File

@ -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;

View File

@ -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");

View File

@ -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) {

193
main/timer_sync.cpp Normal file
View File

@ -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);
}

71
main/timer_sync.h Normal file
View File

@ -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

View File

@ -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();
}
}

View File

@ -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;
}

View File

@ -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");

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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();
}

View File

@ -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++) {

View File

@ -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);

View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

@ -237,6 +237,7 @@ public:
NOTIFICATION_TRANSLATION_CHANGED = 24,
NOTIFICATION_INTERNAL_PROCESS = 25,
NOTIFICATION_INTERNAL_PHYSICS_PROCESS = 26,
NOTIFICATION_POST_ENTER_TREE = 27,
};

View File

@ -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;

View File

@ -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));