Browse Source

Merge pull request #57866 from fire-forge/better_array_editor

Rémi Verschelde 3 years ago
parent
commit
f21a62b620

+ 108 - 81
editor/editor_inspector.cpp

@@ -1422,6 +1422,7 @@ EditorInspectorSection::~EditorInspectorSection() {
 
 ////////////////////////////////////////////////
 ////////////////////////////////////////////////
+
 int EditorInspectorArray::_get_array_count() {
 	if (mode == MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION) {
 		List<PropertyInfo> object_property_list;
@@ -1440,31 +1441,8 @@ void EditorInspectorArray::_add_button_pressed() {
 	_move_element(-1, -1);
 }
 
-void EditorInspectorArray::_first_page_button_pressed() {
-	emit_signal(SNAME("page_change_request"), 0);
-}
-
-void EditorInspectorArray::_prev_page_button_pressed() {
-	emit_signal(SNAME("page_change_request"), MAX(0, page - 1));
-}
-
-void EditorInspectorArray::_page_line_edit_text_submitted(String p_text) {
-	if (p_text.is_valid_int()) {
-		int new_page = p_text.to_int() - 1;
-		new_page = MIN(MAX(0, new_page), max_page);
-		page_line_edit->set_text(Variant(new_page));
-		emit_signal(SNAME("page_change_request"), new_page);
-	} else {
-		page_line_edit->set_text(Variant(page));
-	}
-}
-
-void EditorInspectorArray::_next_page_button_pressed() {
-	emit_signal(SNAME("page_change_request"), MIN(max_page, page + 1));
-}
-
-void EditorInspectorArray::_last_page_button_pressed() {
-	emit_signal(SNAME("page_change_request"), max_page);
+void EditorInspectorArray::_paginator_page_changed(int p_page) {
+	emit_signal("page_change_request", p_page);
 }
 
 void EditorInspectorArray::_rmb_popup_id_pressed(int p_id) {
@@ -1636,17 +1614,17 @@ void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) {
 	// Handle page change and update counts.
 	if (p_element_index < 0) {
 		int added_index = p_to_pos < 0 ? count : p_to_pos;
-		emit_signal(SNAME("page_change_request"), added_index / page_lenght);
+		emit_signal(SNAME("page_change_request"), added_index / page_length);
 		count += 1;
 	} else if (p_to_pos < 0) {
 		count -= 1;
-		if (page == max_page && (MAX(0, count - 1) / page_lenght != max_page)) {
+		if (page == max_page && (MAX(0, count - 1) / page_length != max_page)) {
 			emit_signal(SNAME("page_change_request"), max_page - 1);
 		}
 	}
-	begin_array_index = page * page_lenght;
-	end_array_index = MIN(count, (page + 1) * page_lenght);
-	max_page = MAX(0, count - 1) / page_lenght;
+	begin_array_index = page * page_length;
+	end_array_index = MIN(count, (page + 1) * page_length);
+	max_page = MAX(0, count - 1) / page_length;
 }
 
 void EditorInspectorArray::_clear_array() {
@@ -1860,9 +1838,9 @@ void EditorInspectorArray::_resize_dialog_confirmed() {
 void EditorInspectorArray::_setup() {
 	// Setup counts.
 	count = _get_array_count();
-	begin_array_index = page * page_lenght;
-	end_array_index = MIN(count, (page + 1) * page_lenght);
-	max_page = MAX(0, count - 1) / page_lenght;
+	begin_array_index = page * page_length;
+	end_array_index = MIN(count, (page + 1) * page_length);
+	max_page = MAX(0, count - 1) / page_length;
 	array_elements.resize(MAX(0, end_array_index - begin_array_index));
 	if (page < 0 || page > max_page) {
 		WARN_PRINT(vformat("Invalid page number %d", page));
@@ -1920,18 +1898,12 @@ void EditorInspectorArray::_setup() {
 	// Hide/show the add button.
 	add_button->set_visible(page == max_page);
 
-	if (max_page == 0) {
-		hbox_pagination->hide();
-	} else {
-		// Update buttons.
-		first_page_button->set_disabled(page == 0);
-		prev_page_button->set_disabled(page == 0);
-		next_page_button->set_disabled(page == max_page);
-		last_page_button->set_disabled(page == max_page);
-
-		// Update page number and page count.
-		page_line_edit->set_text(vformat("%d", page + 1));
-		page_count_label->set_text(vformat("/ %d", max_page + 1));
+	// Add paginator if there's more than 1 page.
+	if (max_page > 0) {
+		EditorPaginator *paginator = memnew(EditorPaginator);
+		paginator->update(page, max_page);
+		paginator->connect("page_changed", callable_mp(this, &EditorInspectorArray::_paginator_page_changed));
+		vbox->add_child(paginator);
 	}
 }
 
@@ -1996,10 +1968,6 @@ void EditorInspectorArray::_notification(int p_what) {
 			}
 
 			add_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
-			first_page_button->set_icon(get_theme_icon(SNAME("PageFirst"), SNAME("EditorIcons")));
-			prev_page_button->set_icon(get_theme_icon(SNAME("PagePrevious"), SNAME("EditorIcons")));
-			next_page_button->set_icon(get_theme_icon(SNAME("PageNext"), SNAME("EditorIcons")));
-			last_page_button->set_icon(get_theme_icon(SNAME("PageLast"), SNAME("EditorIcons")));
 			update_minimum_size();
 		} break;
 		case NOTIFICATION_DRAG_BEGIN: {
@@ -2092,38 +2060,6 @@ EditorInspectorArray::EditorInspectorArray() {
 	add_button->connect("pressed", callable_mp(this, &EditorInspectorArray::_add_button_pressed));
 	vbox->add_child(add_button);
 
-	hbox_pagination = memnew(HBoxContainer);
-	hbox_pagination->set_h_size_flags(SIZE_EXPAND_FILL);
-	hbox_pagination->set_alignment(BoxContainer::ALIGNMENT_CENTER);
-	vbox->add_child(hbox_pagination);
-
-	first_page_button = memnew(Button);
-	first_page_button->set_flat(true);
-	first_page_button->connect("pressed", callable_mp(this, &EditorInspectorArray::_first_page_button_pressed));
-	hbox_pagination->add_child(first_page_button);
-
-	prev_page_button = memnew(Button);
-	prev_page_button->set_flat(true);
-	prev_page_button->connect("pressed", callable_mp(this, &EditorInspectorArray::_prev_page_button_pressed));
-	hbox_pagination->add_child(prev_page_button);
-
-	page_line_edit = memnew(LineEdit);
-	page_line_edit->connect("text_submitted", callable_mp(this, &EditorInspectorArray::_page_line_edit_text_submitted));
-	page_line_edit->add_theme_constant_override("minimum_character_width", 2);
-	hbox_pagination->add_child(page_line_edit);
-
-	page_count_label = memnew(Label);
-	hbox_pagination->add_child(page_count_label);
-	next_page_button = memnew(Button);
-	next_page_button->set_flat(true);
-	next_page_button->connect("pressed", callable_mp(this, &EditorInspectorArray::_next_page_button_pressed));
-	hbox_pagination->add_child(next_page_button);
-
-	last_page_button = memnew(Button);
-	last_page_button->set_flat(true);
-	last_page_button->connect("pressed", callable_mp(this, &EditorInspectorArray::_last_page_button_pressed));
-	hbox_pagination->add_child(last_page_button);
-
 	control_dropping = memnew(Control);
 	control_dropping->connect("draw", callable_mp(this, &EditorInspectorArray::_control_dropping_draw));
 	control_dropping->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
@@ -2149,6 +2085,97 @@ EditorInspectorArray::EditorInspectorArray() {
 ////////////////////////////////////////////////
 ////////////////////////////////////////////////
 
+void EditorPaginator::_first_page_button_pressed() {
+	emit_signal("page_changed", 0);
+}
+
+void EditorPaginator::_prev_page_button_pressed() {
+	emit_signal("page_changed", MAX(0, page - 1));
+}
+
+void EditorPaginator::_page_line_edit_text_submitted(String p_text) {
+	if (p_text.is_valid_int()) {
+		int new_page = p_text.to_int() - 1;
+		new_page = MIN(MAX(0, new_page), max_page);
+		page_line_edit->set_text(Variant(new_page));
+		emit_signal("page_changed", new_page);
+	} else {
+		page_line_edit->set_text(Variant(page));
+	}
+}
+
+void EditorPaginator::_next_page_button_pressed() {
+	emit_signal("page_changed", MIN(max_page, page + 1));
+}
+
+void EditorPaginator::_last_page_button_pressed() {
+	emit_signal("page_changed", max_page);
+}
+
+void EditorPaginator::update(int p_page, int p_max_page) {
+	page = p_page;
+	max_page = p_max_page;
+
+	// Update buttons.
+	first_page_button->set_disabled(page == 0);
+	prev_page_button->set_disabled(page == 0);
+	next_page_button->set_disabled(page == max_page);
+	last_page_button->set_disabled(page == max_page);
+
+	// Update page number and page count.
+	page_line_edit->set_text(vformat("%d", page + 1));
+	page_count_label->set_text(vformat("/ %d", max_page + 1));
+}
+
+void EditorPaginator::_notification(int p_what) {
+	if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
+		first_page_button->set_icon(get_theme_icon(SNAME("PageFirst"), SNAME("EditorIcons")));
+		prev_page_button->set_icon(get_theme_icon(SNAME("PagePrevious"), SNAME("EditorIcons")));
+		next_page_button->set_icon(get_theme_icon(SNAME("PageNext"), SNAME("EditorIcons")));
+		last_page_button->set_icon(get_theme_icon(SNAME("PageLast"), SNAME("EditorIcons")));
+	}
+}
+
+void EditorPaginator::_bind_methods() {
+	ADD_SIGNAL(MethodInfo("page_changed", PropertyInfo(Variant::INT, "page")));
+}
+
+EditorPaginator::EditorPaginator() {
+	set_h_size_flags(SIZE_EXPAND_FILL);
+	set_alignment(ALIGNMENT_CENTER);
+
+	first_page_button = memnew(Button);
+	first_page_button->set_flat(true);
+	first_page_button->connect("pressed", callable_mp(this, &EditorPaginator::_first_page_button_pressed));
+	add_child(first_page_button);
+
+	prev_page_button = memnew(Button);
+	prev_page_button->set_flat(true);
+	prev_page_button->connect("pressed", callable_mp(this, &EditorPaginator::_prev_page_button_pressed));
+	add_child(prev_page_button);
+
+	page_line_edit = memnew(LineEdit);
+	page_line_edit->connect("text_submitted", callable_mp(this, &EditorPaginator::_page_line_edit_text_submitted));
+	page_line_edit->add_theme_constant_override("minimum_character_width", 2);
+	add_child(page_line_edit);
+
+	page_count_label = memnew(Label);
+	add_child(page_count_label);
+
+	next_page_button = memnew(Button);
+	next_page_button->set_flat(true);
+	next_page_button->connect("pressed", callable_mp(this, &EditorPaginator::_next_page_button_pressed));
+	add_child(next_page_button);
+
+	last_page_button = memnew(Button);
+	last_page_button->set_flat(true);
+	last_page_button->connect("pressed", callable_mp(this, &EditorPaginator::_last_page_button_pressed));
+	add_child(last_page_button);
+}
+
+////////////////////////////////////////////////
+////////////////////////////////////////////////
+
 Ref<EditorInspectorPlugin> EditorInspector::inspector_plugins[MAX_PLUGINS];
 int EditorInspector::inspector_plugin_count = 0;
 

+ 30 - 14
editor/editor_inspector.h

@@ -317,18 +317,11 @@ class EditorInspectorArray : public EditorInspectorSection {
 	LineEdit *new_size_line_edit;
 
 	// Pagination
-	int page_lenght = 5;
+	int page_length = 5;
 	int page = 0;
 	int max_page = 0;
 	int begin_array_index = 0;
 	int end_array_index = 0;
-	HBoxContainer *hbox_pagination;
-	Button *first_page_button;
-	Button *prev_page_button;
-	LineEdit *page_line_edit;
-	Label *page_count_label;
-	Button *next_page_button;
-	Button *last_page_button;
 
 	enum MenuOptions {
 		OPTION_MOVE_UP = 0,
@@ -356,12 +349,7 @@ class EditorInspectorArray : public EditorInspectorSection {
 
 	int _get_array_count();
 	void _add_button_pressed();
-
-	void _first_page_button_pressed();
-	void _prev_page_button_pressed();
-	void _page_line_edit_text_submitted(String p_text);
-	void _next_page_button_pressed();
-	void _last_page_button_pressed();
+	void _paginator_page_changed(int p_page);
 
 	void _rmb_popup_id_pressed(int p_id);
 
@@ -402,6 +390,34 @@ public:
 	EditorInspectorArray();
 };
 
+class EditorPaginator : public HBoxContainer {
+	GDCLASS(EditorPaginator, HBoxContainer);
+
+	int page = 0;
+	int max_page = 0;
+	Button *first_page_button;
+	Button *prev_page_button;
+	LineEdit *page_line_edit;
+	Label *page_count_label;
+	Button *next_page_button;
+	Button *last_page_button;
+
+	void _first_page_button_pressed();
+	void _prev_page_button_pressed();
+	void _page_line_edit_text_submitted(String p_text);
+	void _next_page_button_pressed();
+	void _last_page_button_pressed();
+
+protected:
+	void _notification(int p_what);
+	static void _bind_methods();
+
+public:
+	void update(int p_page, int p_max_page);
+
+	EditorPaginator();
+};
+
 class EditorInspector : public ScrollContainer {
 	GDCLASS(EditorInspector, ScrollContainer);
 

+ 61 - 54
editor/editor_properties_array_dict.cpp

@@ -259,8 +259,8 @@ void EditorPropertyArray::update_property() {
 	}
 
 	int size = array.call("size");
-	int pages = MAX(0, size - 1) / page_length + 1;
-	page_index = MIN(page_index, pages - 1);
+	int max_page = MAX(0, size - 1) / page_length;
+	page_index = MIN(page_index, max_page);
 	int offset = page_index * page_length;
 
 	edit->set_text(arrtype + " (size " + itos(size) + ")");
@@ -292,35 +292,37 @@ void EditorPropertyArray::update_property() {
 			size_slider->connect("value_changed", callable_mp(this, &EditorPropertyArray::_length_changed));
 			hbox->add_child(size_slider);
 
-			page_hbox = memnew(HBoxContainer);
-			vbox->add_child(page_hbox);
+			property_vbox = memnew(VBoxContainer);
+			property_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
+			vbox->add_child(property_vbox);
 
-			label = memnew(Label(TTR("Page: ")));
-			label->set_h_size_flags(SIZE_EXPAND_FILL);
-			page_hbox->add_child(label);
+			button_add_item = memnew(Button);
+			button_add_item->set_text(TTR("Add Element"));
+			button_add_item->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
+			button_add_item->connect(SNAME("pressed"), callable_mp(this, &EditorPropertyArray::_add_element));
+			vbox->add_child(button_add_item);
 
-			page_slider = memnew(EditorSpinSlider);
-			page_slider->set_step(1);
-			page_slider->set_h_size_flags(SIZE_EXPAND_FILL);
-			page_slider->connect("value_changed", callable_mp(this, &EditorPropertyArray::_page_changed));
-			page_hbox->add_child(page_slider);
+			paginator = memnew(EditorPaginator);
+			paginator->connect("page_changed", callable_mp(this, &EditorPropertyArray::_page_changed));
+			vbox->add_child(paginator);
 		} else {
 			// Bye bye children of the box.
-			for (int i = vbox->get_child_count() - 1; i >= 2; i--) {
-				Node *child = vbox->get_child(i);
+			for (int i = property_vbox->get_child_count() - 1; i >= 0; i--) {
+				Node *child = property_vbox->get_child(i);
 				if (child == reorder_selected_element_hbox) {
 					continue; // Don't remove the property that the user is moving.
 				}
 
 				child->queue_delete(); // Button still needed after pressed is called.
-				vbox->remove_child(child);
+				property_vbox->remove_child(child);
 			}
 		}
 
 		size_slider->set_value(size);
-		page_slider->set_max(pages);
-		page_slider->set_value(page_index);
-		page_hbox->set_visible(pages > 1);
+		property_vbox->set_visible(size > 0);
+		button_add_item->set_visible(page_index == max_page);
+		paginator->update(page_index, max_page);
+		paginator->set_visible(max_page > 0);
 
 		if (array.get_type() == Variant::ARRAY) {
 			array = array.call("duplicate");
@@ -343,7 +345,7 @@ void EditorPropertyArray::update_property() {
 			}
 
 			HBoxContainer *hbox = memnew(HBoxContainer);
-			vbox->add_child(hbox);
+			property_vbox->add_child(hbox);
 
 			Button *reorder_button = memnew(Button);
 			reorder_button->set_icon(get_theme_icon(SNAME("TripleBar"), SNAME("EditorIcons")));
@@ -397,7 +399,7 @@ void EditorPropertyArray::update_property() {
 		}
 
 		if (reorder_to_index % page_length > 0) {
-			vbox->move_child(vbox->get_child(2), reorder_to_index % page_length + 2);
+			property_vbox->move_child(property_vbox->get_child(0), reorder_to_index % page_length);
 		}
 
 		updating = false;
@@ -510,6 +512,10 @@ void EditorPropertyArray::_notification(int p_what) {
 		}
 		change_type->add_separator();
 		change_type->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Remove Item"), Variant::VARIANT_MAX);
+
+		if (Object::cast_to<Button>(button_add_item)) {
+			button_add_item->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
+		}
 	}
 
 	if (p_what == NOTIFICATION_DRAG_BEGIN) {
@@ -542,7 +548,7 @@ void EditorPropertyArray::_edit_pressed() {
 	update_property();
 }
 
-void EditorPropertyArray::_page_changed(double p_page) {
+void EditorPropertyArray::_page_changed(int p_page) {
 	if (updating) {
 		return;
 	}
@@ -589,6 +595,10 @@ void EditorPropertyArray::_length_changed(double p_page) {
 	update_property();
 }
 
+void EditorPropertyArray::_add_element() {
+	_length_changed(double(object->get_array().call("size")) + 1.0);
+}
+
 void EditorPropertyArray::setup(Variant::Type p_array_type, const String &p_hint_string) {
 	array_type = p_array_type;
 
@@ -633,9 +643,9 @@ void EditorPropertyArray::_reorder_button_gui_input(const Ref<InputEvent> &p_eve
 			reorder_to_index += direction;
 			if ((direction < 0 && reorder_to_index % page_length == page_length - 1) || (direction > 0 && reorder_to_index % page_length == 0)) {
 				// Automatically move to the next/previous page.
-				page_slider->set_value(page_index + direction);
+				_page_changed(page_index + direction);
 			}
-			vbox->move_child(reorder_selected_element_hbox, reorder_to_index % page_length + 2);
+			property_vbox->move_child(reorder_selected_element_hbox, reorder_to_index % page_length);
 			// Ensure the moving element is visible.
 			InspectorDock::get_inspector_singleton()->ensure_control_visible(reorder_selected_element_hbox);
 		}
@@ -645,7 +655,7 @@ void EditorPropertyArray::_reorder_button_gui_input(const Ref<InputEvent> &p_eve
 void EditorPropertyArray::_reorder_button_down(int p_index) {
 	reorder_from_index = p_index;
 	reorder_to_index = p_index;
-	reorder_selected_element_hbox = Object::cast_to<HBoxContainer>(vbox->get_child(p_index % page_length + 2));
+	reorder_selected_element_hbox = Object::cast_to<HBoxContainer>(property_vbox->get_child(p_index % page_length));
 	reorder_selected_button = Object::cast_to<Button>(reorder_selected_element_hbox->get_child(0));
 	// Ideally it'd to be able to show the mouse but I had issues with
 	// Control's `mouse_exit()`/`mouse_entered()` signals not getting called.
@@ -685,6 +695,7 @@ void EditorPropertyArray::_bind_methods() {
 EditorPropertyArray::EditorPropertyArray() {
 	object.instantiate();
 	page_length = int(EDITOR_GET("interface/inspector/max_array_dictionary_items_per_page"));
+
 	edit = memnew(Button);
 	edit->set_h_size_flags(SIZE_EXPAND_FILL);
 	edit->set_clip_text(true);
@@ -694,9 +705,12 @@ EditorPropertyArray::EditorPropertyArray() {
 	edit->connect("draw", callable_mp(this, &EditorPropertyArray::_button_draw));
 	add_child(edit);
 	add_focusable(edit);
+
 	vbox = nullptr;
-	page_slider = nullptr;
+	property_vbox = nullptr;
 	size_slider = nullptr;
+	button_add_item = nullptr;
+	paginator = nullptr;
 	updating = false;
 	change_type = memnew(PopupMenu);
 	add_child(change_type);
@@ -824,35 +838,32 @@ void EditorPropertyDictionary::update_property() {
 			add_child(vbox);
 			set_bottom_editor(vbox);
 
-			page_hbox = memnew(HBoxContainer);
-			vbox->add_child(page_hbox);
-			Label *label = memnew(Label(TTR("Page: ")));
-			label->set_h_size_flags(SIZE_EXPAND_FILL);
-			page_hbox->add_child(label);
-			page_slider = memnew(EditorSpinSlider);
-			page_slider->set_step(1);
-			page_hbox->add_child(page_slider);
-			page_slider->set_h_size_flags(SIZE_EXPAND_FILL);
-			page_slider->connect("value_changed", callable_mp(this, &EditorPropertyDictionary::_page_changed));
+			property_vbox = memnew(VBoxContainer);
+			property_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
+			vbox->add_child(property_vbox);
+
+			paginator = memnew(EditorPaginator);
+			paginator->connect("page_changed", callable_mp(this, &EditorPropertyDictionary::_page_changed));
+			vbox->add_child(paginator);
 		} else {
 			// Queue children for deletion, deleting immediately might cause errors.
-			for (int i = 1; i < vbox->get_child_count(); i++) {
-				vbox->get_child(i)->queue_delete();
+			for (int i = property_vbox->get_child_count() - 1; i >= 0; i--) {
+				property_vbox->get_child(i)->queue_delete();
 			}
 		}
 
 		int size = dict.size();
 
-		int pages = MAX(0, size - 1) / page_length + 1;
+		int max_page = MAX(0, size - 1) / page_length;
+		page_index = MIN(page_index, max_page);
 
-		page_slider->set_max(pages);
-		page_index = MIN(page_index, pages - 1);
-		page_slider->set_value(page_index);
-		page_hbox->set_visible(pages > 1);
+		paginator->update(page_index, max_page);
+		paginator->set_visible(max_page > 0);
 
 		int offset = page_index * page_length;
 
 		int amount = MIN(size - offset, page_length);
+		int total_amount = page_index == max_page ? amount + 2 : amount; // For the "Add Key/Value Pair" box on last page.
 
 		dict = dict.duplicate();
 
@@ -860,7 +871,7 @@ void EditorPropertyDictionary::update_property() {
 		VBoxContainer *add_vbox = nullptr;
 		double default_float_step = EDITOR_GET("interface/inspector/default_float_step");
 
-		for (int i = 0; i < amount + 2; i++) {
+		for (int i = 0; i < total_amount; i++) {
 			String prop_name;
 			Variant key;
 			Variant value;
@@ -1074,15 +1085,9 @@ void EditorPropertyDictionary::update_property() {
 
 			if (i == amount) {
 				PanelContainer *pc = memnew(PanelContainer);
-				vbox->add_child(pc);
-				Ref<StyleBoxFlat> flat;
-				flat.instantiate();
-				for (int j = 0; j < 4; j++) {
-					flat->set_default_margin(Side(j), 2 * EDSCALE);
-				}
-				flat->set_bg_color(get_theme_color(SNAME("prop_subsection"), SNAME("Editor")));
+				property_vbox->add_child(pc);
+				pc->add_theme_style_override(SNAME("panel"), get_theme_stylebox(SNAME("DictionaryAddItem"), SNAME("EditorStyles")));
 
-				pc->add_theme_style_override("panel", flat);
 				add_vbox = memnew(VBoxContainer);
 				pc->add_child(add_vbox);
 			}
@@ -1110,7 +1115,7 @@ void EditorPropertyDictionary::update_property() {
 			if (add_vbox) {
 				add_vbox->add_child(hbox);
 			} else {
-				vbox->add_child(hbox);
+				property_vbox->add_child(hbox);
 			}
 			hbox->add_child(prop);
 			prop->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -1173,7 +1178,7 @@ void EditorPropertyDictionary::_edit_pressed() {
 	update_property();
 }
 
-void EditorPropertyDictionary::_page_changed(double p_page) {
+void EditorPropertyDictionary::_page_changed(int p_page) {
 	if (updating) {
 		return;
 	}
@@ -1187,6 +1192,7 @@ void EditorPropertyDictionary::_bind_methods() {
 EditorPropertyDictionary::EditorPropertyDictionary() {
 	object.instantiate();
 	page_length = int(EDITOR_GET("interface/inspector/max_array_dictionary_items_per_page"));
+
 	edit = memnew(Button);
 	edit->set_h_size_flags(SIZE_EXPAND_FILL);
 	edit->set_clip_text(true);
@@ -1194,9 +1200,10 @@ EditorPropertyDictionary::EditorPropertyDictionary() {
 	edit->set_toggle_mode(true);
 	add_child(edit);
 	add_focusable(edit);
+
 	vbox = nullptr;
-	page_slider = nullptr;
 	button_add_item = nullptr;
+	paginator = nullptr;
 	updating = false;
 	change_type = memnew(PopupMenu);
 	add_child(change_type);

+ 8 - 6
editor/editor_properties_array_dict.h

@@ -89,9 +89,10 @@ class EditorPropertyArray : public EditorProperty {
 	int changing_type_index;
 	Button *edit;
 	VBoxContainer *vbox;
+	VBoxContainer *property_vbox;
 	EditorSpinSlider *size_slider;
-	EditorSpinSlider *page_slider;
-	HBoxContainer *page_hbox;
+	Button *button_add_item;
+	EditorPaginator *paginator;
 	Variant::Type array_type;
 	Variant::Type subtype;
 	PropertyHint subtype_hint;
@@ -103,8 +104,9 @@ class EditorPropertyArray : public EditorProperty {
 	HBoxContainer *reorder_selected_element_hbox = nullptr;
 	Button *reorder_selected_button = nullptr;
 
-	void _page_changed(double p_page);
+	void _page_changed(int p_page);
 	void _length_changed(double p_page);
+	void _add_element();
 	void _edit_pressed();
 	void _property_changed(const String &p_property, Variant p_value, const String &p_name = "", bool p_changing = false);
 	void _change_type(Object *p_button, int p_index);
@@ -144,12 +146,12 @@ class EditorPropertyDictionary : public EditorProperty {
 	int changing_type_index;
 	Button *edit;
 	VBoxContainer *vbox;
+	VBoxContainer *property_vbox;
 	EditorSpinSlider *size_slider;
-	EditorSpinSlider *page_slider;
-	HBoxContainer *page_hbox;
 	Button *button_add_item;
+	EditorPaginator *paginator;
 
-	void _page_changed(double p_page);
+	void _page_changed(int p_page);
 	void _edit_pressed();
 	void _property_changed(const String &p_property, Variant p_value, const String &p_name = "", bool p_changing = false);
 	void _change_type(Object *p_button, int p_index);

+ 3 - 0
editor/editor_themes.cpp

@@ -1501,6 +1501,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 	Ref<StyleBoxFlat> theme_preview_picker_label_sb = make_flat_stylebox(theme_preview_picker_label_bg_color, 4.0, 1.0, 4.0, 3.0);
 	theme->set_stylebox("preview_picker_label", "ThemeEditor", theme_preview_picker_label_sb);
 
+	// Dictionary editor add item.
+	theme->set_stylebox("DictionaryAddItem", "EditorStyles", make_flat_stylebox(prop_subsection_color, 4, 4, 4, 4, corner_radius));
+
 	// adaptive script theme constants
 	// for comments and elements with lower relevance
 	const Color dim_color = Color(font_color.r, font_color.g, font_color.b, 0.5);