Merge pull request #4765 from larsbrubaker/master

master
This commit is contained in:
Lars Brubaker 2020-05-30 22:25:23 -07:00 committed by GitHub
commit 02faf202a5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 214 additions and 109 deletions

View file

@ -36,17 +36,17 @@ namespace MatterHackers.MatterControl
{
public class NamedAction
{
public string Title { get; set; }
public string Shortcut { get; set; }
public Action Action { get; set; }
public ImageBuffer Icon { get; set; }
public Func<bool> IsEnabled { get; set; }
public ImageBuffer Icon { get; set; }
public string ID { get; set; }
public string Shortcut { get; set; }
public string Title { get; set; }
}
public class ActionSeparator : NamedAction
@ -60,6 +60,11 @@ namespace MatterHackers.MatterControl
public Action<bool> SetIsActive { get; set; }
}
public class NamedActionGroup : NamedAction
{
public NamedAction[] Group { get; set; }
}
public static class NamedActionExtensions
{
public static void Add(this List<NamedAction> list, string title, Action action)

View file

@ -319,9 +319,7 @@ namespace MatterHackers.MatterControl
var actions = new[]
{
new ActionSeparator(),
workspaceActions["Cut"],
workspaceActions["Copy"],
workspaceActions["Paste"],
workspaceActions["Edit"],
new ActionSeparator(),
new NamedAction()
{
@ -578,7 +576,7 @@ namespace MatterHackers.MatterControl
if (e.Operation != WorkspacesChangedEventArgs.OperationType.Restore)
{
UiThread.RunOnIdle(async() =>
UiThread.RunOnIdle(async () =>
{
await ApplicationController.Instance.PersistUserTabs();
});
@ -1158,38 +1156,35 @@ namespace MatterHackers.MatterControl
|| (sceneContext.EditContext.SourceItem is ILibraryAsset libraryAsset
&& string.Equals(Path.GetExtension(libraryAsset.FileName), ".gcode", StringComparison.OrdinalIgnoreCase))
},
new NamedAction()
new NamedActionGroup()
{
ID = "Cut",
Title = "Cut".Localize(),
Shortcut = "Ctrl+X",
Action = () =>
ID = "Edit",
Title = "Edit",
Group = new NamedAction[]
{
sceneContext.Scene.Cut();
new NamedAction()
{
ID = "Cut",
Title = "Cut".Localize(),
Action = () => sceneContext.Scene.Cut(),
IsEnabled = () => sceneContext.Scene.SelectedItem != null
},
new NamedAction()
{
ID = "Copy",
Title = "Copy".Localize(),
Action = () => sceneContext.Scene.Copy(),
IsEnabled = () => sceneContext.Scene.SelectedItem != null
},
new NamedAction()
{
ID = "Paste",
Title = "Paste".Localize(),
Action = () => sceneContext.Paste(),
IsEnabled = () => Clipboard.Instance.ContainsImage || Clipboard.Instance.GetText() == "!--IObjectSelection--!"
}
},
IsEnabled = () => sceneContext.Scene.SelectedItem != null
},
new NamedAction()
{
ID = "Copy",
Title = "Copy".Localize(),
Shortcut = "Ctrl+C",
Action = () =>
{
sceneContext.Scene.Copy();
},
IsEnabled = () => sceneContext.Scene.SelectedItem != null
},
new NamedAction()
{
ID = "Paste",
Title = "Paste".Localize(),
Shortcut = "Ctrl+V",
Action = () =>
{
sceneContext.Paste();
},
IsEnabled = () => Clipboard.Instance.ContainsImage || Clipboard.Instance.GetText() == "!--IObjectSelection--!"
IsEnabled = () => true,
},
new NamedAction()
{
@ -2765,6 +2760,11 @@ namespace MatterHackers.MatterControl
public void NotifyPrintersTabRightElement(GuiWidget sourceExentionArea)
{
AddPrintersTabRightElement?.Invoke(this, new WidgetSourceEventArgs(sourceExentionArea));
// after adding content to the right side make sure we hold the space in the tab bar
var leftChild = sourceExentionArea.Parent.Children.First();
var padding = leftChild.Padding;
leftChild.Padding = new BorderDouble(padding.Left, padding.Bottom, sourceExentionArea.Width, padding.Height);
}
public async Task PrintPart(EditContext editContext, PrinterConfig printer, IProgress<ProgressStatus> reporter, CancellationToken cancellationToken)

View file

@ -415,30 +415,83 @@ namespace MatterHackers.MatterControl
}
else
{
PopupMenu.MenuItem menuItem;
if (menuAction is NamedBoolAction boolAction)
if (menuAction is NamedActionGroup namedActionButtons)
{
menuItem = popupMenu.CreateBoolMenuItem(menuAction.Title, boolAction.GetIsActive, boolAction.SetIsActive);
var content = new FlowLayoutWidget()
{
HAnchor = HAnchor.Fit | HAnchor.Stretch
};
var textWidget = new TextWidget(menuAction.Title, pointSize: this.DefaultFontSize, textColor: this.TextColor)
{
// Padding = MenuPadding,
VAnchor = VAnchor.Center
};
content.AddChild(textWidget);
content.AddChild(new HorizontalSpacer());
foreach (var actionButton in namedActionButtons.Group)
{
var button = new TextButton(actionButton.Title, this)
{
Border = new BorderDouble(1, 0, 0, 0),
BorderColor = this.MinimalShade,
HoverColor = this.AccentMimimalOverlay,
Enabled = actionButton.IsEnabled()
};
content.AddChild(button);
if (actionButton.IsEnabled())
{
button.Click += (s, e) =>
{
actionButton.Action();
popupMenu.Unfocus();
};
}
}
var menuItem = new PopupMenu.MenuItem(content, this)
{
HAnchor = HAnchor.Fit | HAnchor.Stretch,
VAnchor = VAnchor.Fit,
HoverColor = Color.Transparent,
};
popupMenu.AddChild(menuItem);
menuItem.Padding = new BorderDouble(menuItem.Padding.Left,
menuItem.Padding.Bottom,
0,
menuItem.Padding.Top);
}
else
{
menuItem = popupMenu.CreateMenuItem(menuAction.Title, menuAction.Icon, menuAction.Shortcut);
}
PopupMenu.MenuItem menuItem;
menuItem.Name = $"{menuAction.Title} Menu Item";
menuItem.Enabled = menuAction.Action != null
&& menuAction.IsEnabled?.Invoke() != false;
menuItem.ClearRemovedFlag();
if (menuItem.Enabled)
{
menuItem.Click += (s, e) =>
if (menuAction is NamedBoolAction boolAction)
{
menuAction.Action();
};
menuItem = popupMenu.CreateBoolMenuItem(menuAction.Title, boolAction.GetIsActive, boolAction.SetIsActive);
}
else
{
menuItem = popupMenu.CreateMenuItem(menuAction.Title, menuAction.Icon, menuAction.Shortcut);
}
menuItem.Name = $"{menuAction.Title} Menu Item";
menuItem.Enabled = menuAction is NamedActionGroup
|| (menuAction.Action != null && menuAction.IsEnabled?.Invoke() != false);
menuItem.ClearRemovedFlag();
if (menuItem.Enabled)
{
menuItem.Click += (s, e) =>
{
menuAction.Action();
};
}
}
}
}

View file

@ -41,19 +41,19 @@ namespace MatterHackers.Agg.UI
{
public Action<ISceneContext> Action { get; set; }
public Func<ISceneContext, bool> IsEnabled { get; set; } = (sceneContext) => true;
public Type OperationType { get; set; }
public Func<bool, ImageBuffer> Icon { get; set; }
public Func<string> TitleResolver { get; set; }
public string Title => this.TitleResolver?.Invoke();
public Func<ISceneContext, bool> IsEnabled { get; set; } = (sceneContext) => true;
public Func<string> HelpTextResolver { get; set; }
public Func<string> TitleResolver { get; set; }
public string HelpText => this.HelpTextResolver?.Invoke();
public string Title => this.TitleResolver?.Invoke();
public Type OperationType { get; set; }
}
public class SceneSelectionSeparator : SceneSelectionOperation

View file

@ -85,6 +85,14 @@ namespace MatterHackers.MatterControl.CustomWidgets
this.Invalidate();
}
protected override void OnClick(MouseEventArgs mouseEvent)
{
if (mouseEvent.Button == MouseButtons.Left)
{
base.OnClick(mouseEvent);
}
}
public override void OnKeyUp(KeyEventArgs keyEvent)
{
if (keyEvent.KeyCode == Keys.Enter

View file

@ -38,6 +38,7 @@ using MatterHackers.Agg.Platform;
using MatterHackers.Agg.UI;
using MatterHackers.DataConverters3D;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.MatterControl.Library;
using MatterHackers.MatterControl.PartPreviewWindow.PlusTab;
using MatterHackers.MatterControl.PrintLibrary;
@ -752,9 +753,20 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
AggContext.StaticData.LoadIcon("cube.png", 16, 16, theme.InvertIcons))
{
Name = "newPart" + tabControl.AllTabs.Count(),
MinimumSize = new Vector2(120, theme.TabButtonHeight)
MinimumSize = new Vector2(120, theme.TabButtonHeight),
};
partTab.MaximumSize = new Vector2(partTab.Width, partTab.MaximumSize.Y);
partTab.HAnchor = HAnchor.Stretch;
var textWidget = partTab.Descendants<TextWidget>().First();
textWidget.HAnchor = HAnchor.Stretch;
var tabPill = partTab.Descendants<SimpleTab.TabPill>().First();
partTab.ToolTipText = textWidget.Text;
tabPill.HAnchor = HAnchor.Stretch;
var tabPillMarign = tabPill.Margin;
tabPill.Margin = new BorderDouble(tabPillMarign.Left, tabPillMarign.Bottom, tabPillMarign.Right + 10, tabPillMarign.Top);
tabControl.AddTab(partTab);
void Tab_CloseClicked(object sender, EventArgs args)

View file

@ -123,7 +123,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
public PopupMenu SubMenu { get; set; }
public SubMenuItemButton(GuiWidget content, ThemeConfig theme) : base(content, theme)
{
}
@ -308,7 +307,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
UiThread.RunOnIdle(() =>
{
populateSubMenu(subMenu);
systemWindow.ShowPopup(
new MatePoint(subMenuItemButton)
{
@ -319,15 +318,14 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
Mate = new MateOptions(MateEdge.Left, MateEdge.Top),
AltMate = new MateOptions(MateEdge.Right, MateEdge.Top)
}
);// altBounds: new RectangleDouble(mouseEvent.X + 1, mouseEvent.Y + 1, mouseEvent.X + 1, mouseEvent.Y + 1));
}); // altBounds: new RectangleDouble(mouseEvent.X + 1, mouseEvent.Y + 1, mouseEvent.X + 1, mouseEvent.Y + 1));
});
subMenu.Closed += (s1, e1) =>
{
subMenu.ClearRemovedFlag();
subMenuItemButton.SubMenu = null;
if(!this.ContainsFocus)
if (!this.ContainsFocus)
{
this.Close();
}
@ -365,7 +363,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
public MenuItem CreateBoolMenuItem(GuiWidget guiWidget, string name, Func<bool> getter, Action<bool> setter, bool useRadioStyle = false, IList<GuiWidget> siblingRadioButtonList = null)
{
bool isChecked = (getter?.Invoke() == true);
bool isChecked = getter?.Invoke() == true;
MenuItem menuItem;
@ -397,7 +395,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
return;
}
isChecked = radioMenu.Checked = !radioMenu.Checked;
isChecked = radioMenu.Checked = !radioMenu.Checked;
}
else if (menuItem is CheckboxMenuItem checkboxMenu)
{
@ -433,10 +431,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
private GuiWidget content;
public MenuItem(GuiWidget content, ThemeConfig theme)
: base (theme)
: base(theme)
{
// Inflate padding to match the target (MenuGutterWidth) after scale operation in assignment
this.Padding = new BorderDouble(left: Math.Ceiling(theme.MenuGutterWidth / GuiWidget.DeviceScale) , right: 15);
this.Padding = new BorderDouble(left: Math.Ceiling(theme.MenuGutterWidth / DeviceScale), right: 15);
this.HAnchor = HAnchor.MaxFitOrStretch;
this.VAnchor = VAnchor.Fit;
this.MinimumSize = new Vector2(150 * GuiWidget.DeviceScale, theme.ButtonHeight);
@ -455,6 +453,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
public ImageBuffer Image { get; set; }
private ImageBuffer _disabledImage;
public ImageBuffer DisabledImage
{
get
@ -491,7 +490,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
var x = this.LocalBounds.Left + (this.GutterWidth / 2 - this.Image.Width / 2);
var y = this.Size.Y / 2 - this.Image.Height / 2;
graphics2D.Render((this.Enabled) ? this.Image : this.DisabledImage, (int)x, (int)y);
graphics2D.Render(this.Enabled ? this.Image : this.DisabledImage, (int)x, (int)y);
}
base.OnDraw(graphics2D);

View file

@ -76,12 +76,21 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
scene = sceneContext.Scene;
// put in the container for dynamic actions
primaryActionsPanel = new FlowLayoutWidget()
{
HAnchor = HAnchor.Fit,
VAnchor = VAnchor.Center | VAnchor.Fit
};
toolbar.AddChild(primaryActionsPanel);
// put in a make permanent button
var icon = AggContext.StaticData.LoadIcon("noun_766157.png", 16, 16, theme.InvertIcons).SetPreMultiply();
var icon = AggContext.StaticData.LoadIcon("apply.png", 16, 16, theme.InvertIcons).SetPreMultiply();
flattenButton = new IconButton(icon, theme)
{
Margin = theme.ButtonSpacing,
ToolTipText = "Flatten".Localize(),
ToolTipText = "Apply".Localize(),
Enabled = true
};
flattenButton.Click += (s, e) =>
@ -103,10 +112,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
toolbar.AddChild(flattenButton);
// put in a remove button
removeButton = new IconButton(AggContext.StaticData.LoadIcon("remove.png", 16, 16, theme.InvertIcons), theme)
removeButton = new IconButton(AggContext.StaticData.LoadIcon("cancel.png", 16, 16, theme.InvertIcons), theme)
{
Margin = theme.ButtonSpacing,
ToolTipText = "Delete".Localize(),
ToolTipText = "Cancel".Localize(),
Enabled = scene.SelectedItem != null
};
removeButton.Click += (s, e) =>
@ -119,14 +128,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
};
toolbar.AddChild(removeButton);
primaryActionsPanel = new FlowLayoutWidget()
{
HAnchor = HAnchor.Fit,
VAnchor = VAnchor.Center | VAnchor.Fit
};
toolbar.AddChild(primaryActionsPanel);
overflowButton = new OverflowBar.OverflowMenuButton(theme)
{
Enabled = scene.SelectedItem != null,
@ -229,6 +230,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
}
}
if(primaryActionsPanel.Children.Any())
{
// add in a separator from the apply and cancel buttons
primaryActionsPanel.AddChild(new ToolbarSeparator(theme));
}
editorSectionWidget.Text = selectedItem.Name ?? selectedItemType.Name;
HashSet<IObject3DEditor> mappedEditors = ApplicationController.Instance.Extensions.GetEditorsForType(selectedItemType);
@ -430,7 +437,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
flattenButton.Enabled = selectedItem != null
&& (selectedItem is GroupObject3D
|| selectedItem.GetType() == typeof(Object3D)
|| (selectedItem.GetType() == typeof(Object3D) && selectedItem.Children.Any())
|| selectedItem.CanFlatten);
removeButton.Enabled = selectedItem != null;
overflowButton.Enabled = selectedItem != null;

View file

@ -191,7 +191,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
// When the widgets position changes, sync the popup position
systemWindow?.AddChild(popup.Widget);
if(secondsToClose > 0)
if (secondsToClose > 0)
{
UiThread.RunOnIdle(() => anchor_Closed(null, null), secondsToClose);
}

View file

@ -384,19 +384,24 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
tabPill = new TabPill(tabLabel, theme.TextColor, tabImageUrl, pointSize);
}
tabPill.Margin = (hasClose) ? new BorderDouble(right: 16) : 0;
tabPill.Margin = hasClose ? new BorderDouble(right: 16) : 0;
this.AddChild(tabPill);
if (hasClose)
{
// var fadeRegion = new LeftClipFlowLayoutWidget();
// fadeRegion.HAnchor |= HAnchor.Right;
// this.AddChild(fadeRegion);
var closeButton = theme.CreateSmallResetButton();
closeButton.HAnchor = HAnchor.Right;
closeButton.Margin = new BorderDouble(right: 7, top: 1);
closeButton.Name = "Close Tab Button";
closeButton.ToolTipText = "Close".Localize();
closeButton.Click += (s, e) => ConditionallyCloseTab();
closeButton.HAnchor |= HAnchor.Right;
// fadeRegion.AddChild(closeButton);
this.AddChild(closeButton);
}
}
@ -455,13 +460,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
});
}
protected class TabPill : FlowLayoutWidget
public class TabPill : FlowLayoutWidget
{
private TextWidget label;
private ImageWidget imageWidget;
public TabPill(string tabTitle, Color textColor, string imageUrl = null, double pointSize = 12)
: this (tabTitle, textColor, string.IsNullOrEmpty(imageUrl) ? null : new ImageBuffer(16, 16).CreateScaledImage(GuiWidget.DeviceScale), pointSize)
: this(tabTitle, textColor, string.IsNullOrEmpty(imageUrl) ? null : new ImageBuffer(16, 16).CreateScaledImage(GuiWidget.DeviceScale), pointSize)
{
if (imageWidget != null
&& !string.IsNullOrEmpty(imageUrl))
@ -577,8 +582,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
int position = siblings.IndexOf(this);
//MainTab leftSibling = (position > 0) ? siblings[position - 1] : null;
//MainTab rightSibling = (position < siblings.Count - 1) ? siblings[position + 1] : null;
// MainTab leftSibling = (position > 0) ? siblings[position - 1] : null;
// MainTab rightSibling = (position < siblings.Count - 1) ? siblings[position + 1] : null;
var activeTab = parentTabControl.ActiveTab;
@ -598,6 +603,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
tabShape.LineTo(rect.Right, rect.Bottom);
}
tabShape.LineTo(rect.Right - tabInsetDistance, rect.Bottom);
tabShape.LineTo(rect.Left + tabInsetDistance, rect.Bottom);
if (!drawLeftTabOverlap)

View file

@ -240,6 +240,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
}
bool buttonIsBeingClicked;
private void SwitchModes_Click(object sender, MouseEventArgs e)
{
buttonIsBeingClicked = true;
@ -260,6 +261,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
printer.ViewState.ViewMode = PartViewMode.Model;
}
}
buttonIsBeingClicked = false;
}
@ -363,7 +365,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
Title = "Restore Settings".Localize(),
Action = () =>
{
DialogWindow.Show(new PrinterProfileHistoryPage(printer));
}
},
@ -445,6 +446,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
DialogWindow.Show(repetierEEPromPage);
}
break;
case FirmwareTypes.Marlin:
@ -462,6 +464,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
DialogWindow.Show(marlinEEPromPage);
}
break;
default:

View file

@ -1537,12 +1537,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
new MatePoint(this)
{
Mate = new MateOptions(MateEdge.Left, MateEdge.Top),
AltMate = new MateOptions(MateEdge.Left, MateEdge.Top)
AltMate = new MateOptions(MateEdge.Right, MateEdge.Bottom)
},
new MatePoint(menu)
{
Mate = new MateOptions(MateEdge.Left, MateEdge.Top),
AltMate = new MateOptions(MateEdge.Left, MateEdge.Top)
AltMate = new MateOptions(MateEdge.Right, MateEdge.Bottom)
},
altBounds: new RectangleDouble(mouseEvent.X + 1, mouseEvent.Y + 1, mouseEvent.X + 1, mouseEvent.Y + 1));
}
@ -1585,12 +1585,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
new MatePoint(this)
{
Mate = new MateOptions(MateEdge.Left, MateEdge.Bottom),
AltMate = new MateOptions(MateEdge.Left, MateEdge.Top)
AltMate = new MateOptions(MateEdge.Right, MateEdge.Top)
},
new MatePoint(popupMenu)
{
Mate = new MateOptions(MateEdge.Left, MateEdge.Top),
AltMate = new MateOptions(MateEdge.Left, MateEdge.Top)
Mate = new MateOptions(MateEdge.Left, MateEdge.Bottom),
AltMate = new MateOptions(MateEdge.Right, MateEdge.Top)
},
altBounds: popupBounds);
}

View file

@ -574,9 +574,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
var actions = new NamedAction[] {
new ActionSeparator(),
workspaceActions["Cut"],
workspaceActions["Copy"],
workspaceActions["Paste"],
workspaceActions["Edit"],
new ActionSeparator(),
workspaceActions["Print"],
new ActionSeparator(),

View file

@ -125,8 +125,7 @@ namespace Markdig.Renderers.Agg.Inlines
{
WebCache.RetrieveImageSquenceAsync(imageSequence, ImageUrl, () =>
{
MinimumSize = new Vector2(Math.Max(20 * DeviceScale, MinimumSize.X), MinimumSize.Y);
MaximumSize = new Vector2(imageSequence.Width, imageSequence.Height);
this.MinStretchOrFitHorizontal(20, imageSequence.Width);
UiThread.RunOnIdle(() =>
{
if (aggRenderer.RootWidget.Parents<MarkdownWidget>().FirstOrDefault() is MarkdownWidget markdownWidget)
@ -143,6 +142,21 @@ namespace Markdig.Renderers.Agg.Inlines
base.OnDraw(graphics2D);
}
/// <summary>
/// Sets this control to Stretch and all direct parent FlowLayoutWidgets to Stretch, it then ensures
/// this and all direct parent FlowLayouts have a max width of the contents of this.
/// </summary>
/// <param name="absoluteMinWidth">The minimum size will be set to the larger of the existing minimum size or this value.</param>
/// <param name="absoluteMaxWidth">The maximum size will be set to this value.</param>
private void MinStretchOrFitHorizontal(double absoluteMinWidth, double absoluteMaxWidth)
{
this.HAnchor = HAnchor.Stretch;
MinimumSize = new Vector2(Math.Max(absoluteMinWidth * DeviceScale, MinimumSize.X), MinimumSize.Y);
MaximumSize = new Vector2(absoluteMaxWidth, MaximumSize.Y);
}
public string ImageUrl { get; }
private string LinkUrl { get; }

BIN
StaticData/Icons/apply.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
StaticData/Icons/cancel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -1 +1 @@
Subproject commit 924fcb33e812d9e2b3014bd00283d5c43045039e
Subproject commit 157e57e1fb2081b38dccd59b3eab4300fb18845a

@ -1 +1 @@
Subproject commit 9449ca5a432c5219508f786e4c7c9078ebf49b59
Subproject commit d712fdb82c56c66ff5650002a61ffe45a54aa65f