diff --git a/ApplicationView/ThemeConfig.cs b/ApplicationView/ThemeConfig.cs index e68f13460..5b01e300f 100644 --- a/ApplicationView/ThemeConfig.cs +++ b/ApplicationView/ThemeConfig.cs @@ -60,7 +60,7 @@ namespace MatterHackers.MatterControl public int DefaultFontSize { get; } = 12; - private int shortButtonHeight = 25; + internal int shortButtonHeight = 25; private int sideBarButtonWidth; public int H1PointSize { get; set; } = 13; @@ -90,12 +90,6 @@ namespace MatterHackers.MatterControl public TextImageButtonFactory imageConverterExpandMenuOptionFactory; - internal void SetPrinterTabStyles(MainTab printerTab) - { - printerTab.Margin = new BorderDouble(10, 0, 0, 5); - printerTab.Padding = new BorderDouble(8, 4, 12, 6); - } - public TextImageButtonFactory imageConverterButtonFactory; public Color TabBodyBackground => new Color(ActiveTheme.Instance.TertiaryBackgroundColor, 175); @@ -135,9 +129,9 @@ namespace MatterHackers.MatterControl } else { - restoreNormal = ColorCircle(size, new Color(128, 128, 128)); + restoreNormal = ColorCircle(size, Color.Transparent); } - restoreHover = ColorCircle(size, new Color(200, 0, 0)); + restoreHover = ColorCircle(size, new Color("#DB4437")); restorePressed = ColorCircle(size, new Color(255, 0, 0)); } @@ -412,9 +406,20 @@ namespace MatterHackers.MatterControl ImageBuffer imageBuffer = new ImageBuffer(size, size); Graphics2D normalGraphics = imageBuffer.NewGraphics2D(); Vector2 center = new Vector2(size / 2.0, size / 2.0); - normalGraphics.Circle(center, size / 2.0, color); - normalGraphics.Line(center + new Vector2(-size / 4.0, -size / 4.0), center + new Vector2(size / 4.0, size / 4.0), Color.White, 2 * GuiWidget.DeviceScale); - normalGraphics.Line(center + new Vector2(-size / 4.0, size / 4.0), center + new Vector2(size / 4.0, -size / 4.0), Color.White, 2 * GuiWidget.DeviceScale); + + Color barColor; + if (color != Color.Transparent) + { + normalGraphics.Circle(center, size / 2.0, color); + barColor = Color.White; + } + else + { + barColor = new Color("#999"); + } + + normalGraphics.Line(center + new Vector2(-size / 4.0, -size / 4.0), center + new Vector2(size / 4.0, size / 4.0), barColor, 2 * GuiWidget.DeviceScale); + normalGraphics.Line(center + new Vector2(-size / 4.0, size / 4.0), center + new Vector2(size / 4.0, -size / 4.0), barColor, 2 * GuiWidget.DeviceScale); return imageBuffer; } diff --git a/ApplicationView/WidescreenPanel.cs b/ApplicationView/WidescreenPanel.cs index 9524abd96..0aea24725 100644 --- a/ApplicationView/WidescreenPanel.cs +++ b/ApplicationView/WidescreenPanel.cs @@ -31,8 +31,10 @@ using MatterHackers.Agg; using MatterHackers.Agg.Platform; using MatterHackers.Agg.UI; using MatterHackers.MatterControl.ConfigurationPage; +using MatterHackers.MatterControl.CustomWidgets; using MatterHackers.MatterControl.PartPreviewWindow; using MatterHackers.MatterControl.PrintLibrary; +using MatterHackers.VectorMath; namespace MatterHackers.MatterControl { @@ -49,11 +51,13 @@ namespace MatterHackers.MatterControl this.AnchorAll(); this.Name = "WidescreenPanel"; + var theme = ApplicationController.Instance.Theme; + var library3DViewSplitter = new Splitter() { SplitterDistance = UserSettings.Instance.LibraryViewWidth, - SplitterWidth = ApplicationController.Instance.Theme.SplitterWidth, - SplitterBackground = ApplicationController.Instance.Theme.SplitterBackground + SplitterWidth = theme.SplitterWidth, + SplitterBackground = theme.SplitterBackground }; library3DViewSplitter.AnchorAll(); @@ -67,12 +71,21 @@ namespace MatterHackers.MatterControl var leftNav = new FlowLayoutWidget(FlowDirection.TopToBottom); leftNav.AnchorAll(); - leftNav.AddChild(new BrandMenuButton() + var toolbar = new Toolbar(null, theme) + { + HAnchor = HAnchor.Stretch, + VAnchor = VAnchor.Fit, + MinimumSize = new Vector2(16, 16) + }; + toolbar.SeparatorLine.BackgroundColor = ApplicationController.Instance.Theme.SlightShade; + toolbar.SeparatorLine.Height = 2; + toolbar.ActionBar.AddChild(new BrandMenuButton(theme) { MinimumSize = new VectorMath.Vector2(0, 34), HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit }); + leftNav.AddChild(toolbar); var partPreviewContent = new PartPreviewContent() { @@ -80,7 +93,7 @@ namespace MatterHackers.MatterControl HAnchor = HAnchor.Left | HAnchor.Right }; - leftNav.AddChild(new PrintLibraryWidget(partPreviewContent, ApplicationController.Instance.Theme)); + leftNav.AddChild(new PrintLibraryWidget(partPreviewContent, theme)); // put in the left column library3DViewSplitter.Panel1.AddChild(leftNav); @@ -90,56 +103,40 @@ namespace MatterHackers.MatterControl } } - public class BrandMenuButton : GuiWidget + public class BrandMenuButton : PopupButton { - public BrandMenuButton() + public BrandMenuButton(ThemeConfig theme) { - this.Padding = new BorderDouble(left: 2); - - Name = "MatterControl BrandMenuButton"; - var buttonView = new FlowLayoutWidget() - { - HAnchor = HAnchor.Stretch, - VAnchor = VAnchor.Fit, - Margin = 0 - }; - - var buttonHeight = ApplicationController.Instance.Theme.ButtonHeight; - - var iconContainer = new GuiWidget() - { - Width = buttonHeight, - Height = buttonHeight - }; - iconContainer.AddChild(new ImageWidget(AggContext.StaticData.LoadIcon("mh-app-logo.png", IconColor.Theme)) - { - VAnchor = VAnchor.Center, - HAnchor = HAnchor.Center - }); - - buttonView.AddChild(iconContainer); - - buttonView.AddChild(new TextWidget(ApplicationController.Instance.ShortProductName, textColor: ActiveTheme.Instance.PrimaryTextColor) - { - Margin = 0, - VAnchor = VAnchor.Center - }); - - var popupButton = new PopupButton(buttonView) - { - VAnchor = VAnchor.Center, - HAnchor = HAnchor.Stretch, - Margin = 0 - }; - popupButton.PopupContent = new ApplicationSettingsWidget(ApplicationController.Instance.Theme.MenuButtonFactory) + this.Name = "MatterControl BrandMenuButton"; + this.VAnchor = VAnchor.Stretch; + this.HAnchor = HAnchor.Stretch; + this.Margin = 0; + this.PopupContent = new ApplicationSettingsWidget(theme.MenuButtonFactory) { HAnchor = HAnchor.Absolute, - VAnchor = VAnchor.Fit, + VAnchor = VAnchor.Center, Width = 500, BackgroundColor = Color.White }; - this.AddChild(popupButton); + var row = new FlowLayoutWidget() + { + HAnchor = HAnchor.Stretch, + VAnchor = VAnchor.Stretch, + }; + this.AddChild(row); + + row.AddChild(new IconButton(AggContext.StaticData.LoadIcon("mh-app-logo.png", IconColor.Theme), theme) + { + VAnchor = VAnchor.Center, + Margin = new BorderDouble(right: 4), + Selectable = false + }); + + row.AddChild(new TextWidget(ApplicationController.Instance.ShortProductName, textColor: ActiveTheme.Instance.PrimaryTextColor) + { + VAnchor = VAnchor.Center + }); } } diff --git a/Library/Widgets/ListView/IconListView.cs b/Library/Widgets/ListView/IconListView.cs index f0d681e23..c0f6ee48d 100644 --- a/Library/Widgets/ListView/IconListView.cs +++ b/Library/Widgets/ListView/IconListView.cs @@ -194,41 +194,55 @@ namespace MatterHackers.MatterControl.CustomWidgets { this.VAnchor = VAnchor.Fit; this.HAnchor = HAnchor.Fit; - this.Padding = 4; + this.Padding = 2; this.Margin = new BorderDouble(6, 0, 0, 6); - var container = new FlowLayoutWidget(FlowDirection.TopToBottom); - this.AddChild(container); - - imageWidget = new ImageWidget(thumbWidth, thumbHeight) - { - AutoResize = false, - Name = "List Item Thumbnail", - BackgroundColor = item.ListView.ThumbnailBackground, - Margin = 0, - }; - container.AddChild(imageWidget); - - this.SetItemThumbnail(loadingImage); - int maxWidth = thumbWidth - 4; - var text = new TextWidget(item.Model.Name, 0, 0, 9, textColor: ActiveTheme.Instance.PrimaryTextColor) + if (thumbWidth < 75) { - AutoExpandBoundsToText = false, - EllipsisIfClipped = true, - HAnchor = HAnchor.Center, - Margin = new BorderDouble(0, 0, 0, 3), - }; + imageWidget = new ImageWidget(thumbWidth, thumbHeight) + { + AutoResize = false, + Name = "List Item Thumbnail", + BackgroundColor = item.ListView.ThumbnailBackground, + Margin = 0, + }; + this.AddChild(imageWidget); + } + else + { + var container = new FlowLayoutWidget(FlowDirection.TopToBottom); + this.AddChild(container); - text.MaximumSize = new Vector2(maxWidth, 20); - if (text.Printer.LocalBounds.Width > maxWidth) - { - text.Width = maxWidth; - text.Text = item.Model.Name; + imageWidget = new ImageWidget(thumbWidth, thumbHeight) + { + AutoResize = false, + Name = "List Item Thumbnail", + BackgroundColor = item.ListView.ThumbnailBackground, + Margin = 0, + }; + container.AddChild(imageWidget); + + var text = new TextWidget(item.Model.Name, 0, 0, 9, textColor: ActiveTheme.Instance.PrimaryTextColor) + { + AutoExpandBoundsToText = false, + EllipsisIfClipped = true, + HAnchor = HAnchor.Center, + Margin = new BorderDouble(0, 0, 0, 3), + }; + + text.MaximumSize = new Vector2(maxWidth, 20); + if (text.Printer.LocalBounds.Width > maxWidth) + { + text.Width = maxWidth; + text.Text = item.Model.Name; + } + + container.AddChild(text); } - container.AddChild(text); + this.SetItemThumbnail(loadingImage); } public override async void OnLoad(EventArgs args) diff --git a/Library/Widgets/PrintLibraryWidget.cs b/Library/Widgets/PrintLibraryWidget.cs index 483a8b5c9..2d38f6ae8 100644 --- a/Library/Widgets/PrintLibraryWidget.cs +++ b/Library/Widgets/PrintLibraryWidget.cs @@ -431,7 +431,7 @@ namespace MatterHackers.MatterControl.PrintLibrary var bedConfig = new BedConfig(); var newTab = partPreviewContent.CreatePartTab(firstItem.Name, bedConfig, theme); - if (newTab.TabPage is PartTabPage printerTab) + if (newTab.TabContent is PartTabPage printerTab) { bedConfig.Scene.Children.Modify(list => { @@ -606,6 +606,29 @@ namespace MatterHackers.MatterControl.PrintLibrary }, }); + menuActions.Add(new PrintItemAction() + { + Title = "View XSmall Icons".Localize(), + AlwaysEnabled = true, + Action = (selectedLibraryItems, listView) => + { + listView.ListContentView = new IconListView(18); + listView.Reload().ConfigureAwait(false); + }, + }); + + + menuActions.Add(new PrintItemAction() + { + Title = "View Small Icons".Localize(), + AlwaysEnabled = true, + Action = (selectedLibraryItems, listView) => + { + listView.ListContentView = new IconListView(70); + listView.Reload().ConfigureAwait(false); + }, + }); + menuActions.Add(new PrintItemAction() { Title = "View Icons".Localize(), diff --git a/MatterControl.csproj b/MatterControl.csproj index aae1344d1..f923444ff 100644 --- a/MatterControl.csproj +++ b/MatterControl.csproj @@ -113,13 +113,14 @@ + - + diff --git a/PartPreviewWindow/GCode2DWidget.cs b/PartPreviewWindow/GCode2DWidget.cs index 31deebacd..44dd705cc 100644 --- a/PartPreviewWindow/GCode2DWidget.cs +++ b/PartPreviewWindow/GCode2DWidget.cs @@ -28,16 +28,11 @@ either expressed or implied, of the FreeBSD Project. */ using System; -using System.Diagnostics; -using System.Threading.Tasks; using MatterHackers.Agg; using MatterHackers.Agg.Transform; using MatterHackers.Agg.UI; using MatterHackers.Agg.VertexSource; using MatterHackers.GCodeVisualizer; -using MatterHackers.Localizations; -using MatterHackers.MatterControl.SlicerConfiguration; -using MatterHackers.MeshVisualizer; using MatterHackers.RenderOpenGl; using MatterHackers.RenderOpenGl.OpenGl; using MatterHackers.VectorMath; diff --git a/PartPreviewWindow/MainTab.cs b/PartPreviewWindow/MainTab.cs index bf13c956a..fd36ddbed 100644 --- a/PartPreviewWindow/MainTab.cs +++ b/PartPreviewWindow/MainTab.cs @@ -27,38 +27,161 @@ of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project. */ +using System; +using System.Linq; using MatterHackers.Agg; using MatterHackers.Agg.Image; using MatterHackers.Agg.UI; using MatterHackers.Agg.VertexSource; -using MatterHackers.VectorMath; +using MatterHackers.Localizations; namespace MatterHackers.MatterControl.PartPreviewWindow { - public class MainTab : ThreeViewTab + public class MainTab : GuiWidget, ITab { + public event EventHandler CloseClicked; + + private SimpleTabs parentTabControl; + + public MainTab(string tabLabel, SimpleTabs parentTabControl, GuiWidget tabContent, string tabImageUrl = null) + { + this.HAnchor = HAnchor.Fit; + this.VAnchor = VAnchor.Fit | VAnchor.Bottom; + this.Padding = 0; + this.Margin = 0; + + this.TabContent = tabContent; + this.parentTabControl = parentTabControl; + + this.AddChild( + new TabPill(tabLabel, ActiveTheme.Instance.PrimaryTextColor, tabImageUrl) + { + Margin = new BorderDouble(right: 16) + }); + + var closeButton = ApplicationController.Instance.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 += (sender, e) => + { + UiThread.RunOnIdle(() => + { + this.CloseClicked?.Invoke(this, null); + }); + }; + + this.AddChild(closeButton); + } + + public GuiWidget TabContent { get; } + + public static Color ActiveTabColor = ApplicationController.Instance.Theme.SlightShade; + + public static Color InactiveTabColor = ApplicationController.Instance.Theme.PrimaryTabFillColor; + + private static int tabInsetDistance = 14 / 2; + + internal MainTab NextTab { get; set; } + + internal MainTab PreviousTab { get; set; } + + public override void OnDraw(Graphics2D graphics2D) + { + var rect = LocalBounds; + var centerY = rect.YCenter; + + var siblings = this.Parent.Children.OfType().ToList(); + + int position = siblings.IndexOf(this); + + //MainTab leftSibling = (position > 0) ? siblings[position - 1] : null; + //MainTab rightSibling = (position < siblings.Count - 1) ? siblings[position + 1] : null; + + var activeTab = parentTabControl.ActiveTab; + + bool isFirstTab = position == 0; + bool rightSiblingSelected = this.NextTab == activeTab; + + // Tab - core + var tabShape = new VertexStorage(); + tabShape.MoveTo(rect.Left, centerY); + tabShape.LineTo(rect.Left + tabInsetDistance, rect.Top); + tabShape.LineTo(rect.Right - tabInsetDistance, rect.Top); + tabShape.LineTo(rect.Right, centerY); + if (!rightSiblingSelected) + { + tabShape.LineTo(rect.Right, rect.Bottom); + } + tabShape.LineTo(rect.Right - tabInsetDistance, rect.Bottom); + tabShape.LineTo(rect.Left + tabInsetDistance, rect.Bottom); + + if (isFirstTab) + { + tabShape.LineTo(rect.Left, rect.Bottom); + } + + graphics2D.Render( + tabShape, + (this == activeTab) ? ActiveTabColor : InactiveTabColor); + + if (!isFirstTab) + { + DrawTabLowerLeft( + graphics2D, + rect, + (this.PreviousTab == activeTab || this == activeTab) ? ActiveTabColor : InactiveTabColor); + } + + if (rightSiblingSelected) + { + DrawTabLowerRight(graphics2D, rect, ActiveTabColor); + } + + base.OnDraw(graphics2D); + } + + public static void DrawTabLowerRight(Graphics2D graphics2D, RectangleDouble rect, Color color) + { + // Tab - right nub + var tabRight = new VertexStorage(); + tabRight.MoveTo(rect.Right, rect.YCenter); + tabRight.LineTo(rect.Right, rect.Bottom); + tabRight.LineTo(rect.Right - tabInsetDistance, rect.Bottom); + + graphics2D.Render(tabRight, color); + } + + public static void DrawTabLowerLeft(Graphics2D graphics2D, RectangleDouble rect, Color color) + { + // Tab - left nub + var tabLeft = new VertexStorage(); + tabLeft.MoveTo(rect.Left, rect.YCenter); + tabLeft.LineTo(rect.Left + tabInsetDistance, rect.Bottom); + tabLeft.LineTo(rect.Left, rect.Bottom); + + graphics2D.Render(tabLeft, color); + } + private class TabPill : FlowLayoutWidget { private TextWidget label; public TabPill(string tabTitle, Color textColor, string imageUrl = null) { - var imageWidget = new ImageWidget(new ImageBuffer(16, 16)) - { - Margin = new BorderDouble(right: 6), - VAnchor = VAnchor.Center - }; - this.AddChild(imageWidget); - - label = new TextWidget(tabTitle) - { - TextColor = textColor, - VAnchor = VAnchor.Center - }; - this.AddChild(label); + this.Selectable = false; + this.Padding = new BorderDouble(10, 5, 10, 4); if (!string.IsNullOrEmpty(imageUrl)) { + var imageWidget = new ImageWidget(new ImageBuffer(16, 16)) + { + Margin = new BorderDouble(right: 6, bottom: 2), + VAnchor = VAnchor.Center + }; + this.AddChild(imageWidget); + // Attempt to load image try { @@ -67,11 +190,18 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } catch { } } + + label = new TextWidget(tabTitle) + { + TextColor = textColor, + VAnchor = VAnchor.Center + }; + this.AddChild(label); } public Color TextColor { - get => label.TextColor; + get => label.TextColor; set => label.TextColor = value; } @@ -81,46 +211,5 @@ namespace MatterHackers.MatterControl.PartPreviewWindow set => label.Text = value; } } - - public MainTab(string tabTitle, string tabName, TabPage tabPage, string tabImageUrl = null) - : this( - new TabPill(tabTitle, new Color(ActiveTheme.Instance.PrimaryTextColor, 140), tabImageUrl), - new TabPill(tabTitle, ActiveTheme.Instance.PrimaryTextColor, tabImageUrl), - new TabPill(tabTitle, ActiveTheme.Instance.PrimaryTextColor, tabImageUrl), - tabName, - tabPage) - { - } - - public MainTab(GuiWidget normalWidget, GuiWidget hoverWidget, GuiWidget pressedWidget, string tabName, TabPage tabPage) - : base(tabName, normalWidget, hoverWidget, pressedWidget, tabPage) - { - this.HAnchor = HAnchor.Fit; - this.VAnchor = VAnchor.Fit | VAnchor.Bottom; - } - - public int BorderWidth { get; set; } = 1; - public int borderRadius { get; set; } = 4; - - private Color activeTabColor = ApplicationController.Instance.Theme.SlightShade; - private Color inactiveTabColor = ApplicationController.Instance.Theme.PrimaryTabFillColor; - - public override void OnDraw(Graphics2D graphics2D) - { - RectangleDouble borderRectangle = LocalBounds; - borderRectangle.ExpandToInclude(new Vector2(0, -15)); - - if (BorderWidth > 0) - { - var r = new RoundedRect(borderRectangle, this.borderRadius); - r.normalize_radius(); - - graphics2D.Render( - r, - selectedWidget.Visible ? activeTabColor : inactiveTabColor); - } - - base.OnDraw(graphics2D); - } } } diff --git a/PartPreviewWindow/IconTab.cs b/PartPreviewWindow/NewTabButton.cs similarity index 71% rename from PartPreviewWindow/IconTab.cs rename to PartPreviewWindow/NewTabButton.cs index 7a7c60e78..9778b5ac1 100644 --- a/PartPreviewWindow/IconTab.cs +++ b/PartPreviewWindow/NewTabButton.cs @@ -27,6 +27,7 @@ of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project. */ +using System.Linq; using MatterHackers.Agg; using MatterHackers.Agg.Image; using MatterHackers.Agg.UI; @@ -34,27 +35,38 @@ using MatterHackers.MatterControl.CustomWidgets; namespace MatterHackers.MatterControl.PartPreviewWindow { - public class IconTab : Tab + public class NewTabButton : GuiWidget { - private IconButton iconButton; + private SimpleTabs parentTabControl; - public IconTab(string tabName, TabPage tabPage, ImageBuffer imageBuffer, ThemeConfig theme) - : base(tabName, tabPage) + public IconButton IconButton { get; } + + public NewTabButton(ImageBuffer imageBuffer, SimpleTabs parentTabControl, ThemeConfig theme) { - iconButton = new IconButton(imageBuffer, theme) + this.parentTabControl = parentTabControl; + this.HAnchor = HAnchor.Fit; + + IconButton = new IconButton(imageBuffer, theme) { + HAnchor = HAnchor.Left, Height = theme.MicroButton.Options.FixedHeight, Width = theme.MicroButton.Options.FixedHeight, - Selectable = false + Margin = new BorderDouble(left: 10), }; - this.AddChild(iconButton); + this.AddChild(IconButton); } - protected override void OnTabIndexChanged() + public ITab LastTab { get; set; } + + public override void OnDraw(Graphics2D graphics2D) { - iconButton.BackgroundColor = (this.TabPage == TabBarContaningTab.GetActivePage()) ? ActiveTheme.Instance.TertiaryBackgroundColor : Color.Transparent; - base.OnTabIndexChanged(); + MainTab.DrawTabLowerLeft( + graphics2D, + this.LocalBounds, + (parentTabControl.ActiveTab == this.LastTab) ? MainTab.ActiveTabColor : MainTab.InactiveTabColor); + + base.OnDraw(graphics2D); } } } \ No newline at end of file diff --git a/PartPreviewWindow/PartPreviewContent.cs b/PartPreviewWindow/PartPreviewContent.cs index e30804966..df02cbe98 100644 --- a/PartPreviewWindow/PartPreviewContent.cs +++ b/PartPreviewWindow/PartPreviewContent.cs @@ -30,13 +30,12 @@ either expressed or implied, of the FreeBSD Project. using System; using System.Linq; using MatterHackers.Agg; -using MatterHackers.Agg.Platform; using MatterHackers.Agg.UI; using MatterHackers.Localizations; using MatterHackers.MatterControl.AboutPage; -using MatterHackers.MatterControl.CustomWidgets; using MatterHackers.MatterControl.SettingsManagement; using MatterHackers.MatterControl.SlicerConfiguration; +using MatterHackers.VectorMath; namespace MatterHackers.MatterControl.PartPreviewWindow { @@ -45,20 +44,33 @@ namespace MatterHackers.MatterControl.PartPreviewWindow private EventHandler unregisterEvents; private MainTab printerTab = null; - private TabControl tabControl; + private NewTabButton plusTabSelect; + private ChromeTabs tabControl; public PartPreviewContent() + : base(FlowDirection.TopToBottom) { var printer = ApplicationController.Instance.ActivePrinter; var theme = ApplicationController.Instance.Theme; this.AnchorAll(); - tabControl = ApplicationController.Instance.Theme.CreateTabControl(2); + var extensionArea = new FlowLayoutWidget(); - tabControl.TabBar.TabIndexChanged += (s, e) => + tabControl = new ChromeTabs(extensionArea, theme) { - if (tabControl.GetTabPage(tabControl.SelectedTabIndex) is PartTabPage tabPage) + VAnchor = VAnchor.Stretch, + HAnchor = HAnchor.Stretch, + BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor, + NewTabPage = () => + { + return new PlusTabPage(this, tabControl, theme); + } + }; + + tabControl.ActiveTabChanged += (s, e) => + { + if (this.tabControl.ActiveTab?.TabContent is PartTabPage tabPage) { var dragDropData = ApplicationController.Instance.DragDropData; @@ -68,58 +80,27 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } }; - var separator = tabControl.Children().FirstOrDefault(); - separator.BackgroundColor = ApplicationController.Instance.Theme.SlightShade; + tabControl.TabBar.Padding = new BorderDouble(top: 4); + tabControl.TabBar.SeparatorLine.BackgroundColor = ApplicationController.Instance.Theme.SlightShade; + tabControl.TabBar.SeparatorLine.Height = 2; - Color selectedTabColor; - if (!UserSettings.Instance.IsTouchScreen) - { - tabControl.TabBar.BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor; - selectedTabColor = ActiveTheme.Instance.TabLabelSelected; - } - else - { - tabControl.TabBar.BackgroundColor = ActiveTheme.Instance.TransparentLightOverlay; - selectedTabColor = ActiveTheme.Instance.SecondaryAccentColor; - } + Color selectedTabColor = ActiveTheme.Instance.TabLabelSelected; // Add a tab for the current printer if (ActiveSliceSettings.Instance.PrinterSelected) { string tabTitle = ActiveSliceSettings.Instance.GetValue(SettingsKey.printer_name); printerTab = CreatePrinterTab(printer, theme, tabTitle); + tabControl.AddTab(printerTab); } else { - this.CreatePartTab("New Part", printer.Bed, theme, 0); + this.CreatePartTab("New Part", printer.Bed, theme); } - // TODO: add in the printers and designs that are currently open (or were open last run). - var plusTabSelect = new IconTab( - "Create New", - new TabPage(new PlusTabPage(this, printer, theme), "+"), - AggContext.StaticData.LoadIcon("fa-plus_12.png", IconColor.Theme), - theme); - - plusTabSelect.VAnchor = VAnchor.Bottom; - - plusTabSelect.MinimumSize = new VectorMath.Vector2(16, 16); - plusTabSelect.Margin = new BorderDouble(left: 10, top: 6); - plusTabSelect.Padding = 0; - plusTabSelect.ToolTipText = "Create New".Localize(); - tabControl.AddTab(plusTabSelect); - - tabControl.TabBar.AddChild(new HorizontalSpacer()); - // add in the update available button - LinkButtonFactory linkButtonFactory = new LinkButtonFactory() - { - textColor = ActiveTheme.Instance.PrimaryTextColor, - fontSize = 12, - }; - - Button updateAvailableButton = linkButtonFactory.Generate("Update Available"); + Button updateAvailableButton = theme.LinkButtonFactory.Generate("Update Available"); updateAvailableButton.Name = "Update Available Link"; updateAvailableButton.Visible = UpdateControlData.Instance.UpdateStatus == UpdateControlData.UpdateStatusStates.UpdateAvailable; updateAvailableButton.ToolTipText = "There is a new update available for download".Localize(); @@ -133,7 +114,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow DialogWindow.Show(); }); }); - tabControl.TabBar.AddChild(updateAvailableButton); + + tabControl.AddChild(updateAvailableButton); UpdateControlData.Instance.UpdateStatusChanged.RegisterEvent((s, e) => { @@ -141,17 +123,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow }, ref unregisterEvents); // this causes the update button to be centered - tabControl.TabBar.AddChild(new HorizontalSpacer()); - - // put in the login logout control - var rightPanelArea = new FlowLayoutWidget() - { - VAnchor = VAnchor.Stretch - }; - - var extensionArea = new FlowLayoutWidget(); - - rightPanelArea.AddChild(extensionArea); + //tabControl.TabBar.AddChild(new HorizontalSpacer()); //rightPanelArea.AddChild( // new ImageWidget( @@ -161,7 +133,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow // DebugShowBounds = true // }); - tabControl.TabBar.AddChild(rightPanelArea); + //this.AddChild(tabControl); this.AddChild(tabControl); @@ -171,7 +143,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow && stringEvent.Data == SettingsKey.printer_name && printerTab != null) { - printerTab.TabPage.Text = ActiveSliceSettings.Instance.GetValue(SettingsKey.printer_name); + printerTab.Text = ActiveSliceSettings.Instance.GetValue(SettingsKey.printer_name); } }, ref unregisterEvents); @@ -187,38 +159,36 @@ namespace MatterHackers.MatterControl.PartPreviewWindow }, ref unregisterEvents); } - private static MainTab CreatePrinterTab(PrinterConfig printer, ThemeConfig theme, string tabTitle) + private MainTab CreatePrinterTab(PrinterConfig printer, ThemeConfig theme, string tabTitle) { string oemName = printer.Settings.GetValue(SettingsKey.make); OemSettings.Instance.OemUrls.TryGetValue(oemName, out string oemUrl); - var printerTab = new MainTab( + return new MainTab( tabTitle, - "3D View Tab", + tabControl, new PrinterTabPage(printer, theme, tabTitle.ToUpper()), - "https://www.google.com/s2/favicons?domain=" + oemUrl ?? "www.matterhackers.com"); - printerTab.ToolTipText = "Preview 3D Design".Localize(); - - theme.SetPrinterTabStyles(printerTab); - return printerTab; + "https://www.google.com/s2/favicons?domain=" + oemUrl ?? "www.matterhackers.com") + { + Name = "3D View Tab", + MinimumSize = new Vector2(120, theme.shortButtonHeight) + }; } - internal MainTab CreatePartTab(string tabTitle, BedConfig sceneContext, ThemeConfig theme, int tabIndex = 1) + internal MainTab CreatePartTab(string tabTitle, BedConfig sceneContext, ThemeConfig theme) { var partTab = new MainTab( tabTitle, - "newPart" + tabControl.TabCount, + tabControl, new PartTabPage(null, sceneContext, theme, "xxxxx"), - "https://i.imgur.com/nkeYgfU.png"); + "https://i.imgur.com/nkeYgfU.png") + { + Name = "newPart" + tabControl.AllTabs.Count(), + MinimumSize = new Vector2(120, theme.shortButtonHeight) + }; - theme.SetPrinterTabStyles(partTab); - - var margin = partTab.Margin; - partTab.Margin = new BorderDouble(1, margin.Bottom, 1, margin.Top); - - tabControl.AddTab(partTab, tabPosition: tabIndex); - tabControl.SelectedTabIndex = tabIndex; + tabControl.AddTab(partTab); return partTab; } diff --git a/PartPreviewWindow/PartTabPage.cs b/PartPreviewWindow/PartTabPage.cs index 7e4f2eb7c..3dffd5b44 100644 --- a/PartPreviewWindow/PartTabPage.cs +++ b/PartPreviewWindow/PartTabPage.cs @@ -71,7 +71,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } }; viewControls3D.OverflowMenu.DynamicPopupContent = this.GetViewControls3DOverflowMenu; - + bool isPrinterType = this is PrinterTabPage; // The 3D model view diff --git a/PartPreviewWindow/PlusTabPage.cs b/PartPreviewWindow/PlusTabPage.cs index ed5e94585..139a7996e 100644 --- a/PartPreviewWindow/PlusTabPage.cs +++ b/PartPreviewWindow/PlusTabPage.cs @@ -40,7 +40,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow { public class PlusTabPage : FlowLayoutWidget { - public PlusTabPage(PartPreviewContent partPreviewContent, PrinterConfig printer, ThemeConfig theme) + public PlusTabPage(PartPreviewContent partPreviewContent, SimpleTabs simpleTabs, ThemeConfig theme) : base(FlowDirection.TopToBottom) { this.HAnchor = HAnchor.Stretch; @@ -58,7 +58,11 @@ namespace MatterHackers.MatterControl.PartPreviewWindow createItemsSection.AddChild(createPart); createPart.Click += (s, e) => { - partPreviewContent.CreatePartTab("New Part", new BedConfig(), theme); + UiThread.RunOnIdle(() => + { + simpleTabs.RemoveTab(simpleTabs.ActiveTab); + partPreviewContent.CreatePartTab("New Part", new BedConfig(), theme); + }); }; var createPrinter = theme.ButtonFactory.Generate("Create Printer".Localize()); @@ -67,20 +71,20 @@ namespace MatterHackers.MatterControl.PartPreviewWindow createPrinter.HAnchor = HAnchor.Left; createPrinter.Click += (s, e) => { - if (ApplicationController.Instance.ActivePrinter.Connection.PrinterIsPrinting + UiThread.RunOnIdle(() => + { + simpleTabs.RemoveTab(simpleTabs.ActiveTab); + + if (ApplicationController.Instance.ActivePrinter.Connection.PrinterIsPrinting || ApplicationController.Instance.ActivePrinter.Connection.PrinterIsPaused) - { - UiThread.RunOnIdle(() => - StyledMessageBox.ShowMessageBox("Please wait until the print has finished and try again.".Localize(), "Can't add printers while printing".Localize()) - ); - } - else - { - UiThread.RunOnIdle(() => + { + StyledMessageBox.ShowMessageBox("Please wait until the print has finished and try again.".Localize(), "Can't add printers while printing".Localize()); + } + else { DialogWindow.Show(PrinterSetup.GetBestStartPage(PrinterSetup.StartPageOptions.ShowMakeModel)); - }); - } + } + }); }; createItemsSection.AddChild(createPrinter); @@ -99,6 +103,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow if (!string.IsNullOrEmpty(result.FileName) && File.Exists(result.FileName)) { + simpleTabs.RemoveTab(simpleTabs.ActiveTab); ImportSettingsPage.ImportFromExisting(result.FileName); } }); @@ -122,8 +127,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow redeemDesignCode.HAnchor = HAnchor.Left; redeemDesignCode.Click += (s, e) => { - // Implementation already does RunOnIdle - ApplicationController.Instance.RedeemDesignCode?.Invoke(); + UiThread.RunOnIdle(() => + { + simpleTabs.RemoveTab(simpleTabs.ActiveTab); + // Implementation already does RunOnIdle + ApplicationController.Instance.RedeemDesignCode?.Invoke(); + }); }; otherItemsSection.AddChild(redeemDesignCode); @@ -133,8 +142,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow redeemShareCode.HAnchor = HAnchor.Left; redeemShareCode.Click += (s, e) => { - // Implementation already does RunOnIdle - ApplicationController.Instance.EnterShareCode?.Invoke(); + UiThread.RunOnIdle(() => + { + simpleTabs.RemoveTab(simpleTabs.ActiveTab); + + // Implementation already does RunOnIdle + ApplicationController.Instance.EnterShareCode?.Invoke(); + }); }; otherItemsSection.AddChild(redeemShareCode); @@ -147,17 +161,22 @@ namespace MatterHackers.MatterControl.PartPreviewWindow shopButton.Margin = buttonSpacing; shopButton.Click += (sender, e) => { - double activeFilamentDiameter = 0; - if (ActiveSliceSettings.Instance.PrinterSelected) + UiThread.RunOnIdle(() => { - activeFilamentDiameter = 3; - if (ActiveSliceSettings.Instance.GetValue(SettingsKey.filament_diameter) < 2) - { - activeFilamentDiameter = 1.75; - } - } + simpleTabs.RemoveTab(simpleTabs.ActiveTab); - MatterControlApplication.Instance.LaunchBrowser("http://www.matterhackers.com/mc/store/redirect?d={0}&clk=mcs&a={1}".FormatWith(activeFilamentDiameter, OemSettings.Instance.AffiliateCode)); + double activeFilamentDiameter = 0; + if (ActiveSliceSettings.Instance.PrinterSelected) + { + activeFilamentDiameter = 3; + if (ActiveSliceSettings.Instance.GetValue(SettingsKey.filament_diameter) < 2) + { + activeFilamentDiameter = 1.75; + } + } + + MatterControlApplication.Instance.LaunchBrowser("http://www.matterhackers.com/mc/store/redirect?d={0}&clk=mcs&a={1}".FormatWith(activeFilamentDiameter, OemSettings.Instance.AffiliateCode)); + }); }; otherItemsSection.AddChild(shopButton); } diff --git a/PartPreviewWindow/PrinterTabPage.cs b/PartPreviewWindow/PrinterTabPage.cs index 06e078197..42234eff1 100644 --- a/PartPreviewWindow/PrinterTabPage.cs +++ b/PartPreviewWindow/PrinterTabPage.cs @@ -53,7 +53,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow private DoubleSolidSlider layerRenderRatioSlider; private SystemWindow parentSystemWindow; private SliceLayerSelector layerScrollbar; - private PrinterConfig printer; + internal PrinterConfig printer; internal GCode3DWidget gcode3DWidget; public PrinterTabPage(PrinterConfig printer, ThemeConfig theme, string tabTitle) @@ -281,7 +281,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow { Visible = (this.ViewMode == PartViewMode.Layers2D) }; - view3DContainer.AddChild(gcode2DWidget); + view3DWidget.InteractionLayer.AddChild(gcode2DWidget); viewControls3D.Layers2DButton.Enabled = true; } diff --git a/PartPreviewWindow/Toolbar.cs b/PartPreviewWindow/Toolbar.cs new file mode 100644 index 000000000..d2871e8a8 --- /dev/null +++ b/PartPreviewWindow/Toolbar.cs @@ -0,0 +1,268 @@ +/* +Copyright (c) 2017, 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.Collections.Generic; +using System.Linq; +using MatterHackers.Agg.Platform; +using MatterHackers.Agg.UI; +using MatterHackers.Localizations; +using MatterHackers.MatterControl.CustomWidgets; +using MatterHackers.VectorMath; + +namespace MatterHackers.MatterControl.PartPreviewWindow +{ + /// + /// A toolbar with an optional right anchored element and an ActionBar child to add actions to the bar + /// + public class Toolbar : Bar + { + public FlowLayoutWidget ActionBar { get; } + + public HorizontalLine SeparatorLine { get; } + + public Toolbar(GuiWidget rightAnchorItem, ThemeConfig theme, bool bottomBorder = true) + : base(rightAnchorItem, theme) + { + GuiWidget context = this; + + this.ActionBar = new FlowLayoutWidget() + { + HAnchor = HAnchor.Stretch + }; + + if (bottomBorder) + { + var column = new FlowLayoutWidget(FlowDirection.TopToBottom) + { + HAnchor = HAnchor.Stretch, + VAnchor = VAnchor.Fit + }; + this.AddChild(column, 0); + + column.AddChild(this.ActionBar); + column.AddChild(this.SeparatorLine = new HorizontalLine(40)); + } + else + { + this.AddChild(this.ActionBar, 0); + } + } + } + + public interface ITab + { + GuiWidget TabContent { get; } + } + + /// + /// A toolbar like item with an optional right anchored element + /// + public class Bar : GuiWidget + { + public Bar(GuiWidget rightAnchorItem, ThemeConfig theme) + { + if (rightAnchorItem != null) + { + rightAnchorItem.HAnchor |= HAnchor.Right; + this.AddChild(rightAnchorItem); + } + } + } + + /// + /// A toolbar and associated tab body + /// + public class SimpleTabs : FlowLayoutWidget + { + public Toolbar TabBar { get; } + + private GuiWidget body; + + public SimpleTabs(GuiWidget rightAnchorItem, ThemeConfig theme, bool bottomBorder = true) + : base(FlowDirection.TopToBottom) + { + this.AddChild(TabBar = new Toolbar(rightAnchorItem, theme, bottomBorder) + { + HAnchor = HAnchor.Stretch, + VAnchor = VAnchor.Fit + }); + + this.AddChild(body = new GuiWidget() + { + HAnchor = HAnchor.Stretch, + VAnchor = VAnchor.Stretch, + }); + } + + public event EventHandler ActiveTabChanged; + + private List _allTabs = new List(); + + public IEnumerable AllTabs => _allTabs; + + public void AddTab(GuiWidget tabWidget, int position) + { + var iTab = tabWidget as ITab; + + _allTabs.Add(tabWidget as ITab); + + tabWidget.Click += TabWidget_Click; + + this.TabBar.ActionBar.AddChild(tabWidget, position); + + this.body.AddChild(iTab.TabContent); + } + + private void TabWidget_Click(object sender, MouseEventArgs e) + { + this.ActiveTab = sender as ITab; + } + + internal void RemoveTab(ITab tab) + { + _allTabs.Remove(tab); + + TabBar.ActionBar.RemoveChild(tab as GuiWidget); + body.RemoveChild(tab.TabContent); + + ActiveTab = _allTabs.LastOrDefault(); + } + + private ITab _activeTab; + public ITab ActiveTab + { + get => _activeTab; + set + { + if (_activeTab != value) + { + _activeTab = value; + + var clickedWidget = value as GuiWidget; + + foreach (var tab in _allTabs) + { + tab.TabContent.Visible = (tab == clickedWidget); + } + + this.OnActiveTabChanged(); + } + } + } + + protected virtual void OnActiveTabChanged() + { + this.ActiveTabChanged?.Invoke(this, null); + } + } + + public class ChromeTabs : SimpleTabs + { + private NewTabButton plusTabButton; + + public ChromeTabs(GuiWidget rightAnchorItem, ThemeConfig theme) + : base(rightAnchorItem, theme) + { + // TODO: add in the printers and designs that are currently open (or were open last run). + var leadingTabAdornment = new GuiWidget() + { + MinimumSize = new VectorMath.Vector2(16, theme.shortButtonHeight), + VAnchor = VAnchor.Bottom + }; + leadingTabAdornment.AfterDraw += (s, e) => + { + var firstItem = this.AllTabs.OfType().FirstOrDefault(); + MainTab.DrawTabLowerRight(e.graphics2D, leadingTabAdornment.LocalBounds, (firstItem == this.ActiveTab) ? MainTab.ActiveTabColor : MainTab.InactiveTabColor); + }; + this.TabBar.ActionBar.AddChild(leadingTabAdornment); + + // TODO: add in the printers and designs that are currently open (or were open last run). + plusTabButton = new NewTabButton( + AggContext.StaticData.LoadIcon("fa-plus_12.png", IconColor.Theme), + this, + theme) + { + VAnchor = VAnchor.Bottom, + MinimumSize = new Vector2(16, theme.shortButtonHeight), + ToolTipText = "Create New".Localize() + }; + plusTabButton.IconButton.Click += (s, e) => + { + this.AddTab( + new MainTab("New Tab".Localize(), this, this.NewTabPage()) + { + MinimumSize = new Vector2(0, theme.shortButtonHeight) + }); + }; + + this.TabBar.ActionBar.AddChild(plusTabButton); + } + + public void AddTab(GuiWidget tab) + { + var position = this.TabBar.ActionBar.GetChildIndex(plusTabButton); + + if (tab is MainTab mainTab) + { + mainTab.PreviousTab = this.AllTabs.OfType().LastOrDefault(); + if (mainTab.PreviousTab != null) + { + mainTab.PreviousTab.NextTab = mainTab; + } + + this.AddTab(tab, position); + + mainTab.CloseClicked += MainTab_CloseClicked; + this.ActiveTab = mainTab; + } + } + + private void MainTab_CloseClicked(object sender, EventArgs e) + { + if (sender is ITab tab) + { + this.RemoveTab(sender as ITab); + + if (tab.TabContent is PrinterTabPage printerTab) + { + printerTab.printer.Settings.Helpers.SetMarkedForDelete(true); + } + } + } + + public Func NewTabPage { get; set; } + + protected override void OnActiveTabChanged() + { + plusTabButton.LastTab = this.AllTabs.LastOrDefault(); + base.OnActiveTabChanged(); + } + } +} \ No newline at end of file diff --git a/PartPreviewWindow/View3D/SlicePopupMenu.cs b/PartPreviewWindow/View3D/SlicePopupMenu.cs index b4cfc80cd..6f75112c1 100644 --- a/PartPreviewWindow/View3D/SlicePopupMenu.cs +++ b/PartPreviewWindow/View3D/SlicePopupMenu.cs @@ -30,15 +30,12 @@ either expressed or implied, of the FreeBSD Project. using System; using System.Diagnostics; using System.Linq; -using System.Threading; using System.Threading.Tasks; using MatterHackers.Agg; using MatterHackers.Agg.UI; using MatterHackers.GCodeVisualizer; using MatterHackers.Localizations; using MatterHackers.MatterControl.CustomWidgets; -using MatterHackers.MatterControl.PrintQueue; -using MatterHackers.MatterControl.SlicerConfiguration; namespace MatterHackers.MatterControl.PartPreviewWindow {