private void addCategory(string title, string icon, string colour) { customCategory c = new customCategory(title, icon, colour); c.initialise(); customSubCategory dummySC = new customSubCategory("all", title, ""); dummySC.initialise(); }
private void addSubCategory(string title, string category, string icon) { subCategoryNodes.Add(cfgConstructors.newSubCategoryNode(title, category, icon)); customSubCategory newSC = new customSubCategory(title, category, icon); newSC.initialise(); FilterExtensions.Core.Instance.refreshList(); }
/// <summary> /// if a subcategory doesn't have any parts, it shouldn't be used. Doesn't account for the blackListed parts the first time the editor is entered /// </summary> /// <param name="sC">the subcat to check</param> /// <param name="category">the category for logging purposes</param> /// <returns>true if the subcategory contains any parts</returns> public static bool checkSubCategoryHasParts(customSubCategory sC, string category) { for (int i = 0; i < PartLoader.Instance.parts.Count; i++) { if (sC.checkFilters(PartLoader.Instance.parts[i])) return true; } if (instance.debug) { if (!string.IsNullOrEmpty(category)) Log(sC.subCategoryTitle + " in category " + category + " has no valid parts and was not initialised"); else Log(sC.subCategoryTitle + " has no valid parts and was not initialised"); } return false; }
private bool checkForConflicts(customSubCategory sCToCheck) { foreach (customSubCategory sC in subCategories) // iterate through the already added sC's { // collision only possible within a category if (sC.category == sCToCheck.category) { if (sC.subCategoryTitle == sCToCheck.subCategoryTitle) // if they have the same name, just add the new filters on (OR'd together) { Log(sC.subCategoryTitle + " has multiple entries. Filters are being combined"); sCToCheck.filters.AddRange(sC.filters); return(false); // all other elements of this list have already been check for this condition. Don't need to continue } if (compareFilterLists(sC.filters, sCToCheck.filters)) // check for duplicated filters { Log(sC.subCategoryTitle + " has duplicated the filters of " + sCToCheck.subCategoryTitle); return(false); // ignore this subCategory, only the first processed sC in a conflict will get through } } } return(true); }
/// <summary> /// creating subcategories and then trying to edit them during initialisation causes all sorts of problems. Instead, make the edits prior to initialisation /// </summary> /// <param name="sCs"></param> private void customSCEditDelete(List <customSubCategory> sCs) { foreach (customSubCategory sC in sCs) { customSubCategory sCToEdit = subCategories.FirstOrDefault(sub => sub.category == sC.category && (sub.subCategoryTitle == sC.oldTitle || sub.subCategoryTitle == sC.subCategoryTitle)); if (sCToEdit != null) { if (!string.IsNullOrEmpty(sC.subCategoryTitle)) { sCToEdit.subCategoryTitle = sC.subCategoryTitle; sCToEdit.iconName = sC.iconName; } else { subCategories.Remove(sCToEdit); } } else { subCategories.Add(sC); } } }
private void drawWindow(int id) { ConfigNode category = new ConfigNode(); ConfigNode subCategory = new ConfigNode(); ConfigNode active_subCategory_node = new ConfigNode(); GUILayout.BeginHorizontal(); // Categories column GUILayout.BeginVertical(); if (GUILayout.Button("Create Category")) { showCatWindow = !showCatWindow; } categoryScroll = GUILayout.BeginScrollView(categoryScroll, GUILayout.Height((float)(Screen.height * 0.7)), GUILayout.Width(240)); foreach (PartCategorizer.Category c in PartCategorizer.Instance.filters) { category = categoryNodes.FirstOrDefault(n => n.GetValue("title") == c.button.categoryName); string label = string.Format("title: {0}\r\nicon: {1}\r\ncolour: {2}", c.button.categoryName, category == null ? "" : category.GetValue("icon"), category == null ? "" : category.GetValue("colour")); if (GUILayout.Toggle(activeCategory == c, label, HighLogic.Skin.button, GUILayout.Width(200))) { activeCategory = c; } } GUILayout.EndScrollView(); GUILayout.EndVertical(); // subCategories column GUILayout.BeginVertical(); if (GUILayout.Button("Create Sub-Category") && activeCategory != null) { addSubCategory("blah", activeCategory.button.categoryName, "testIcon"); } subCategoryScroll = GUILayout.BeginScrollView(subCategoryScroll, GUILayout.Height((float)(Screen.height * 0.7)), GUILayout.Width(240)); if (activeCategory != null) { foreach (PartCategorizer.Category sC in activeCategory.subcategories) { subCategory = subCategoryNodes.FirstOrDefault(n => n.GetValue("title") == sC.button.categoryName && n.GetValue("category").Split(',').Any(s => s.Trim() == activeCategory.button.categoryName)); if (subCategory != null) { if (GUILayout.Toggle(activeSubCategory == sC, "title: " + sC.button.categoryName + "\r\ncategory: " + subCategory.GetValue("category").Split(',').FirstOrDefault(s => s.Trim() == activeCategory.button.categoryName) + "\r\noldTitle: " + subCategory.GetValue("oldTitle") + "\r\nicon: " + subCategory.GetValue("icon"), HighLogic.Skin.button, GUILayout.Width(200))) { activeSubCategory = sC; active_subCategory_node = subCategoryNodes.FirstOrDefault(n => n.GetValue("title") == sC.button.categoryName); } } } } GUILayout.EndScrollView(); GUILayout.EndVertical(); // Filters column GUILayout.BeginVertical(); if (GUILayout.Button("Create Filter") && active_subCategory_node != null) { addFilter(active_subCategory_node); } int index = 0, sel = 0; filterScroll = GUILayout.BeginScrollView(filterScroll, GUILayout.Height((float)(Screen.height * 0.7)), GUILayout.Width(240)); if (active_subCategory_node != null && active_subCategory_node.GetNodes("FILTER") != null) { foreach (ConfigNode fil in active_subCategory_node.GetNodes("FILTER")) { index++; if (GUILayout.Toggle(activeFilter == fil, "invert: " + fil.GetValue("invert"), HighLogic.Skin.button, GUILayout.Width(200))) { sel = index; activeFilter = fil; } } } GUILayout.EndScrollView(); GUILayout.EndVertical(); // Checks column GUILayout.BeginVertical(); if (GUILayout.Button("Create Check") && activeFilter != null) { addCheck(active_subCategory_node, activeFilter, "folder", "Squad", sel); } checkScroll = GUILayout.BeginScrollView(checkScroll, GUILayout.Height((float)(Screen.height * 0.7)), GUILayout.Width(240)); if (activeFilter != null && activeFilter.GetNodes("CHECK") != null) { foreach (ConfigNode check in activeFilter.GetNodes("CHECK")) { if (GUILayout.Toggle(activeCheck == check, "type: " + check.GetValue("type") + "\r\nvalue: " + check.GetValue("value") + "\r\ninvert: " + check.GetValue("invert"), HighLogic.Skin.button, GUILayout.Width(200))) { activeCheck = check; } } } GUILayout.EndScrollView(); GUILayout.EndVertical(); // Parts column if (active_subCategory_node != null) { GUILayout.BeginVertical(); customSubCategory sC = new customSubCategory(active_subCategory_node, ""); partsScroll = GUILayout.BeginScrollView(partsScroll, GUILayout.Height((float)(Screen.height * 0.7)), GUILayout.Width(240)); foreach (AvailablePart ap in PartLoader.Instance.parts) { if (sC.checkFilters(ap)) { GUILayout.Label(ap.title, GUILayout.Width(200)); } } GUILayout.EndScrollView(); GUILayout.EndVertical(); } GUILayout.EndHorizontal(); GUI.DragWindow(); }
private void addFilter(customSubCategory sC, bool invert = false) { sC.filters.Add(new Filter(invert)); }
void Awake() { instance = this; Log("Version 1.16"); // Add event for when the Editor GUI becomes active. This is never removed because we need it to fire every time GameEvents.onGUIEditorToolbarReady.Add(editor); // generate the associations between parts and folders, create all the mod categories, get all propellant combinations associateParts(); // mod categories key: title, value: folder // used for adding the folder check to subCategories Dictionary <string, string> folderToCategoryDict = new Dictionary <string, string>(); // load all category configs foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("CATEGORY")) { customCategory C = new customCategory(node); if (Categories.Find(n => n.categoryName == C.categoryName) == null) { Categories.Add(C); if (C.value != null) { if (!folderToCategoryDict.ContainsKey(C.categoryName)) { folderToCategoryDict.Add(C.categoryName, C.value.Trim()); } } } } List <customSubCategory> editList = new List <customSubCategory>(); // load all subCategory configs foreach (ConfigNode node in GameDatabase.Instance.GetConfigNodes("SUBCATEGORY")) { // if multiple categories are specified, create multiple subCategories string[] categories = node.GetValue("category").Split(','); foreach (string s in categories) { customSubCategory sC = new customSubCategory(node, s.Trim()); if (sC.hasFilters && folderToCategoryDict.ContainsKey(sC.category)) { foreach (Filter f in sC.filters) { f.checks.Add(new Check("folder", folderToCategoryDict[sC.category])); } } if (sC.hasFilters && checkForConflicts(sC)) { subCategories.Add(sC); } if (!sC.hasFilters) { editList.Add(sC); } } } customSCEditDelete(editList); foreach (KeyValuePair <string, customSubCategory> kvp in categoryAllSub) { customSubCategory sC = kvp.Value; if (folderToCategoryDict.ContainsKey(kvp.Key)) { foreach (Filter f in sC.filters) { f.checks.Add(new Check("folder", folderToCategoryDict[sC.category])); } } subCategories.Insert(0, sC); } checkForEmptySubCategories(); loadIcons(); }
private void associateParts() { // Build list of mod folder names and Dict associating parts with mods List <string> modNames = new List <string>(); foreach (AvailablePart p in PartLoader.Instance.parts) { // don't want dummy parts if (p.category == PartCategories.none) { continue; } if (string.IsNullOrEmpty(p.partUrl)) { RepairAvailablePartUrl(p); } // if the url is still borked, can't associate a mod to the part if (string.IsNullOrEmpty(p.partUrl)) { continue; } string name = p.partUrl.Split(new char[] { '/', '\\' })[0]; // mod folder name (\\ is escaping the \, read as '\') // if we haven't seen any from this mod before if (!modNames.Contains(name)) { modNames.Add(name); } // associate the mod to the part if (!partFolderDict.ContainsKey(p.name)) { partFolderDict.Add(p.name, name); } else { Log(p.name + " duplicated part key in part-mod dictionary"); } if (p != null && PartType.isEngine(p)) { foreach (ModuleEngines e in p.partPrefab.GetModuleEngines()) { List <string> propellants = new List <string>(); foreach (Propellant prop in e.propellants) { propellants.Add(prop.name); } propellants.Sort(); if (!stringListComparer(propellants)) { propellantCombos.Add(propellants); } } foreach (ModuleEnginesFX ex in p.partPrefab.GetModuleEnginesFx()) { List <string> propellants = new List <string>(); foreach (Propellant prop in ex.propellants) { propellants.Add(prop.name); } propellants.Sort(); if (!stringListComparer(propellants)) { propellantCombos.Add(propellants); } } } } // Create subcategories for Manufacturer category foreach (string s in modNames) { Check ch = new Check("folder", s); Filter f = new Filter(false); customSubCategory sC = new customSubCategory(s, "Filter by Manufacturer", s); f.checks.Add(ch); sC.filters.Add(f); subCategories.Add(sC); } }
/// <summary> /// turn the loaded category and subcategory nodes into useable data /// </summary> private void processFilterDefinitions() { ConfigNode[] nodes = GameDatabase.Instance.GetConfigNodes("CATEGORY"); for (int i = 0; i < nodes.Length; i++) { ConfigNode node = nodes[i]; customCategory C = new customCategory(node); if (C.subCategories == null) continue; if (!Categories.Any(n => n.categoryName == C.categoryName)) Categories.Add(C); } //load all subCategory configs nodes = GameDatabase.Instance.GetConfigNodes("SUBCATEGORY"); for (int i = 0; i < nodes.Length; i++) { ConfigNode node = nodes[i]; customSubCategory sC = new customSubCategory(node); if (!sC.hasFilters || string.IsNullOrEmpty(sC.subCategoryTitle)) continue; customSubCategory subcategory; if (subCategoriesDict.TryGetValue(sC.subCategoryTitle, out subcategory)) // if something does have the same title subcategory.filters.AddRange(sC.filters); else // if nothing else has the same title subCategoriesDict.Add(sC.subCategoryTitle, sC); } customCategory Cat = Categories.Find(C => C.categoryName == "Filter by Resource"); if (Cat != null) { for (int i = 0; i < resources.Count; i++) { string s = resources[i]; // add spaces before each capital letter string name = System.Text.RegularExpressions.Regex.Replace(s, @"\B([A-Z])", " $1"); customSubCategory subcategory; if (subCategoriesDict.TryGetValue(name, out subcategory)) { // if the collision is already looking for the specified resource if (customSubCategory.checkForCheckMatch(subcategory, CheckType.resource, s)) continue; name = "res_" + name; } if (!string.IsNullOrEmpty(name) && !subCategoriesDict.ContainsKey(name)) { customSubCategory sC = new customSubCategory(name, name); Check c = new Check("resource", s); Filter f = new Filter(false); f.checks.Add(c); sC.filters.Add(f); subCategoriesDict.Add(name, sC); } if (!string.IsNullOrEmpty(name)) Cat.subCategories.AddUnique(new subCategoryItem(name)); } } for (int i = 0; i < Categories.Count; i++) { customCategory C = Categories[i]; if (C == null || !C.all) continue; List<Filter> filterList = new List<Filter>(); if (C.subCategories != null) { for (int j = 0; j < C.subCategories.Count; j++) { subCategoryItem s = C.subCategories[j]; if (s == null) continue; customSubCategory subcategory; if (subCategoriesDict.TryGetValue(s.subcategoryName, out subcategory)) filterList.AddUniqueRange(subcategory.filters); } } customSubCategory newSub = new customSubCategory("All parts in " + C.categoryName, C.iconName); newSub.filters = filterList; subCategoriesDict.Add(newSub.subCategoryTitle, newSub); C.subCategories.Insert(0, new subCategoryItem(newSub.subCategoryTitle)); } }
/// <summary> /// create the subcategories for filter by manufacturer by discovered GameData folder /// </summary> /// <param name="modNames"></param> private void processFilterByManufacturer(List<string> modNames) { // define the mod subcategories List<string> subCatNames = new List<string>(); for (int i = 0; i < modNames.Count; i++) { string name = modNames[i]; if (subCategoriesDict.ContainsKey(modNames[i])) name = "mod_" + name; string icon = name; SetNameAndIcon(ref name, ref icon); if (!subCategoriesDict.ContainsKey(name)) { subCatNames.Add(name); Check ch = new Check("folder", modNames[i]); Filter f = new Filter(false); customSubCategory sC = new customSubCategory(name, icon); f.checks.Add(ch); sC.filters.Add(f); subCategoriesDict.Add(name, sC); } } customCategory fbm = Categories.FirstOrDefault(C => C.categoryName == "Filter by Manufacturer"); if (fbm == null) { ConfigNode manufacturerSubs = new ConfigNode("SUBCATEGORIES"); for (int i = 0; i < subCatNames.Count; i++) manufacturerSubs.AddValue("list", i.ToString() + "," + subCatNames[i]); ConfigNode filterByManufacturer = new ConfigNode("CATEGORY"); filterByManufacturer.AddValue("name", "Filter by Manufacturer"); filterByManufacturer.AddValue("type", "stock"); filterByManufacturer.AddValue("value", "replace"); filterByManufacturer.AddNode(manufacturerSubs); Categories.Add(new customCategory(filterByManufacturer)); } else { for (int i = 0; i < modNames.Count; i++) fbm.subCategories.AddUnique(new subCategoryItem(modNames[i])); // append the mod names } }