예제 #1
0
        public override Task Rebuild()
        {
            var rebuildLocks = this.RebuilLockAll();

            // spin up a task to calculate the paint
            return(ApplicationController.Instance.Tasks.Execute("Replacing".Localize(), null, (reporter, cancellationToken) =>
            {
                try
                {
                    SubtractAndReplace(cancellationToken, reporter);
                    var newComputedChildren = new SelectedChildren();

                    foreach (var id in SelectedChildren)
                    {
                        newComputedChildren.Add(id);
                    }

                    ComputedChildren = newComputedChildren;
                }
                catch
                {
                }

                rebuildLocks.Dispose();
                Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
                return Task.CompletedTask;
            }));
        }
예제 #2
0
        public void AddEditorTransparents(Object3DControlsLayer layer, List <Object3DView> transparentMeshes, DrawEventArgs e)
        {
            if (layer.Scene.SelectedItem != null &&
                layer.Scene.SelectedItem == this)
            {
                var parentOfSubtractTargets = this.SourceContainer.DescendantsAndSelfMultipleChildrenFirstOrSelf();

                var removeObjects = parentOfSubtractTargets.Children
                                    .Where(i => SelectedChildren.Contains(i.ID))
                                    .SelectMany(c => c.VisibleMeshes())
                                    .ToList();

                foreach (var item in removeObjects)
                {
                    var color = item.WorldColor(checkOutputType: true);
                    transparentMeshes.Add(new Object3DView(item, color.WithAlpha(color.Alpha0To1 * .2)));
                }
            }
        }
예제 #3
0
        public void DrawEditor(Object3DControlsLayer layer, List <Object3DView> transparentMeshes, DrawEventArgs e)
        {
            if (layer.Scene.SelectedItem != null &&
                layer.Scene.SelectedItem == this)
            {
                var parentOfSubtractTargets = this.SourceContainer.DescendantsAndSelfMultipleChildrenFirstOrSelf();

                var removeObjects = parentOfSubtractTargets.Children
                                    .Where(i => SelectedChildren.Contains(i.ID))
                                    .SelectMany(c => c.VisibleMeshes())
                                    .ToList();

                foreach (var item in removeObjects)
                {
                    transparentMeshes.Add(new Object3DView(item, new Color(item.WorldColor(this.SourceContainer), 80)));
                }

                var keepItems = parentOfSubtractTargets.Children
                                .Where(i => !SelectedChildren.Contains(i.ID))
                                .ToList();

                foreach (var keepItem in keepItems)
                {
                    var drawItem = keepItem;

                    var keepItemResult = this.Children.Where(i => i.OwnerID == keepItem.ID).FirstOrDefault();
                    drawItem = keepItemResult != null ? keepItemResult : drawItem;

                    foreach (var item in drawItem.VisibleMeshes())
                    {
                        GLHelper.Render(item.Mesh,
                                        item.WorldColor(),
                                        item.WorldMatrix(),
                                        RenderTypes.Outlines,
                                        item.WorldMatrix() * layer.World.ModelviewMatrix);
                    }
                }
            }
        }
예제 #4
0
        private static GuiWidget CreateSelector(SelectedChildren childSelector, IObject3D parent, ThemeConfig theme)
        {
            GuiWidget tabContainer = new FlowLayoutWidget(FlowDirection.TopToBottom);

            void UpdateSelectColors(bool selectionChanged = false)
            {
                foreach (var child in parent.Children.ToList())
                {
                    using (child.RebuildLock())
                    {
                        if (selectionChanged)
                        {
                            child.Visible = true;
                        }
                    }
                }
            }

            tabContainer.Closed += (s, e) => UpdateSelectColors();

            var children = parent.Children.ToList();

            var objectChecks = new Dictionary <ICheckbox, IObject3D>();

            var radioSiblings = new List <GuiWidget>();

            for (int i = 0; i < children.Count; i++)
            {
                var itemIndex    = i;
                var child        = children[itemIndex];
                var rowContainer = new FlowLayoutWidget();

                GuiWidget selectWidget;
                if (children.Count == 2)
                {
                    var radioButton = new RadioButton(string.IsNullOrWhiteSpace(child.Name) ? $"{itemIndex}" : $"{child.Name}")
                    {
                        Checked   = childSelector.Contains(child.ID),
                        TextColor = theme.TextColor
                    };
                    radioSiblings.Add(radioButton);
                    radioButton.SiblingRadioButtonList = radioSiblings;
                    selectWidget = radioButton;
                }
                else
                {
                    selectWidget = new CheckBox(string.IsNullOrWhiteSpace(child.Name) ? $"{itemIndex}" : $"{child.Name}")
                    {
                        Checked   = childSelector.Contains(child.ID),
                        TextColor = theme.TextColor
                    };
                }

                objectChecks.Add((ICheckbox)selectWidget, child);

                rowContainer.AddChild(selectWidget);
                var checkBox = selectWidget as ICheckbox;

                checkBox.CheckedStateChanged += (s, e) =>
                {
                    if (s is ICheckbox checkbox)
                    {
                        if (checkBox.Checked)
                        {
                            if (!childSelector.Contains(objectChecks[checkbox].ID))
                            {
                                childSelector.Add(objectChecks[checkbox].ID);
                            }
                        }
                        else
                        {
                            if (childSelector.Contains(objectChecks[checkbox].ID))
                            {
                                childSelector.Remove(objectChecks[checkbox].ID);
                            }
                        }

                        if (parent is MeshWrapperObject3D meshWrapper)
                        {
                            using (meshWrapper.RebuildLock())
                            {
                                meshWrapper.ResetMeshWrapperMeshes(Object3DPropertyFlags.All, CancellationToken.None);
                            }
                        }

                        UpdateSelectColors(true);
                    }
                };

                tabContainer.AddChild(rowContainer);
                UpdateSelectColors();
            }

            return(tabContainer);
        }
예제 #5
0
        private static GuiWidget CreateSourceChildSelector(SelectedChildren childSelector, OperationSourceContainerObject3D sourceContainer, ThemeConfig theme, Action selectionChanged)
        {
            GuiWidget tabContainer = new FlowLayoutWidget(FlowDirection.TopToBottom)
            {
                Margin = new BorderDouble(0, 3, 0, 0),
            };

            var parentOfSubtractTargets = sourceContainer.SourceContainer.DescendantsAndSelfMultipleChildrenFirstOrSelf();

            var sourceChildren = parentOfSubtractTargets.Children.ToList();

            var objectChecks = new Dictionary <ICheckbox, IObject3D>();

            var radioSiblings = new List <GuiWidget>();

            for (int i = 0; i < sourceChildren.Count; i++)
            {
                var itemIndex    = i;
                var child        = sourceChildren[itemIndex];
                var rowContainer = new FlowLayoutWidget()
                {
                    Padding = new BorderDouble(15, 0, 0, 3)
                };

                GuiWidget selectWidget;
                if (sourceChildren.Count == 2)
                {
                    var radioButton = new RadioButton(string.IsNullOrWhiteSpace(child.Name) ? $"{itemIndex}" : $"{child.Name}")
                    {
                        Checked   = childSelector.Contains(child.ID),
                        TextColor = theme.TextColor,
                        Margin    = 0,
                    };
                    radioSiblings.Add(radioButton);
                    radioButton.SiblingRadioButtonList = radioSiblings;
                    selectWidget = radioButton;
                }
                else
                {
                    selectWidget = new CheckBox(string.IsNullOrWhiteSpace(child.Name) ? $"{itemIndex}" : $"{child.Name}")
                    {
                        Checked   = childSelector.Contains(child.ID),
                        TextColor = theme.TextColor,
                    };
                }

                objectChecks.Add((ICheckbox)selectWidget, child);

                rowContainer.AddChild(selectWidget);
                var checkBox = selectWidget as ICheckbox;

                checkBox.CheckedStateChanged += (s, e) =>
                {
                    if (s is ICheckbox checkbox)
                    {
                        if (checkBox.Checked)
                        {
                            if (!childSelector.Contains(objectChecks[checkbox].ID))
                            {
                                childSelector.Add(objectChecks[checkbox].ID);
                            }
                        }
                        else
                        {
                            if (childSelector.Contains(objectChecks[checkbox].ID))
                            {
                                childSelector.Remove(objectChecks[checkbox].ID);
                            }
                        }

                        selectionChanged?.Invoke();
                    }
                };

                tabContainer.AddChild(rowContainer);
            }

            return(tabContainer);
        }
예제 #6
0
        public static GuiWidget CreatePropertyEditor(EditableProperty property, UndoBuffer undoBuffer, PPEContext context, ThemeConfig theme)
        {
            var object3D             = property.Item;
            var propertyGridModifier = property.Item as IPropertyGridModifier;

            GuiWidget rowContainer = null;

            // Get reflected property value once, then test for each case below
            var propertyValue = property.Value;

            void RegisterValueChanged(UIField field, Func <string, object> valueFromString, Func <object, string> valueToString = null)
            {
                field.ValueChanged += (s, e) =>
                {
                    var newValue = field.Value;
                    var oldValue = property.Value.ToString();
                    if (valueToString != null)
                    {
                        oldValue = valueToString(property.Value);
                    }

                    // field.Content
                    if (undoBuffer != null)
                    {
                        undoBuffer.AddAndDo(new UndoRedoActions(() =>
                        {
                            property.SetValue(valueFromString(oldValue));
                            object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                            propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
                        },
                                                                () =>
                        {
                            property.SetValue(valueFromString(newValue));
                            object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                            propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
                        }));
                    }
                    else
                    {
                        property.SetValue(valueFromString(newValue));
                        object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                        propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
                    }
                };
            }

            var readOnly = property.PropertyInfo.GetCustomAttributes(true).OfType <ReadOnlyAttribute>().FirstOrDefault() != null;

            // create a double editor
            if (propertyValue is double doubleValue)
            {
                if (readOnly)
                {
                    var valueField = new TextWidget(string.Format("{0:n}", doubleValue), textColor: theme.TextColor, pointSize: 10)
                    {
                        AutoExpandBoundsToText = true
                    };

                    rowContainer = new SettingsRow(property.DisplayName.Localize(),
                                                   property.Description,
                                                   valueField,
                                                   theme);

                    void RefreshField(object s, InvalidateArgs e)
                    {
                        if (e.InvalidateType.HasFlag(InvalidateType.DisplayValues))
                        {
                            double newValue = (double)property.Value;
                            valueField.Text = string.Format("{0:n}", newValue);
                        }
                    }

                    object3D.Invalidated += RefreshField;
                    valueField.Closed    += (s, e) => object3D.Invalidated -= RefreshField;
                }
                else                 // normal edit row
                {
                    var field = new DoubleField(theme);
                    field.Initialize(0);
                    field.DoubleValue = doubleValue;
                    field.ClearUndoHistory();
                    RegisterValueChanged(field, (valueString) => { return(double.Parse(valueString)); });

                    void RefreshField(object s, InvalidateArgs e)
                    {
                        if (e.InvalidateType.HasFlag(InvalidateType.DisplayValues))
                        {
                            double newValue = (double)property.Value;
                            if (newValue != field.DoubleValue)
                            {
                                field.DoubleValue = newValue;
                            }
                        }
                    }

                    object3D.Invalidated += RefreshField;
                    field.Content.Descendants <InternalTextEditWidget>().First().Name = property.DisplayName + " Edit";
                    field.Content.Closed += (s, e) => object3D.Invalidated -= RefreshField;

                    rowContainer = CreateSettingsRow(property, field, theme);
                }
            }
            else if (propertyValue is Color color)
            {
                var field = new ColorField(theme, object3D.Color);
                field.Initialize(0);
                field.ValueChanged += (s, e) =>
                {
                    property.SetValue(field.Color);
                    object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                    propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
                };

                rowContainer = CreateSettingsRow(property, field, theme);
            }
            else if (propertyValue is Vector2 vector2)
            {
                var field = new Vector2Field(theme);
                field.Initialize(0);
                field.Vector2 = vector2;
                field.ClearUndoHistory();

                RegisterValueChanged(field,
                                     (valueString) => Vector2.Parse(valueString),
                                     (value) =>
                {
                    var s = ((Vector2)value).ToString();
                    return(s.Substring(1, s.Length - 2));
                });

                rowContainer = CreateSettingsColumn(property, field);
            }
            else if (propertyValue is Vector3 vector3)
            {
                var field = new Vector3Field(theme);
                field.Initialize(0);
                field.Vector3 = vector3;
                field.ClearUndoHistory();

                RegisterValueChanged(
                    field,
                    (valueString) => Vector3.Parse(valueString),
                    (value) =>
                {
                    var s = ((Vector3)value).ToString();
                    return(s.Substring(1, s.Length - 2));
                });

                rowContainer = CreateSettingsColumn(property, field);
            }
            else if (propertyValue is DirectionVector directionVector)
            {
                var field = new DirectionVectorField(theme);
                field.Initialize(0);
                field.SetValue(directionVector);
                field.ClearUndoHistory();

                field.ValueChanged += (s, e) =>
                {
                    property.SetValue(field.DirectionVector);
                    object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                    propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
                };

                rowContainer = CreateSettingsRow(property, field, theme);
            }
            else if (propertyValue is DirectionAxis directionAxis)
            {
                rowContainer = CreateSettingsColumn(property);

                var field1 = new DirectionVectorField(theme);
                field1.Initialize(0);
                field1.ClearUndoHistory();

                field1.SetValue(new DirectionVector()
                {
                    Normal = directionAxis.Normal
                });

                rowContainer.AddChild(new SettingsRow("Axis".Localize(), null, field1.Content, theme));

                // the direction axis
                // the distance from the center of the part
                // create a double editor
                var field2 = new Vector3Field(theme);
                field2.Initialize(0);
                field2.Vector3 = directionAxis.Origin - property.Item.Children.First().GetAxisAlignedBoundingBox().Center;
                field2.ClearUndoHistory();

                var row2 = CreateSettingsColumn("Offset".Localize(), field2);

                // update this when changed
                void UpdateData(object s, InvalidateArgs e)
                {
                    field2.Vector3 = ((DirectionAxis)property.Value).Origin - property.Item.Children.First().GetAxisAlignedBoundingBox().Center;
                }

                property.Item.Invalidated += UpdateData;
                field2.Content.Closed     += (s, e) =>
                {
                    property.Item.Invalidated -= UpdateData;
                };

                // update functions
                field1.ValueChanged += (s, e) =>
                {
                    property.SetValue(new DirectionAxis()
                    {
                        Normal = field1.DirectionVector.Normal,
                        Origin = property.Item.Children.First().GetAxisAlignedBoundingBox().Center + field2.Vector3
                    });
                    object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                    propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
                };
                field2.ValueChanged += (s, e) =>
                {
                    property.SetValue(new DirectionAxis()
                    {
                        Normal = field1.DirectionVector.Normal,
                        Origin = property.Item.Children.First().GetAxisAlignedBoundingBox().Center + field2.Vector3
                    });
                    object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                    propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
                };

                rowContainer.AddChild(row2);
            }
            else if (propertyValue is SelectedChildren childSelector)
            {
                var showAsList = property.PropertyInfo.GetCustomAttributes(true).OfType <ShowAsListAttribute>().FirstOrDefault() != null;
                if (showAsList)
                {
                    UIField field = new ChildrenSelectorListField(property, theme);

                    field.Initialize(0);
                    RegisterValueChanged(field,
                                         (valueString) =>
                    {
                        var childrenSelector = new SelectedChildren();
                        foreach (var child in valueString.Split(','))
                        {
                            childrenSelector.Add(child);
                        }

                        return(childrenSelector);
                    });

                    rowContainer = CreateSettingsRow(property, field, theme);
                }
                else                 // show the subtract editor for boolean subtract and subtract and replace
                {
                    rowContainer = CreateSettingsColumn(property);
                    if (property.Item is OperationSourceContainerObject3D sourceContainer)
                    {
                        Action selected = null;
                        if (!(context.item.GetType().GetCustomAttributes(typeof(ShowUpdateButtonAttribute), true).FirstOrDefault() is ShowUpdateButtonAttribute showUpdate))
                        {
                            selected = () =>
                            {
                                object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                            };
                        }

                        rowContainer.AddChild(CreateSourceChildSelector(childSelector, sourceContainer, theme, selected));
                    }
                    else
                    {
                        rowContainer.AddChild(CreateSelector(childSelector, property.Item, theme));
                    }
                }
            }
            else if (propertyValue is ImageBuffer imageBuffer)
            {
                rowContainer = CreateSettingsColumn(property);
                rowContainer.AddChild(new ImageWidget(imageBuffer)
                {
                    HAnchor = HAnchor.Left,
                    Margin  = new BorderDouble(0, 3)
                });
            }
#if !__ANDROID__
            else if (propertyValue is List <string> stringList)
            {
                var field = new SurfacedEditorsField(theme, property.Item);
                field.Initialize(0);
                field.ListValue     = stringList;
                field.ValueChanged += (s, e) =>
                {
                    property.SetValue(field.ListValue);
                };

                rowContainer = CreateSettingsColumn(property, field);

                rowContainer.Descendants <HorizontalSpacer>().FirstOrDefault()?.Close();
            }
#endif
            // create a int editor
            else if (propertyValue is int intValue)
            {
                if (readOnly)
                {
                    var valueField = new TextWidget(string.Format("{0:n0}", intValue),
                                                    textColor: theme.TextColor,
                                                    pointSize: 10)
                    {
                        AutoExpandBoundsToText = true
                    };

                    rowContainer = new SettingsRow(property.DisplayName.Localize(),
                                                   property.Description,
                                                   valueField,
                                                   theme);

                    void RefreshField(object s, InvalidateArgs e)
                    {
                        if (e.InvalidateType.HasFlag(InvalidateType.DisplayValues))
                        {
                            int newValue = (int)property.Value;
                            valueField.Text = string.Format("{0:n0}", newValue);
                        }
                    }

                    object3D.Invalidated += RefreshField;
                    valueField.Closed    += (s, e) => object3D.Invalidated -= RefreshField;
                }
                else                 // normal edit row
                {
                    var field = new IntField(theme);
                    field.Initialize(0);
                    field.IntValue = intValue;
                    field.ClearUndoHistory();

                    RegisterValueChanged(field, (valueString) => { return(int.Parse(valueString)); });

                    void RefreshField(object s, InvalidateArgs e)
                    {
                        if (e.InvalidateType.HasFlag(InvalidateType.DisplayValues))
                        {
                            int newValue = (int)property.Value;
                            if (newValue != field.IntValue)
                            {
                                field.IntValue = newValue;
                            }
                        }
                    }

                    object3D.Invalidated += RefreshField;
                    field.Content.Closed += (s, e) => object3D.Invalidated -= RefreshField;

                    rowContainer = CreateSettingsRow(property, field, theme);
                }
            }
            else if (propertyValue is bool boolValue)
            {
                // create a bool editor
                var field = new ToggleboxField(theme);
                field.Initialize(0);
                field.Checked = boolValue;

                RegisterValueChanged(field,
                                     (valueString) => { return(valueString == "1"); },
                                     (value) => { return(((bool)value) ? "1" : "0"); });
                rowContainer = CreateSettingsRow(property, field, theme);
            }
            else if (propertyValue is string stringValue)
            {
                if (readOnly)
                {
                    rowContainer = new WrappedTextWidget(stringValue,
                                                         textColor: theme.TextColor,
                                                         pointSize: 10)
                    {
                        Margin = 5
                    };
                }
                else                 // normal edit row
                {
                    var multiLineEditAttribute = property.PropertyInfo.GetCustomAttributes(true).OfType <MultiLineEditAttribute>().FirstOrDefault();

                    if (multiLineEditAttribute != null)
                    {
                        // create a a multi-line string editor
                        var field = new MultilineStringField(theme);
                        field.Initialize(0);
                        field.SetValue(stringValue, false);
                        field.ClearUndoHistory();
                        field.Content.HAnchor = HAnchor.Stretch;
                        // field.Content.MinimumSize = new Vector2(0, 200 * GuiWidget.DeviceScale);
                        RegisterValueChanged(field, (valueString) => valueString);
                        rowContainer = CreateSettingsColumn(property, field, fullWidth: true);
                    }
                    else
                    {
                        // create a string editor
                        var field = new TextField(theme);
                        field.Initialize(0);
                        field.SetValue(stringValue, false);
                        field.ClearUndoHistory();
                        field.Content.HAnchor = HAnchor.Stretch;
                        RegisterValueChanged(field, (valueString) => valueString);
                        rowContainer = CreateSettingsRow(property, field, theme);

                        var label = rowContainer.Children.First();

                        var spacer = rowContainer.Children.OfType <HorizontalSpacer>().FirstOrDefault();
                        spacer.HAnchor = HAnchor.Absolute;
                        spacer.Width   = Math.Max(0, 100 - label.Width);
                    }
                }
            }
            else if (propertyValue is char charValue)
            {
                // create a char editor
                var field = new CharField(theme);
                field.Initialize(0);
                field.SetValue(charValue.ToString(), false);
                field.ClearUndoHistory();
                field.ValueChanged += (s, e) =>
                {
                    property.SetValue(Convert.ToChar(field.Value));
                    object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                    propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
                };

                rowContainer = CreateSettingsRow(property, field, theme);
            }
            else if (property.PropertyType.IsEnum)
            {
                // create an enum editor
                UIField field;
                var     enumDisplayAttribute = property.PropertyInfo.GetCustomAttributes(true).OfType <EnumDisplayAttribute>().FirstOrDefault();
                var     addToSettingsRow     = true;
                if (enumDisplayAttribute != null)
                {
                    field = new EnumDisplayField(property, enumDisplayAttribute, theme)
                    {
                        InitialValue = propertyValue.ToString(),
                    };

                    if (enumDisplayAttribute.Mode == EnumDisplayAttribute.PresentationMode.Tabs)
                    {
                        addToSettingsRow = false;
                    }
                }
                else
                {
                    if (property.PropertyType == typeof(NamedTypeFace))
                    {
                        field = new FontSelectorField(property, theme);
                    }
                    else
                    {
                        field = new EnumField(property, theme);
                    }
                }

                field.Initialize(0);
                RegisterValueChanged(field,
                                     (valueString) =>
                {
                    return(Enum.Parse(property.PropertyType, valueString));
                });

                field.ValueChanged += (s, e) =>
                {
                    if (property.Value.ToString() != field.Value)
                    {
                        property.SetValue(Enum.Parse(property.PropertyType, field.Value));
                        object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                        propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
                    }
                };

                if (addToSettingsRow)
                {
                    rowContainer = CreateSettingsRow(property, field, theme);
                }
                else
                {
                    // field.Content.Margin = new BorderDouble(3, 0);
                    field.Content.HAnchor = HAnchor.Stretch;
                    rowContainer          = field.Content;
                }
            }
            else if (propertyValue is IObject3D item &&
                     ApplicationController.Instance.Extensions.GetEditorsForType(property.PropertyType)?.FirstOrDefault() is IObject3DEditor iObject3DEditor)
            {
                // Use known IObject3D editors
                rowContainer = iObject3DEditor.Create(item, undoBuffer, theme);
            }

            // remember the row name and widget
            context.editRows.Add(property.PropertyInfo.Name, rowContainer);

            return(rowContainer);
        }
예제 #7
0
        private void SubtractAndReplace(CancellationToken cancellationToken, IProgress <ProgressStatus> reporter)
        {
            SourceContainer.Visible = true;
            RemoveAllButSource();

            var parentOfPaintTargets = SourceContainer.DescendantsAndSelfMultipleChildrenFirstOrSelf();

            if (parentOfPaintTargets.Children.Count() < 2)
            {
                if (parentOfPaintTargets.Children.Count() == 1)
                {
                    this.Children.Add(SourceContainer.Clone());
                    SourceContainer.Visible = false;
                }

                return;
            }

            SubtractObject3D_2.CleanUpSelectedChildrenNames(this);

            var paintObjects = parentOfPaintTargets.Children
                               .Where((i) => SelectedChildren
                                      .Contains(i.ID))
                               .SelectMany(c => c.VisibleMeshes())
                               .ToList();

            var keepItems = parentOfPaintTargets.Children
                            .Where((i) => !SelectedChildren
                                   .Contains(i.ID));

            var keepVisibleItems = keepItems.SelectMany(c => c.VisibleMeshes()).ToList();

            if (paintObjects.Any() &&
                keepVisibleItems.Any())
            {
                var    totalOperations    = paintObjects.Count * keepVisibleItems.Count;
                double amountPerOperation = 1.0 / totalOperations;
                double ratioCompleted     = 0;

                var progressStatus = new ProgressStatus
                {
                    Status = "Do CSG"
                };

                foreach (var keep in keepVisibleItems)
                {
                    var keepResultsMesh = keep.Mesh;
                    var keepWorldMatrix = keep.WorldMatrix(SourceContainer);

                    foreach (var paint in paintObjects)
                    {
                        if (cancellationToken.IsCancellationRequested)
                        {
                            SourceContainer.Visible = true;
                            RemoveAllButSource();
                            return;
                        }

                        Mesh paintMesh = BooleanProcessing.Do(keepResultsMesh,
                                                              keepWorldMatrix,
                                                              // paint data
                                                              paint.Mesh,
                                                              paint.WorldMatrix(SourceContainer),
                                                              // operation type
                                                              CsgModes.Intersect,
                                                              Processing,
                                                              InputResolution,
                                                              OutputResolution,
                                                              // reporting data
                                                              reporter,
                                                              amountPerOperation,
                                                              ratioCompleted,
                                                              progressStatus,
                                                              cancellationToken);

                        keepResultsMesh = BooleanProcessing.Do(keepResultsMesh,
                                                               keepWorldMatrix,
                                                               // point data
                                                               paint.Mesh,
                                                               paint.WorldMatrix(SourceContainer),
                                                               // operation type
                                                               CsgModes.Subtract,
                                                               Processing,
                                                               InputResolution,
                                                               OutputResolution,
                                                               // reporting data
                                                               reporter,
                                                               amountPerOperation,
                                                               ratioCompleted,
                                                               progressStatus,
                                                               cancellationToken);

                        // after the first time we get a result the results mesh is in the right coordinate space
                        keepWorldMatrix = Matrix4X4.Identity;

                        // store our intersection (paint) results mesh
                        var paintResultsItem = new Object3D()
                        {
                            Mesh    = paintMesh,
                            Visible = false,
                            OwnerID = paint.ID
                        };
                        // copy all the properties but the matrix
                        paintResultsItem.CopyWorldProperties(paint, SourceContainer, Object3DPropertyFlags.All & (~(Object3DPropertyFlags.Matrix | Object3DPropertyFlags.Visible)));
                        // and add it to this
                        this.Children.Add(paintResultsItem);

                        // report our progress
                        ratioCompleted += amountPerOperation;
                        progressStatus.Progress0To1 = ratioCompleted;
                        reporter?.Report(progressStatus);
                    }

                    // store our results mesh
                    var keepResultsItem = new Object3D()
                    {
                        Mesh    = keepResultsMesh,
                        Visible = false,
                        OwnerID = keep.ID
                    };
                    // copy all the properties but the matrix
                    keepResultsItem.CopyWorldProperties(keep, SourceContainer, Object3DPropertyFlags.All & (~(Object3DPropertyFlags.Matrix | Object3DPropertyFlags.Visible)));
                    // and add it to this
                    this.Children.Add(keepResultsItem);
                }

                foreach (var child in Children)
                {
                    child.Visible = true;
                }

                SourceContainer.Visible = false;
            }
        }
        private void Subtract(CancellationToken cancellationToken, IProgress <ProgressStatus> reporter)
        {
            SourceContainer.Visible = true;
            RemoveAllButSource();

            var parentOfSubtractTargets = SourceContainer.DescendantsAndSelfMultipleChildrenFirstOrSelf();

            if (parentOfSubtractTargets.Children.Count() < 2)
            {
                if (parentOfSubtractTargets.Children.Count() == 1)
                {
                    this.Children.Add(SourceContainer.Clone());
                    SourceContainer.Visible = false;
                }

                return;
            }

            CleanUpSelectedChildrenNames(this);

            var removeVisibleItems = parentOfSubtractTargets.Children
                                     .Where((i) => SelectedChildren
                                            .Contains(i.ID))
                                     .SelectMany(c => c.VisiblePaths())
                                     .ToList();

            var keepItems = parentOfSubtractTargets.Children
                            .Where((i) => !SelectedChildren
                                   .Contains(i.ID));

            var keepVisibleItems = keepItems.SelectMany(c => c.VisiblePaths()).ToList();

            if (removeVisibleItems.Any() &&
                keepVisibleItems.Any())
            {
                var    totalOperations    = removeVisibleItems.Count * keepVisibleItems.Count;
                double amountPerOperation = 1.0 / totalOperations;
                double percentCompleted   = 0;

                var progressStatus = new ProgressStatus
                {
                    Status = "Do Subtract"
                };

                bool first = true;
                foreach (var keep in keepVisibleItems)
                {
                    var resultsVertexSource = (keep as IPathObject).VertexSource.Transform(keep.Matrix);

                    foreach (var remove in removeVisibleItems)
                    {
                        resultsVertexSource = resultsVertexSource.MergePaths(((IPathObject)remove).VertexSource.Transform(remove.Matrix), ClipperLib.ClipType.ctDifference);

                        // report our progress
                        percentCompleted           += amountPerOperation;
                        progressStatus.Progress0To1 = percentCompleted;
                        reporter?.Report(progressStatus);
                    }

                    if (first)
                    {
                        this.VertexSource = resultsVertexSource;
                        first             = false;
                    }
                    else
                    {
                        this.VertexSource.MergePaths(resultsVertexSource, ClipperLib.ClipType.ctUnion);
                    }
                }

                // this.VertexSource = this.VertexSource.Transform(Matrix.Inverted);
                first = true;
                foreach (var child in Children)
                {
                    if (first)
                    {
                        // hide the source item
                        child.Visible = false;
                        first         = false;
                    }
                    else
                    {
                        child.Visible = true;
                    }
                }
            }
        }
예제 #9
0
        private void Subtract(CancellationToken cancellationToken, IProgress <ProgressStatus> reporter)
        {
            SourceContainer.Visible = true;
            RemoveAllButSource();

            var parentOfSubtractTargets = SourceContainer.DescendantsAndSelfMultipleChildrenFirstOrSelf();

            if (parentOfSubtractTargets.Children.Count() < 2)
            {
                if (parentOfSubtractTargets.Children.Count() == 1)
                {
                    this.Children.Add(SourceContainer.Clone());
                    SourceContainer.Visible = false;
                }

                return;
            }

            CleanUpSelectedChildrenNames(this);

            var removeVisibleItems = parentOfSubtractTargets.Children
                                     .Where((i) => SelectedChildren
                                            .Contains(i.ID))
                                     .SelectMany(c => c.VisibleMeshes())
                                     .ToList();

            var keepItems = parentOfSubtractTargets.Children
                            .Where((i) => !SelectedChildren
                                   .Contains(i.ID));

            var keepVisibleItems = keepItems.SelectMany(c => c.VisibleMeshes()).ToList();

            if (removeVisibleItems.Any() &&
                keepVisibleItems.Any())
            {
                var    totalOperations    = removeVisibleItems.Count * keepVisibleItems.Count;
                double amountPerOperation = 1.0 / totalOperations;
                double percentCompleted   = 0;

                var progressStatus = new ProgressStatus
                {
                    Status = "Do CSG"
                };
                foreach (var keep in keepVisibleItems)
                {
                    var resultsMesh     = keep.Mesh;
                    var keepWorldMatrix = keep.WorldMatrix(SourceContainer);

                    foreach (var remove in removeVisibleItems)
                    {
                        resultsMesh = BooleanProcessing.Do(resultsMesh,
                                                           keepWorldMatrix,
                                                           // other mesh
                                                           remove.Mesh,
                                                           remove.WorldMatrix(SourceContainer),
                                                           // operation type
                                                           BooleanProcessing.CsgModes.Subtract,
                                                           Processing,
                                                           InputResolution,
                                                           OutputResolution,
                                                           // reporting
                                                           reporter,
                                                           amountPerOperation,
                                                           percentCompleted,
                                                           progressStatus,
                                                           cancellationToken);

                        // after the first time we get a result the results mesh is in the right coordinate space
                        keepWorldMatrix = Matrix4X4.Identity;

                        // report our progress
                        percentCompleted           += amountPerOperation;
                        progressStatus.Progress0To1 = percentCompleted;
                        reporter?.Report(progressStatus);
                    }

                    // store our results mesh
                    var resultsItem = new Object3D()
                    {
                        Mesh    = resultsMesh,
                        Visible = false,
                        OwnerID = keep.ID
                    };

                    // copy all the properties but the matrix
                    resultsItem.CopyWorldProperties(keep, SourceContainer, Object3DPropertyFlags.All & (~(Object3DPropertyFlags.Matrix | Object3DPropertyFlags.Visible)));
                    // and add it to this
                    this.Children.Add(resultsItem);
                }

                bool first = true;
                foreach (var child in Children)
                {
                    if (first)
                    {
                        // hid the source item
                        child.Visible = false;
                        first         = false;
                    }
                    else
                    {
                        child.Visible = true;
                    }
                }
            }
        }
        public static GuiWidget CreatePropertyEditor(EditableProperty property, UndoBuffer undoBuffer, PPEContext context, ThemeConfig theme)
        {
            var object3D             = property.Item;
            var propertyGridModifier = property.Item as IPropertyGridModifier;

            GuiWidget rowContainer = null;

            // Get reflected property value once, then test for each case below
            var propertyValue = property.Value;

            void RegisterValueChanged(UIField field, Func <string, object> valueFromString, Func <object, string> valueToString = null)
            {
                field.ValueChanged += (s, e) =>
                {
                    var newValue = field.Value;
                    var oldValue = property.Value.ToString();
                    if (valueToString != null)
                    {
                        oldValue = valueToString(property.Value);
                    }

                    //field.Content
                    if (undoBuffer != null)
                    {
                        undoBuffer.AddAndDo(new UndoRedoActions(() =>
                        {
                            property.SetValue(valueFromString(oldValue));
                            object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                            propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
                        },
                                                                () =>
                        {
                            property.SetValue(valueFromString(newValue));
                            object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                            propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
                        }));
                    }
                    else
                    {
                        property.SetValue(valueFromString(newValue));
                        object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                        propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
                    }
                };
            }

            // create a double editor
            if (propertyValue is double doubleValue)
            {
                var field = new DoubleField(theme);
                field.Initialize(0);
                field.DoubleValue = doubleValue;
                RegisterValueChanged(field, (valueString) => { return(double.Parse(valueString)); });

                void RefreshField(object s, InvalidateArgs e)
                {
                    if (e.InvalidateType.HasFlag(InvalidateType.DisplayValues))
                    {
                        double newValue = (double)property.Value;
                        if (newValue != field.DoubleValue)
                        {
                            field.DoubleValue = newValue;
                        }
                    }
                }

                object3D.Invalidated += RefreshField;
                field.Content.Closed += (s, e) => object3D.Invalidated -= RefreshField;

                rowContainer = CreateSettingsRow(property, field);
            }
            else if (propertyValue is Color color)
            {
                var field = new ColorField(theme, object3D.Color);
                field.Initialize(0);
                field.ValueChanged += (s, e) =>
                {
                    property.SetValue(field.Color);
                    object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                    propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
                };

                rowContainer = CreateSettingsRow(property, field);
            }
            else if (propertyValue is Vector2 vector2)
            {
                var field = new Vector2Field(theme);
                field.Initialize(0);
                field.Vector2 = vector2;
                RegisterValueChanged(field,
                                     (valueString) => Vector2.Parse(valueString),
                                     (value) =>
                {
                    var s = ((Vector2)value).ToString();
                    return(s.Substring(1, s.Length - 2));
                });
                rowContainer = CreateSettingsColumn(property, field);
            }
            else if (propertyValue is Vector3 vector3)
            {
                var field = new Vector3Field(theme);
                field.Initialize(0);
                field.Vector3 = vector3;

                RegisterValueChanged(
                    field,
                    (valueString) => Vector3.Parse(valueString),
                    (value) =>
                {
                    var s = ((Vector3)value).ToString();
                    return(s.Substring(1, s.Length - 2));
                });

                rowContainer = CreateSettingsColumn(property, field);
            }
            else if (propertyValue is DirectionVector directionVector)
            {
                var field = new DirectionVectorField(theme);
                field.Initialize(0);
                field.SetValue(directionVector);
                field.ValueChanged += (s, e) =>
                {
                    property.SetValue(field.DirectionVector);
                    object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                    propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
                };

                rowContainer = CreateSettingsRow(property, field);
            }
            else if (propertyValue is DirectionAxis directionAxis)
            {
                rowContainer = CreateSettingsColumn(property);
                var newDirectionVector = new DirectionVector()
                {
                    Normal = directionAxis.Normal
                };
                var row1   = CreateSettingsRow("Axis".Localize());
                var field1 = new DirectionVectorField(theme);
                field1.Initialize(0);
                field1.SetValue(newDirectionVector);
                row1.AddChild(field1.Content);

                rowContainer.AddChild(row1);

                // the direction axis
                // the distance from the center of the part
                // create a double editor
                var field2 = new Vector3Field(theme);
                field2.Initialize(0);
                field2.Vector3 = directionAxis.Origin - property.Item.Children.First().GetAxisAlignedBoundingBox().Center;
                var row2 = CreateSettingsColumn("Offset", field2);

                // update this when changed
                EventHandler <InvalidateArgs> updateData = (s, e) =>
                {
                    field2.Vector3 = ((DirectionAxis)property.Value).Origin - property.Item.Children.First().GetAxisAlignedBoundingBox().Center;
                };
                property.Item.Invalidated += updateData;
                field2.Content.Closed     += (s, e) =>
                {
                    property.Item.Invalidated -= updateData;
                };

                // update functions
                field1.ValueChanged += (s, e) =>
                {
                    property.SetValue(new DirectionAxis()
                    {
                        Normal = field1.DirectionVector.Normal,
                        Origin = property.Item.Children.First().GetAxisAlignedBoundingBox().Center + field2.Vector3
                    });
                    object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                    propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
                };
                field2.ValueChanged += (s, e) =>
                {
                    property.SetValue(new DirectionAxis()
                    {
                        Normal = field1.DirectionVector.Normal,
                        Origin = property.Item.Children.First().GetAxisAlignedBoundingBox().Center + field2.Vector3
                    });
                    object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                    propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
                };

                rowContainer.AddChild(row2);
            }
            else if (propertyValue is SelectedChildren childSelector)
            {
                var showAsList = property.PropertyInfo.GetCustomAttributes(true).OfType <ShowAsListAttribute>().FirstOrDefault() != null;
                if (showAsList)
                {
                    UIField field = new ChildrenSelectorListField(property, theme);

                    field.Initialize(0);
                    RegisterValueChanged(field,
                                         (valueString) =>
                    {
                        var childrenSelector = new SelectedChildren();
                        foreach (var child in valueString.Split(','))
                        {
                            childrenSelector.Add(child);
                        }
                        return(childrenSelector);
                    });

                    rowContainer = CreateSettingsRow(property, field);
                }
                else                 // show the subtract editor for boolean subtract and subtract and replace
                {
                    rowContainer = CreateSettingsColumn(property);
                    if (property.Item is OperationSourceContainerObject3D sourceContainer)
                    {
                        rowContainer.AddChild(CreateSourceChildSelector(childSelector, sourceContainer, theme));
                    }
                    else
                    {
                        rowContainer.AddChild(CreateSelector(childSelector, property.Item, theme));
                    }
                }
            }
            else if (propertyValue is ImageBuffer imageBuffer)
            {
                rowContainer = CreateSettingsColumn(property);
                rowContainer.AddChild(CreateImageDisplay(imageBuffer, property.Item, theme));
            }
#if !__ANDROID__
            else if (propertyValue is List <string> stringList)
            {
                var selectedItem = ApplicationController.Instance.DragDropData.SceneContext.Scene.SelectedItem;

                var field = new SurfacedEditorsField(theme, selectedItem);
                field.Initialize(0);
                field.ListValue     = stringList;
                field.ValueChanged += (s, e) =>
                {
                    property.SetValue(field.ListValue);
                };

                rowContainer = CreateSettingsColumn(property, field);

                rowContainer.Descendants <HorizontalSpacer>().FirstOrDefault()?.Close();
            }
#endif
            // create a int editor
            else if (propertyValue is int intValue)
            {
                var field = new IntField(theme);
                field.Initialize(0);
                field.IntValue = intValue;
                RegisterValueChanged(field, (valueString) => { return(int.Parse(valueString)); });

                void RefreshField(object s, InvalidateArgs e)
                {
                    if (e.InvalidateType.HasFlag(InvalidateType.DisplayValues))
                    {
                        int newValue = (int)property.Value;
                        if (newValue != field.IntValue)
                        {
                            field.IntValue = newValue;
                        }
                    }
                }

                object3D.Invalidated += RefreshField;
                field.Content.Closed += (s, e) => object3D.Invalidated -= RefreshField;

                rowContainer = CreateSettingsRow(property, field);
            }
            // create a bool editor
            else if (propertyValue is bool boolValue)
            {
                var field = new ToggleboxField(theme);
                field.Initialize(0);
                field.Checked = boolValue;

                RegisterValueChanged(field,
                                     (valueString) => { return(valueString == "1"); },
                                     (value) => { return(((bool)(value)) ? "1" : "0"); });
                rowContainer = CreateSettingsRow(property, field);
            }
            // create a string editor
            else if (propertyValue is string stringValue)
            {
                var field = new TextField(theme);
                field.Initialize(0);
                field.SetValue(stringValue, false);
                field.Content.HAnchor = HAnchor.Stretch;
                RegisterValueChanged(field, (valueString) => valueString);
                rowContainer = CreateSettingsRow(property, field);

                var label = rowContainer.Children.First();

                if (field is TextField)
                {
                    var spacer = rowContainer.Children.OfType <HorizontalSpacer>().FirstOrDefault();
                    spacer.HAnchor = HAnchor.Absolute;
                    spacer.Width   = Math.Max(0, 100 - label.Width);
                }
            }
            // create a char editor
            else if (propertyValue is char charValue)
            {
                var field = new CharField(theme);
                field.Initialize(0);
                field.SetValue(charValue.ToString(), false);
                field.ValueChanged += (s, e) =>
                {
                    property.SetValue(Convert.ToChar(field.Value));
                    object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                    propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
                };

                rowContainer = CreateSettingsRow(property, field);
            }
            // create an enum editor
            else if (property.PropertyType.IsEnum)
            {
                UIField field;
                var     iconsAttribute = property.PropertyInfo.GetCustomAttributes(true).OfType <IconsAttribute>().FirstOrDefault();
                if (iconsAttribute != null)
                {
                    field = new IconEnumField(property, iconsAttribute, theme)
                    {
                        InitialValue = propertyValue.ToString()
                    };
                }
                else
                {
                    field = new EnumField(property, theme);
                }

                field.Initialize(0);
                RegisterValueChanged(field,
                                     (valueString) =>
                {
                    return(Enum.Parse(property.PropertyType, valueString));
                });

                field.ValueChanged += (s, e) =>
                {
                    property.SetValue(Enum.Parse(property.PropertyType, field.Value));
                    object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties));
                    propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
                };

                rowContainer = CreateSettingsRow(property, field, theme);
            }
            // Use known IObject3D editors
            else if (propertyValue is IObject3D item &&
                     ApplicationController.Instance.Extensions.GetEditorsForType(property.PropertyType)?.FirstOrDefault() is IObject3DEditor iObject3DEditor)
            {
                rowContainer = iObject3DEditor.Create(item, undoBuffer, theme);
            }

            // remember the row name and widget
            context.editRows.Add(property.PropertyInfo.Name, rowContainer);

            return(rowContainer);
        }
예제 #11
0
        public void DrawEditor(Object3DControlsLayer layer, List <Object3DView> transparentMeshes, DrawEventArgs e)
        {
            var parentOfSourceItems = this.SourceContainer.DescendantsAndSelfMultipleChildrenFirstOrSelf();

            var sourceItems = parentOfSourceItems.Children.ToList();

            foreach (var paintItem in sourceItems)
            {
                var paintItemResults  = this.Children.Where(i => i.OwnerID == paintItem.ID);
                var wasSelected       = ComputedChildren.Contains(paintItem.ID);
                var currentlySelected = SelectedChildren.Contains(paintItem.ID);

                if (currentlySelected)
                {
                    // if this is selected always paint a transparent source
                    foreach (var item in paintItem.VisibleMeshes())
                    {
                        transparentMeshes.Add(new Object3DView(item, new Color(item.WorldColor(this.SourceContainer), 80)));
                    }

                    // if it was also selected in before (the results are right)
                    if (wasSelected)
                    {
                        // paint solid results
                        if (paintItemResults != null)
                        {
                            foreach (var paintItemResult in paintItemResults)
                            {
                                foreach (var item in paintItemResult.VisibleMeshes())
                                {
                                    GLHelper.Render(item.Mesh,
                                                    item.WorldColor(),
                                                    item.WorldMatrix(),
                                                    RenderTypes.Outlines,
                                                    item.WorldMatrix() * layer.World.ModelviewMatrix);
                                }
                            }
                        }
                    }
                }
                else if (wasSelected)
                {
                    // it is not selected now but was selected before (changed state)
                    // pant the solid source
                    foreach (var item in paintItem.VisibleMeshes())
                    {
                        GLHelper.Render(item.Mesh,
                                        item.WorldColor(),
                                        item.WorldMatrix(),
                                        RenderTypes.Outlines,
                                        item.WorldMatrix() * layer.World.ModelviewMatrix);
                    }
                }
                else                 // it is not selected now and was not before (same state)
                {
                    // paint the results
                    if (paintItemResults != null && paintItemResults.Count() > 0)
                    {
                        foreach (var paintItemResult in paintItemResults)
                        {
                            foreach (var item in paintItemResult.VisibleMeshes())
                            {
                                GLHelper.Render(item.Mesh,
                                                item.WorldColor(),
                                                item.WorldMatrix(),
                                                RenderTypes.Outlines,
                                                item.WorldMatrix() * layer.World.ModelviewMatrix);
                            }
                        }
                    }
                    else                     // we don't have any results yet
                    {
                        foreach (var item in paintItem.VisibleMeshes())
                        {
                            GLHelper.Render(item.Mesh,
                                            item.WorldColor(),
                                            item.WorldMatrix(),
                                            RenderTypes.Outlines,
                                            item.WorldMatrix() * layer.World.ModelviewMatrix);
                        }
                    }
                }
            }
        }
        private static GuiWidget CreateSourceChildSelector(SelectedChildren childSelector, OperationSourceContainerObject3D sourceCantainer, ThemeConfig theme)
        {
            GuiWidget tabContainer = new FlowLayoutWidget(FlowDirection.TopToBottom);

            var sourceChildren = sourceCantainer.SourceContainer.VisibleMeshes().ToList();

            var objectChecks = new Dictionary <ICheckbox, IObject3D>();

            var radioSiblings = new List <GuiWidget>();

            for (int i = 0; i < sourceChildren.Count; i++)
            {
                var itemIndex    = i;
                var child        = sourceChildren[itemIndex];
                var rowContainer = new FlowLayoutWidget();

                GuiWidget selectWidget;
                if (sourceChildren.Count == 2)
                {
                    var radioButton = new RadioButton(string.IsNullOrWhiteSpace(child.Name) ? $"{itemIndex}" : $"{child.Name}")
                    {
                        Checked   = childSelector.Contains(child.Name),
                        TextColor = theme.TextColor
                    };
                    radioSiblings.Add(radioButton);
                    radioButton.SiblingRadioButtonList = radioSiblings;
                    selectWidget = radioButton;
                }
                else
                {
                    selectWidget = new CheckBox(string.IsNullOrWhiteSpace(child.Name) ? $"{itemIndex}" : $"{child.Name}")
                    {
                        Checked   = childSelector.Contains(child.Name),
                        TextColor = theme.TextColor
                    };
                }

                objectChecks.Add((ICheckbox)selectWidget, child);

                rowContainer.AddChild(selectWidget);
                var checkBox = selectWidget as ICheckbox;

                checkBox.CheckedStateChanged += (s, e) =>
                {
                    if (s is ICheckbox checkbox)
                    {
                        if (checkBox.Checked)
                        {
                            if (!childSelector.Contains(objectChecks[checkbox].Name))
                            {
                                childSelector.Add(objectChecks[checkbox].Name);
                            }
                        }
                        else
                        {
                            if (childSelector.Contains(objectChecks[checkbox].Name))
                            {
                                childSelector.Remove(objectChecks[checkbox].Name);
                            }
                        }
                    }
                };

                tabContainer.AddChild(rowContainer);
            }

            return(tabContainer);
        }