diff --git a/MatterControl.csproj b/MatterControl.csproj index 1f210f4cc..e2ca59fc1 100644 --- a/MatterControl.csproj +++ b/MatterControl.csproj @@ -117,7 +117,9 @@ + + diff --git a/PartPreviewWindow/PlusTab/ExploreItem.cs b/PartPreviewWindow/PlusTab/ExploreItem.cs new file mode 100644 index 000000000..f5af1d9a5 --- /dev/null +++ b/PartPreviewWindow/PlusTab/ExploreItem.cs @@ -0,0 +1,94 @@ +/* +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 MatterHackers.Agg; +using MatterHackers.Agg.Image; +using MatterHackers.Agg.UI; + +namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab +{ + public class ExploreItem : FlowLayoutWidget + { + public ExploreItem(ExplorerFeedItem item) + { + var content = new FlowLayoutWidget() + { + Border = new BorderDouble(2), + BorderColor = ActiveTheme.Instance.PrimaryTextColor, + HAnchor = HAnchor.Absolute, + Width = 220 * GuiWidget.DeviceScale, + Margin = new BorderDouble(5), + }; + this.AddChild(content); + + if (item.icon != null) + { + ImageBuffer image = new ImageBuffer((int)(64 * GuiWidget.DeviceScale), (int)(64 * GuiWidget.DeviceScale)); + ImageWidget imageWidget = new ImageWidget(image) + { + Selectable = false, + VAnchor = VAnchor.Top, + Margin = new BorderDouble(3) + }; + + imageWidget.Load += (s, e) => ApplicationController.Instance.DownloadToImageAsync(image, item.icon, true, new BlenderPreMultBGRA()); + content.AddChild(imageWidget); + } + + var wrappedText = new WrappedTextWidget(item.title, textColor: ActiveTheme.Instance.PrimaryTextColor) + { + Selectable = false, + VAnchor = VAnchor.Center | VAnchor.Fit, + Margin = new BorderDouble(3) + }; + content.AddChild(wrappedText); + wrappedText.Load += (s, e) => + { + wrappedText.VAnchor = VAnchor.Top | VAnchor.Fit; + }; + + if (item.url != null) + { + content.Cursor = Cursors.Hand; + content.Click += (s, e) => + { + MatterControlApplication.Instance.LaunchBrowser("http://www.matterhackers.com/" + item.url); + }; + } + else if (item.reference != null) + { + content.Cursor = Cursors.Hand; + content.Click += (s, e) => + { + MatterControlApplication.Instance.LaunchBrowser(item.reference); + }; + } + } + } +} \ No newline at end of file diff --git a/PartPreviewWindow/PlusTab/ExplorePanel.cs b/PartPreviewWindow/PlusTab/ExplorePanel.cs index a1d4142a0..e97f716c7 100644 --- a/PartPreviewWindow/PlusTab/ExplorePanel.cs +++ b/PartPreviewWindow/PlusTab/ExplorePanel.cs @@ -39,78 +39,6 @@ using Newtonsoft.Json; namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab { - public class ExploreFeedContent - { - public string content_type; - public List group_items; - public string group_link; - public string group_subtitle; - public string group_title; - public string icon_url; - public string image_url; - public string link; - public string theme_filter; - } - - public class ExploreItem : FlowLayoutWidget - { - public ExploreItem(ExplorerFeedItem item) - { - var content = new FlowLayoutWidget() - { - Border = new BorderDouble(2), - BorderColor = ActiveTheme.Instance.PrimaryTextColor, - HAnchor = HAnchor.Absolute, - Width = 220 * GuiWidget.DeviceScale, - Margin = new BorderDouble(5), - }; - this.AddChild(content); - - if (item.icon != null) - { - ImageBuffer image = new ImageBuffer((int)(64 * GuiWidget.DeviceScale), (int)(64 * GuiWidget.DeviceScale)); - ImageWidget imageWidget = new ImageWidget(image) - { - Selectable = false, - VAnchor = VAnchor.Top, - Margin = new BorderDouble(3) - }; - - imageWidget.Load += (s, e) => ApplicationController.Instance.DownloadToImageAsync(image, item.icon, true, new BlenderPreMultBGRA()); - content.AddChild(imageWidget); - } - - var wrappedText = new WrappedTextWidget(item.title) - { - Selectable = false, - VAnchor = VAnchor.Center | VAnchor.Fit, - Margin = new BorderDouble(3) - }; - content.AddChild(wrappedText); - wrappedText.Load += (s, e) => - { - wrappedText.VAnchor = VAnchor.Top | VAnchor.Fit; - }; - - if (item.url != null) - { - content.Cursor = Cursors.Hand; - content.Click += (s, e) => - { - MatterControlApplication.Instance.LaunchBrowser("http://www.matterhackers.com/" + item.url); - }; - } - else if(item.reference != null) - { - content.Cursor = Cursors.Hand; - content.Click += (s, e) => - { - MatterControlApplication.Instance.LaunchBrowser(item.reference); - }; - } - } - } - public class ExplorePanel : ScrollableWidget { public ExplorePanel() @@ -138,6 +66,14 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab // add a bunch of content AddControlsForContent(content); + + UiThread.RunOnIdle(() => + { + // Force layout to change to get it working + var oldMargin = this.Margin; + this.Margin = new BorderDouble(20); + this.Margin = oldMargin; + }); } catch { @@ -202,6 +138,21 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab } } + #region json expand classes + + public class ExploreFeedContent + { + public string content_type; + public List group_items; + public string group_link; + public string group_subtitle; + public string group_title; + public string icon_url; + public string image_url; + public string link; + public string theme_filter; + } + public class ExplorerFeed { public List Content; @@ -216,132 +167,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab public string description; public string hero; public string icon; + public string reference; public string title; public string url; - public string reference; } - public class ExploreSection : FlowLayoutWidget - { - private List allIconViews = new List(); - private int cellIndex = 0; - private int columnCount = 1; - private ExploreFeedContent content; - private int lastReflowWidth = -1; - private int leftRightMargin; - private FlowLayoutWidget rowButtonContainer = null; - - public ExploreSection(ExploreFeedContent content) - : base(FlowDirection.TopToBottom) - { - this.content = content; - this.HAnchor = HAnchor.Stretch; - - foreach (var item in content.group_items) - { - allIconViews.Add(new ExploreItem(item)); - } - } - - public override void OnBoundsChanged(EventArgs e) - { - int currentWidth = (int)this.Size.X; - if (lastReflowWidth != currentWidth) - { - lastReflowWidth = currentWidth; - - int newColumnCount = RecomputeFlowValues(); - if (newColumnCount != columnCount) - { - columnCount = newColumnCount; - - // Reflow Children - foreach (var iconView in allIconViews) - { - iconView.Parent?.RemoveChild(iconView); - iconView.Margin = new BorderDouble(leftRightMargin, 0); - } - - this.CloseAllChildren(); - - if (content.group_title != null) - { - this.AddChild(new TextWidget(content.group_title, pointSize: 16, textColor: ActiveTheme.Instance.PrimaryTextColor) - { - HAnchor = HAnchor.Left, - Margin = new BorderDouble(5) - }); - } - - foreach (var iconView in allIconViews) - { - iconView.ClearRemovedFlag(); - AddColumnAndChild(iconView); - } - } - else - { - foreach (var iconView in allIconViews) - { - iconView.Margin = new BorderDouble(leftRightMargin, 0); - } - } - } - - base.OnBoundsChanged(e); - } - - private void AddColumnAndChild(ExploreItem iconView) - { - if (rowButtonContainer == null) - { - rowButtonContainer = new FlowLayoutWidget(FlowDirection.LeftToRight) - { - HAnchor = HAnchor.Stretch, - Padding = 0 - }; - this.AddChild(rowButtonContainer); - } - - rowButtonContainer.AddChild(iconView); - - if (cellIndex++ >= columnCount - 1) - { - rowButtonContainer = null; - cellIndex = 0; - } - } - - private int RecomputeFlowValues() - { - int padding = 4; - int itemWidth = (int)allIconViews[0].Width + (padding * 2); - - int newColumnCount = (int)Math.Floor(this.LocalBounds.Width / itemWidth); - int remainingSpace = (int)this.LocalBounds.Width - columnCount * itemWidth; - - // Reset position before reflow - cellIndex = 0; - rowButtonContainer = null; - - // There should always be at least one visible column - if (newColumnCount < 1) - { - newColumnCount = 1; - } - - // Only center items if extra space exists - - // we find the space we want between each column and the sides - double spacePerColumn = (remainingSpace > 0) ? remainingSpace / (newColumnCount + 1) : 0; - - // set the margin to be 1/2 the space (it will happen on each side of each icon) - leftRightMargin = (int)(remainingSpace > 0 ? spacePerColumn / 2 : 0); - - // put in padding to get the "other" side of the outside icons - this.Padding = new BorderDouble(leftRightMargin, 0); - - return newColumnCount; - } - } + #endregion json expand classes } \ No newline at end of file diff --git a/PartPreviewWindow/PlusTab/ExploreSection.cs b/PartPreviewWindow/PlusTab/ExploreSection.cs new file mode 100644 index 000000000..b6ce8a895 --- /dev/null +++ b/PartPreviewWindow/PlusTab/ExploreSection.cs @@ -0,0 +1,160 @@ +/* +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 MatterHackers.Agg; +using MatterHackers.Agg.UI; + +namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab +{ + public class ExploreSection : FlowLayoutWidget + { + private List allIconViews = new List(); + private int cellIndex = 0; + private int columnCount = 1; + private ExploreFeedContent content; + private int lastReflowWidth = -1; + private int leftRightMargin; + private FlowLayoutWidget rowButtonContainer = null; + + public ExploreSection(ExploreFeedContent content) + : base(FlowDirection.TopToBottom) + { + this.content = content; + this.HAnchor = HAnchor.Stretch; + + foreach (var item in content.group_items) + { + allIconViews.Add(new ExploreItem(item)); + } + } + + public override void OnBoundsChanged(EventArgs e) + { + int currentWidth = (int)this.Size.X; + if (lastReflowWidth != currentWidth) + { + lastReflowWidth = currentWidth; + + int newColumnCount = RecomputeFlowValues(); + if (newColumnCount != columnCount) + { + columnCount = newColumnCount; + + // Reflow Children + foreach (var iconView in allIconViews) + { + iconView.Parent?.RemoveChild(iconView); + iconView.Margin = new BorderDouble(leftRightMargin, 0); + } + + this.CloseAllChildren(); + + if (content.group_title != null) + { + this.AddChild(new TextWidget(content.group_title, pointSize: 16, textColor: ActiveTheme.Instance.PrimaryTextColor) + { + HAnchor = HAnchor.Left, + Margin = new BorderDouble(5) + }); + } + + foreach (var iconView in allIconViews) + { + iconView.ClearRemovedFlag(); + AddColumnAndChild(iconView); + } + } + else + { + foreach (var iconView in allIconViews) + { + iconView.Margin = new BorderDouble(leftRightMargin, 0); + } + } + } + + base.OnBoundsChanged(e); + } + + private void AddColumnAndChild(ExploreItem iconView) + { + if (rowButtonContainer == null) + { + rowButtonContainer = new FlowLayoutWidget(FlowDirection.LeftToRight) + { + HAnchor = HAnchor.Stretch, + Padding = 0 + }; + this.AddChild(rowButtonContainer); + } + + rowButtonContainer.AddChild(iconView); + + if (cellIndex++ >= columnCount - 1) + { + rowButtonContainer = null; + cellIndex = 0; + } + } + + private int RecomputeFlowValues() + { + int padding = 4; + int itemWidth = (int)allIconViews[0].Width + (padding * 2); + + int newColumnCount = (int)Math.Floor(this.LocalBounds.Width / itemWidth); + int remainingSpace = (int)this.LocalBounds.Width - columnCount * itemWidth; + + // Reset position before reflow + cellIndex = 0; + rowButtonContainer = null; + + // There should always be at least one visible column + if (newColumnCount < 1) + { + newColumnCount = 1; + } + + // Only center items if extra space exists + + // we find the space we want between each column and the sides + double spacePerColumn = (remainingSpace > 0) ? remainingSpace / (newColumnCount + 1) : 0; + + // set the margin to be 1/2 the space (it will happen on each side of each icon) + leftRightMargin = (int)(remainingSpace > 0 ? spacePerColumn / 2 : 0); + + // put in padding to get the "other" side of the outside icons + this.Padding = new BorderDouble(leftRightMargin, 0); + + return newColumnCount; + } + } +} \ No newline at end of file diff --git a/Submodules/agg-sharp b/Submodules/agg-sharp index 0d8468bd3..0d57ebf6a 160000 --- a/Submodules/agg-sharp +++ b/Submodules/agg-sharp @@ -1 +1 @@ -Subproject commit 0d8468bd3f43708eb921d677e4a0e35b8b6dcbd3 +Subproject commit 0d57ebf6abaa365881fd9f9b18562c288ab8cb66