diff --git a/MatterControlLib/ApplicationView/BrandMenuButton.cs b/MatterControlLib/ApplicationView/BrandMenuButton.cs index 9fd10783f..e4a3edaca 100644 --- a/MatterControlLib/ApplicationView/BrandMenuButton.cs +++ b/MatterControlLib/ApplicationView/BrandMenuButton.cs @@ -53,7 +53,7 @@ namespace MatterHackers.MatterControl this.HAnchor = HAnchor.Fit; this.Margin = 0; - this.DynamicPopupContent = () => BrandMenuButton.CreatePopupMenu(); + this.DynamicPopupContent = () => BrandMenuButton.CreatePopupMenu(theme); var row = new FlowLayoutWidget() { @@ -80,7 +80,7 @@ namespace MatterHackers.MatterControl } } - private static PopupMenu CreatePopupMenu() + private static PopupMenu CreatePopupMenu(ThemeConfig theme) { var menuTheme = ApplicationController.Instance.MenuTheme; diff --git a/MatterControlLib/ApplicationView/Themes/ThemeConfigExtensions.cs b/MatterControlLib/ApplicationView/Themes/ThemeConfigExtensions.cs index 5f059c1a0..44b0072c8 100644 --- a/MatterControlLib/ApplicationView/Themes/ThemeConfigExtensions.cs +++ b/MatterControlLib/ApplicationView/Themes/ThemeConfigExtensions.cs @@ -45,26 +45,26 @@ namespace MatterHackers.MatterControl private static double MicroButtonWidth => 30 * GuiWidget.DeviceScale; - public static SectionWidget ApplyBoxStyle(this ThemeConfig config, SectionWidget sectionWidget) + public static SectionWidget ApplyBoxStyle(this ThemeConfig theme, SectionWidget sectionWidget) { - return config.ApplyBoxStyle( + return theme.ApplyBoxStyle( sectionWidget, - config.SectionBackgroundColor, - margin: new BorderDouble(config.DefaultContainerPadding, 0, config.DefaultContainerPadding, config.DefaultContainerPadding)); + theme.SectionBackgroundColor, + margin: new BorderDouble(theme.DefaultContainerPadding, 0, theme.DefaultContainerPadding, theme.DefaultContainerPadding)); } // ApplySquareBoxStyle - public static SectionWidget ApplyBoxStyle(this ThemeConfig config, SectionWidget sectionWidget, BorderDouble margin) + public static SectionWidget ApplyBoxStyle(this ThemeConfig theme, SectionWidget sectionWidget, BorderDouble margin) { - sectionWidget.BackgroundColor = config.SectionBackgroundColor; + sectionWidget.BackgroundColor = theme.SectionBackgroundColor; sectionWidget.Margin = 0; sectionWidget.Border = new BorderDouble(bottom: 1); - sectionWidget.BorderColor = config.RowBorder; + sectionWidget.BorderColor = theme.RowBorder; return sectionWidget; } - public static SectionWidget ApplyBoxStyle(this ThemeConfig config, SectionWidget sectionWidget, Color backgroundColor, BorderDouble margin) + public static SectionWidget ApplyBoxStyle(this ThemeConfig theme, SectionWidget sectionWidget, Color backgroundColor, BorderDouble margin) { // Enforce panel padding // sectionWidget.ContentPanel.Padding = new BorderDouble(10, 0, 10, 2); @@ -78,11 +78,11 @@ namespace MatterHackers.MatterControl return sectionWidget; } - public static void ApplyPrimaryActionStyle(this ThemeConfig config, GuiWidget guiWidget) + public static void ApplyPrimaryActionStyle(this ThemeConfig theme, GuiWidget guiWidget) { - guiWidget.BackgroundColor = new Color(config.AccentMimimalOverlay, 50); + guiWidget.BackgroundColor = new Color(theme.AccentMimimalOverlay, 50); - Color hoverColor = config.AccentMimimalOverlay; + Color hoverColor = theme.AccentMimimalOverlay; switch (guiWidget) { @@ -100,28 +100,28 @@ namespace MatterHackers.MatterControl } } - public static SolidSlider ApplySliderStyle(this ThemeConfig config, SolidSlider solidSlider) + public static SolidSlider ApplySliderStyle(this ThemeConfig theme, SolidSlider solidSlider) { - solidSlider.View.TrackColor = config.SlightShade; + solidSlider.View.TrackColor = theme.SlightShade; solidSlider.View.TrackRadius = 4; return solidSlider; } - public static DoubleSolidSlider ApplySliderStyle(this ThemeConfig config, DoubleSolidSlider solidSlider) + public static DoubleSolidSlider ApplySliderStyle(this ThemeConfig theme, DoubleSolidSlider solidSlider) { - solidSlider.View.TrackColor = config.SlightShade; + solidSlider.View.TrackColor = theme.SlightShade; solidSlider.View.TrackRadius = 4; return solidSlider; } - public static JogControls.ExtrudeButton CreateExtrudeButton(this ThemeConfig config, PrinterConfig printer, string label, double movementFeedRate, int extruderNumber, bool levelingButtons = false) + public static JogControls.ExtrudeButton CreateExtrudeButton(this ThemeConfig theme, PrinterConfig printer, string label, double movementFeedRate, int extruderNumber, bool levelingButtons = false) { - return new JogControls.ExtrudeButton(printer, label, movementFeedRate, extruderNumber, config) + return new JogControls.ExtrudeButton(printer, label, movementFeedRate, extruderNumber, theme) { - BackgroundColor = config.MinimalShade, - BorderColor = config.BorderColor40, + BackgroundColor = theme.MinimalShade, + BorderColor = theme.BorderColor40, BackgroundOutlineWidth = 1, VAnchor = VAnchor.Absolute, HAnchor = HAnchor.Absolute, @@ -132,7 +132,7 @@ namespace MatterHackers.MatterControl }; } - public static FlowLayoutWidget CreateMenuItems(this ThemeConfig config, PopupMenu popupMenu, IEnumerable menuActions) + public static FlowLayoutWidget CreateMenuItems(this ThemeConfig theme, PopupMenu popupMenu, IEnumerable menuActions) { // Create menu items in the DropList for each element in this.menuActions foreach (var menuAction in menuActions) @@ -150,7 +150,7 @@ namespace MatterHackers.MatterControl HAnchor = HAnchor.Fit | HAnchor.Stretch }; - var textWidget = new TextWidget(menuAction.Title, pointSize: config.DefaultFontSize, textColor: config.TextColor) + var textWidget = new TextWidget(menuAction.Title, pointSize: theme.DefaultFontSize, textColor: theme.TextColor) { // Padding = MenuPadding, VAnchor = VAnchor.Center @@ -161,11 +161,11 @@ namespace MatterHackers.MatterControl foreach (var actionButton in namedActionButtons.Group) { - var button = new TextButton(actionButton.Title, config) + var button = new TextButton(actionButton.Title, theme) { Border = new BorderDouble(1, 0, 0, 0), - BorderColor = config.MinimalShade, - HoverColor = config.AccentMimimalOverlay, + BorderColor = theme.MinimalShade, + HoverColor = theme.AccentMimimalOverlay, Enabled = actionButton.IsEnabled() }; @@ -181,7 +181,7 @@ namespace MatterHackers.MatterControl } } - var menuItem = new PopupMenu.MenuItem(content, config) + var menuItem = new PopupMenu.MenuItem(content, theme) { HAnchor = HAnchor.Fit | HAnchor.Stretch, VAnchor = VAnchor.Fit, @@ -227,18 +227,18 @@ namespace MatterHackers.MatterControl return popupMenu; } - public static RadioTextButton CreateMicroRadioButton(this ThemeConfig config, string text, IList siblingRadioButtonList = null) + public static RadioTextButton CreateMicroRadioButton(this ThemeConfig theme, string text, IList siblingRadioButtonList = null) { - var radioButton = new RadioTextButton(text, config, config.FontSize8) + var radioButton = new RadioTextButton(text, theme, theme.FontSize8) { SiblingRadioButtonList = siblingRadioButtonList, Padding = new BorderDouble(5, 0), - SelectedBackgroundColor = config.SlightShade, - UnselectedBackgroundColor = config.SlightShade, - HoverColor = config.AccentMimimalOverlay, + SelectedBackgroundColor = theme.SlightShade, + UnselectedBackgroundColor = theme.SlightShade, + HoverColor = theme.AccentMimimalOverlay, Margin = new BorderDouble(right: 1), HAnchor = HAnchor.Absolute, - Height = config.MicroButtonHeight, + Height = theme.MicroButtonHeight, Width = MicroButtonWidth }; @@ -248,12 +248,12 @@ namespace MatterHackers.MatterControl return radioButton; } - public static JogControls.MoveButton CreateMoveButton(this ThemeConfig config, PrinterConfig printer, string label, PrinterConnection.Axis axis, double movementFeedRate, bool levelingButtons = false) + public static JogControls.MoveButton CreateMoveButton(this ThemeConfig theme, PrinterConfig printer, string label, PrinterConnection.Axis axis, double movementFeedRate, bool levelingButtons = false) { - return new JogControls.MoveButton(label, printer, axis, movementFeedRate, config) + return new JogControls.MoveButton(label, printer, axis, movementFeedRate, theme) { - BackgroundColor = config.MinimalShade, - BorderColor = config.BorderColor40, + BackgroundColor = theme.MinimalShade, + BorderColor = theme.BorderColor40, BackgroundOutlineWidth = 1, VAnchor = VAnchor.Absolute, HAnchor = HAnchor.Absolute, @@ -264,31 +264,31 @@ namespace MatterHackers.MatterControl }; } - public static GuiWidget CreateSearchButton(this ThemeConfig config) + public static GuiWidget CreateSearchButton(this ThemeConfig theme) { - return new IconButton(StaticData.Instance.LoadIcon("icon_search_24x24.png", 16, 16).SetToColor(config.TextColor), config) + return new IconButton(StaticData.Instance.LoadIcon("icon_search_24x24.png", 16, 16).SetToColor(theme.TextColor), theme) { ToolTipText = "Search".Localize(), }; } - public static GuiWidget CreateSmallResetButton(this ThemeConfig config) + public static GuiWidget CreateSmallResetButton(this ThemeConfig theme) { - return new HoverImageWidget(config.RestoreNormal, config.RestoreHover) + return new HoverImageWidget(theme.RestoreNormal, theme.RestoreHover) { VAnchor = VAnchor.Center, Margin = new BorderDouble(0, 0, 5, 0) }; } - public static PopupMenuButton CreateSplitButton(this ThemeConfig config, SplitButtonParams buttonParams, OperationGroup operationGroup = null) + public static PopupMenuButton CreateSplitButton(this ThemeConfig theme, SplitButtonParams buttonParams, OperationGroup operationGroup = null) { PopupMenuButton menuButton = null; GuiWidget innerButton; if (buttonParams.ButtonText == null) { - innerButton = new IconButton(buttonParams.Icon, config) + innerButton = new IconButton(buttonParams.Icon, theme) { Name = buttonParams.ButtonName + " Inner SplitButton", Enabled = buttonParams.ButtonEnabled, @@ -302,7 +302,7 @@ namespace MatterHackers.MatterControl { if (buttonParams.Icon == null) { - innerButton = new TextButton(buttonParams.ButtonText, config) + innerButton = new TextButton(buttonParams.ButtonText, theme) { Name = buttonParams.ButtonName, Enabled = buttonParams.ButtonEnabled, @@ -311,7 +311,7 @@ namespace MatterHackers.MatterControl } else { - innerButton = new TextIconButton(buttonParams.ButtonText, buttonParams.Icon, config) + innerButton = new TextIconButton(buttonParams.ButtonText, buttonParams.Icon, theme) { Name = buttonParams.ButtonName, Enabled = buttonParams.ButtonEnabled, @@ -328,14 +328,13 @@ namespace MatterHackers.MatterControl if (operationGroup == null) { - menuButton = new PopupMenuButton(innerButton, config); + menuButton = new PopupMenuButton(innerButton, theme); } else { - menuButton = new OperationGroupButton(operationGroup, innerButton, config); + menuButton = new OperationGroupButton(operationGroup, innerButton, theme); } - var theme = ApplicationController.Instance.MenuTheme; menuButton.DynamicPopupContent = () => { var popupMenu = new PopupMenu(theme); @@ -348,13 +347,13 @@ namespace MatterHackers.MatterControl menuButton.BackgroundColor = buttonParams.BackgroundColor; if (menuButton.BackgroundColor == Color.Transparent) { - menuButton.BackgroundColor = config.ToolbarButtonBackground; + menuButton.BackgroundColor = theme.ToolbarButtonBackground; } - menuButton.HoverColor = config.ToolbarButtonHover; - menuButton.MouseDownColor = config.ToolbarButtonDown; + menuButton.HoverColor = theme.ToolbarButtonHover; + menuButton.MouseDownColor = theme.ToolbarButtonDown; menuButton.DrawArrow = true; - menuButton.Margin = config.ButtonSpacing; + menuButton.Margin = theme.ButtonSpacing; menuButton.DistinctPopupButton = true; menuButton.BackgroundRadius = new RadiusCorners(theme.ButtonRadius * GuiWidget.DeviceScale, theme.ButtonRadius * GuiWidget.DeviceScale, 0, 0); @@ -362,12 +361,12 @@ namespace MatterHackers.MatterControl return menuButton; } - public static void RebuildTheme(this ThemeConfig config) + public static void RebuildTheme(this ThemeConfig theme) { - config.GeneratingThumbnailIcon = StaticData.Instance.LoadIcon("building_thumbnail_40x40.png", 40, 40).SetToColor(config.TextColor); + theme.GeneratingThumbnailIcon = StaticData.Instance.LoadIcon("building_thumbnail_40x40.png", 40, 40).SetToColor(theme.TextColor); } - public static void RemovePrimaryActionStyle(this ThemeConfig config, GuiWidget guiWidget) + public static void RemovePrimaryActionStyle(this ThemeConfig theme, GuiWidget guiWidget) { guiWidget.BackgroundColor = Color.Transparent; @@ -377,11 +376,11 @@ namespace MatterHackers.MatterControl switch (guiWidget) { case SimpleFlowButton flowButton: - flowButton.HoverColor = parentIsToolbar ? config.ToolbarButtonHover : Color.Transparent; + flowButton.HoverColor = parentIsToolbar ? theme.ToolbarButtonHover : Color.Transparent; break; case SimpleButton button: - button.HoverColor = parentIsToolbar ? config.ToolbarButtonHover : Color.Transparent; + button.HoverColor = parentIsToolbar ? theme.ToolbarButtonHover : Color.Transparent; break; } } diff --git a/MatterControlLib/ConfigurationPage/ApplicationSettings/ThemeColorPanel.cs b/MatterControlLib/ConfigurationPage/ApplicationSettings/ThemeColorPanel.cs index 4f22a9dc4..81ae59ab2 100644 --- a/MatterControlLib/ConfigurationPage/ApplicationSettings/ThemeColorPanel.cs +++ b/MatterControlLib/ConfigurationPage/ApplicationSettings/ThemeColorPanel.cs @@ -142,7 +142,6 @@ namespace MatterHackers.MatterControl.ConfigurationPage VAnchor = VAnchor.Absolute, Width = 80 * GuiWidget.DeviceScale, Height = 65 * GuiWidget.DeviceScale, - Mode = themeName, Border = 1, BorderColor = theme.BorderColor20, Margin = new BorderDouble(theme.DefaultContainerPadding, 0, theme.DefaultContainerPadding, theme.DefaultContainerPadding) diff --git a/MatterControlLib/ConfigurationPage/ApplicationSettings/ThemePreviewButton.cs b/MatterControlLib/ConfigurationPage/ApplicationSettings/ThemePreviewButton.cs index 6a8cf5d8e..1a656f8fc 100644 --- a/MatterControlLib/ConfigurationPage/ApplicationSettings/ThemePreviewButton.cs +++ b/MatterControlLib/ConfigurationPage/ApplicationSettings/ThemePreviewButton.cs @@ -125,7 +125,7 @@ namespace MatterHackers.MatterControl.ConfigurationPage overlay.Click += (s, e) => { // Activate the theme - themeColorPanel.SetThemeColor(this.ThemeSet, primaryAccentColor, this.Mode); + themeColorPanel.SetThemeColor(this.ThemeSet, primaryAccentColor); // Disable further theme clicks until reload completes themeColorPanel.Enabled = false; @@ -136,8 +136,6 @@ namespace MatterHackers.MatterControl.ConfigurationPage public ThemeSet ThemeSet { get; } - public string Mode { get; internal set; } - public void PreviewThemeColor(Color sourceColor) { var adjustedAccentColor = sourceColor; diff --git a/MatterControlLib/DesignTools/Primitives/ComponentObject3D.cs b/MatterControlLib/DesignTools/Primitives/ComponentObject3D.cs index 42c5fc958..c39011d9b 100644 --- a/MatterControlLib/DesignTools/Primitives/ComponentObject3D.cs +++ b/MatterControlLib/DesignTools/Primitives/ComponentObject3D.cs @@ -295,11 +295,11 @@ namespace MatterHackers.MatterControl.DesignTools } } - public void AddRightClickMenuItemsItems(PopupMenu popupMenu) + public void AddRightClickMenuItemsItems(PopupMenu popupMenu, ThemeConfig theme) { - popupMenu.CreateSeparator(); + popupMenu.CreateSeparator(); - string componentID = this.ComponentID; + string componentID = this.ComponentID; var helpItem = popupMenu.CreateMenuItem("Help".Localize()); var helpArticlesByID = ApplicationController.Instance.HelpArticlesByID; @@ -316,5 +316,10 @@ namespace MatterHackers.MatterControl.DesignTools } }; } - } + + public void AddRightClickMenuItemsItems(PopupMenu popupMenu) + { + throw new System.NotImplementedException(); + } + } } \ No newline at end of file diff --git a/MatterControlLib/Library/Widgets/LibraryWidget.cs b/MatterControlLib/Library/Widgets/LibraryWidget.cs index 138c9ab5d..35e3882a8 100644 --- a/MatterControlLib/Library/Widgets/LibraryWidget.cs +++ b/MatterControlLib/Library/Widgets/LibraryWidget.cs @@ -234,14 +234,14 @@ namespace MatterHackers.MatterControl.Library.Widgets viewOptionsButton.DynamicPopupContent = () => { var popupMenu = new PopupMenu(theme); - CreateSortingMenu(popupMenu, libraryView); + CreateSortingMenu(popupMenu, theme, libraryView); return popupMenu; }; return viewOptionsButton; } - public static PopupMenu CreateSortingMenu(PopupMenu popupMenu, LibraryListView libraryView) + public static PopupMenu CreateSortingMenu(PopupMenu popupMenu, ThemeConfig theme, LibraryListView libraryView) { var siblingList = new List(); diff --git a/MatterControlLib/Library/Widgets/PrintLibraryWidget.cs b/MatterControlLib/Library/Widgets/PrintLibraryWidget.cs index 8b1d7e6f8..b11106504 100644 --- a/MatterControlLib/Library/Widgets/PrintLibraryWidget.cs +++ b/MatterControlLib/Library/Widgets/PrintLibraryWidget.cs @@ -106,7 +106,7 @@ namespace MatterHackers.MatterControl.Library.Widgets toolbar.OverflowButton.Name = "Print Library View Options"; toolbar.Padding = theme.ToolbarPadding; - toolbar.ExtendOverflowMenu = (popupMenu) => LibraryWidget.CreateSortingMenu(popupMenu, libraryView); + toolbar.ExtendOverflowMenu = (popupMenu) => LibraryWidget.CreateSortingMenu(popupMenu, theme, libraryView); allControls.AddChild(toolbar); diff --git a/MatterControlLib/PartPreviewWindow/ArrowDirection.cs b/MatterControlLib/PartPreviewWindow/ArrowDirection.cs deleted file mode 100644 index 89edc18ea..000000000 --- a/MatterControlLib/PartPreviewWindow/ArrowDirection.cs +++ /dev/null @@ -1,41 +0,0 @@ -/* -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. -*/ - - -namespace MatterHackers.MatterControl.PartPreviewWindow -{ - public enum ArrowDirection - { - Right, - Left, - Up, - Down, - None - } -} diff --git a/MatterControlLib/PartPreviewWindow/DropButton.cs b/MatterControlLib/PartPreviewWindow/DropButton.cs index 0de2c8eb2..df4fd4c66 100644 --- a/MatterControlLib/PartPreviewWindow/DropButton.cs +++ b/MatterControlLib/PartPreviewWindow/DropButton.cs @@ -115,6 +115,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow popupContent.Closed += PopupContent_Closed; systemWindow.ShowPopup( + theme, this.AnchorMate, this.PopupMate, this.AltPopupBounds); diff --git a/MatterControlLib/PartPreviewWindow/MainViewWidget.cs b/MatterControlLib/PartPreviewWindow/MainViewWidget.cs index 935d32953..0947c5c21 100644 --- a/MatterControlLib/PartPreviewWindow/MainViewWidget.cs +++ b/MatterControlLib/PartPreviewWindow/MainViewWidget.cs @@ -122,6 +122,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow var systemWindow = this.Parents().FirstOrDefault(); systemWindow.ShowRightSplitPopup( + theme, new MatePoint(searchButton), new MatePoint(searchPanel), borderWidth: 0); @@ -700,6 +701,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow var systemWindow = this.Parents().FirstOrDefault(); systemWindow.ShowPopup( + theme, new MatePoint(themePanel) { Mate = new MateOptions(MateEdge.Right, MateEdge.Top), diff --git a/MatterControlLib/PartPreviewWindow/PopupMenu.cs b/MatterControlLib/PartPreviewWindow/PopupMenu.cs deleted file mode 100644 index 9221cca85..000000000 --- a/MatterControlLib/PartPreviewWindow/PopupMenu.cs +++ /dev/null @@ -1,654 +0,0 @@ -/* -Copyright (c) 2017, 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 System; -using System.Collections.Generic; -using System.Linq; -using MatterHackers.Agg; -using MatterHackers.Agg.Image; -using MatterHackers.Agg.Platform; -using MatterHackers.Agg.UI; -using MatterHackers.Agg.VertexSource; -using MatterHackers.ImageProcessing; -using MatterHackers.MatterControl.CustomWidgets; -using MatterHackers.MatterControl.SlicerConfiguration; -using MatterHackers.VectorMath; - -namespace MatterHackers.MatterControl.PartPreviewWindow -{ - public class PopupMenu : FlowLayoutWidget, IIgnoredPopupChild - { - private ThemeConfig theme; - - public static BorderDouble MenuPadding => new BorderDouble(40, 8, 20, 8); - - public static Color DisabledTextColor { get; set; } = Color.Gray; - - public PopupMenu(ThemeConfig theme) - : base(FlowDirection.TopToBottom) - { - this.theme = theme; - this.VAnchor = VAnchor.Fit; - this.HAnchor = HAnchor.Fit; - this.BackgroundColor = theme.BackgroundColor; - } - - public HorizontalLine CreateSeparator(double height = 1) - { - var line = new HorizontalLine(ApplicationController.Instance.MenuTheme.BorderColor20) - { - Margin = new BorderDouble(8, 1), - BackgroundColor = theme.RowBorder, - Height = height * DeviceScale, - }; - - this.AddChild(line); - - return line; - } - - public MenuItem CreateMenuItem(string name, ImageBuffer icon = null, string shortCut = null) - { - GuiWidget content; - - var textWidget = new TextWidget(name, pointSize: theme.DefaultFontSize, textColor: theme.TextColor) - { - Padding = MenuPadding, - }; - - if (shortCut != null) - { - content = new GuiWidget() - { - HAnchor = HAnchor.Stretch, - VAnchor = VAnchor.Fit - }; - - content.AddChild(new TextWidget(shortCut, pointSize: theme.DefaultFontSize, textColor: theme.TextColor) - { - HAnchor = HAnchor.Right - }); - - content.AddChild(textWidget); - } - else - { - content = textWidget; - } - - content.Selectable = false; - - var menuItem = new MenuItem(content, theme) - { - Name = name + " Menu Item", - Image = icon - }; - - menuItem.Click += (s, e) => - { - Unfocus(); - }; - - this.AddChild(menuItem); - - return menuItem; - } - - public class SubMenuItemButton : MenuItem, IIgnoredPopupChild - { - public PopupMenu SubMenu { get; set; } - - public SubMenuItemButton(GuiWidget content, ThemeConfig theme) : base(content, theme) - { - } - - public override void OnDraw(Graphics2D graphics2D) - { - base.OnDraw(graphics2D); - - // draw the right arrow - var x = this.LocalBounds.Right - this.LocalBounds.Height / 2; - var y = this.Size.Y / 2 + 2; - - var arrow = new VertexStorage(); - arrow.MoveTo(x + 3, y); - arrow.LineTo(x - 3, y + 5); - arrow.LineTo(x - 3, y - 5); - - graphics2D.Render(arrow, theme.TextColor); - } - - public bool KeepMenuOpen - { - get - { - if (SubMenu != null) - { - return SubMenu.ContainsFocus; - } - - return false; - } - } - } - - public class CheckboxMenuItem : MenuItem, IIgnoredPopupChild, ICheckbox - { - private bool _checked; - - private ImageBuffer faChecked; - - public CheckboxMenuItem(GuiWidget widget, ThemeConfig theme) - : base(widget, theme) - { - faChecked = StaticData.Instance.LoadIcon("fa-check_16.png", 16, 16).SetToColor(theme.TextColor); - } - - public override void OnLoad(EventArgs args) - { - this.Image = _checked ? faChecked : null; - base.OnLoad(args); - } - - public bool KeepMenuOpen => false; - - public bool Checked - { - get => _checked; - set - { - if (_checked != value) - { - _checked = value; - this.Image = _checked ? faChecked : null; - - this.CheckedStateChanged?.Invoke(this, null); - this.Invalidate(); - } - } - } - - public event EventHandler CheckedStateChanged; - } - - public class RadioMenuItem : MenuItem, IIgnoredPopupChild, IRadioButton - { - private bool _checked; - - private ImageBuffer radioIconChecked; - - private ImageBuffer radioIconUnchecked; - - public RadioMenuItem(GuiWidget widget, ThemeConfig theme) - : base(widget, theme) - { - } - - public override void OnLoad(EventArgs args) - { - // Init static radio icons if null - if (radioIconChecked == null) - { - var size = (int)Math.Round(16 * GuiWidget.DeviceScale); - radioIconChecked = new ImageBuffer(size, size).SetPreMultiply(); - radioIconUnchecked = new ImageBuffer(size, size).SetPreMultiply(); - - var rect = new RectangleDouble(0, 0, size, size); - - RadioImage.DrawCircle( - radioIconChecked.NewGraphics2D(), - rect.Center, - theme.TextColor, - isChecked: true, - isActive: false); - - RadioImage.DrawCircle( - radioIconUnchecked.NewGraphics2D(), - rect.Center, - theme.TextColor, - isChecked: false, - isActive: false); - } - - this.Image = _checked ? radioIconChecked : radioIconUnchecked; - - this.Invalidate(); - - if (!this.SiblingRadioButtonList.Contains(this)) - { - this.SiblingRadioButtonList.Add(this); - } - - base.OnLoad(args); - } - - public bool KeepMenuOpen => false; - - public IList SiblingRadioButtonList { get; set; } - - public bool Checked - { - get => _checked; - set - { - if (_checked != value) - { - _checked = value; - - this.Image = _checked ? radioIconChecked : radioIconUnchecked; - - if (_checked) - { - this.UncheckSiblings(); - } - - this.CheckedStateChanged?.Invoke(this, null); - - this.Invalidate(); - } - } - } - - public event EventHandler CheckedStateChanged; - } - - public void CreateSubMenu(string menuTitle, ThemeConfig menuTheme, Action populateSubMenu, ImageBuffer icon = null) - { - var content = new TextWidget(menuTitle, pointSize: theme.DefaultFontSize, textColor: theme.TextColor) - { - Padding = MenuPadding, - }; - - content.Selectable = false; - - var subMenuItemButton = new SubMenuItemButton(content, theme) - { - Name = menuTitle + " Menu Item", - Image = icon - }; - - this.AddChild(subMenuItemButton); - - subMenuItemButton.Click += (s, e) => - { - var systemWindow = this.Parents().FirstOrDefault(); - if (systemWindow == null) - { - return; - } - - var subMenu = new PopupMenu(menuTheme); - subMenuItemButton.SubMenu = subMenu; - - UiThread.RunOnIdle(() => - { - populateSubMenu(subMenu); - - systemWindow.ShowPopup( - new MatePoint(subMenuItemButton) - { - Mate = new MateOptions(MateEdge.Right, MateEdge.Top), - AltMate = new MateOptions(MateEdge.Left, MateEdge.Bottom) - }, - new MatePoint(subMenu) - { - Mate = new MateOptions(MateEdge.Left, MateEdge.Top), - AltMate = new MateOptions(MateEdge.Right, MateEdge.Bottom) - }); - }); - - subMenu.Closed += (s1, e1) => - { - subMenu.ClearRemovedFlag(); - subMenuItemButton.SubMenu = null; - if (!this.ContainsFocus) - { - this.Close(); - } - }; - }; - } - - public MenuItem CreateBoolMenuItem(string name, Func getter, Action setter, bool useRadioStyle = false, IList siblingRadioButtonList = null) - { - var textWidget = new TextWidget(name, pointSize: theme.DefaultFontSize, textColor: theme.TextColor) - { - Padding = MenuPadding, - }; - - return this.CreateBoolMenuItem(textWidget, name, getter, setter, useRadioStyle, siblingRadioButtonList); - } - - public MenuItem CreateBoolMenuItem(string name, ImageBuffer icon, Func getter, Action setter, bool useRadioStyle = false, IList siblingRadioButtonList = null) - { - var row = new FlowLayoutWidget() - { - Selectable = false - }; - row.AddChild(new IconButton(icon, theme)); - - var textWidget = new TextWidget(name, pointSize: theme.DefaultFontSize, textColor: theme.TextColor) - { - Padding = MenuPadding, - VAnchor = VAnchor.Center - }; - row.AddChild(textWidget); - - return this.CreateBoolMenuItem(row, name, getter, setter, useRadioStyle, siblingRadioButtonList); - } - - public MenuItem CreateBoolMenuItem(GuiWidget guiWidget, string name, Func getter, Action setter, bool useRadioStyle = false, IList siblingRadioButtonList = null) - { - bool isChecked = getter?.Invoke() == true; - - MenuItem menuItem; - - if (useRadioStyle) - { - menuItem = new RadioMenuItem(guiWidget, theme) - { - Name = name + " Menu Item", - Checked = isChecked, - SiblingRadioButtonList = siblingRadioButtonList - }; - } - else - { - menuItem = new CheckboxMenuItem(guiWidget, theme) - { - Name = name + " Menu Item", - Checked = isChecked - }; - } - - menuItem.Click += (s, e) => - { - if (menuItem is RadioMenuItem radioMenu) - { - // Do nothing on reclick of active radio menu - if (radioMenu.Checked) - { - return; - } - - isChecked = radioMenu.Checked = !radioMenu.Checked; - } - else if (menuItem is CheckboxMenuItem checkboxMenu) - { - isChecked = checkboxMenu.Checked = !isChecked; - } - - setter?.Invoke(isChecked); - }; - - this.AddChild(menuItem); - - return menuItem; - } - - /// - /// Create and add a new menu item - /// - /// The text of the item - /// - /// - /// - /// - public MenuItem CreateButtonSelectMenuItem(string text, IEnumerable<(string key, string text)> buttonKvps, string startingValue, Action setter, double minSpacerWidth = 0) - { - var textWidget = new TextWidget(text, pointSize: theme.DefaultFontSize, textColor: theme.TextColor) - { - Padding = MenuPadding, - VAnchor = VAnchor.Center, - }; - - return this.CreateButtonSelectMenuItem(textWidget, text, buttonKvps, startingValue, setter, minSpacerWidth); - } - - public MenuItem CreateButtonMenuItem(string text, - IEnumerable<(string key, string text, EventHandler 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 setter) - { - var row = new FlowLayoutWidget() - { - Selectable = false - }; - row.AddChild(new IconButton(icon, theme)); - - var textWidget = new TextWidget(text, pointSize: theme.DefaultFontSize, textColor: theme.TextColor) - { - Padding = MenuPadding, - VAnchor = VAnchor.Center - }; - row.AddChild(textWidget); - - return this.CreateButtonSelectMenuItem(row, text, buttonKvps, startingValue, setter); - } - - public MenuItem CreateButtonSelectMenuItem(GuiWidget guiWidget, string name, IEnumerable<(string key, string text)> buttonKvps, string startingValue, Action setter, 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 localKey = buttonKvp.key; - var button = EnumDisplayField.CreateThemedRadioButton(buttonKvp.text, buttonKvp.key, "", startingValue == buttonKvp.key, () => - { - setter?.Invoke(localKey); - }, theme); - row.AddChild(button); - } - - var menuItem = new MenuItemHoldOpen(row, theme) - { - }; - - this.AddChild(menuItem); - - return menuItem; - } - - public MenuItem CreateButtonMenuItem(GuiWidget guiWidget, string name, IEnumerable<(string key, string text, EventHandler 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) - { - Text = name, - Name = name + " Menu Item", - Image = icon - }; - - this.AddChild(menuItem); - - return menuItem; - } - - public bool KeepMenuOpen => false; - - public class MenuItem : SimpleButton - { - private GuiWidget content; - - public MenuItem(GuiWidget content, ThemeConfig theme) - : base(theme) - { - // Inflate padding to match the target (MenuGutterWidth) after scale operation in assignment - 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); - this.content = content; - this.GutterWidth = theme.MenuGutterWidth; - this.HoverColor = theme.AccentMimimalOverlay; - - content.VAnchor = VAnchor.Center; - content.HAnchor |= HAnchor.Left; - - this.AddChild(content); - } - - public double GutterWidth { get; set; } - - public ImageBuffer Image { get; set; } - - private ImageBuffer _disabledImage; - - public ImageBuffer DisabledImage - { - get - { - // Lazy construct on first access - if (this.Image != null && - _disabledImage == null) - { - _disabledImage = this.Image.AjustAlpha(0.2); - } - - return _disabledImage; - } - } - - public override bool Enabled - { - get => base.Enabled; - set - { - if (content is TextWidget textWidget) - { - textWidget.Enabled = value; - } - - base.Enabled = value; - } - } - - public bool KeepMenuOpen => false; - - public override void OnDraw(Graphics2D graphics2D) - { - if (this.Image != null) - { - 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); - } - - base.OnDraw(graphics2D); - } - } - - public class MenuItemHoldOpen : MenuItem, IIgnoredPopupChild - { - public MenuItemHoldOpen(GuiWidget content, ThemeConfig theme) - : base(content, theme) - { - } - - public bool KeepMenuOpen => false; - } - } - - public static class PopupMenuExtensions - { - public static void ShowMenu(this PopupMenu popupMenu, GuiWidget anchorWidget, MouseEventArgs mouseEvent) - { - popupMenu.ShowMenu(anchorWidget, mouseEvent.Position); - } - - public static void ShowMenu(this PopupMenu popupMenu, GuiWidget anchorWidget, Vector2 menuPosition) - { - var systemWindow = anchorWidget.Parents().LastOrDefault(); - systemWindow.ToolTipManager.Clear(); - systemWindow.ShowPopup( - new MatePoint(anchorWidget) - { - Mate = new MateOptions(MateEdge.Left, MateEdge.Top), - AltMate = new MateOptions(MateEdge.Left, MateEdge.Bottom) - }, - new MatePoint(popupMenu) - { - Mate = new MateOptions(MateEdge.Left, MateEdge.Top), - AltMate = new MateOptions(MateEdge.Right, MateEdge.Bottom) - }, - altBounds: new RectangleDouble(menuPosition.X + 1, menuPosition.Y + 1, menuPosition.X + 1, menuPosition.Y + 1)); - } - } -} \ No newline at end of file diff --git a/MatterControlLib/PartPreviewWindow/SystemWindowExtension.cs b/MatterControlLib/PartPreviewWindow/SystemWindowExtension.cs deleted file mode 100644 index 7c9e3d039..000000000 --- a/MatterControlLib/PartPreviewWindow/SystemWindowExtension.cs +++ /dev/null @@ -1,418 +0,0 @@ -/* -Copyright (c) 2017, 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 System; -using System.Collections.Generic; -using System.Linq; -using MatterHackers.Agg; -using MatterHackers.Agg.UI; -using MatterHackers.Agg.VertexSource; -using MatterHackers.DataConverters3D; -using MatterHackers.MatterControl.CustomWidgets; -using MatterHackers.MatterControl.SlicerConfiguration; -using MatterHackers.VectorMath; - -namespace MatterHackers.MatterControl.PartPreviewWindow -{ - [Flags] - public enum MateEdge - { - Top = 1, - Bottom = 2, - Left = 4, - Right = 8 - } - - public class MateOptions - { - public MateOptions(MateEdge horizontalEdge = MateEdge.Left, MateEdge verticalEdge = MateEdge.Bottom) - { - this.HorizontalEdge = horizontalEdge; - this.VerticalEdge = verticalEdge; - } - - public MateEdge HorizontalEdge { get; set; } - - public MateEdge VerticalEdge { get; set; } - - public bool Top => this.VerticalEdge.HasFlag(MateEdge.Top); - - public bool Bottom => this.VerticalEdge.HasFlag(MateEdge.Bottom); - - public bool Left => this.HorizontalEdge.HasFlag(MateEdge.Left); - - public bool Right => this.HorizontalEdge.HasFlag(MateEdge.Right); - } - - public class MatePoint - { - public MateOptions Mate { get; set; } = new MateOptions(); - - public MateOptions AltMate { get; set; } = new MateOptions(); - - public GuiWidget Widget { get; set; } - - public MatePoint() - { - } - - public MatePoint(GuiWidget widget) - { - this.Widget = widget; - } - - public RectangleDouble Offset { get; set; } - } - - public interface IOverrideAutoClose - { - bool AllowAutoClose { get; } - } - - public static class SystemWindowExtension - { - public static void ShowPopover(this SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds = default(RectangleDouble), double secondsToClose = 0) - { - var settingsRow = anchor.Widget as SettingsRow; - var sliceSettingsPopover = popup.Widget as ClickablePopover; - - var hookedWidgets = new HashSet(); - - void Anchor_Closed(object sender, EventArgs e) - { - if (popup.Widget is IOverrideAutoClose overideAutoClose - && !overideAutoClose.AllowAutoClose) - { - return; - } - - // If the owning widget closed, so should we - popup.Widget.Close(); - - foreach (var widget in hookedWidgets) - { - widget.Closed -= Anchor_Closed; - } - } - - void WidgetRelativeTo_PositionChanged(object sender, EventArgs e) - { - if (anchor.Widget?.Parent != null) - { - // Calculate left aligned screen space position (using widgetRelativeTo.parent) - Vector2 anchorLeft = anchor.Widget.Parent.TransformToScreenSpace(anchor.Widget.Position); - anchorLeft += new Vector2(altBounds.Left, altBounds.Bottom); - - Vector2 popupPosition = anchorLeft; - - var bounds = altBounds == default(RectangleDouble) ? anchor.Widget.LocalBounds : altBounds; - - Vector2 xPosition = GetXAnchor(anchor.Mate, popup.Mate, popup.Widget, bounds); - - Vector2 screenPosition; - - screenPosition = anchorLeft + xPosition; - - // Constrain - if (screenPosition.X + popup.Widget.Width > systemWindow.Width - || screenPosition.X < 0) - { - var altXPosition = GetXAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds); - - var altScreenPosition = anchorLeft + altXPosition; - - // Prefer clipping on edge revealed by resize - if ((popup.AltMate.Right && altScreenPosition.X > -15) - || (popup.AltMate.Left && altScreenPosition.X + popup.Widget.Width < systemWindow.Width)) - { - xPosition = altXPosition; - - if (settingsRow != null - && sliceSettingsPopover != null) - { - sliceSettingsPopover.ArrowDirection = settingsRow.ArrowDirection == ArrowDirection.Left ? ArrowDirection.Right : ArrowDirection.Left; - } - } - } - - popupPosition += xPosition; - - Vector2 yPosition = GetYAnchor(anchor.Mate, popup.Mate, popup.Widget, bounds); - - screenPosition = anchorLeft + yPosition; - - // Constrain - if (anchor.AltMate != null - && (screenPosition.Y + popup.Widget.Height > systemWindow.Height - || screenPosition.Y < 0)) - { - yPosition = GetYAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds); - - if (settingsRow != null) - { - settingsRow.ArrowDirection = settingsRow.ArrowDirection == ArrowDirection.Up ? ArrowDirection.Down : ArrowDirection.Up; - } - } - - popup.Widget.Closed += Anchor_Closed; - anchor.Widget.Closed += Anchor_Closed; - hookedWidgets.Add(anchor.Widget); - - foreach (var widget in anchor.Widget.Parents()) - { - widget.Closed += Anchor_Closed; - hookedWidgets.Add(widget); - } - - popupPosition += yPosition; - - popup.Widget.Position = popupPosition; - } - } - - WidgetRelativeTo_PositionChanged(anchor.Widget, null); - - popup.Widget.BoundsChanged += (s, e) => WidgetRelativeTo_PositionChanged(anchor.Widget, null); - - // When the widgets position changes, sync the popup position - systemWindow?.AddChild(popup.Widget); - - if (secondsToClose > 0) - { - UiThread.RunOnIdle(() => Anchor_Closed(null, null), secondsToClose); - } - } - - private static void RightHorizontalSplitPopup(SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds) - { - // Calculate left for right aligned split - Vector2 popupPosition = new Vector2(systemWindow.Width - popup.Widget.Width, 0); - - Vector2 anchorLeft = anchor.Widget.Parent.TransformToScreenSpace(anchor.Widget.Position); - - popup.Widget.Height = anchorLeft.Y; - - popup.Widget.Position = popupPosition; - } - - public static void ShowPopup(this SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds = default(RectangleDouble), int borderWidth = 1) - { - ShowPopup(systemWindow, anchor, popup, altBounds, borderWidth, BestPopupPosition); - } - - public static void ShowRightSplitPopup(this SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds = default(RectangleDouble), int borderWidth = 1) - { - ShowPopup(systemWindow, anchor, popup, altBounds, borderWidth, RightHorizontalSplitPopup); - } - - public static void ShowPopup(this SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds, int borderWidth, Action layoutHelper) - { - var hookedParents = new HashSet(); - - List ignoredWidgets = popup.Widget.Children.OfType().ToList(); - - void Widget_Draw(object sender, DrawEventArgs e) - { - if (borderWidth > 0) - { - e.Graphics2D.Render( - new Stroke( - new RoundedRect(popup.Widget.LocalBounds, 0), - borderWidth * 2), - AppContext.Theme.PopupBorderColor); - } - } - - void WidgetRelativeTo_PositionChanged(object sender, EventArgs e) - { - if (anchor.Widget?.Parent != null) - { - layoutHelper.Invoke(systemWindow, anchor, popup, altBounds); - } - } - - void CloseMenu() - { - popup.Widget.AfterDraw -= Widget_Draw; - - popup.Widget.Close(); - - anchor.Widget.Closed -= Anchor_Closed; - - // Unbind callbacks on parents for position_changed if we're closing - foreach (GuiWidget widget in hookedParents) - { - widget.PositionChanged -= WidgetRelativeTo_PositionChanged; - widget.BoundsChanged -= WidgetRelativeTo_PositionChanged; - } - - // Long lived originating item must be unregistered - anchor.Widget.Closed -= Anchor_Closed; - - // Restore focus to originating widget on close - if (anchor.Widget?.HasBeenClosed == false) - { - anchor.Widget.Focus(); - } - } - - void FocusChanged(object s, EventArgs e) - { - UiThread.RunOnIdle(() => - { - // Fired any time focus changes. Traditionally we closed the menu if we weren't focused. - // To accommodate children (or external widgets) having focus we also query for and consider special cases - bool specialChildHasFocus = ignoredWidgets.Any(w => w.ContainsFocus || w.Focused || w.KeepMenuOpen); - bool descendantIsHoldingOpen = popup.Widget.Descendants().Any(w => w is IIgnoredPopupChild ignoredPopupChild - && ignoredPopupChild.KeepMenuOpen); - - // If the focused changed and we've lost focus and no special cases permit, close the menu - if (!popup.Widget.ContainsFocus - && !specialChildHasFocus - && !descendantIsHoldingOpen - && !PopupWidget.DebugKeepOpen) - { - CloseMenu(); - } - }); - } - - void Anchor_Closed(object sender, EventArgs e) - { - // If the owning widget closed, so should we - CloseMenu(); - } - - foreach (var ancestor in anchor.Widget.Parents().Where(p => p != systemWindow)) - { - if (hookedParents.Add(ancestor)) - { - ancestor.PositionChanged += WidgetRelativeTo_PositionChanged; - ancestor.BoundsChanged += WidgetRelativeTo_PositionChanged; - } - } - - popup.Widget.ContainsFocusChanged += FocusChanged; - popup.Widget.AfterDraw += Widget_Draw; - - WidgetRelativeTo_PositionChanged(anchor.Widget, null); - anchor.Widget.Closed += Anchor_Closed; - - // When the widgets position changes, sync the popup position - systemWindow?.AddChild(popup.Widget); - - popup.Widget.Closed += (s, e) => - { - Console.WriteLine(); - }; - - popup.Widget.Focus(); - - popup.Widget.Invalidate(); - } - - private static void BestPopupPosition(SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds) - { - // Calculate left aligned screen space position (using widgetRelativeTo.parent) - Vector2 anchorLeft = anchor.Widget.Parent.TransformToScreenSpace(anchor.Widget.Position); - anchorLeft += new Vector2(altBounds.Left, altBounds.Bottom); - - Vector2 popupPosition = anchorLeft; - - var bounds = altBounds == default(RectangleDouble) ? anchor.Widget.LocalBounds : altBounds; - - Vector2 xPosition = GetXAnchor(anchor.Mate, popup.Mate, popup.Widget, bounds); - - Vector2 screenPosition; - - screenPosition = anchorLeft + xPosition; - - // Constrain - if (screenPosition.X + popup.Widget.Width > systemWindow.Width - || screenPosition.X < 0) - { - xPosition = GetXAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds); - } - - popupPosition += xPosition; - - Vector2 yPosition = GetYAnchor(anchor.Mate, popup.Mate, popup.Widget, bounds); - - screenPosition = anchorLeft + yPosition; - - // Constrain - if (anchor.AltMate != null - && (screenPosition.Y + popup.Widget.Height > systemWindow.Height - || screenPosition.Y < 0)) - { - yPosition = GetYAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds); - } - - popupPosition += yPosition; - - popup.Widget.Position = popupPosition; - } - - private static Vector2 GetYAnchor(MateOptions anchor, MateOptions popup, GuiWidget popupWidget, RectangleDouble bounds) - { - if (anchor.Top && popup.Bottom) - { - return new Vector2(0, bounds.Height); - } - else if (anchor.Top && popup.Top) - { - return new Vector2(0, popupWidget.Height - bounds.Height) * -1; - } - else if (anchor.Bottom && popup.Top) - { - return new Vector2(0, -popupWidget.Height); - } - - return Vector2.Zero; - } - - private static Vector2 GetXAnchor(MateOptions anchor, MateOptions popup, GuiWidget popupWidget, RectangleDouble bounds) - { - if (anchor.Right && popup.Left) - { - return new Vector2(bounds.Width, 0); - } - else if (anchor.Left && popup.Right) - { - return new Vector2(-popupWidget.Width, 0); - } - else if (anchor.Right && popup.Right) - { - return new Vector2(popupWidget.Width - bounds.Width, 0) * -1; - } - - return Vector2.Zero; - } - } -} \ No newline at end of file diff --git a/MatterControlLib/PartPreviewWindow/View3D/View3DWidget.cs b/MatterControlLib/PartPreviewWindow/View3D/View3DWidget.cs index 5059fa9d6..2b4a350a7 100644 --- a/MatterControlLib/PartPreviewWindow/View3D/View3DWidget.cs +++ b/MatterControlLib/PartPreviewWindow/View3D/View3DWidget.cs @@ -2074,6 +2074,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow var systemWindow = this.Parents().FirstOrDefault(); systemWindow.ShowPopup( + theme, new MatePoint(this) { Mate = new MateOptions(MateEdge.Left, MateEdge.Bottom), diff --git a/MatterControlLib/SlicerConfiguration/SettingsRow.cs b/MatterControlLib/SlicerConfiguration/SettingsRow.cs index 51a64fcaa..1d096ce65 100644 --- a/MatterControlLib/SlicerConfiguration/SettingsRow.cs +++ b/MatterControlLib/SlicerConfiguration/SettingsRow.cs @@ -28,7 +28,6 @@ either expressed or implied, of the FreeBSD Project. */ using System; -using System.Collections.Generic; using System.Linq; using Markdig.Agg; using MatterHackers.Agg; @@ -40,7 +39,7 @@ using MatterHackers.VectorMath; namespace MatterHackers.MatterControl.CustomWidgets { - public class SettingsRow : FlowLayoutWidget + public class SettingsRow : FlowLayoutWidget { protected GuiWidget overrideIndicator; protected const bool debugLayout = false; diff --git a/MatterControlLib/SlicerConfiguration/SettingsRowExtensions.cs b/MatterControlLib/SlicerConfiguration/SettingsRowExtensions.cs new file mode 100644 index 000000000..3219ff427 --- /dev/null +++ b/MatterControlLib/SlicerConfiguration/SettingsRowExtensions.cs @@ -0,0 +1,153 @@ +/* +Copyright (c) 2022, 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 System; +using System.Collections.Generic; +using MatterHackers.Agg; +using MatterHackers.Agg.UI; +using MatterHackers.MatterControl.PartPreviewWindow; +using MatterHackers.VectorMath; + +namespace MatterHackers.MatterControl.CustomWidgets +{ + public static class SettingsRowExtensions + { + public static void ShowPopover(this SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds = default(RectangleDouble), double secondsToClose = 0) + { + var settingsRow = anchor.Widget as SettingsRow; + var sliceSettingsPopover = popup.Widget as ClickablePopover; + + var hookedWidgets = new HashSet(); + + void Anchor_Closed(object sender, EventArgs e) + { + if (popup.Widget is IOverrideAutoClose overideAutoClose + && !overideAutoClose.AllowAutoClose) + { + return; + } + + // If the owning widget closed, so should we + popup.Widget.Close(); + + foreach (var widget in hookedWidgets) + { + widget.Closed -= Anchor_Closed; + } + } + + void WidgetRelativeTo_PositionChanged(object sender, EventArgs e) + { + if (anchor.Widget?.Parent != null) + { + // Calculate left aligned screen space position (using widgetRelativeTo.parent) + Vector2 anchorLeft = anchor.Widget.Parent.TransformToScreenSpace(anchor.Widget.Position); + anchorLeft += new Vector2(altBounds.Left, altBounds.Bottom); + + Vector2 popupPosition = anchorLeft; + + var bounds = altBounds == default(RectangleDouble) ? anchor.Widget.LocalBounds : altBounds; + + Vector2 xPosition = PopupMenu.GetXAnchor(anchor.Mate, popup.Mate, popup.Widget, bounds); + + Vector2 screenPosition; + + screenPosition = anchorLeft + xPosition; + + // Constrain + if (screenPosition.X + popup.Widget.Width > systemWindow.Width + || screenPosition.X < 0) + { + var altXPosition = PopupMenu.GetXAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds); + + var altScreenPosition = anchorLeft + altXPosition; + + // Prefer clipping on edge revealed by resize + if ((popup.AltMate.Right && altScreenPosition.X > -15) + || (popup.AltMate.Left && altScreenPosition.X + popup.Widget.Width < systemWindow.Width)) + { + xPosition = altXPosition; + + if (settingsRow != null + && sliceSettingsPopover != null) + { + sliceSettingsPopover.ArrowDirection = settingsRow.ArrowDirection == ArrowDirection.Left ? ArrowDirection.Right : ArrowDirection.Left; + } + } + } + + popupPosition += xPosition; + + Vector2 yPosition = PopupMenu.GetYAnchor(anchor.Mate, popup.Mate, popup.Widget, bounds); + + screenPosition = anchorLeft + yPosition; + + // Constrain + if (anchor.AltMate != null + && (screenPosition.Y + popup.Widget.Height > systemWindow.Height + || screenPosition.Y < 0)) + { + yPosition = PopupMenu.GetYAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds); + + if (settingsRow != null) + { + settingsRow.ArrowDirection = settingsRow.ArrowDirection == ArrowDirection.Up ? ArrowDirection.Down : ArrowDirection.Up; + } + } + + popup.Widget.Closed += Anchor_Closed; + anchor.Widget.Closed += Anchor_Closed; + hookedWidgets.Add(anchor.Widget); + + foreach (var widget in anchor.Widget.Parents()) + { + widget.Closed += Anchor_Closed; + hookedWidgets.Add(widget); + } + + popupPosition += yPosition; + + popup.Widget.Position = popupPosition; + } + } + + WidgetRelativeTo_PositionChanged(anchor.Widget, null); + + popup.Widget.BoundsChanged += (s, e) => WidgetRelativeTo_PositionChanged(anchor.Widget, null); + + // When the widgets position changes, sync the popup position + systemWindow?.AddChild(popup.Widget); + + if (secondsToClose > 0) + { + UiThread.RunOnIdle(() => Anchor_Closed(null, null), secondsToClose); + } + } + } +} diff --git a/MatterControlLib/SlicerConfiguration/UIFields/EnumDisplayField.cs b/MatterControlLib/SlicerConfiguration/UIFields/EnumDisplayField.cs index 401078f4f..6cee490d2 100644 --- a/MatterControlLib/SlicerConfiguration/UIFields/EnumDisplayField.cs +++ b/MatterControlLib/SlicerConfiguration/UIFields/EnumDisplayField.cs @@ -375,4 +375,120 @@ namespace MatterHackers.MatterControl.SlicerConfiguration base.OnValueChanged(fieldChangedEventArgs); } } + + public static class MenuExtensions + { + public static MenuItem CreateButtonSelectMenuItem(this PopupMenu popuMenu, GuiWidget guiWidget, string name, IEnumerable<(string key, string text)> buttonKvps, string startingValue, Action setter, 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 localKey = buttonKvp.key; + var button = EnumDisplayField.CreateThemedRadioButton(buttonKvp.text, buttonKvp.key, "", startingValue == buttonKvp.key, () => + { + setter?.Invoke(localKey); + }, popuMenu.Theme); + row.AddChild(button); + } + + MenuItem menuItem = new MenuItemHoldOpen(row); + + popuMenu.AddChild(menuItem); + + return menuItem; + } + + public static MenuItem CreateButtonMenuItem(this PopupMenu popupMenu, GuiWidget guiWidget, string name, IEnumerable<(string key, string text, EventHandler 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, "", popupMenu.Theme); + button.Click += buttonKvp.click; + row.AddChild(button); + } + + var menuItem = new MenuItemHoldOpen(row) + { + }; + + popupMenu.AddChild(menuItem); + + return menuItem; + } + + /// + /// Create and add a new menu item + /// + /// The text of the item + /// + /// + /// + /// + public static MenuItem CreateButtonSelectMenuItem(this PopupMenu popupMenu, string text, IEnumerable<(string key, string text)> buttonKvps, string startingValue, Action setter, double minSpacerWidth = 0) + { + var textWidget = new TextWidget(text, pointSize: popupMenu.Theme.DefaultFontSize, textColor: popupMenu.Theme.TextColor) + { + Padding = PopupMenu.MenuPadding, + VAnchor = VAnchor.Center, + }; + + return popupMenu.CreateButtonSelectMenuItem(textWidget, text, buttonKvps, startingValue, setter, minSpacerWidth); + } + + public static MenuItem CreateButtonMenuItem(this PopupMenu popupMenu, + string text, + IEnumerable<(string key, string text, EventHandler click)> buttonKvps, + double minSpacerWidth = 0, + bool bold = false) + { + var textWidget = new TextWidget(text, pointSize: popupMenu.Theme.DefaultFontSize, textColor: popupMenu.Theme.TextColor, bold: bold) + { + Padding = PopupMenu.MenuPadding, + VAnchor = VAnchor.Center, + }; + + return popupMenu.CreateButtonMenuItem(textWidget, text, buttonKvps, minSpacerWidth); + } + + public static MenuItem CreateButtonSelectMenuItem(this PopupMenu popupMenu, string text, ImageBuffer icon, IEnumerable<(string key, string text)> buttonKvps, string startingValue, Action setter) + { + var row = new FlowLayoutWidget() + { + Selectable = false + }; + row.AddChild(new ThemedIconButton(icon, popupMenu.Theme)); + + var textWidget = new TextWidget(text, pointSize: popupMenu.Theme.DefaultFontSize, textColor: popupMenu.Theme.TextColor) + { + Padding = PopupMenu.MenuPadding, + VAnchor = VAnchor.Center + }; + row.AddChild(textWidget); + + return popupMenu.CreateButtonSelectMenuItem(row, text, buttonKvps, startingValue, setter); + } + } } diff --git a/StaticData/Translations/Master.txt b/StaticData/Translations/Master.txt index 91a2d91e2..13151d6fc 100644 --- a/StaticData/Translations/Master.txt +++ b/StaticData/Translations/Master.txt @@ -1282,6 +1282,9 @@ Translated:Design Apps English:Design Name Translated:Design Name +English:Design Tools +Translated:Design Tools + English:Desktop Translated:Desktop diff --git a/Submodules/MatterSlice b/Submodules/MatterSlice index 68c71c98b..54748bc6d 160000 --- a/Submodules/MatterSlice +++ b/Submodules/MatterSlice @@ -1 +1 @@ -Subproject commit 68c71c98b5f598f0f98f786cafbc06abb4e3915f +Subproject commit 54748bc6d030bb65593e17b76d320884a7747eb2 diff --git a/Submodules/agg-sharp b/Submodules/agg-sharp index 3e6a51dc8..f3a1fbc74 160000 --- a/Submodules/agg-sharp +++ b/Submodules/agg-sharp @@ -1 +1 @@ -Subproject commit 3e6a51dc89c50b69e62613bc7922508a75a2cd42 +Subproject commit f3a1fbc748f00e0b7318909b0854a5627fa0476d diff --git a/Tests/MatterControl.Tests/MatterControl/PopupAnchorTests.cs b/Tests/MatterControl.Tests/MatterControl/PopupAnchorTests.cs index 60bea8b0d..493ecd1bc 100644 --- a/Tests/MatterControl.Tests/MatterControl/PopupAnchorTests.cs +++ b/Tests/MatterControl.Tests/MatterControl/PopupAnchorTests.cs @@ -56,6 +56,7 @@ namespace MatterControl.Tests.MatterControl button.Click += (s, e) => { systemWindow.ShowPopup( + new ThemeConfig(), new MatePoint() { Widget = button @@ -530,7 +531,7 @@ namespace MatterControl.Tests.MatterControl BorderColor = Color.LightBlue.Blend(Color.Black, 0.4) }; - systemWindow.ShowPopup(anchor, popup); + systemWindow.ShowPopup(new ThemeConfig(), anchor, popup); }; anchor.Widget = button;