Merge pull request #5347 from larsbrubaker/main

Adding a send g-code object
This commit is contained in:
Lars Brubaker 2022-06-19 22:11:53 -07:00 committed by GitHub
commit f8153190fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 662 additions and 158 deletions

View file

@ -227,7 +227,7 @@ namespace MatterHackers.MatterControl.CustomWidgets
this.ConstrainedWidth = resizePage.Width;
};
tabControl = new SimpleTabs(theme, this.CreatePinButton())
tabControl = new SimpleTabs(theme, null, this.CreatePinButton())
{
VAnchor = VAnchor.Stretch,
HAnchor = HAnchor.Stretch,

View file

@ -42,10 +42,13 @@ namespace MatterHackers.MatterControl.DesignTools
AxisAlignedBoundingBox GetEditorWorldspaceAABB(Object3DControlsLayer layer);
}
public interface ICustomEditorDraw : IEditorDraw
public interface IEditorDrawControled : IEditorDraw
{
bool DoEditorDraw(bool isSelected);
}
public interface ICustomEditorDraw : IEditorDrawControled
{
void AddEditorTransparents(Object3DControlsLayer object3DControlLayer, List<Object3DView> transparentMeshes, DrawEventArgs e);
bool DoEditorDraw(bool isSelected);
}
}

View file

@ -0,0 +1,209 @@
/*
Copyright (c) 2019, Lars Brubaker
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 System.Collections.Generic;
using System.Threading.Tasks;
using MatterControl.Printing;
using MatterHackers.Agg;
using MatterHackers.Agg.Font;
using MatterHackers.Agg.Image;
using MatterHackers.Agg.UI;
using MatterHackers.Agg.VertexSource;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.PartPreviewWindow;
using MatterHackers.PolygonMesh;
using MatterHackers.PolygonMesh.Processors;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.DesignTools
{
public class SendGCodeObject3D : Object3D, IObject3DControlsProvider, IGCodeTransformer, IEditorDrawControled
{
private bool hasBeenReached;
private double accumulatedLayerHeight;
public SendGCodeObject3D()
{
Name = "Send G-Code".Localize();
Color = Color.White.WithAlpha(.4);
Mesh = new RoundedRect(-20, -20, 20, 20, 3)
{
ResolutionScale = 10
}.Extrude(.2);
}
public static async Task<SendGCodeObject3D> Create()
{
var item = new SendGCodeObject3D();
await item.Rebuild();
return item;
}
public string GCodeToSend { get; set; } = "";
public override bool Printable => false;
public void AddObject3DControls(Object3DControlsLayer object3DControlsLayer)
{
object3DControlsLayer.AddControls(ControlTypes.MoveInZ | ControlTypes.Shadow | ControlTypes.ScaleMatrixXY);
}
public override async void OnInvalidate(InvalidateArgs invalidateType)
{
if (invalidateType.InvalidateType.HasFlag(InvalidateType.Properties)
&& invalidateType.Source == this)
{
await Rebuild();
}
else
{
base.OnInvalidate(invalidateType);
}
}
public override Task Rebuild()
{
this.DebugDepth("Rebuild");
using (RebuildLock())
{
using (new CenterAndHeightMaintainer(this))
{
}
}
Invalidate(InvalidateType.DisplayValues);
UpdateTexture();
this.CancelAllParentBuilding();
Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Mesh));
return Task.CompletedTask;
}
private (string gcode, double worldZ) displayInfo = ("", double.MinValue);
private double WorldZ => default(Vector3).Transform(this.WorldMatrix()).Z;
public IEnumerable<string> ProcessCGcode(string lineToWrite, PrinterConfig printer)
{
if (!hasBeenReached
&& lineToWrite.StartsWith("; LAYER_HEIGHT:"))
{
double layerHeight = 0;
if (GCodeFile.GetFirstNumberAfter("; LAYER_HEIGHT", lineToWrite, ref layerHeight, out _, stopCheckingString: ":"))
{
accumulatedLayerHeight += layerHeight;
if (accumulatedLayerHeight > WorldZ)
{
hasBeenReached = true;
yield return $"{GCodeToSend} ; G-Code from Scene Object";
}
}
}
}
public void Reset()
{
hasBeenReached = false;
accumulatedLayerHeight = 0;
}
public void DrawEditor(Object3DControlsLayer object3DControlLayer, DrawEventArgs e)
{
if (displayInfo.worldZ != WorldZ
|| displayInfo.gcode != DisplayGCode)
{
UpdateTexture();
}
}
private string DisplayGCode
{
get
{
var max40Chars = GCodeToSend;
if (GCodeToSend.Length > 35)
{
max40Chars = GCodeToSend.Substring(0, 35) + "...";
}
EnglishTextWrapping wrapper = new EnglishTextWrapping(10);
max40Chars = wrapper.InsertCRs(max40Chars, 120);
return max40Chars;
}
}
private void UpdateTexture()
{
Mesh.FaceTextures.Clear();
displayInfo.worldZ = WorldZ;
displayInfo.gcode = DisplayGCode;
var theme = AppContext.Theme;
var texture = new ImageBuffer(128, 128, 32);
var graphics2D = texture.NewGraphics2D();
graphics2D.Clear(theme.BackgroundColor);
graphics2D.DrawString($"Height: {displayInfo.worldZ:0.##}",
texture.Width / 2,
texture.Height * .7,
14,
Agg.Font.Justification.Center,
Agg.Font.Baseline.BoundsCenter,
theme.TextColor);
graphics2D.DrawString($"G-Code",
texture.Width / 2,
texture.Height * .45,
14,
Agg.Font.Justification.Center,
Agg.Font.Baseline.BoundsCenter,
theme.TextColor);
var height = texture.Height * .37;
graphics2D.Line(texture.Width / 5, height, texture.Width / 5 * 4, height, theme.TextColor);
graphics2D.DrawString($"{displayInfo.gcode}",
texture.Width / 2,
texture.Height * .3,
10,
Agg.Font.Justification.Center,
Agg.Font.Baseline.BoundsCenter,
theme.TextColor);
Mesh.PlaceTextureOnFaces(0, texture);
}
public AxisAlignedBoundingBox GetEditorWorldspaceAABB(Object3DControlsLayer layer)
{
return AxisAlignedBoundingBox.Empty();
}
public bool DoEditorDraw(bool isSelected)
{
return true;
}
}
}

View file

@ -43,7 +43,7 @@ using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.DesignTools
{
public class SetTemperatureObject3D : Object3D, IObject3DControlsProvider, IGCodeTransformer, IEditorDraw
public class SetTemperatureObject3D : Object3D, IObject3DControlsProvider, IGCodeTransformer, IEditorDrawControled
{
private bool hasBeenReached;
private double accumulatedLayerHeight;
@ -178,5 +178,10 @@ namespace MatterHackers.MatterControl.DesignTools
{
return AxisAlignedBoundingBox.Empty();
}
public bool DoEditorDraw(bool isSelected)
{
return true;
}
}
}

View file

@ -39,7 +39,7 @@ using MatterHackers.MatterControl.DesignTools;
namespace MatterHackers.MatterControl.Library
{
public class CalibrationPartsContainer : LibraryContainer
public class CalibrationPartsContainer : LibraryContainer
{
public CalibrationPartsContainer()
{
@ -53,13 +53,6 @@ namespace MatterHackers.MatterControl.Library
var oemParts = StaticData.Instance.GetFiles(Path.Combine("OEMSettings", "SampleParts"));
Items = new SafeList<ILibraryItem>(oemParts.Select(s => new StaticDataItem(s)));
Items.Add(new GeneratorItem(
"Set Temperature".Localize(),
async () => await SetTemperatureObject3D.Create())
{
Category = this.Name
});
Items.Add(new GeneratorItem(
"PLA Temperature Tower".Localize(),
async () => await TemperatureTowerObject3D.Create(220))

View file

@ -56,6 +56,16 @@ namespace MatterHackers.MatterControl.Library
IsReadOnly = true
});
this.ChildContainers.Add(
new DynamicContainerLink(
"Scripting".Localize(),
StaticData.Instance.LoadIcon(Path.Combine("Library", "folder.png")),
StaticData.Instance.LoadIcon(Path.Combine("Library", "scripting_icon.png")),
() => new ScriptingPartsContainer())
{
IsReadOnly = true
});
this.ChildContainers.Add(
new DynamicContainerLink(
"Primitives".Localize(),

View file

@ -0,0 +1,124 @@
/*
Copyright (c) 2019, John Lewin
Copyright (c) 2021, Lars Brubaker
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 System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using MatterHackers.Agg;
using MatterHackers.Agg.Platform;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.DesignTools;
namespace MatterHackers.MatterControl.Library
{
public class ScriptingPartsContainer : LibraryContainer
{
public ScriptingPartsContainer()
{
this.ChildContainers = new SafeList<ILibraryContainerLink>();
this.Items = new SafeList<ILibraryItem>();
this.Name = "Scripting".Localize();
}
public override void Load()
{
Items = new SafeList<ILibraryItem>();
Items.Add(new GeneratorItem(
"Set Temperature".Localize(),
async () => await SetTemperatureObject3D.Create())
{
Category = this.Name
});
Items.Add(new GeneratorItem(
"Send G-Code".Localize(),
async () => await SendGCodeObject3D.Create())
{
Category = this.Name
});
}
private class StaticDataItem : ILibraryAssetStream
{
public StaticDataItem()
{
}
public StaticDataItem(string relativePath)
{
this.AssetPath = relativePath;
}
public string FileName => Path.GetFileName(AssetPath);
public string ContentType => Path.GetExtension(AssetPath).ToLower().Trim('.');
public string AssetPath { get; }
public long FileSize { get; } = -1;
public bool LocalContentExists => true;
public string Category { get; } = "";
public string ID => agg_basics.GetLongHashCode(AssetPath).ToString();
public event EventHandler NameChanged;
public string Name
{
get => this.FileName;
set
{
// do nothing (can't rename)
}
}
public bool IsProtected => true;
public bool IsVisible => true;
public DateTime DateModified { get; } = DateTime.Now;
public DateTime DateCreated { get; } = DateTime.Now;
public Task<StreamAndLength> GetStream(Action<double, string> progress)
{
return Task.FromResult(new StreamAndLength()
{
Stream = StaticData.Instance.OpenStream(AssetPath),
Length = -1
});
}
}
}
}

View file

@ -47,7 +47,7 @@ namespace MatterHackers.MatterControl
this.WindowTitle = "MatterControl - " + "Markdown Edit".Localize();
this.HeaderText = "Edit Page".Localize() + ":";
var tabControl = new SimpleTabs(theme, new GuiWidget())
var tabControl = new SimpleTabs(theme, null, new GuiWidget())
{
HAnchor = HAnchor.Stretch,
VAnchor = VAnchor.Stretch,

View file

@ -59,12 +59,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
this.BackgroundColor = theme.BackgroundColor;
}
public HorizontalLine CreateSeparator()
public HorizontalLine CreateSeparator(double height = 1)
{
var line = new HorizontalLine(ApplicationController.Instance.MenuTheme.BorderColor20)
{
Margin = new BorderDouble(8, 1),
BackgroundColor = theme.RowBorder
BackgroundColor = theme.RowBorder,
Height = height * DeviceScale,
};
this.AddChild(line);
@ -430,6 +431,20 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
return this.CreateButtonSelectMenuItem(textWidget, text, buttonKvps, startingValue, setter, minSpacerWidth);
}
public MenuItem CreateButtonMenuItem(string text,
IEnumerable<(string key, string text, EventHandler<MouseEventArgs> click)> buttonKvps,
double minSpacerWidth = 0,
bool bold = false)
{
var textWidget = new TextWidget(text, pointSize: theme.DefaultFontSize, textColor: theme.TextColor, bold: bold)
{
Padding = MenuPadding,
VAnchor = VAnchor.Center,
};
return this.CreateButtonMenuItem(textWidget, text, buttonKvps, minSpacerWidth);
}
public MenuItem CreateButtonSelectMenuItem(string text, ImageBuffer icon, IEnumerable<(string key, string text)> buttonKvps, string startingValue, Action<string> setter)
{
var row = new FlowLayoutWidget()
@ -481,6 +496,36 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
return menuItem;
}
public MenuItem CreateButtonMenuItem(GuiWidget guiWidget, string name, IEnumerable<(string key, string text, EventHandler<MouseEventArgs> click)> buttonKvps, double minSpacerWidth = 0)
{
var row = new FlowLayoutWidget()
{
HAnchor = HAnchor.MaxFitOrStretch,
Name = name + " Menu Item",
};
row.AddChild(guiWidget);
row.AddChild(new HorizontalSpacer()
{
MinimumSize = new Vector2(minSpacerWidth, 0)
});
foreach (var buttonKvp in buttonKvps)
{
var button = EnumDisplayField.CreateThemedButton(buttonKvp.text, buttonKvp.key, "", theme);
button.Click += buttonKvp.click;
row.AddChild(button);
}
var menuItem = new MenuItemHoldOpen(row, theme)
{
};
this.AddChild(menuItem);
return menuItem;
}
public MenuItem CreateMenuItem(GuiWidget guiWidget, string name, ImageBuffer icon = null)
{
var menuItem = new MenuItem(guiWidget, theme)

View file

@ -608,7 +608,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
sideBar.AddPage(
"Printer",
"Printer".Localize(),
"Printer Settings".Localize(),
new ConfigurePrinterWidget(sliceSettingsWidget.SettingsContext, Printer, theme)
{
HAnchor = HAnchor.Stretch,

View file

@ -89,8 +89,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
public DrawStage DrawStage { get; } = DrawStage.First;
public bool LookingDownOnBed { get; set; }
public bool SelectedObjectUnderBed { get; set; }
public void Draw(GuiWidget sender, DrawEventArgs e, Matrix4X4 itemMaxtrix, WorldView world)
public void Draw(GuiWidget sender, DrawEventArgs e, Matrix4X4 itemMaxtrix, WorldView world)
{
if (!sceneContext.RendererOptions.RenderBed)
{
@ -101,13 +102,24 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
this.EnsureBedTexture(sceneContext.Scene.SelectedItem);
var alpha = 255;
if (SelectedObjectUnderBed)
{
alpha = 200;
}
if (!LookingDownOnBed)
{
alpha = 32;
}
GL.Disable(EnableCap.Lighting);
GLHelper.Render(
sceneContext.Mesh,
theme.UnderBedColor.WithAlpha(32),
Color.White.WithAlpha(alpha),
RenderTypes.Shaded,
world.ModelviewMatrix,
blendTexture: !this.LookingDownOnBed,
forceCullBackFaces: false);
GL.Enable(EnableCap.Lighting);
if (sceneContext.PrinterShape != null)
{

View file

@ -131,11 +131,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
};
toolbar.AddChild(cancelButton);
overflowButton = new OverflowBar.OverflowMenuButton(theme)
overflowButton = new PopupMenuButton("Action".Localize(), theme)
{
Enabled = scene.SelectedItem != null,
DrawArrow = true,
};
overflowButton.ToolTipText = "Selected Object Options".Localize();
overflowButton.ToolTipText = "Object Actions".Localize();
overflowButton.DynamicPopupContent = () =>
{
return ApplicationController.Instance.GetModifyMenu(view3DWidget.sceneContext);
@ -175,7 +176,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
private readonly JsonPathContext pathGetter = new JsonPathContext();
private readonly IconButton applyButton;
private readonly IconButton cancelButton;
private readonly OverflowBar.OverflowMenuButton overflowButton;
private readonly PopupMenuButton overflowButton;
private readonly InteractiveScene scene;
private readonly FlowLayoutWidget primaryActionsPanel;

View file

@ -58,14 +58,14 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
/// </summary>
public class SimpleTabs : FlowLayoutWidget
{
public SimpleTabs(ThemeConfig theme, GuiWidget rightAnchorItem = null)
public SimpleTabs(ThemeConfig theme, string overflowText, GuiWidget rightAnchorItem = null)
: base(FlowDirection.TopToBottom)
{
this.TabContainer = this;
if (rightAnchorItem == null)
{
TabBar = new OverflowBar(theme)
TabBar = new OverflowBar(null, theme, overflowText)
{
HAnchor = HAnchor.Stretch,
VAnchor = VAnchor.Fit
@ -252,7 +252,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
public event EventHandler PlusClicked;
public ChromeTabs(GuiWidget rightAnchorItem, ThemeConfig theme)
: base(theme, rightAnchorItem)
: base(theme, null, rightAnchorItem)
{
leadingTabAdornment = new GuiWidget()
{

View file

@ -214,8 +214,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
zHeightDisplayInfo.Visible = true;
double distanceToHit = Vector3Ex.Dot(mouseEvent3D.info.HitPosition, mouseEvent3D.MouseRay.directionNormal);
hitPlane = new PlaneShape(mouseEvent3D.MouseRay.directionNormal, distanceToHit, null);
var upNormal = Vector3.UnitZ;
var sideNormal = upNormal.Cross(mouseEvent3D.MouseRay.directionNormal).GetNormal();
var planeNormal = upNormal.Cross(sideNormal).GetNormal();
hitPlane = new PlaneShape(new Plane(planeNormal, mouseEvent3D.info.HitPosition), null);
initialHitPosition = mouseEvent3D.info.HitPosition;
transformOnMouseDown = selectedItem.Matrix;

View file

@ -1088,7 +1088,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
}
}
foreach (var item in scene.Descendants().Where(i => i is ICustomEditorDraw customEditorDraw1 && customEditorDraw1.DoEditorDraw(i == selectedItem)))
foreach (var item in scene.Descendants().Where(i => i is IEditorDrawControled customEditorDraw1 && customEditorDraw1.DoEditorDraw(i == selectedItem)))
{
editorDrawItems.Add(item);
}
@ -1126,11 +1126,21 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
var bedNormalInViewSpace = Vector3Ex.TransformNormal(Vector3.UnitZ, World.ModelviewMatrix).GetNormal();
var pointOnBedInViewSpace = Vector3Ex.Transform(new Vector3(10, 10, 0), World.ModelviewMatrix);
var lookingDownOnBed = Vector3Ex.Dot(bedNormalInViewSpace, pointOnBedInViewSpace) < 0;
floorDrawable.LookingDownOnBed = Vector3Ex.Dot(bedNormalInViewSpace, pointOnBedInViewSpace) < 0;
floorDrawable.LookingDownOnBed = lookingDownOnBed;
floorDrawable.SelectedObjectUnderBed = false;
if (selectedItem != null)
{
var aabb = selectedItem.GetAxisAlignedBoundingBox();
if (aabb.MinXYZ.Z < 0)
{
floorDrawable.SelectedObjectUnderBed = true;
}
}
if (lookingDownOnBed)
var renderBedTransparent = !floorDrawable.LookingDownOnBed || floorDrawable.SelectedObjectUnderBed;
if (renderBedTransparent)
{
floorDrawable.Draw(this, e, Matrix4X4.Identity, this.World);
}
@ -1174,7 +1184,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
forceCullBackFaces: false);
}
if (!lookingDownOnBed)
if (!renderBedTransparent)
{
floorDrawable.Draw(this, e, Matrix4X4.Identity, this.World);
}

View file

@ -51,17 +51,28 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
: this(null, theme)
{ }
public OverflowBar(ImageBuffer icon, ThemeConfig theme)
public OverflowBar(ImageBuffer icon, ThemeConfig theme, string text = null)
: base(theme.TabbarPadding)
{
this.theme = theme;
if (icon == null)
{
this.OverflowButton = new OverflowMenuButton(this, theme)
if (text != null)
{
AlignToRightEdge = true,
};
this.OverflowButton = new PopupMenuButton(text, theme)
{
AlignToRightEdge = true,
DrawArrow = true,
};
}
else
{
this.OverflowButton = new OverflowMenuButton(this, theme)
{
AlignToRightEdge = true,
};
}
}
else
{
@ -70,6 +81,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
AlignToRightEdge = true,
};
}
AddMenuItemsFunction(OverflowButton);
// We want to set right margin to overflow button width but width is already scaled - need to inflate value by amount needed to hit width when rescaled in Margin setter
this.ActionArea.Margin = new BorderDouble(right: Math.Ceiling(this.OverflowButton.Width / GuiWidget.DeviceScale));
@ -78,7 +90,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
private ThemeConfig theme;
public OverflowMenuButton OverflowButton { get; }
public PopupMenuButton OverflowButton { get; }
public Action<PopupMenu> ExtendOverflowMenu { get; set; }
@ -120,6 +132,55 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
}
}
private void AddMenuItemsFunction(PopupMenuButton menuButton)
{
menuButton.DynamicPopupContent = () =>
{
var menuTheme = ApplicationController.Instance.MenuTheme;
var popupMenu = new PopupMenu(menuTheme);
// Perform overflow
bool hasOverflowItems = false;
foreach (var widget in this.ActionArea.Children.Where(c => !c.Visible && !ignoredInMenuTypes.Contains(c.GetType())))
{
if (widget is ToolbarSeparator)
{
popupMenu.CreateSeparator();
continue;
}
hasOverflowItems = true;
PopupMenu.MenuItem menuItem;
var iconButton = widget as IconButton;
var iconImage = iconButton?.IconImage;
menuItem = popupMenu.CreateMenuItem(
widget.ToolTipText ?? widget.Text,
iconImage);
menuItem.Enabled = widget.Enabled;
menuItem.Click += (s, e) =>
{
widget.InvokeClick();
};
}
if (hasOverflowItems)
{
popupMenu.CreateSeparator();
}
// Extend menu with non-overflow/standard items
this.OnExtendPopupMenu(popupMenu);
return popupMenu;
};
}
/// <summary>
/// A PopupMenuButton with the standard overflow icon
/// </summary>
@ -142,55 +203,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
public OverflowMenuButton(OverflowBar overflowBar, ImageBuffer icon, ThemeConfig theme)
: base(icon, theme)
{
this.DynamicPopupContent = () =>
{
var menuTheme = ApplicationController.Instance.MenuTheme;
var popupMenu = new PopupMenu(menuTheme);
{
}
// Perform overflow
bool hasOverflowItems = false;
foreach (var widget in overflowBar.ActionArea.Children.Where(c => !c.Visible && !ignoredInMenuTypes.Contains(c.GetType())))
{
if (widget is ToolbarSeparator)
{
popupMenu.CreateSeparator();
continue;
}
hasOverflowItems = true;
PopupMenu.MenuItem menuItem;
var iconButton = widget as IconButton;
var iconImage = iconButton?.IconImage;
menuItem = popupMenu.CreateMenuItem(
widget.ToolTipText ?? widget.Text,
iconImage);
menuItem.Enabled = widget.Enabled;
menuItem.Click += (s, e) =>
{
widget.InvokeClick();
};
}
if (hasOverflowItems)
{
popupMenu.CreateSeparator();
}
// Extend menu with non-overflow/standard items
overflowBar.OnExtendPopupMenu(popupMenu);
return popupMenu;
};
}
private static ImageBuffer CreateOverflowIcon(ThemeConfig theme)
private static ImageBuffer CreateOverflowIcon(ThemeConfig theme)
{
return StaticData.Instance.LoadIcon(Path.Combine("ViewTransformControls", "overflow.png"), 32, 32).SetToColor(theme.TextColor);
}

View file

@ -64,7 +64,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
private Dictionary<PartViewMode, RadioIconButton> viewModes = new Dictionary<PartViewMode, RadioIconButton>();
public PrinterActionsBar(PrinterConfig printer, PrinterTabPage printerTabPage, ThemeConfig theme)
: base(theme)
: base(null, theme, "Printer Options".Localize())
{
this.printer = printer;
this.printerTabPage = printerTabPage;
@ -232,7 +232,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
}
this.OverflowButton.Name = "Printer Overflow Menu";
this.OverflowButton.ToolTipText = "Printer Options".Localize();
this.ExtendOverflowMenu = (popupMenu) =>
{
this.GeneratePrinterOverflowMenu(popupMenu, ApplicationController.Instance.MenuTheme);

View file

@ -298,10 +298,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
// add the options menu
this.AddChild(new HorizontalSpacer());
var overflowIcon = StaticData.Instance.LoadIcon(Path.Combine("ViewTransformControls", "overflow.png"), 32, 32).SetToColor(theme.TextColor);
var optionsButton = new PopupMenuButton(overflowIcon, theme)
optionsButton = new PopupMenuButton("Tools".Localize(), theme)
{
AlignToRightEdge = true
AlignToRightEdge = true,
DrawArrow = true,
};
this.AddChild(optionsButton);
optionsButton.Name = "ToolBar Overflow Menu";
@ -336,6 +336,22 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
private string Default;
private string Hide_All;
private string Expand_All;
private PopupMenuButton optionsButton;
private IEnumerable<OperationGroup> GroupOperations
{
get
{
foreach (var namedAction in SceneOperations.All)
{
if (namedAction is OperationGroup operationGroup)
{
yield return operationGroup;
}
}
}
}
private PopupMenu GenerateToolBarOptionsMenu(ThemeConfig theme)
{
@ -344,36 +360,64 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
Padding = new BorderDouble(0, 7),
};
#if false
// buttons for the control of defaults
var topButtonData = new (string, string)[]
#if true
void DefaultClicked(object e, MouseEventArgs mouseEvent)
{
(nameof(Default), "Default".Localize()),
(nameof(Expand_All), "Expand All".Localize()),
(nameof(Hide_All), "Hide All".Localize()),
foreach (var operationGroup in GroupOperations)
{
switch(operationGroup.Id)
{
case "Path":
case "Printing":
case "Design Apps":
operationGroup.Visible = false;
break;
default:
operationGroup.Collapse = true;
operationGroup.Visible = true;
break;
}
}
optionsButton.InvokeClick();
UiThread.RunOnIdle(optionsButton.InvokeClick);
}
void HideAll(object e, MouseEventArgs mouseEvent)
{
foreach (var operationGroup in GroupOperations)
{
operationGroup.Visible = false;
}
optionsButton.InvokeClick();
UiThread.RunOnIdle(optionsButton.InvokeClick);
}
void ExpandAll(object e, MouseEventArgs mouseEvent)
{
foreach (var operationGroup in GroupOperations)
{
operationGroup.Collapse = false;
operationGroup.Visible = true;
}
optionsButton.InvokeClick();
UiThread.RunOnIdle(optionsButton.InvokeClick);
}
// buttons for the control of defaults
var topButtonData = new (string, string, EventHandler<MouseEventArgs>)[]
{
(nameof(Default), nameof(Default).Replace("_", " ").Localize(), DefaultClicked),
(nameof(Expand_All), nameof(Expand_All).Replace("_", " ").Localize(), ExpandAll),
(nameof(Hide_All), nameof(Hide_All).Replace("_", " ").Localize(), HideAll),
};
popupMenu.CreateButtonSelectMenuItem("Group Setings".Localize(), topButtonData, nameof(Default), (value) =>
{
switch (value)
{
case nameof(Expanded):
operationGroup.Collapse = false;
operationGroup.Visible = true;
break;
popupMenu.CreateButtonMenuItem("Design Tools".Localize(), topButtonData, 40 * GuiWidget.DeviceScale, true);
case nameof(Collapsed):
operationGroup.Collapse = true;
operationGroup.Visible = true;
break;
case nameof(Hidden):
operationGroup.Visible = false;
break;
}
}, 40 * GuiWidget.DeviceScale);
popupMenu.CreateSeparator();
popupMenu.CreateSeparator(5);
#endif
// the buttons per setting
@ -384,38 +428,35 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
(nameof(Hidden), "Hide".Localize()),
};
foreach (var namedAction in SceneOperations.All)
foreach (var operationGroup in GroupOperations)
{
if (namedAction is OperationGroup operationGroup)
var startingValue = operationGroup.Collapse ? nameof(Collapsed) : nameof(Expanded);
if (!operationGroup.Visible)
{
var startingValue = operationGroup.Collapse ? nameof(Collapsed) : nameof(Expanded);
if(!operationGroup.Visible)
{
startingValue = nameof(Hidden);
}
popupMenu.CreateButtonSelectMenuItem(operationGroup.Title, buttonData, startingValue, (value) =>
{
switch (value)
{
case nameof(Expanded):
operationGroup.Collapse = false;
operationGroup.Visible = true;
break;
case nameof(Collapsed):
operationGroup.Collapse = true;
operationGroup.Visible = true;
break;
case nameof(Hidden):
operationGroup.Visible = false;
break;
}
}, 40 * GuiWidget.DeviceScale);
popupMenu.CreateSeparator();
startingValue = nameof(Hidden);
}
popupMenu.CreateButtonSelectMenuItem(operationGroup.Title, buttonData, startingValue, (value) =>
{
switch (value)
{
case nameof(Expanded):
operationGroup.Collapse = false;
operationGroup.Visible = true;
break;
case nameof(Collapsed):
operationGroup.Collapse = true;
operationGroup.Visible = true;
break;
case nameof(Hidden):
operationGroup.Visible = false;
break;
}
}, 40 * GuiWidget.DeviceScale);
popupMenu.CreateSeparator();
};
return popupMenu;

View file

@ -78,7 +78,12 @@ namespace MatterHackers.MatterControl.SetupWizard
var profile = ProfileManager.Instance[printer.Settings.ID];
var results = await ApplicationController.GetProfileHistory?.Invoke(profile.DeviceToken);
Dictionary<string, string> results = null;
if (ApplicationController.GetProfileHistory != null)
{
results = await ApplicationController.GetProfileHistory.Invoke(profile.DeviceToken);
}
printerProfileData = results;
if(printerProfileData != null)
{

View file

@ -580,7 +580,12 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
private static async Task<PrinterSettings> GetFirstValidHistoryItem(PrinterInfo printerInfo)
{
var recentProfileHistoryItems = await ApplicationController.GetProfileHistory?.Invoke(printerInfo.DeviceToken);
Dictionary<string, string> recentProfileHistoryItems = null;
if (ApplicationController.GetProfileHistory != null)
{
recentProfileHistoryItems = await ApplicationController.GetProfileHistory.Invoke(printerInfo.DeviceToken);
}
if (recentProfileHistoryItems != null)
{
// Iterate history, skipping the first item, limiting to the next five, attempt to load and return the first success

View file

@ -182,7 +182,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
string databaseMRUKey,
string justMySettingsTitle,
Action<PopupMenu> extendPopupMenu = null)
: base(theme)
: base(theme, "View".Localize())
{
using (this.LayoutLock())
{

View file

@ -294,6 +294,22 @@ namespace MatterHackers.MatterControl.SlicerConfiguration
return radioButton;
}
public static TextButton CreateThemedButton(string text, string key, string toolTipText, ThemeConfig theme)
{
var button = new TextButton(text, theme)
{
VAnchor = VAnchor.Center | VAnchor.Fit,
BackgroundRadius = (theme.ButtonRadius + 4) * GuiWidget.DeviceScale,
Margin = new BorderDouble(5, 0, 0, 0),
Padding = new BorderDouble(9, 5),
// BackgroundInset = new BorderDouble(5, 4),
BackgroundColor = theme.MinimalShade,
ToolTipText = toolTipText
};
return button;
}
private void AddIconRow(List<(string key, string name, string description)> items)
{
var iconsRow = new FlowLayoutWidget();

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View file

@ -1984,6 +1984,9 @@ Translated:Fuzzy Frequency
English:Fuzzy Thickness
Translated:Fuzzy Thickness
English:G Code To Send
Translated:G Code To Send
English:G Key
Translated:G Key
@ -4369,6 +4372,9 @@ Translated:Scale Offset
English:Scale Type
Translated:Scale Type
English:Scripting
Translated:Scripting
English:SD Card
Translated:SD Card
@ -4459,6 +4465,9 @@ Translated:Send
English:Send email notifications
Translated:Send email notifications
English:Send G-Code
Translated:Send G-Code
English:Send SMS notifications
Translated:Send SMS notifications

@ -1 +1 @@
Subproject commit b2b6261e0936f91a9f018da860c636dfafef2d91
Subproject commit cce755cd9c356a96edb641ed515113caa6bf6ad3

@ -1 +1 @@
Subproject commit 238b25271497943ece9ab855b119810abe2c9809
Subproject commit 338231d1f1bafe87d200435b065035846e75ca60

View file

@ -406,7 +406,7 @@ namespace MatterHackers.MatterControl.Tests.Automation
// print a part
testRunner.AddItemToBed()
.AddItemToBed(partName: "Row Item Set Temperature")
.AddItemToBed("Scripting Row Item Collection", "Row Item Set Temperature")
.DragDropByName("MoveInZControl", "MoveInZControl", offsetDrag: new Point2D(0, 0), offsetDrop: new Point2D(0, 10))
.ClickByName("Temperature Edit")
.Type("222.2")

View file

@ -586,6 +586,7 @@ namespace MatterHackers.MatterControl.Tests.Automation
.SwitchToSliceSettings()
.ClickByName("Slice Settings Overflow Menu")
.ClickByName("Advanced Menu Item")
.Delay()
.SelectSliceSettingsField(SettingsKey.bed_temperature)
.SelectSliceSettingsField(SettingsKey.temperature)
// Uncheck Has Heated Bed checkbox and make sure Bed Temp Textbox is not visible

View file

@ -717,6 +717,7 @@ namespace MatterHackers.MatterControl.Tests.Automation
break;
case "Calibration Parts Row Item Collection":
case "Scripting Row Item Collection":
case "Primitives Row Item Collection":
// If visible, navigate into Libraries container before opening target
testRunner.DoubleClickByName("Design Apps Row Item Collection")
@ -1289,13 +1290,10 @@ namespace MatterHackers.MatterControl.Tests.Automation
if (!testRunner.NameExists("Printer Tab", 0.1))
{
testRunner.ClickByName("Printer Overflow Menu")
.ClickByName("Show Printer Menu Item");
if (!pinSettingsOpen)
{
.Delay()
.ClickByName("Show Printer Menu Item")
// close the menu
testRunner.ClickByName("Printer Overflow Menu");
}
.ClickByName("Printer Overflow Menu");
}
if (pinSettingsOpen)