private GraphicalUiElement CreateIpsoForElement(ElementSave elementSave) { GraphicalUiElement rootIpso = null; bool isScreen = elementSave is ScreenSave; rootIpso = new GraphicalUiElement(); // If we don't turn off layouts, layouts can be called tens of thousands of times for // complex elements. We'll turn off layouts, then turn them back on at the end and manually // layout: GraphicalUiElement.IsAllLayoutSuspended = true; { rootIpso.Tag = elementSave; mGraphicalElements.Add(rootIpso); rootIpso.ElementSave = elementSave; if (isScreen == false) { // We used to not add the IPSO for the root element to the list of graphical elements // and this prevented selection. I'm not sure if this was intentionally left out or not // but I think it should be here mGraphicalElements.Add(rootIpso); rootIpso.CreateGraphicalComponent(elementSave, null); // can be null if the element save references a bad file if (rootIpso.Component != null) { rootIpso.Component.Name = elementSave.Name; rootIpso.Component.Tag = elementSave; } RecursiveVariableFinder rvf = new DataTypes.RecursiveVariableFinder(SelectedState.Self.SelectedStateSaveOrDefault); string guide = rvf.GetValue <string>("Guide"); SetGuideParent(null, rootIpso, guide); } var exposedVariables = elementSave .DefaultState .Variables .Where(item => !string.IsNullOrEmpty(item.ExposedAsName) && string.IsNullOrEmpty(item.SourceObject)) .ToArray(); foreach (var exposedVariable in exposedVariables) { rootIpso.AddExposedVariable(exposedVariable.ExposedAsName, exposedVariable.Name); } List <GraphicalUiElement> newlyAdded = new List <GraphicalUiElement>(); List <ElementWithState> elementStack = new List <ElementWithState>(); ElementWithState elementWithState = new ElementWithState(elementSave); if (elementSave == SelectedState.Self.SelectedElement) { if (SelectedState.Self.SelectedStateSave != null) { elementWithState.StateName = SelectedState.Self.SelectedStateSave.Name; } else { elementWithState.StateName = "Default"; } } elementStack.Add(elementWithState); // parallel screws up the ordering of objects, so we'll do it on the primary thread for now // and parallelize it later: //Parallel.ForEach(elementSave.Instances, instance => foreach (var instance in elementSave.Instances) { GraphicalUiElement child = CreateRepresentationForInstance(instance, null, elementStack, rootIpso); if (child == null) { // This can occur // if an instance references // a component that doesn't exist. // I don't think we need to do anything // here. } else { newlyAdded.Add(child); mGraphicalElements.Add(child); } } SetUpParentRelationship(newlyAdded, elementStack, elementSave.Instances); elementStack.Remove(elementStack.FirstOrDefault(item => item.Element == elementSave)); rootIpso.SetStatesAndCategoriesRecursively(elementSave); // First we need to the default state (and do so recursively) try { rootIpso.SetVariablesRecursively(elementSave, elementSave.DefaultState); } catch (Exception e) { // this barfed, but we don't want to crash the tool GumCommands.Self.GuiCommands.PrintOutput($"Error loading {elementSave}:\n{e.ToString()}"); } // then we override it with the current state if one is set: if (SelectedState.Self.SelectedStateSave != elementSave.DefaultState && SelectedState.Self.SelectedStateSave != null) { var state = SelectedState.Self.SelectedStateSave; rootIpso.ApplyState(state); } if (elementSave is StandardElementSave && elementSave.Name == "Text") { // We created a new Text object, so let's try generating fonts for it: FontManager.Self.ReactToFontValueSet(null); } // I think this has to be *after* we set varaibles because that's where clipping gets set if (rootIpso != null) { gueManager.Add(rootIpso); rootIpso.AddToManagers(); } } GraphicalUiElement.IsAllLayoutSuspended = false; // There is a bug that currently requires layout to be performed twice. // Update Nov 19, 2019 - I don't know when this was written, but layout has // been continually improving, even as recently as today. I'm going to remove // the 2nd call to make things faster and to see if I can spot other issues that // remain after a single UpdateLayout call: //rootIpso.UpdateLayout(); rootIpso.UpdateLayout(); return(rootIpso); }