Put TreeView into MatterContrlol

This commit is contained in:
Lars Brubaker 2018-05-21 13:30:06 -07:00
parent 0489641c9c
commit 1936b69cc8
7 changed files with 861 additions and 141 deletions

View file

@ -0,0 +1,391 @@
/*
Copyright (c) 2016, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using MatterHackers.Agg;
using MatterHackers.Agg.Font;
using MatterHackers.Agg.Image;
using MatterHackers.Agg.UI;
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
namespace MatterHackers.MatterControl.CustomWidgets.TreeView
{
public class TreeNode : FlowLayoutWidget, ICheckbox
{
private GuiWidget content;
public TreeNode()
: base(FlowDirection.TopToBottom)
{
HAnchor = HAnchor.Fit | HAnchor.Left;
VAnchor = VAnchor.Fit;
TitleBar = new FlowLayoutWidget();
TitleBar.Click += (s, e) =>
{
if (TreeView != null)
{
TreeView.SelectedNode = this;
}
};
AddChild(TitleBar);
RebuildTitleBar();
content = new FlowLayoutWidget(FlowDirection.TopToBottom)
{
HAnchor = HAnchor.Fit | HAnchor.Left,
Visible = false, // content starts out not visible
Name = "content",
Margin = new BorderDouble(25, 3),
};
AddChild(content);
Nodes.CollectionChanged += Nodes_CollectionChanged;
}
public FlowLayoutWidget TitleBar { get; }
public void BeginEdit()
{
throw new NotImplementedException();
}
public void Collapse(bool collapseChildren)
{
throw new NotImplementedException();
}
public void Collapse()
{
throw new NotImplementedException();
}
public void EndEdit(bool cancel)
{
throw new NotImplementedException();
}
public void EnsureVisible()
{
throw new NotImplementedException();
}
public void ExpandAll()
{
throw new NotImplementedException();
}
public int GetNodeCount(bool includeSubTrees)
{
if (includeSubTrees)
{
return this.Descendants<TreeNode>().Count();
}
return content.Children.Where((c) => c is TreeNode).Count();
}
public override void OnTextChanged(EventArgs e)
{
RebuildTitleBar();
base.OnTextChanged(e);
}
public void Remove()
{
throw new NotImplementedException();
}
public void Toggle()
{
content.Visible = !content.Visible;
}
private void Nodes_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
RebuildContentSection();
}
private void RebuildContentSection()
{
// If the node count is starting at 0 we are adding content and need to rebuild the title bar so it will have a + in it
bool needToRebuildTitleBar = GetNodeCount(false) == 0;
// Remove but don't close all the current nodes
content.RemoveAllChildren();
// Then add them back in (after the change)
foreach (var node in Nodes)
{
node.NodeParent = this;
node.ClearRemovedFlag();
content.AddChild(node);
}
// If the node count is ending at 0 we removed content and need to rebuild the title bar so it will net have a + in it
needToRebuildTitleBar |= GetNodeCount(false) == 0;
if (needToRebuildTitleBar)
{
RebuildTitleBar();
}
}
private void RebuildTitleBar()
{
TitleBar.RemoveAllChildren();
if (content != null
&& GetNodeCount(false) > 0)
{
// add a check box
var expandCheckBox = new CheckBox("")
{
Checked = Expanded,
VAnchor = VAnchor.Center
};
ExpandedChanged += (s, e) =>
{
expandCheckBox.Checked = Expanded;
};
expandCheckBox.CheckedStateChanged += (s, e) =>
{
Expanded = expandCheckBox.Checked;
};
TitleBar.AddChild(expandCheckBox);
}
// add a check box
if (Image != null)
{
TitleBar.AddChild(new ImageWidget(Image)
{
VAnchor = VAnchor.Center,
//BorderColor = new Color(ActiveTheme.Instance.PrimaryTextColor, 20),
BackgroundColor = new Color(ActiveTheme.Instance.PrimaryTextColor, 12),
Border = 1,
Margin = 2,
});
};
TitleBar.AddChild(new TextWidget(Text)
{
Selectable = false
});
}
#region Properties
private ImageBuffer _image = new ImageBuffer(16, 16);
public bool Checked { get; set; }
public bool Editing { get; }
public bool Expanded
{
get
{
return content.Visible;
}
set
{
if (content.Visible != value)
{
content.Visible = value;
ExpandedChanged?.Invoke(this, null);
}
}
}
public TreeNode FirstNode { get; }
public ImageBuffer Image
{
get
{
return _image;
}
set
{
if (_image != value)
{
_image = value;
OnImageChanged(null);
}
}
}
public TreeNode LastNode { get; }
/// <summary>
/// Gets the zero-based depth of the tree node in the TreeView control.
/// </summary>
public int Level { get; }
//
// Summary:
// Gets the next sibling tree node.
//
// Returns:
// A TreeNode that represents the next sibling tree node.
public TreeNode NextNode { get; }
//
// Summary:
// Gets the next visible tree node.
//
// Returns:
// A TreeNode that represents the next visible tree node.
public TreeNode NextVisibleNode { get; }
//
// Summary:
// Gets or sets the font that is used to display the text on the tree node label.
//
// Returns:
// The StyledTypeFace that is used to display the text on the tree node label.
public StyledTypeFace NodeFont { get; set; }
//
// Summary:
// Gets the parent tree node of the current tree node.
//
// Returns:
// A TreeNode that represents the parent of the current tree
// node.
public TreeNode NodeParent { get; protected set; }
public ObservableCollection<TreeNode> Nodes { get; } = new ObservableCollection<TreeNode>();
public int PointSize { get; set; }
//
// Summary:
// Gets the previous sibling tree node.
//
// Returns:
// A TreeNode that represents the previous sibling tree node.
public TreeNode PrevNode { get; }
//
// Summary:
// Gets the previous visible tree node.
//
// Returns:
// A TreeNode that represents the previous visible tree node.
public TreeNode PrevVisibleNode { get; }
//
// Summary:
// Gets a value indicating whether the tree node is in the selected state.
//
// Returns:
// true if the tree node is in the selected state; otherwise, false.
public bool Selected
{
get
{
if (TreeView != null)
{
return TreeView.SelectedNode == this;
}
return false;
}
}
//
// Summary:
// Gets or sets the image list index value of the image that is displayed when the
// tree node is in the selected state.
//
// Returns:
// A zero-based index value that represents the image position in an ImageList.
public ImageBuffer SelectedImage { get; set; }
//
// Summary:
// Gets or sets the index of the image that is used to indicate the state of the
// TreeNode when the parent TreeView has
// its TreeView.CheckBoxes property set to false.
//
// Returns:
// The index of the image that is used to indicate the state of the TreeNode.
//
// Exceptions:
// T:System.ArgumentOutOfRangeException:
// The specified index is less than -1 or greater than 14.
public ImageBuffer StateImage { get; set; }
//
// Summary:
// Gets or sets the object that contains data about the tree node.
//
// Returns:
// An System.Object that contains data about the tree node. The default is null.
public object Tag { get; set; }
public Color TextColor { get; set; }
//
// Summary:
// Gets the parent tree view that the tree node is assigned to.
//
// Returns:
// A TreeView that represents the parent tree view that the
// tree node is assigned to, or null if the node has not been assigned to a tree
// view.
public virtual TreeView TreeView
{
get
{
return NodeParent.TreeView;
}
}
private void OnImageChanged(EventArgs args)
{
ImageChanged?.Invoke(this, null);
RebuildTitleBar();
}
#endregion Properties
#region Events
public event EventHandler CheckedStateChanged;
public event EventHandler ExpandedChanged;
public event EventHandler ImageChanged;
#endregion Events
}
}

View file

@ -0,0 +1,370 @@
/*
Copyright (c) 2016, Lars Brubaker, John Lewin
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
*/
using MatterHackers.Agg;
using MatterHackers.Agg.Image;
using MatterHackers.Agg.UI;
using MatterHackers.VectorMath;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace MatterHackers.MatterControl.CustomWidgets.TreeView
{
public class TopNode : TreeNode
{
internal TreeView treeView;
public override TreeView TreeView => treeView;
}
public class TreeView : ScrollableWidget
{
public TreeView(TopNode topNode)
: this(topNode, 0, 0)
{
}
public TreeView(TopNode topNode, int width, int height)
: base(width, height)
{
AutoScroll = true;
topNode.treeView = this;
TopNode = topNode;
HAnchor = HAnchor.Stretch;
VAnchor = VAnchor.Stretch;
AddChild(TopNode);
}
#region Events
public event EventHandler AfterCheck;
public event EventHandler AfterCollapse;
public event EventHandler AfterExpand;
public event EventHandler AfterLabelEdit;
public event EventHandler<TreeNode> AfterSelect;
public event EventHandler BeforeCheck;
public event EventHandler BeforeCollapse;
public event EventHandler BeforeExpand;
public event EventHandler BeforeLabelEdit;
public event EventHandler<TreeNode> BeforeSelect;
public event EventHandler NodeMouseClick;
public event EventHandler NodeMouseDoubleClick;
public event EventHandler NodeMouseHover;
#endregion Events
#region Properties
//
// Summary:
// Gets or sets a value indicating whether check boxes are displayed next to the
// tree nodes in the tree view control.
//
// Returns:
// true if a check box is displayed next to each tree node in the tree view control;
// otherwise, false. The default is false.
public bool CheckBoxes { get; set; }
//
// Summary:
// Gets or sets a value indicating whether the selection highlight spans the width
// of the tree view control.
//
// Returns:
// true if the selection highlight spans the width of the tree view control; otherwise,
// false. The default is false.
public bool FullRowSelect { get; set; }
//
// Summary:
// Gets or sets a value indicating whether the selected tree node remains highlighted
// even when the tree view has lost the focus.
//
// Returns:
// true if the selected tree node is not highlighted when the tree view has lost
// the focus; otherwise, false. The default is true.
public bool HideSelection { get; set; }
//
// Summary:
// Gets or sets the distance to indent each child tree node level.
//
// Returns:
// The distance, in pixels, to indent each child tree node level. The default value
// is 19.
//
// Exceptions:
// T:System.ArgumentOutOfRangeException:
// The assigned value is less than 0 (see Remarks).-or- The assigned value is greater
// than 32,000.
public int Indent { get; set; }
//
// Summary:
// Gets or sets the height of each tree node in the tree view control.
//
// Returns:
// The height, in pixels, of each tree node in the tree view.
//
// Exceptions:
// T:System.ArgumentOutOfRangeException:
// The assigned value is less than one.-or- The assigned value is greater than the
// System.Int16.MaxValue value.
public int ItemHeight { get; set; }
//
// Summary:
// Gets or sets a value indicating whether the label text of the tree nodes can
// be edited.
//
// Returns:
// true if the label text of the tree nodes can be edited; otherwise, false. The
// default is false.
public bool LabelEdit { get; set; }
//
// Summary:
// Gets or sets the color of the lines connecting the nodes of the TreeView
// control.
//
// Returns:
// The System.Drawing.Color of the lines connecting the tree nodes.
public Color LineColor { get; set; }
//
// Summary:
// Gets or sets the delimiter string that the tree node path uses.
//
// Returns:
// The delimiter string that the tree node TreeNode.FullPath
// property uses. The default is the backslash character (\).
public string PathSeparator { get; set; }
public Color TextColor { get; set; } = Color.Black;
public double PointSize { get; set; } = 12;
//
// Summary:
// Gets or sets a value indicating whether the tree view control displays scroll
// bars when they are needed.
//
// Returns:
// true if the tree view control displays scroll bars when they are needed; otherwise,
// false. The default is true.
public bool Scrollable { get; set; }
//
// Summary:
// Gets or sets the tree node that is currently selected in the tree view control.
//
// Returns:
// The TreeNode that is currently selected in the tree view
// control.
TreeNode _selectedNode;
public TreeNode SelectedNode
{
get => _selectedNode; set
{
if (value != _selectedNode)
{
OnBeforeSelect(null);
foreach (var node in this.Descendants<TreeNode>().Where((c) => c != value))
{
node.TitleBar.BackgroundColor = Color.Transparent;
}
_selectedNode = value;
_selectedNode.TitleBar.BackgroundColor = Color.Red;
OnAfterSelect(null);
}
}
}
public bool ShowLines { get; set; }
public bool ShowNodeToolTips { get; set; }
public bool ShowPlusMinus { get; set; }
public bool ShowRootLines { get; set; }
public bool Sorted { get; set; }
public TreeNode TopNode { get; }
public IComparer TreeViewNodeSorter { get; set; }
//
// Summary:
// Gets the number of tree nodes that can be fully visible in the tree view control.
//
// Returns:
// The number of TreeNode items that can be fully visible in
// the TreeView control.
public int VisibleCount { get; }
#endregion Properties
//
// Summary:
// Disables any redrawing of the tree view.
public void BeginUpdate()
{
throw new NotImplementedException();
}
//
// Summary:
// Collapses all the tree nodes.
public void CollapseAll()
{
throw new NotImplementedException();
}
//
// Summary:
// Enables the redrawing of the tree view.
public void EndUpdate()
{
throw new NotImplementedException();
}
//
// Summary:
// Expands all the tree nodes.
public void ExpandAll()
{
throw new NotImplementedException();
}
//
// Summary:
// Retrieves the tree node that is at the specified point.
//
// Parameters:
// pt:
// The System.Drawing.Point to evaluate and retrieve the node from.
//
// Returns:
// The TreeNode at the specified point, in tree view (client)
// coordinates, or null if there is no node at that location.
public TreeNode GetNodeAt(Vector2 pt)
{
throw new NotImplementedException();
}
/// <summary>
/// Retrieves the number of tree nodes, optionally including those in all subtrees,
/// assigned to the tree view control.
/// </summary>
/// <param name="includeSubTrees">true to count the TreeNode items that the subtrees contain;
/// otherwise, false.</param>
/// <returns>The number of tree nodes, optionally including those in all subtrees, assigned
/// to the tree view control.</returns>
public int GetNodeCount(bool includeSubTrees)
{
throw new NotImplementedException();
}
public void Sort()
{
throw new NotImplementedException();
}
protected internal virtual void OnAfterCollapse(EventArgs e)
{
throw new NotImplementedException();
}
protected internal virtual void OnBeforeCollapse(EventArgs e)
{
throw new NotImplementedException();
}
protected virtual void OnAfterCheck(EventArgs e)
{
throw new NotImplementedException();
}
protected virtual void OnAfterExpand(EventArgs e)
{
throw new NotImplementedException();
}
protected virtual void OnAfterLabelEdit(EventArgs e)
{
throw new NotImplementedException();
}
protected virtual void OnAfterSelect(TreeNode e)
{
AfterSelect?.Invoke(this, e);
}
protected virtual void OnBeforeCheck(EventArgs e)
{
throw new NotImplementedException();
}
protected virtual void OnBeforeExpand(EventArgs e)
{
throw new NotImplementedException();
}
protected virtual void OnBeforeLabelEdit(EventArgs e)
{
throw new NotImplementedException();
}
protected virtual void OnBeforeSelect(TreeNode e)
{
BeforeSelect?.Invoke(this, e);
}
protected virtual void OnNodeMouseClick(EventArgs e)
{
throw new NotImplementedException();
}
protected virtual void OnNodeMouseDoubleClick(EventArgs e)
{
throw new NotImplementedException();
}
}
}

View file

@ -65,32 +65,6 @@ namespace MatterHackers.MatterControl.CustomWidgets
this.thumbHeight = height;
}
// TODO: Why is this static?
private static bool WidgetOnScreen(GuiWidget widget, RectangleDouble bounds)
{
if (!widget.Visible)
{
return false;
}
else
{
if (widget.Parent != null)
{
var boundsInParentSpace = widget.TransformToParentSpace(widget.Parent, bounds);
var intersects = boundsInParentSpace.IntersectRectangles(boundsInParentSpace, widget.Parent.LocalBounds);
if (!intersects
|| boundsInParentSpace.Width <= 0
|| boundsInParentSpace.Height <= 0
|| !WidgetOnScreen(widget.Parent, boundsInParentSpace))
{
return false;
}
}
}
return true;
}
public Task LoadItemThumbnail()
{
return LoadItemThumbnail(
@ -99,7 +73,7 @@ namespace MatterHackers.MatterControl.CustomWidgets
this.thumbWidth,
this.thumbHeight,
this.SetItemThumbnail,
() => ListViewItemBase.WidgetOnScreen(this, this.LocalBounds));
() => this.ActuallyVisibleOnScreen());
}
private static async Task LoadItemThumbnail(ILibraryItem libraryItem, ILibraryContainer libraryContainer, int thumbWidth, int thumbHeight, Action<ImageBuffer, bool> thumbnailSetter, Func<bool> shouldGenerateThumbnail)

View file

@ -77,6 +77,8 @@
<Compile Include="ApplicationView\LogoSpinner.cs" />
<Compile Include="ConfigurationPage\PrintLeveling\LevelWizard100PointRadial.cs" />
<Compile Include="ConfigurationPage\PrintLeveling\LevelWizardMesh.cs" />
<Compile Include="CustomWidgets\TreeView\TreeNode.cs" />
<Compile Include="CustomWidgets\TreeView\TreeView.cs" />
<Compile Include="DesignTools\Attributes\ShowSearchFieldAttribute.cs" />
<Compile Include="DesignTools\Primitives\HalfCylinderObject3D.cs" />
<Compile Include="DesignTools\Primitives\HalfWedgeObject3D.cs" />

View file

@ -33,20 +33,20 @@ using System.Linq;
using MatterHackers.Agg;
using MatterHackers.Agg.Platform;
using MatterHackers.Agg.UI;
using MatterHackers.Agg.UI.TreeView;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.MatterControl.DesignTools;
using MatterHackers.MatterControl.Library;
using MatterHackers.VectorMath;
using MatterHackers.MatterControl.CustomWidgets.TreeView;
namespace MatterHackers.MatterControl.PartPreviewWindow
{
[HideUpdateButtonAttribute]
public class SelectedObjectPanel : FlowLayoutWidget, IContentStore
{
private IObject3D item = new Object3D();
private IObject3D rootSelectedItem = new Object3D();
private ThemeConfig theme;
private View3DWidget view3DWidget;
@ -77,9 +77,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
});
inlineTitleEdit.TitleChanged += (s, e) =>
{
if (item != null)
if (rootSelectedItem != null)
{
item.Name = inlineTitleEdit.Text;
rootSelectedItem.Name = inlineTitleEdit.Text;
}
};
@ -131,7 +131,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
bed,
theme);
var clonedItem = this.item.Clone();
var clonedItem = this.rootSelectedItem.Clone();
// Edit in Identity transform
clonedItem.Matrix = Matrix4X4.Identity;
@ -143,16 +143,16 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
var replacement = object3D.Clone();
this.item.Parent.Children.Modify(list =>
this.rootSelectedItem.Parent.Children.Modify(list =>
{
list.Remove(item);
list.Remove(rootSelectedItem);
// Restore matrix of item being replaced
replacement.Matrix = item.Matrix;
replacement.Matrix = rootSelectedItem.Matrix;
list.Add(replacement);
item = replacement;
rootSelectedItem = replacement;
});
scene.SelectedItem = replacement;
@ -172,7 +172,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
applyButton.Click += (s, e) =>
{
scene.SelectedItem = null;
this.item.Apply(view3DWidget.Scene.UndoBuffer);
this.rootSelectedItem.Apply(view3DWidget.Scene.UndoBuffer);
};
scene.SelectionChanged += (s, e) => applyButton.Enabled = scene.SelectedItem?.CanApply == true;
toolbar.AddChild(applyButton);
@ -186,7 +186,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
removeButton.Click += (s, e) =>
{
scene.SelectedItem = null;
this.item.Remove(view3DWidget.Scene.UndoBuffer);
this.rootSelectedItem.Remove(view3DWidget.Scene.UndoBuffer);
};
scene.SelectionChanged += (s, e) => removeButton.Enabled = scene.SelectedItem?.CanRemove == true;
toolbar.AddChild(removeButton);
@ -260,29 +260,11 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
inlineTitleEdit.Text = selectedItem.Name ?? selectedItemType.Name;
this.item = selectedItem;
this.rootSelectedItem = selectedItem;
var viewMode = printer?.ViewState.ViewMode;
HashSet<IObject3DEditor> mappedEditors = ApplicationController.Instance.GetEditorsForType(selectedItemType);
var activeEditors = new List<(IObject3DEditor, IObject3D, string)>();
foreach (var child in selectedItem.DescendantsAndSelf())
{
if (ApplicationController.Instance.GetEditorsForType(child.GetType())?.FirstOrDefault() is IObject3DEditor editor)
{
activeEditors.Add((editor, child, child.Name));
}
// If the object is not persistable than don't show its details.
if(!child.Persistable)
{
break;
}
}
ShowObjectEditor(activeEditors, selectedItem);
ShowObjectEditor(selectedItem);
}
private class OperationButton :TextButton
@ -303,107 +285,118 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
}
}
private void ShowObjectEditor(IEnumerable<(IObject3DEditor editor, IObject3D item, string displayName)> scope, IObject3D rootSelection)
private void ShowObjectEditor(IObject3D selectedItem)
{
editorPanel.CloseAllChildren();
if (scope == null)
// Add the tree view container. eventually we may want to make this a stretch container of some type
var treeViewContainer = new GuiWidget()
{
return;
}
HAnchor = HAnchor.Stretch,
VAnchor = VAnchor.Absolute
};
treeViewContainer.Height = 250;
editorPanel.AddChild(treeViewContainer);
if (scope.Count() > 1)
// add the tree view
var treeView = GetPartTreeView(selectedItem);
treeViewContainer.AddChild(treeView);
// Add the selected item editor container. eventually we may want to make this a stretch container of some type
GuiWidget selectedItemContaner = new GuiWidget()
{
editorPanel.AddChild(GetPartTreeView(rootSelection));
}
HAnchor = HAnchor.Stretch,
VAnchor = VAnchor.Fit
};
treeViewContainer.Height = 250;
editorPanel.AddChild(selectedItemContaner);
foreach (var scopeItem in scope)
treeView.AfterSelect += (s, e) =>
{
var selectedItem = scopeItem.item;
var selectedItemType = selectedItem.GetType();
selectedItemContaner.CloseAllChildren();
var selectedNodeItem = (IObject3D)treeView.SelectedNode.Tag;
var selectedNodeItemType = selectedNodeItem.GetType();
var editorWidget = scopeItem.editor.Create(selectedItem, view3DWidget, theme);
editorWidget.HAnchor = HAnchor.Stretch;
editorWidget.VAnchor = VAnchor.Fit;
if (scopeItem.item != rootSelection
&& scopeItem.editor is PublicPropertyEditor)
HashSet<IObject3DEditor> mappedEditors = ApplicationController.Instance.GetEditorsForType(selectedNodeItemType);
if (ApplicationController.Instance.GetEditorsForType(selectedNodeItemType)?.FirstOrDefault() is IObject3DEditor editor)
{
var editorWidget = editor.Create(selectedNodeItem, view3DWidget, theme);
editorWidget.HAnchor = HAnchor.Stretch;
editorWidget.VAnchor = VAnchor.Fit;
editorWidget.Padding = new BorderDouble(10, 10, 10, 0);
// EditOutline section
var sectionWidget = new SectionWidget(
scopeItem.displayName ?? "Unknown",
string.IsNullOrWhiteSpace(selectedNodeItem.Name) ? "Unknown" : selectedNodeItem.Name,
editorWidget,
theme);
theme.ApplyBoxStyle(sectionWidget, margin: 0);
editorWidget = sectionWidget;
}
else
{
editorWidget.Padding = 0;
}
editorPanel.AddChild(editorWidget);
selectedItemContaner.AddChild(editorWidget);
var buttons = new List<OperationButton>();
var buttons = new List<OperationButton>();
foreach (var nodeOperation in ApplicationController.Instance.Graph.Operations)
{
foreach (var type in nodeOperation.MappedTypes)
foreach (var nodeOperation in ApplicationController.Instance.Graph.Operations)
{
if (type.IsAssignableFrom(selectedItemType)
&& (nodeOperation.IsVisible == null || nodeOperation.IsVisible(selectedItem)))
foreach (var type in nodeOperation.MappedTypes)
{
var button = new OperationButton(nodeOperation, selectedItem, theme)
if (type.IsAssignableFrom(selectedNodeItemType)
&& (nodeOperation.IsVisible == null || nodeOperation.IsVisible(selectedNodeItem)))
{
BackgroundColor = theme.MinimalShade,
Margin = theme.ButtonSpacing
};
button.EnsureAvailablity();
button.Click += (s, e) =>
{
nodeOperation.Operation(selectedItem, scene).ConfigureAwait(false);
};
var button = new OperationButton(nodeOperation, selectedNodeItem, theme)
{
BackgroundColor = theme.MinimalShade,
Margin = theme.ButtonSpacing
};
button.EnsureAvailablity();
button.Click += (s1, e1) =>
{
nodeOperation.Operation(selectedNodeItem, scene).ConfigureAwait(false);
};
buttons.Add(button);
buttons.Add(button);
}
}
}
}
if (buttons.Any())
{
var toolbar = new Toolbar(theme)
if (buttons.Any())
{
HAnchor = HAnchor.Stretch,
VAnchor = VAnchor.Fit,
Padding = theme.ToolbarPadding,
Margin = new BorderDouble(0, 8)
};
editorPanel.AddChild(toolbar);
foreach (var button in buttons)
{
toolbar.AddChild(button);
}
// TODO: Fix likely leak
selectedItem.Invalidated += (s, e) =>
{
foreach (var button in toolbar.ActionArea.Children.OfType<OperationButton>())
var toolbar = new Toolbar(theme)
{
button.EnsureAvailablity();
HAnchor = HAnchor.Stretch,
VAnchor = VAnchor.Fit,
Padding = theme.ToolbarPadding,
Margin = new BorderDouble(0, 8)
};
selectedItemContaner.AddChild(toolbar);
foreach (var button in buttons)
{
toolbar.AddChild(button);
}
};
// TODO: Fix likely leak
selectedNodeItem.Invalidated += (s2, e2) =>
{
foreach (var button in toolbar.ActionArea.Children.OfType<OperationButton>())
{
button.EnsureAvailablity();
}
};
}
else
{
// If the button toolbar isn't added, ensure panel has bottom margin
editorWidget.Margin = editorWidget.Margin.Clone(bottom: 15);
}
}
else
{
// If the button toolbar isn't added, ensure panel has bottom margin
editorWidget.Margin = editorWidget.Margin.Clone(bottom: 15);
}
}
};
treeView.SelectedNode = treeView.TopNode;
}
private void AddTree(IObject3D item, TreeNode parent)
@ -464,7 +457,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
return nameToWrite;
}
private GuiWidget GetPartTreeView(IObject3D rootSelection)
private TreeView GetPartTreeView(IObject3D rootSelection)
{
var topNode = new TopNode()
{
@ -474,42 +467,33 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
PointSize = theme.DefaultFontSize
};
// eventually we may want to make this a stretch container of some type
var treeViewContainer = new GuiWidget();
var treeView = new TreeView(topNode)
{
TextColor = theme.Colors.PrimaryTextColor,
PointSize = theme.DefaultFontSize
};
treeViewContainer.AddChild(treeView);
treeView.SuspendLayout();
selectionTreeNodes.Clear();
selectionTreeNodes.Add(rootSelection, topNode);
// add the children to the root node
foreach (var child in item.Children)
foreach (var child in rootSelectedItem.Children)
{
AddTree(child, topNode);
}
treeView.ResumeLayout();
var partTreeContainer = new SectionWidget("Part Details".Localize(), treeViewContainer, theme, serializationKey: UserSettingsKey.EditorPanelPartTree, defaultExpansion: true);
treeViewContainer.VAnchor = VAnchor.Absolute;
treeViewContainer.Height = 250;
return partTreeContainer;
return treeView;
}
public void Save(ILibraryItem item, IObject3D content)
{
this.item.Parent.Children.Modify(children =>
this.rootSelectedItem.Parent.Children.Modify(children =>
{
children.Remove(this.item);
children.Remove(this.rootSelectedItem);
children.Add(content);
});
}

View file

@ -22,7 +22,6 @@ namespace MatterHackers.MatterControl
public const string CredentialsInvalidReason = nameof(CredentialsInvalidReason);
public const string defaultRenderSetting = nameof(defaultRenderSetting);
public const string DisplayedTip_LoadFilament = nameof(DisplayedTip_LoadFilament);
public const string EditorPanelPartTree = nameof(EditorPanelPartTree);
public const string EditorPanelExpanded = nameof(EditorPanelExpanded);
public const string GCodeLineColorStyle = nameof(GCodeLineColorStyle);
public const string GcodeModelView = nameof(GcodeModelView);

@ -1 +1 @@
Subproject commit 374d122946eefe057d7a6c72b16c93a3f76c81bb
Subproject commit cc7fbfc1baf618ef49920b73c180595a727f069d