4242#include  " editor/settings/editor_settings.h" 
4343#include  " editor/themes/editor_scale.h" 
4444#include  " scene/3d/camera_3d.h" 
45+ #include  " scene/gui/check_box.h" 
4546#include  " scene/gui/dialogs.h" 
47+ #include  " scene/gui/item_list.h" 
4648#include  " scene/gui/label.h" 
4749#include  " scene/gui/menu_button.h" 
4850#include  " scene/gui/separator.h" 
51+ #include  " scene/gui/slider.h" 
52+ #include  " scene/gui/spin_box.h" 
53+ #include  " scene/gui/split_container.h" 
54+ #include  " scene/gui/tree.h" 
4955#include  " scene/main/window.h" 
5056
5157void  GridMapEditor::_configure () {
@@ -934,48 +940,195 @@ void GridMapEditor::update_palette() {
934940	search_box->set_editable (true );
935941	info_message->hide ();
936942
937- 	Vector<int > ids;
938- 	ids = mesh_library->get_item_list ();
943+ 	TreeItem *ti_selected = item_tree->get_selected ();
939944
940- 	List<_CGMEItemSort> il;
941- 	for  (int  i = 0 ; i < ids.size (); i++) {
945+ 	Vector<int > item_ids;
946+ 	if  (ti_selected) {
947+ 		item_ids = ti_selected->get_metadata (0 );
948+ 	} else  {
949+ 		item_ids = mesh_library->get_item_list ();
950+ 	}
951+ 
952+ 	const  String searched_string = search_box->get_text ().strip_edges ().to_lower ();
953+ 
954+ 	//  Sort alphabetically by item name.
955+ 	List<_CGMEItemSort> items_sorted;
956+ 	for  (int  item_id : item_ids) {
942957		_CGMEItemSort is;
943- 		is.id  = ids[i] ;
944- 		is.name  = mesh_library->get_item_name (ids[i] );
945- 		il .push_back (is);
958+ 		is.id  = item_id ;
959+ 		is.name  = mesh_library->get_item_name (item_id );
960+ 		items_sorted .push_back (is);
946961	}
947- 	il.sort ();
962+ 	items_sorted.sort ();
963+ 
964+ 	for  (_CGMEItemSort &E : items_sorted) {
965+ 		int  item_id = E.id ;
948966
949- 	String filter = search_box->get_text ().strip_edges ();
967+ 		String item_name = mesh_library->get_item_name (item_id);
968+ 		const  StringName item_category = mesh_library->get_item_category (item_id);
969+ 		const  Ref<Texture2D> &item_preview = mesh_library->get_item_preview (item_id);
950970
951- 	int  item  = 0 ;
971+ 		 bool  skip_item  = false ;
952972
953- 	for  (_CGMEItemSort &E : il) {
954- 		int  id = E.id ;
955- 		String name = mesh_library->get_item_name (id);
956- 		Ref<Texture2D> preview = mesh_library->get_item_preview (id);
973+ 		if  (!searched_string.is_empty ()) {
974+ 			bool  item_matches_search_string = false ;
957975
958- 		if  (name.is_empty ()) {
959- 			name = " #"   + itos (id);
976+ 			if  (item_name.contains (searched_string)) {
977+ 				item_matches_search_string = true ;
978+ 			}
979+ 			if  (!item_matches_search_string && String (item_category).contains (searched_string)) {
980+ 				item_matches_search_string = true ;
981+ 			}
982+ 
983+ 			if  (!item_matches_search_string) {
984+ 				skip_item = true ;
985+ 			}
960986		}
961987
962- 		if  (!filter. is_empty () && !filter. is_subsequence_ofn (name) ) {
988+ 		if  (skip_item ) {
963989			continue ;
964990		}
965991
966- 		mesh_library_palette->add_item (" "  );
967- 		if  (preview.is_valid ()) {
968- 			mesh_library_palette->set_item_icon (item, preview);
969- 			mesh_library_palette->set_item_tooltip (item, name);
992+ 		if  (item_name.is_empty ()) {
993+ 			item_name = " #"   + itos (item_id);
994+ 		}
995+ 
996+ 		const  int  list_id = mesh_library_palette->add_item (item_name, item_preview);
997+ 		mesh_library_palette->set_item_text (list_id, item_name);
998+ 		mesh_library_palette->set_item_metadata (list_id, item_id);
999+ 		if  (item_preview.is_valid ()) {
1000+ 			mesh_library_palette->set_item_icon (list_id, item_preview);
1001+ 			mesh_library_palette->set_item_tooltip (list_id, item_name);
1002+ 		}
1003+ 	}
1004+ }
1005+ 
1006+ void  GridMapEditor::_on_item_tree_item_activated () {
1007+ 	TreeItem *ti_selected = item_tree->get_selected ();
1008+ 	if  (ti_selected) {
1009+ 		bool  collapsed = ti_selected->is_collapsed ();
1010+ 		ti_selected->set_collapsed (!collapsed);
1011+ 	}
1012+ }
1013+ 
1014+ void  GridMapEditor::_rebuild_item_tree () {
1015+ 	ERR_FAIL_NULL (item_tree);
1016+ 
1017+ 	item_tree->clear ();
1018+ 
1019+ 	if  (mesh_library.is_null ()) {
1020+ 		return ;
1021+ 	}
1022+ 
1023+ 	const  Vector<int > &item_ids = mesh_library->get_item_list ();
1024+ 
1025+ 	item_tree->create_item ();
1026+ 	TreeItem *tree_root = item_tree->get_root ();
1027+ 	tree_root->set_text (0 , " All"  );
1028+ 	tree_root->set_text (1 , vformat (" (%s)"  , item_ids.size ()));
1029+ 	tree_root->set_metadata (0 , item_ids);
1030+ 
1031+ 	LocalVector<StringName> root_categories;
1032+ 
1033+ 	AHashMap<StringName, HashSet<int >> category_to_items;
1034+ 	AHashMap<StringName, HashSet<StringName>> category_to_category_children;
1035+ 
1036+ 	for  (int  item_id = 0 ; item_id < item_ids.size (); item_id++) {
1037+ 		const  StringName item_category = mesh_library->get_item_category (item_id);
1038+ 
1039+ 		Vector<String> item_categories = String (item_category).split (" /"  , false );
1040+ 
1041+ 		String item_category_path = " "  ;
1042+ 		for  (int  i = 0 ; i < item_categories.size (); i++) {
1043+ 			const  String category = item_categories[i];
1044+ 
1045+ 			if  (i == 0 ) {
1046+ 				if  (!root_categories.has (category)) {
1047+ 					root_categories.push_back (category);
1048+ 				}
1049+ 			}
1050+ 
1051+ 			String parent_item_category_path = item_category_path;
1052+ 
1053+ 			item_category_path = item_category_path.path_join (category);
1054+ 
1055+ 			{
1056+ 				AHashMap<StringName, HashSet<int >>::Iterator existing = category_to_items.find (item_category_path);
1057+ 				if  (!existing) {
1058+ 					existing = category_to_items.insert (item_category_path, HashSet<int >());
1059+ 				}
1060+ 				existing->value .insert (item_id);
1061+ 			}
1062+ 
1063+ 			{
1064+ 				{
1065+ 					AHashMap<StringName, HashSet<StringName>>::Iterator existing = category_to_category_children.find (parent_item_category_path);
1066+ 					if  (!existing) {
1067+ 						existing = category_to_category_children.insert (parent_item_category_path, HashSet<StringName>());
1068+ 					}
1069+ 					existing->value .insert (item_category_path);
1070+ 				}
1071+ 				{
1072+ 					AHashMap<StringName, HashSet<StringName>>::Iterator existing = category_to_category_children.find (item_category_path);
1073+ 					if  (!existing) {
1074+ 						existing = category_to_category_children.insert (item_category_path, HashSet<StringName>());
1075+ 					}
1076+ 				}
1077+ 			}
9701078		}
971- 		mesh_library_palette->set_item_text (item, name);
972- 		mesh_library_palette->set_item_metadata (item, id);
1079+ 	}
1080+ 
1081+ 	ItemCategoryMapping item_mapping;
1082+ 	item_mapping.category_to_category_children  = category_to_category_children;
1083+ 	item_mapping.category_to_items  = category_to_items;
9731084
974- 		if  (selected_palette == id) {
975- 			mesh_library_palette->select (item);
1085+ 	for  (const  StringName &root_category : root_categories) {
1086+ 		_add_child_categories_recursive (
1087+ 				item_tree,
1088+ 				tree_root,
1089+ 				root_category,
1090+ 				item_mapping);
1091+ 	}
1092+ 
1093+ 	update_palette ();
1094+ }
1095+ 
1096+ void  GridMapEditor::_add_child_categories_recursive (Tree *p_item_tree, TreeItem *p_ti_parent, const  StringName &p_category, const  GridMapEditor::ItemCategoryMapping &p_mapping) {
1097+ 	int  category_user_count = 0 ;
1098+ 	Vector<int > category_items_meta = Vector<int >();
1099+ 
1100+ 	{
1101+ 		const  AHashMap<StringName, HashSet<int >>::ConstIterator category_items_kv = p_mapping.category_to_items .find (p_category);
1102+ 		if  (category_items_kv) {
1103+ 			const  HashSet<int > &category_items = category_items_kv->value ;
1104+ 			category_user_count = category_items.size ();
1105+ 
1106+ 			for  (int  item_id : category_items) {
1107+ 				category_items_meta.push_back (item_id);
1108+ 			}
9761109		}
1110+ 	}
9771111
978- 		item++;
1112+ 	TreeItem *ti_category = p_item_tree->create_item (p_ti_parent);
1113+ 	{
1114+ 		Vector<String> sub_categories = String (p_category).split (" /"  , false );
1115+ 		ti_category->set_collapsed (true );
1116+ 		ti_category->set_text (0 , vformat (" %s"  , sub_categories[sub_categories.size () - 1 ]));
1117+ 		ti_category->set_metadata (0 , category_items_meta);
1118+ 		ti_category->set_text (1 , vformat (" (%s)"  , category_user_count));
1119+ 	}
1120+ 
1121+ 	{
1122+ 		const  AHashMap<StringName, HashSet<StringName>>::ConstIterator category_to_category_children_kv = p_mapping.category_to_category_children .find (p_category);
1123+ 		if  (category_to_category_children_kv) {
1124+ 			const  HashSet<StringName> &category_children = category_to_category_children_kv->value ;
1125+ 
1126+ 			if  (!category_children.is_empty ()) {
1127+ 				for  (const  StringName &category_child : category_children) {
1128+ 					_add_child_categories_recursive (p_item_tree, ti_category, category_child, p_mapping);
1129+ 				}
1130+ 			}
1131+ 		}
9791132	}
9801133}
9811134
@@ -1011,8 +1164,10 @@ void GridMapEditor::edit(GridMap *p_gridmap) {
10111164	if  (node) {
10121165		node->disconnect (SNAME (" cell_size_changed"  ), callable_mp (this , &GridMapEditor::_draw_grids));
10131166		node->disconnect (CoreStringName (changed), callable_mp (this , &GridMapEditor::_update_mesh_library));
1167+ 		node->disconnect (CoreStringName (changed), callable_mp (this , &GridMapEditor::_rebuild_item_tree));
10141168		if  (mesh_library.is_valid ()) {
10151169			mesh_library->disconnect_changed (callable_mp (this , &GridMapEditor::update_palette));
1170+ 			mesh_library->disconnect_changed (callable_mp (this , &GridMapEditor::_rebuild_item_tree));
10161171			mesh_library = Ref<MeshLibrary>();
10171172		}
10181173	}
@@ -1049,7 +1204,10 @@ void GridMapEditor::edit(GridMap *p_gridmap) {
10491204
10501205	node->connect (SNAME (" cell_size_changed"  ), callable_mp (this , &GridMapEditor::_draw_grids));
10511206	node->connect (CoreStringName (changed), callable_mp (this , &GridMapEditor::_update_mesh_library));
1207+ 	node->connect (CoreStringName (changed), callable_mp (this , &GridMapEditor::_rebuild_item_tree));
10521208	_update_mesh_library ();
1209+ 
1210+ 	_rebuild_item_tree ();
10531211}
10541212
10551213void  GridMapEditor::update_grid () {
@@ -1262,8 +1420,10 @@ void GridMapEditor::_update_cursor_instance() {
12621420		cursor_instance = RenderingServer::get_singleton ()->instance_create2 (cursor_mesh, scenario);
12631421	}
12641422
1265- 	//  Make the cursor translucent so that it can be distinguished from already-placed tiles.
1266- 	RenderingServer::get_singleton ()->instance_geometry_set_transparency (cursor_instance, 0.5 );
1423+ 	if  (cursor_instance.is_valid ()) {
1424+ 		//  Make the cursor translucent so that it can be distinguished from already-placed tiles.
1425+ 		RenderingServer::get_singleton ()->instance_geometry_set_transparency (cursor_instance, 0.5 );
1426+ 	}
12671427
12681428	_update_cursor_transform ();
12691429}
@@ -1541,7 +1701,7 @@ GridMapEditor::GridMapEditor() {
15411701
15421702	mesh_library_palette = memnew (ItemList);
15431703	mesh_library_palette->set_auto_translate_mode (AUTO_TRANSLATE_MODE_DISABLED);
1544- 	add_child ( mesh_library_palette);
1704+ 	mesh_library_palette-> set_h_size_flags (SIZE_EXPAND_FILL );
15451705	mesh_library_palette->set_v_size_flags (SIZE_EXPAND_FILL);
15461706	mesh_library_palette->connect (SceneStringName (gui_input), callable_mp (this , &GridMapEditor::_mesh_library_palette_input));
15471707
@@ -1555,6 +1715,45 @@ GridMapEditor::GridMapEditor() {
15551715	info_message->set_anchors_and_offsets_preset (PRESET_FULL_RECT, PRESET_MODE_KEEP_SIZE, 8  * EDSCALE);
15561716	mesh_library_palette->add_child (info_message);
15571717
1718+ 	{
1719+ 		item_palette_container = memnew (VBoxContainer);
1720+ 		item_palette_container->set_h_size_flags (SIZE_EXPAND_FILL);
1721+ 		item_palette_container->set_v_size_flags (SIZE_EXPAND_FILL);
1722+ 		add_child (item_palette_container);
1723+ 
1724+ 		ScrollContainer *item_tree_scrollcontainer = memnew (ScrollContainer);
1725+ 		item_tree_scrollcontainer->set_horizontal_scroll_mode (ScrollContainer::SCROLL_MODE_DISABLED);
1726+ 
1727+ 		VBoxContainer *scrollcontainer_vbox = memnew (VBoxContainer);
1728+ 		scrollcontainer_vbox->set_custom_minimum_size (Size2 (256 , 0 ) * EDSCALE);
1729+ 		scrollcontainer_vbox->set_h_size_flags (SIZE_EXPAND_FILL);
1730+ 		scrollcontainer_vbox->set_v_size_flags (SIZE_EXPAND_FILL);
1731+ 		item_tree_scrollcontainer->add_child (scrollcontainer_vbox);
1732+ 
1733+ 		item_tree = memnew (Tree);
1734+ 		item_tree->set_select_mode (Tree::SelectMode::SELECT_SINGLE);
1735+ 		item_tree->connect (SNAME (" item_activated"  ), callable_mp (this , &GridMapEditor::_on_item_tree_item_activated));
1736+ 		item_tree->connect (SceneStringName (item_selected), callable_mp (this , &GridMapEditor::update_palette));
1737+ 		item_tree->set_columns (2 );
1738+ 		item_tree->set_column_expand (0 , true );
1739+ 		item_tree->set_column_expand (1 , false );
1740+ 		item_tree->set_column_custom_minimum_width (1 , 64  * EDSCALE);
1741+ 		item_tree->set_h_size_flags (SIZE_EXPAND_FILL);
1742+ 		item_tree->set_v_size_flags (SIZE_EXPAND_FILL);
1743+ 		item_tree->set_hide_root (false );
1744+ 
1745+ 		scrollcontainer_vbox->add_child (item_tree);
1746+ 
1747+ 		HSplitContainer *hsplitcontainer = memnew (HSplitContainer);
1748+ 		hsplitcontainer->set_split_offset (256  * EDSCALE);
1749+ 		hsplitcontainer->set_h_size_flags (SIZE_EXPAND_FILL);
1750+ 		hsplitcontainer->set_v_size_flags (SIZE_EXPAND_FILL);
1751+ 		hsplitcontainer->add_child (item_tree_scrollcontainer);
1752+ 		hsplitcontainer->add_child (mesh_library_palette);
1753+ 
1754+ 		item_palette_container->add_child (hsplitcontainer);
1755+ 	}
1756+ 
15581757	edit_axis = Vector3::AXIS_Y;
15591758	edit_floor[0 ] = -1 ;
15601759	edit_floor[1 ] = -1 ;
0 commit comments