diff --git a/MatterControlLib/DesignTools/Primitives/ComponentObject3D.cs b/MatterControlLib/DesignTools/Primitives/ComponentObject3D.cs index 739d37f7f..1b8b31dce 100644 --- a/MatterControlLib/DesignTools/Primitives/ComponentObject3D.cs +++ b/MatterControlLib/DesignTools/Primitives/ComponentObject3D.cs @@ -30,6 +30,7 @@ either expressed or implied, of the FreeBSD Project. using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using System.Threading; using MatterHackers.Agg.UI; using MatterHackers.DataConverters3D; using MatterHackers.DataConverters3D.UndoCommands; @@ -132,7 +133,89 @@ namespace MatterHackers.MatterControl.DesignTools Invalidate(InvalidateType.Children); } - public override void Cancel(UndoBuffer undoBuffer) + public (string cellId, string cellData) DecodeContent(int editorIndex) + { + var cellData2 = SurfacedEditors[editorIndex].Substring(1); + var cellId2 = cellData2.ToLower(); + // check if it has embededdata + var separator = cellData2.IndexOf(','); + if (separator != -1) + { + cellId2 = cellData2.Substring(0, separator).ToLower(); + cellData2 = cellData2.Substring(separator + 1); + } + else + { + var firtSheet = this.Descendants().FirstOrDefault(); + if (firtSheet != null) + { + // We don't have any cache of the cell content, get the current content + double.TryParse(firtSheet.SheetData.EvaluateExpression(cellId2), out double value); + cellData2 = value.ToString(); + } + } + + return (cellId2, cellData2); + } + + + private void RecalculateSheet() + { + // if there are editors that reference cells + for (int i=0; i().FirstOrDefault(); + + var componentLock = this.RebuildLock(); + firtSheet.SheetData.Recalculate(); + + UiThread.RunOnIdle(() => + { + // wait until the sheet is done rebuilding (or 30 seconds) + var startTime = UiThread.CurrentTimerMs; + while (firtSheet.RebuildLocked + && startTime + 30000 < UiThread.CurrentTimerMs) + { + Thread.Sleep(1); + } + + componentLock.Dispose(); + }); + } + } + + public override void OnInvalidate(InvalidateArgs invalidateType) + { + switch(invalidateType.InvalidateType) + { + case InvalidateType.SheetUpdated: + RecalculateSheet(); + break; + } + + base.OnInvalidate(invalidateType); + } + + public override void Cancel(UndoBuffer undoBuffer) { // Make any hiden children visible // on any invalidate ensure that the visibility setting are correct for embedded sheet objects diff --git a/MatterControlLib/PartPreviewWindow/SelectedObjectPanel.cs b/MatterControlLib/PartPreviewWindow/SelectedObjectPanel.cs index 127f60bfe..f2ae36720 100644 --- a/MatterControlLib/PartPreviewWindow/SelectedObjectPanel.cs +++ b/MatterControlLib/PartPreviewWindow/SelectedObjectPanel.cs @@ -348,159 +348,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow // put in the normal editor if (selectedItem is ComponentObject3D componentObject && componentObject.Finalized) - { - var context = new PPEContext(); - PublicPropertyEditor.AddUnlockLinkIfRequired(selectedItem, editorPanel, theme); - foreach (var selector in componentObject.SurfacedEditors) - { - // if it is a reference to a sheet cell - if (selector.StartsWith("!")) - { - var firtSheet = componentObject.Descendants().FirstOrDefault(); - if (firtSheet != null) - { - (string cellId, string cellData) DecodeContent() - { - var cellData2 = selector.Substring(1); - var cellId2 = cellData2.ToLower(); - // check if it has embededdata - var separator = cellData2.IndexOf(','); - if (separator != -1) - { - cellId2 = cellData2.Substring(0, separator).ToLower(); - cellData2 = cellData2.Substring(separator); - } - else - { - // We don't have any cache of the cell content, get the current content - double.TryParse(firtSheet.SheetData.EvaluateExpression(cellId2), out double value); - cellData2 = value.ToString(); - } - - return (cellId2, cellData2); - } - - var (cellId, cellData) = DecodeContent(); - var cell = firtSheet.SheetData[cellId]; - if (cell != null) - { - // create an expresion editor - var field = new ExpressionField(theme) - { - Name = cellId + " Field" - }; - field.Initialize(0); - if (cellData.Contains("=")) - { - field.SetValue(cellData, false); - } - else // make sure it is formatted - { - double.TryParse(cellData, out double value); - var format = "0." + new string('#', 5); - field.SetValue(value.ToString(format), false); - } - - field.ClearUndoHistory(); - - void RecalculateSheet() - { - var componentLock = componentObject.RebuildLock(); - firtSheet.SheetData.Recalculate(); - - UiThread.RunOnIdle(() => - { - // wait until the sheet is done rebuilding (or 30 seconds) - var startTime = UiThread.CurrentTimerMs; - while (firtSheet.RebuildLocked - && startTime + 30000 < UiThread.CurrentTimerMs) - { - Thread.Sleep(1); - } - - componentLock.Dispose(); - }); - } - - var doOrUndoing = false; - field.ValueChanged += (s, e) => - { - if (!doOrUndoing) - { - var oldValue = DecodeContent().cellData; - var newValue = field.Value; - undoBuffer.AddAndDo(new UndoRedoActions(() => - { - doOrUndoing = true; - cell.Expression = oldValue; - RecalculateSheet(); - doOrUndoing = false; - }, - () => - { - doOrUndoing = true; - cell.Expression = newValue; - RecalculateSheet(); - doOrUndoing = false; - })); - } - - }; - - var row = new SettingsRow(cell.Name == null ? cellId : cell.Name, null, field.Content, theme); - editorPanel.AddChild(row); - } - } - } - else // parse it as a path to an object - { - // Get the named property via reflection - // Selector example: '$.Children' - var match = pathGetter.Select(componentObject, selector).ToList(); - - //// - Add editor row for each - foreach (var instance in match) - { - if (instance is IObject3D object3D) - { - if (ApplicationController.Instance.Extensions.GetEditorsForType(object3D.GetType())?.FirstOrDefault() is IObject3DEditor editor) - { - ShowObjectEditor((editor, object3D, object3D.Name), selectedItem); - } - } - else if (JsonPathContext.ReflectionValueSystem.LastMemberValue is ReflectionTarget reflectionTarget) - { - if (reflectionTarget.Source is IObject3D editedChild) - { - context.item = editedChild; - } - else - { - context.item = item; - } - - var editableProperty = new EditableProperty(reflectionTarget.PropertyInfo, reflectionTarget.Source); - - var editor = PublicPropertyEditor.CreatePropertyEditor(rows, editableProperty, undoBuffer, context, theme); - if (editor != null) - { - editorPanel.AddChild(editor); - } - - // Init with custom 'UpdateControls' hooks - (context.item as IPropertyGridModifier)?.UpdateControls(new PublicPropertyChange(context, "Update_Button")); - } - } - } - } - - // Enforce panel padding - foreach (var sectionWidget in editorPanel.Descendants()) - { - sectionWidget.Margin = 0; - } - } - else + { + AddComponentEditor(selectedItem, undoBuffer, rows, componentObject); + } + else { if (item != null && ApplicationController.Instance.Extensions.GetEditorsForType(item.GetType())?.FirstOrDefault() is IObject3DEditor editor) @@ -510,7 +361,131 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } } - private class OperationButton : TextButton + private void AddComponentEditor(IObject3D selectedItem, UndoBuffer undoBuffer, SafeList rows, ComponentObject3D componentObject) + { + var context = new PPEContext(); + PublicPropertyEditor.AddUnlockLinkIfRequired(selectedItem, editorPanel, theme); + var editorList = componentObject.SurfacedEditors; + for (var editorIndex = 0; editorIndex < editorList.Count; editorIndex++) + { + // if it is a reference to a sheet cell + if (editorList[editorIndex].StartsWith("!")) + { + AddSheetCellEditor(undoBuffer, componentObject, editorList, editorIndex); + } + else // parse it as a path to an object + { + // Get the named property via reflection + // Selector example: '$.Children' + var match = pathGetter.Select(componentObject, editorList[editorIndex]).ToList(); + + //// - Add editor row for each + foreach (var instance in match) + { + if (instance is IObject3D object3D) + { + if (ApplicationController.Instance.Extensions.GetEditorsForType(object3D.GetType())?.FirstOrDefault() is IObject3DEditor editor) + { + ShowObjectEditor((editor, object3D, object3D.Name), selectedItem); + } + } + else if (JsonPathContext.ReflectionValueSystem.LastMemberValue is ReflectionTarget reflectionTarget) + { + if (reflectionTarget.Source is IObject3D editedChild) + { + context.item = editedChild; + } + else + { + context.item = item; + } + + var editableProperty = new EditableProperty(reflectionTarget.PropertyInfo, reflectionTarget.Source); + + var editor = PublicPropertyEditor.CreatePropertyEditor(rows, editableProperty, undoBuffer, context, theme); + if (editor != null) + { + editorPanel.AddChild(editor); + } + + // Init with custom 'UpdateControls' hooks + (context.item as IPropertyGridModifier)?.UpdateControls(new PublicPropertyChange(context, "Update_Button")); + } + } + } + } + + // Enforce panel padding + foreach (var sectionWidget in editorPanel.Descendants()) + { + sectionWidget.Margin = 0; + } + } + + private void AddSheetCellEditor(UndoBuffer undoBuffer, ComponentObject3D componentObject, List editorList, int editorIndex) + { + var firtSheet = componentObject.Descendants().FirstOrDefault(); + if (firtSheet != null) + { + var (cellId, cellData) = componentObject.DecodeContent(editorIndex); + var cell = firtSheet.SheetData[cellId]; + if (cell != null) + { + // create an expresion editor + var field = new ExpressionField(theme) + { + Name = cellId + " Field" + }; + field.Initialize(0); + if (cellData.Contains("=")) + { + field.SetValue(cellData, false); + } + else // make sure it is formatted + { + double.TryParse(cellData, out double value); + var format = "0." + new string('#', 5); + field.SetValue(value.ToString(format), false); + } + + field.ClearUndoHistory(); + + var doOrUndoing = false; + field.ValueChanged += (s, e) => + { + if (!doOrUndoing) + { + var oldValue = componentObject.DecodeContent(editorIndex).cellData; + var newValue = field.Value; + undoBuffer.AddAndDo(new UndoRedoActions(() => + { + doOrUndoing = true; + editorList[editorIndex] = "!" + cellId + "," + oldValue; + var expression = new DoubleOrExpression(oldValue); + cell.Expression = expression.Value(componentObject).ToString(); + componentObject.Invalidate(InvalidateType.SheetUpdated); + doOrUndoing = false; + }, + () => + { + doOrUndoing = true; + editorList[editorIndex] = "!" + cellId + "," + newValue; + var expression = new DoubleOrExpression(newValue); + cell.Expression = expression.Value(componentObject).ToString(); + componentObject.Invalidate(InvalidateType.SheetUpdated); + doOrUndoing = false; + })); + } + + }; + + var row = new SettingsRow(cell.Name == null ? cellId : cell.Name, null, field.Content, theme); + editorPanel.AddChild(row); + } + } + } + + private class OperationButton : TextButton { private readonly SceneOperation sceneOperation; private readonly ISceneContext sceneContext;