/// <summary> /// This is the method that actually does the work. /// </summary> /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param> protected override void SolveInstance(IGH_DataAccess DA) { try { if (!hasProperlyGrabbedShadowElements) //if we have not yet succeeded in retoring states from shadows { hasProperlyGrabbedShadowElements = shadowToState(); //try restoring states from shadows } } catch (Exception e) { //hopefully this never happens. AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, String.Format("It threw an {0} error when trying to restore shadow states", e.ToString())); } bool allElementsHaveParents = true; //hacky hack fix for weird deserialization problem. It occasionally happens that elements are deserialized before they belong to a window - //if this happens we have to get them from the shadow state a second time. if (savedStates != null) { foreach (State state in savedStates.states.Values) { foreach (UIElement_Goo goo in state.stateDict.Keys) { if (FindTopmostParent <HumanUIBaseApp.MainWindow>(goo.element) == null) { allElementsHaveParents = false; } } } } if (!allElementsHaveParents) { shadowToState(); } bool saveState = false; bool clearState = false; string stateName = "Unnamed State"; List <object> elementObjects = new List <object>(); List <KeyValuePair <string, UIElement_Goo> > allElements = new List <KeyValuePair <string, UIElement_Goo> >(); List <string> elementFilters = new List <string>(); if (!DA.GetDataList <object>("Elements", elementObjects)) { return; } if (!DA.GetData <string>("State Name", ref stateName)) { return; } DA.GetData <bool>("Save State", ref saveState); DA.GetData <bool>("Clear Saved States", ref clearState); bool hasFilters = DA.GetDataList <string>("Name Filter(s)", elementFilters); List <UIElement_Goo> filteredElements = new List <UIElement_Goo>(); // This is necessary because sometimes elements will come in as UIElement_Goo, // and sometimes they will be wrapped Key-Value pairs from a dictionary. I think this // latter case is now fairly rare - I think only the "Filter UI Element" component was outputting a dictionary // but I'm leaving it in for backwards compatibility. foreach (object o in elementObjects) { switch (o.GetType().ToString()) { case "HumanUI.UIElement_Goo": UIElement_Goo goo = o as UIElement_Goo; filteredElements.Add(goo); break; case "Grasshopper.Kernel.Types.GH_ObjectWrapper": GH_ObjectWrapper wrapper = o as GH_ObjectWrapper; KeyValuePair <string, UIElement_Goo> kvp = (KeyValuePair <string, UIElement_Goo>)wrapper.Value; allElements.Add(kvp); break; default: break; } } if (allElements.Count > 0) //if we've been getting keyvaluepairs and need to filter { //create a dictionary for filtering Dictionary <string, UIElement_Goo> elementDict = allElements.ToDictionary(pair => pair.Key, pair => pair.Value); //filter the dictionary foreach (string fil in elementFilters) { filteredElements.Add(elementDict[fil]); } //if there are no filters, include all values. if (elementFilters.Count == 0) { foreach (UIElement_Goo u in elementDict.Values) { filteredElements.Add(u); } } } //clear the saved state info if (clearState) { savedStates.Clear(); savedShadowStates.Clear(); } //if the user has specified that the state should be saved if (saveState) { baseElems = new List <UIElement>(); //setting up a 1:1 correspondence between base elements and parent elements (UI_ElementGoo). foreach (UIElement_Goo u in filteredElements) { baseElems.Add(HUI_Util.extractBaseElement(u.element)); } State namedState = new State(); //for each element for (int i = 0; i < baseElems.Count; i++) { UIElement u = baseElems[i]; UIElement_Goo parent = filteredElements[i]; //get its state object state = HUI_Util.GetElementValue(u); //add the element and its state to an element state dictionary namedState.AddMember(parent, state); } savedStates.Add(stateName, namedState); } DA.SetData("Saved States", savedStates); DA.SetDataList("Saved State Names", savedStates.Names); }