Merge pull request #5167 from larsbrubaker/main

Improving store page
This commit is contained in:
Lars Brubaker 2021-11-24 17:36:31 -08:00 committed by GitHub
commit 9ed6bf4378
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 315 additions and 55 deletions

View file

@ -33,7 +33,7 @@ using MatterHackers.Agg.UI;
namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab
{
public class ExploreItem : FlowLayoutWidget
public class ArticleItem : FlowLayoutWidget
{
private FeedItemData item;
private ThemeConfig theme;
@ -41,7 +41,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab
public static int IconSize => (int)(40 * GuiWidget.DeviceScale);
public static int ItemSpacing { get; } = 10;
public ExploreItem(FeedItemData item, ThemeConfig theme)
public ArticleItem(FeedItemData item, ThemeConfig theme)
{
this.HAnchor = HAnchor.Absolute;
this.Width = 400 * GuiWidget.DeviceScale;
@ -61,7 +61,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab
Margin = new BorderDouble(right: ItemSpacing)
};
imageWidget.Load += (s, e) => WebCache.RetrieveImageAsync(image, item.icon, true, new BlenderPreMultBGRA());
Load += (s, e) => WebCache.RetrieveImageAsync(image, item.icon, true, new BlenderPreMultBGRA());
this.AddChild(imageWidget);
}
else if (item.widget_url != null)
@ -80,7 +80,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab
VAnchor = VAnchor.Center,
};
imageWidget.Load += (s, e) => WebCache.RetrieveImageAsync(image, item.widget_url, true, new BlenderPreMultBGRA());
Load += (s, e) => WebCache.RetrieveImageAsync(image, item.widget_url, true, new BlenderPreMultBGRA());
whiteBackground.AddChild(imageWidget);
}

View file

@ -27,35 +27,32 @@ 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.Localizations;
using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.VectorMath;
namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab
{
public class ExploreSection : FlowLayoutWidget
public class ArticleSection : FlowLeftRightWithWrapping
{
private List<ExploreItem> allIconViews = new List<ExploreItem>();
private List<ArticleItem> allIconViews = new List<ArticleItem>();
private FeedSectionData content;
private ThemeConfig theme;
private TextButton moreButton;
int maxStuff = 7;
int maxStuff = 20;
public ExploreSection(FeedSectionData content, ThemeConfig theme)
: base(FlowDirection.TopToBottom)
public ArticleSection(FeedSectionData content, ThemeConfig theme)
{
Proportional = true;
VAnchor = VAnchor.Fit | VAnchor.Top;
this.content = content;
this.theme = theme;
foreach (var item in content.group_items)
{
allIconViews.Add(new ExploreItem(item, theme)
allIconViews.Add(new ArticleItem(item, theme)
{
BackgroundColor = theme.MinimalShade,
VAnchor = VAnchor.Fit,
@ -80,15 +77,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab
}
this.CloseChildren();
if (content.group_title != null)
{
this.AddChild(new TextWidget(content.group_title, pointSize: theme.H1PointSize, textColor: theme.TextColor, bold: true)
{
HAnchor = HAnchor.Left,
Margin = new BorderDouble(leftRightMargin, 5)
});
}
int i = 0;
foreach (var iconView in allIconViews)
{
@ -103,10 +91,8 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab
if (content.group_items.Count > maxStuff)
{
moreButton = new TextButton("More".Localize() + "...", theme)
var moreButton = new TextButton("More".Localize() + "...", theme)
{
VAnchor = VAnchor.Absolute,
HAnchor = HAnchor.Right,
BackgroundColor = theme.MinimalShade,
Margin = new BorderDouble(right: leftRightMargin),
};
@ -128,6 +114,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab
scroll.ScrollPositionFromTop = position;
}
};
this.AddChild(moreButton);
}
}

View file

@ -29,15 +29,12 @@ either expressed or implied, of the FreeBSD Project.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using MatterControl.Printing;
using MatterHackers.Agg;
using MatterHackers.Agg.Font;
using MatterHackers.Agg.Image;
using MatterHackers.Agg.UI;
using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.VectorMath;
using Newtonsoft.Json;
@ -49,7 +46,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab
private ThemeConfig theme;
private object locker = new object();
public ExplorePanel(ThemeConfig theme, string relativeUrl)
private GuiWidget topBanner;
private GuiWidget sectionSelectButtons;
private GuiWidget contentSection;
private bool loaded;
public ExplorePanel(ThemeConfig theme, string relativeUrl)
: base(FlowDirection.TopToBottom)
{
this.relativeUrl = relativeUrl;
@ -59,6 +61,16 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab
this.Margin = new BorderDouble(30 - 11, 0);
this.theme = theme;
topBanner = this.AddChild(new GuiWidget() { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit });
sectionSelectButtons = this.AddChild(new FlowLeftRightWithWrapping()
{
HAnchor = HAnchor.Stretch,
VAnchor = VAnchor.Fit,
Proportional = true,
Name = "Select Buttons"
});
contentSection = this.AddChild(new GuiWidget() { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit });
}
public override void OnLoad(EventArgs args)
@ -89,14 +101,14 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab
GuiWidget currentContentContainer = null;
foreach (var content in explorerFeed.Content)
{
AddContentItem(container, ref currentContentContainer, theme, content);
AddContentItem(theme, content);
}
this.CloseChildren();
foreach (var widget in container)
{
this.AddChild(widget);
}
UiThread.RunOnIdle(() =>
{
// Force layout to change to get it working
@ -110,14 +122,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab
}
private static void AddContentItem(List<GuiWidget> container, ref GuiWidget currentContentContainer, ThemeConfig theme, FeedSectionData content)
private void AddContentItem(ThemeConfig theme, FeedSectionData content)
{
switch (content.content_type)
{
case "headline":
/*
{
break;
// use the Golden Ratio to calculate an attractive size relative to the banner
var image = new ImageBuffer(1520, (int)(170 / 1.618));
var imageWidget = new ResponsiveImageWidget(image)
@ -154,12 +165,13 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab
container.Add(imageWidget);
}
*/
break;
case "banner_rotate":
// TODO: make this make a carousel rather than add the first item and rotate between all the items
var rand = new Random();
AddContentItem(container, ref currentContentContainer, theme, content.banner_list[rand.Next(content.banner_list.Count)]);
AddContentItem(theme, content.banner_list[rand.Next(content.banner_list.Count)]);
break;
case "banner_image":
@ -193,24 +205,58 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab
};
}
imageWidget.Load += (s, e) => WebCache.RetrieveImageAsync(image, content.image_url, false, new BlenderPreMultBGRA());
container.Add(imageWidget);
AfterDraw += (s, e) =>
{
if (!loaded)
{
loaded = true;
WebCache.RetrieveImageAsync(image, content.image_url, false, new BlenderPreMultBGRA());
}
};
topBanner.AddChild(imageWidget);
}
}
break;
case "article_group":
case "product_group":
if(currentContentContainer == null)
{
currentContentContainer = new FlowLeftRightWithWrapping()
{
Proportional = true,
};
container.Add(currentContentContainer);
// add the article group button to the button group
// add a content section connected to the button
var sectionButton = new TextButton(content.group_title, theme);
sectionSelectButtons.AddChild(sectionButton);
var exploreSection = new ArticleSection(content, theme)
{
Visible = false,
Name = content.group_title
};
contentSection.AddChild(exploreSection);
sectionButton.Click += (s, e) =>
{
foreach (var contentWidget in contentSection.Children)
{
contentWidget.Visible = contentWidget == exploreSection;
}
};
}
break;
case "product_group":
{
var sectionButton = new TextButton(content.group_title, theme);
sectionSelectButtons.AddChild(sectionButton);
var exploreSection = new ProductSection(content, theme)
{
Name = content.group_title
};
contentSection.AddChild(exploreSection);
sectionButton.Click += (s, e) =>
{
foreach (var contentWidget in contentSection.Children)
{
contentWidget.Visible = contentWidget == exploreSection;
}
};
}
currentContentContainer.AddChild(new ExploreSection(content, theme));
break;
}
}

View file

@ -40,6 +40,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab
public string icon;
public string link;
public string title;
public string subtitle;
public string url;
public string widget_url;
}

View file

@ -0,0 +1,135 @@
/*
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 ProductItem : FlowLayoutWidget
{
private FeedItemData item;
private ThemeConfig theme;
public static int IconSize => (int)(200 * GuiWidget.DeviceScale);
public static int ItemSpacing { get; } = 10;
public ProductItem(FeedItemData item, ThemeConfig theme)
: base(FlowDirection.TopToBottom)
{
this.Padding = ItemSpacing;
this.item = item;
this.theme = theme;
var image = new ImageBuffer(IconSize, IconSize);
if (item.widget_url != null)
{
var whiteBackground = new GuiWidget(IconSize, IconSize)
{
// these images expect to be on white so change the background to white
BackgroundColor = Color.White,
Margin = new BorderDouble(right: ItemSpacing)
};
this.AddChild(whiteBackground);
var imageWidget = new ImageWidget(image)
{
Selectable = false,
VAnchor = VAnchor.Center,
};
Load += (s, e) => WebCache.RetrieveImageAsync(image, item.widget_url, true, new BlenderPreMultBGRA());
whiteBackground.AddChild(imageWidget);
}
var titleText = new WrappedTextWidget(item.title, textColor: theme.TextColor, pointSize: theme.FontSize14)
{
Selectable = false,
VAnchor = VAnchor.Fit,
HAnchor = HAnchor.Stretch,
Margin = new BorderDouble(3, 3, 3, 9)
};
this.AddChild(titleText);
var descriptionText = new WrappedTextWidget(item.subtitle, textColor: theme.TextColor.WithAlpha(.7), pointSize: theme.FontSize8)
{
Selectable = false,
VAnchor = VAnchor.Fit,
HAnchor = HAnchor.Stretch,
Margin = 3
};
this.AddChild(descriptionText);
this.Cursor = Cursors.Hand;
}
public override Color BackgroundColor
{
get => (mouseInBounds) ? theme.AccentMimimalOverlay : base.BackgroundColor;
set => base.BackgroundColor = value;
}
private bool mouseInBounds = false;
public override void OnMouseEnterBounds(MouseEventArgs mouseEvent)
{
mouseInBounds = true;
base.OnMouseEnterBounds(mouseEvent);
this.Invalidate();
}
public override void OnMouseLeaveBounds(MouseEventArgs mouseEvent)
{
mouseInBounds = false;
base.OnMouseLeaveBounds(mouseEvent);
this.Invalidate();
}
protected override void OnClick(MouseEventArgs mouseEvent)
{
if (mouseEvent.Button == MouseButtons.Left)
{
if (item.url != null)
{
ApplicationController.LaunchBrowser("http://www.matterhackers.com/" + item.url);
}
else if (item.link != null)
{
ApplicationController.LaunchBrowser(item.link);
}
}
base.OnClick(mouseEvent);
}
}
}

View file

@ -0,0 +1,88 @@
/*
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.Collections.Generic;
using System.Linq;
using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.Localizations;
using MatterHackers.MatterControl.CustomWidgets;
namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab
{
public class ProductSection : FlowLeftRightWithWrapping
{
private List<ProductItem> allIconViews = new List<ProductItem>();
private FeedSectionData content;
private ThemeConfig theme;
private TextButton moreButton;
public ProductSection(FeedSectionData content, ThemeConfig theme)
{
Proportional = true;
VAnchor = VAnchor.Fit | VAnchor.Top;
this.content = content;
this.theme = theme;
foreach (var item in content.group_items)
{
allIconViews.Add(new ProductItem(item, theme)
{
BackgroundColor = theme.MinimalShade,
VAnchor = VAnchor.Fit,
});
}
AddContent();
}
public void AddContent()
{
int leftRightMargin = 5;
int topBottomMargin = 5;
// Reflow Children
foreach (var iconView in allIconViews)
{
if (this.Children.Contains(iconView))
{
this.RemoveChild(iconView);
}
}
this.CloseChildren();
foreach (var iconView in allIconViews)
{
iconView.ClearRemovedFlag();
iconView.Margin = new BorderDouble(leftRightMargin, topBottomMargin);
this.AddChild(iconView);
}
}
}
}

View file

@ -64,12 +64,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow.PlusTab
public override void OnMouseWheel(MouseEventArgs mouseEvent)
{
if (mouseEvent.WheelDelta != 0)
{
int direction = (mouseEvent.WheelDelta > 0) ? -1 : 1;
this.ScrollPosition += new Vector2(0, (ExploreItem.IconSize + (ExploreItem.ItemSpacing * 2)) * direction);
mouseEvent.WheelDelta = 0;
}
mouseEvent.WheelDelta *= 3;
base.OnMouseWheel(mouseEvent);
}
}
}

View file

@ -51,6 +51,10 @@ namespace MatterHackers.MatterControl
public static void RetrieveImageAsync(ImageBuffer imageToLoadInto, string uriToLoad, bool scaleToImageX, IRecieveBlenderByte scalingBlender = null)
{
var longHash = uriToLoad.GetLongHashCode();
if (scaleToImageX)
{
longHash = imageToLoadInto.Width.GetLongHashCode(longHash);
}
var imageFileName = ApplicationController.CacheablePath("Images", longHash.ToString() + ".png");
if (File.Exists(imageFileName))
@ -387,6 +391,8 @@ namespace MatterHackers.MatterControl
{
StaticData.Instance.LoadImageData(stream, imageToLoadInto);
}
imageToLoadInto.MarkImageChanged();
}
}
}

@ -1 +1 @@
Subproject commit ee639857de9d8157d9a656d3dc76c07aba02818b
Subproject commit 18bb089dfbd5474e518ce578826001f8b9e7f911

@ -1 +1 @@
Subproject commit 183673e004d7c085cb970bd5b8f04fbd3f4750b1
Subproject commit ca13554d458c15488c5e64f7c9dac984d3834aa0