2018-06-08 08:41:15 -07:00
|
|
|
|
/*
|
|
|
|
|
|
Copyright (c) 2018, 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.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2019-01-28 17:10:12 -08:00
|
|
|
|
using System.Collections.Generic;
|
2019-05-20 21:23:45 -07:00
|
|
|
|
using System.ComponentModel;
|
2019-01-28 17:10:12 -08:00
|
|
|
|
using System.Linq;
|
2022-03-21 15:41:57 -07:00
|
|
|
|
using System.Threading;
|
2018-08-10 14:34:24 -07:00
|
|
|
|
using MatterHackers.Agg.UI;
|
2018-06-08 08:41:15 -07:00
|
|
|
|
using MatterHackers.DataConverters3D;
|
2018-08-10 14:34:24 -07:00
|
|
|
|
using MatterHackers.DataConverters3D.UndoCommands;
|
2019-01-28 17:10:12 -08:00
|
|
|
|
using MatterHackers.Localizations;
|
2018-08-10 14:34:24 -07:00
|
|
|
|
using MatterHackers.MatterControl.DesignTools.Operations;
|
2022-06-16 13:11:26 -07:00
|
|
|
|
using MatterHackers.MatterControl.PartPreviewWindow;
|
2018-06-08 08:41:15 -07:00
|
|
|
|
|
|
|
|
|
|
namespace MatterHackers.MatterControl.DesignTools
|
|
|
|
|
|
{
|
2019-05-04 19:39:11 -07:00
|
|
|
|
[HideChildrenFromTreeView]
|
2022-06-16 13:11:26 -07:00
|
|
|
|
public class ComponentObject3D : Object3D, IRightClickMenuProvider
|
2018-06-08 08:41:15 -07:00
|
|
|
|
{
|
2019-05-20 21:23:45 -07:00
|
|
|
|
private const string ImageConverterComponentID = "4D9BD8DB-C544-4294-9C08-4195A409217A";
|
2019-01-24 17:06:05 -08:00
|
|
|
|
|
2018-06-08 08:41:15 -07:00
|
|
|
|
public ComponentObject3D()
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public ComponentObject3D(IEnumerable<IObject3D> children)
|
2018-08-10 14:34:24 -07:00
|
|
|
|
: base(children)
|
2018-06-08 08:41:15 -07:00
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-01-22 15:43:50 -08:00
|
|
|
|
public override bool CanApply => !Finalized || Persistable;
|
2019-05-20 21:23:45 -07:00
|
|
|
|
|
2019-05-23 08:05:51 -07:00
|
|
|
|
public override bool Persistable => ApplicationController.Instance.UserHasPermission(this);
|
2019-05-20 21:23:45 -07:00
|
|
|
|
|
2021-09-28 12:55:39 -07:00
|
|
|
|
private bool _finalizade = true;
|
2022-02-22 16:01:06 -08:00
|
|
|
|
|
|
|
|
|
|
[Description("Switch from editing to distribution")]
|
2021-09-28 12:55:39 -07:00
|
|
|
|
public bool Finalized
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _finalizade;
|
|
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_finalizade = value;
|
|
|
|
|
|
// on any invalidate ensure that the visibility setting are correct for embedded sheet objects
|
|
|
|
|
|
foreach (var child in this.Descendants())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (child is SheetObject3D)
|
|
|
|
|
|
{
|
|
|
|
|
|
child.Visible = !this.Finalized;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2019-05-20 21:23:45 -07:00
|
|
|
|
|
2018-06-08 08:41:15 -07:00
|
|
|
|
public List<string> SurfacedEditors { get; set; } = new List<string>();
|
2019-05-20 21:23:45 -07:00
|
|
|
|
|
|
|
|
|
|
[HideFromEditor]
|
|
|
|
|
|
public string ComponentID { get; set; } = "";
|
|
|
|
|
|
|
|
|
|
|
|
[Description("MatterHackers Internal Use")]
|
2020-05-24 22:52:43 -07:00
|
|
|
|
public bool ProOnly { get; set; }
|
2018-08-28 15:50:23 -07:00
|
|
|
|
|
2022-01-22 15:43:50 -08:00
|
|
|
|
public override void Apply(UndoBuffer undoBuffer)
|
2018-08-10 14:34:24 -07:00
|
|
|
|
{
|
|
|
|
|
|
// we want to end up with just a group of all the visible mesh objects
|
|
|
|
|
|
using (RebuildLock())
|
|
|
|
|
|
{
|
2019-05-20 21:23:45 -07:00
|
|
|
|
var newChildren = new List<IObject3D>();
|
2018-08-10 14:34:24 -07:00
|
|
|
|
|
|
|
|
|
|
// push our matrix into a copy of our visible children
|
|
|
|
|
|
foreach (var child in this.VisibleMeshes())
|
|
|
|
|
|
{
|
2019-05-20 21:23:45 -07:00
|
|
|
|
var meshOnlyItem = new Object3D
|
|
|
|
|
|
{
|
|
|
|
|
|
Matrix = child.WorldMatrix(this),
|
|
|
|
|
|
Color = child.WorldColor(this),
|
|
|
|
|
|
MaterialIndex = child.WorldMaterialIndex(this),
|
|
|
|
|
|
OutputType = child.WorldOutputType(this),
|
|
|
|
|
|
Mesh = child.Mesh,
|
|
|
|
|
|
Name = "Mesh".Localize()
|
|
|
|
|
|
};
|
2018-08-10 14:34:24 -07:00
|
|
|
|
newChildren.Add(meshOnlyItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-01-24 16:51:07 -08:00
|
|
|
|
if (newChildren.Count > 1)
|
2018-08-10 14:34:24 -07:00
|
|
|
|
{
|
2022-04-28 14:08:30 -07:00
|
|
|
|
var group = new GroupHolesAppliedObject3D
|
2019-05-20 21:23:45 -07:00
|
|
|
|
{
|
|
|
|
|
|
Name = this.Name
|
|
|
|
|
|
};
|
2018-08-10 14:34:24 -07:00
|
|
|
|
group.Children.Modify(list =>
|
|
|
|
|
|
{
|
|
|
|
|
|
list.AddRange(newChildren);
|
|
|
|
|
|
});
|
|
|
|
|
|
newChildren.Clear();
|
|
|
|
|
|
newChildren.Add(group);
|
|
|
|
|
|
}
|
2019-01-24 16:51:07 -08:00
|
|
|
|
else if (newChildren.Count == 1)
|
2018-08-10 14:34:24 -07:00
|
|
|
|
{
|
|
|
|
|
|
newChildren[0].Name = this.Name;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// and replace us with the children
|
2019-01-24 16:51:07 -08:00
|
|
|
|
undoBuffer.AddAndDo(new ReplaceCommand(new[] { this }, newChildren));
|
2018-08-10 14:34:24 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-01-28 17:44:00 -08:00
|
|
|
|
Invalidate(InvalidateType.Children);
|
2018-08-10 14:34:24 -07:00
|
|
|
|
}
|
2019-01-24 17:06:05 -08:00
|
|
|
|
|
2022-03-21 15:41:57 -07:00
|
|
|
|
public (string cellId, string cellData) DecodeContent(int editorIndex)
|
|
|
|
|
|
{
|
2022-03-22 09:22:57 -07:00
|
|
|
|
if (SurfacedEditors[editorIndex].StartsWith("!"))
|
2022-03-21 15:41:57 -07:00
|
|
|
|
{
|
2022-03-22 09:22:57 -07:00
|
|
|
|
var cellData2 = SurfacedEditors[editorIndex].Substring(1);
|
|
|
|
|
|
var cellId2 = cellData2.ToLower();
|
|
|
|
|
|
// check if it has embededdata
|
|
|
|
|
|
var separator = cellData2.IndexOf(',');
|
|
|
|
|
|
if (separator != -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
cellId2 = cellData2.Substring(0, separator).ToLower();
|
|
|
|
|
|
cellData2 = cellData2.Substring(separator + 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
2022-03-21 15:41:57 -07:00
|
|
|
|
{
|
2022-03-22 09:22:57 -07:00
|
|
|
|
var firtSheet = this.Descendants<SheetObject3D>().FirstOrDefault();
|
|
|
|
|
|
if (firtSheet != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// We don't have any cache of the cell content, get the current content
|
2022-11-25 13:11:27 -08:00
|
|
|
|
double.TryParse(firtSheet.SheetData.GetCellValue(cellId2), out double value);
|
2022-03-22 09:22:57 -07:00
|
|
|
|
cellData2 = value.ToString();
|
|
|
|
|
|
}
|
2022-03-21 15:41:57 -07:00
|
|
|
|
}
|
2022-03-22 09:22:57 -07:00
|
|
|
|
|
|
|
|
|
|
return (cellId2, cellData2);
|
2022-03-21 15:41:57 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-03-22 09:22:57 -07:00
|
|
|
|
return (null, null);
|
2022-03-21 15:41:57 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void RecalculateSheet()
|
|
|
|
|
|
{
|
|
|
|
|
|
// if there are editors that reference cells
|
|
|
|
|
|
for (int i=0; i<SurfacedEditors.Count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var (cellId, cellData) = this.DecodeContent(i);
|
|
|
|
|
|
if (cellData.StartsWith("="))
|
|
|
|
|
|
{
|
|
|
|
|
|
var expression = new DoubleOrExpression(cellData);
|
|
|
|
|
|
var firtSheet = this.Descendants<SheetObject3D>().FirstOrDefault();
|
|
|
|
|
|
if (firtSheet != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var cell = firtSheet.SheetData[cellId];
|
|
|
|
|
|
if (cell != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
cell.Expression = expression.Value(this).ToString();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (SurfacedEditors.Any(se => se.StartsWith("!"))
|
|
|
|
|
|
&& !this.RebuildLocked)
|
|
|
|
|
|
{
|
|
|
|
|
|
var firtSheet = this.Descendants<SheetObject3D>().FirstOrDefault();
|
|
|
|
|
|
|
|
|
|
|
|
var componentLock = this.RebuildLock();
|
|
|
|
|
|
firtSheet.SheetData.Recalculate();
|
|
|
|
|
|
|
|
|
|
|
|
UiThread.RunOnIdle(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
// wait until the sheet is done rebuilding (or 30 seconds)
|
|
|
|
|
|
var startTime = UiThread.CurrentTimerMs;
|
|
|
|
|
|
while (firtSheet.RebuildLocked
|
|
|
|
|
|
&& startTime + 30000 < UiThread.CurrentTimerMs)
|
|
|
|
|
|
{
|
|
|
|
|
|
Thread.Sleep(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
componentLock.Dispose();
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void OnInvalidate(InvalidateArgs invalidateType)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch(invalidateType.InvalidateType)
|
|
|
|
|
|
{
|
|
|
|
|
|
case InvalidateType.SheetUpdated:
|
2022-03-23 08:15:26 -07:00
|
|
|
|
case InvalidateType.Properties:
|
2022-03-21 15:41:57 -07:00
|
|
|
|
RecalculateSheet();
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
base.OnInvalidate(invalidateType);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void Cancel(UndoBuffer undoBuffer)
|
2019-01-24 17:06:05 -08:00
|
|
|
|
{
|
2022-02-19 10:56:10 -08:00
|
|
|
|
// Make any hiden children visible
|
|
|
|
|
|
// on any invalidate ensure that the visibility setting are correct for embedded sheet objects
|
|
|
|
|
|
foreach (var child in this.Descendants())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (child is SheetObject3D)
|
|
|
|
|
|
{
|
|
|
|
|
|
child.Visible = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-01-24 17:06:05 -08:00
|
|
|
|
// Custom remove for ImageConverter
|
2019-05-20 21:23:45 -07:00
|
|
|
|
if (this.ComponentID == ImageConverterComponentID)
|
2019-01-24 17:06:05 -08:00
|
|
|
|
{
|
|
|
|
|
|
var parent = this.Parent;
|
|
|
|
|
|
|
|
|
|
|
|
using (RebuildLock())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (this.Descendants<ImageObject3D>().FirstOrDefault() is ImageObject3D imageObject3D)
|
|
|
|
|
|
{
|
|
|
|
|
|
imageObject3D.Matrix = this.Matrix;
|
|
|
|
|
|
|
|
|
|
|
|
if (undoBuffer != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
undoBuffer.AddAndDo(new ReplaceCommand(new[] { this }, new[] { imageObject3D }));
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
parent.Children.Modify(list =>
|
|
|
|
|
|
{
|
|
|
|
|
|
list.Remove(this);
|
|
|
|
|
|
list.Add(imageObject3D);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-01-28 14:19:40 -08:00
|
|
|
|
parent.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
2019-01-24 17:06:05 -08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2020-05-24 22:52:43 -07:00
|
|
|
|
if (ProOnly)
|
|
|
|
|
|
{
|
|
|
|
|
|
// just delete it
|
|
|
|
|
|
var parent = this.Parent;
|
|
|
|
|
|
|
|
|
|
|
|
using (RebuildLock())
|
|
|
|
|
|
{
|
|
|
|
|
|
if (undoBuffer != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// and replace us with nothing
|
|
|
|
|
|
undoBuffer.AddAndDo(new ReplaceCommand(new[] { this }, new List<IObject3D>(), false));
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
parent.Children.Modify(list =>
|
|
|
|
|
|
{
|
|
|
|
|
|
list.Remove(this);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
parent.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// remove the component and leave the inside parts
|
2022-01-22 15:43:50 -08:00
|
|
|
|
base.Cancel(undoBuffer);
|
2020-05-24 22:52:43 -07:00
|
|
|
|
}
|
2019-01-24 17:06:05 -08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-06-16 13:11:26 -07:00
|
|
|
|
|
2022-07-15 19:13:44 -07:00
|
|
|
|
public void AddRightClickMenuItemsItems(PopupMenu popupMenu, ThemeConfig theme)
|
2022-06-16 13:11:26 -07:00
|
|
|
|
{
|
2022-07-15 19:13:44 -07:00
|
|
|
|
popupMenu.CreateSeparator();
|
2022-06-16 13:11:26 -07:00
|
|
|
|
|
2022-07-15 19:13:44 -07:00
|
|
|
|
string componentID = this.ComponentID;
|
2022-06-16 13:11:26 -07:00
|
|
|
|
|
|
|
|
|
|
var helpItem = popupMenu.CreateMenuItem("Help".Localize());
|
|
|
|
|
|
var helpArticlesByID = ApplicationController.Instance.HelpArticlesByID;
|
|
|
|
|
|
helpItem.Enabled = !string.IsNullOrEmpty(componentID) && helpArticlesByID.ContainsKey(componentID);
|
|
|
|
|
|
helpItem.Click += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
var helpTab = ApplicationController.Instance.ActivateHelpTab("Docs");
|
|
|
|
|
|
if (helpTab.TabContent is HelpTreePanel helpTreePanel)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (helpArticlesByID.TryGetValue(componentID, out HelpArticle helpArticle))
|
|
|
|
|
|
{
|
|
|
|
|
|
helpTreePanel.ActiveNodePath = componentID;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2022-07-15 19:13:44 -07:00
|
|
|
|
}
|
2018-06-08 08:41:15 -07:00
|
|
|
|
}
|