using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Globalization; using System.Threading; using System.IO; using MatterHackers.Agg.Image; using MatterHackers.Agg.VertexSource; using MatterHackers.Agg; using MatterHackers.Agg.UI; using MatterHackers.VectorMath; using MatterHackers.MatterControl.PartPreviewWindow; using MatterHackers.MatterControl.DataStorage; using MatterHackers.PolygonMesh; using MatterHackers.PolygonMesh.Processors; using MatterHackers.MatterControl.PrintQueue; namespace MatterHackers.MatterControl { public class PartThumbnailWidget : ClickWidget { static Thread thumbNailThread = null; PrintItemWrapper printItem; public PrintItemWrapper PrintItem { get { return printItem; } set { if (printItem != null) { printItem.FileHasChanged -= item_FileHasChanged; } printItem = value; thumbNailHasBeenRequested = false; if (printItem != null) { printItem.FileHasChanged += item_FileHasChanged; } } } ImageBuffer buildingThumbnailImage = new Agg.Image.ImageBuffer(); ImageBuffer noThumbnailImage = new Agg.Image.ImageBuffer(); ImageBuffer image = new Agg.Image.ImageBuffer(); // all te color stuff public double BorderWidth = 0; protected double borderRadius = 0; protected RGBA_Bytes HoverBorderColor = new RGBA_Bytes(); public RGBA_Bytes FillColor = new RGBA_Bytes(255, 255, 255); public RGBA_Bytes HoverBackgroundColor = new RGBA_Bytes(0, 0, 0, 50); RGBA_Bytes normalBackgroundColor = ActiveTheme.Instance.PrimaryAccentColor; bool thumbNailHasBeenRequested = false; event EventHandler unregisterEvents; public PartThumbnailWidget(PrintItemWrapper item, string noThumbnailFileName, string buildingThumbnailFileName, Vector2 size) { this.PrintItem = item; // Set Display Attributes this.Margin = new BorderDouble(0); this.Padding = new BorderDouble(5); this.Width = size.x; this.Height = size.y; this.MinimumSize = size; this.BackgroundColor = normalBackgroundColor; this.Cursor = Cursors.Hand; // set background images if (noThumbnailImage.Width == 0) { ImageBMPIO.LoadImageData(this.GetImageLocation(noThumbnailFileName), noThumbnailImage); ImageBMPIO.LoadImageData(this.GetImageLocation(buildingThumbnailFileName), buildingThumbnailImage); } this.image = new ImageBuffer(buildingThumbnailImage); // Add Handlers this.Click += new ButtonEventHandler(onMouseClick); this.MouseEnterBounds += new EventHandler(onEnter); this.MouseLeaveBounds += new EventHandler(onExit); ActiveTheme.Instance.ThemeChanged.RegisterEvent(onThemeChanged, ref unregisterEvents); CreateThumNailThreadIfNeeded(); } void item_FileHasChanged(object sender, EventArgs e) { thumbNailHasBeenRequested = false; Invalidate(); } private static void CreateThumNailThreadIfNeeded() { if (thumbNailThread == null) { thumbNailThread = new Thread(CreateThumbnailsThread); thumbNailThread.Name = "Queue Create Thumbnail"; thumbNailThread.IsBackground = true; thumbNailThread.Start(); } } public override void OnClosed(EventArgs e) { if (unregisterEvents != null) { unregisterEvents(this, null); } if (printItem != null) { printItem.FileHasChanged -= item_FileHasChanged; } base.OnClosed(e); } static List listOfWidgetsNeedingThumbnails = new List(); static void CreateThumbnailsThread() { while (true) { if (listOfWidgetsNeedingThumbnails.Count > 0) { PartThumbnailWidget thumbnailWidget = listOfWidgetsNeedingThumbnails[0]; if (thumbnailWidget.printItem == null) { thumbnailWidget.image = new ImageBuffer(thumbnailWidget.noThumbnailImage); } else // generate the image { Mesh loadedMesh = StlProcessing.Load(thumbnailWidget.printItem.FileLocation); thumbnailWidget.image = new ImageBuffer(thumbnailWidget.buildingThumbnailImage); thumbnailWidget.Invalidate(); if (loadedMesh != null) { ImageBuffer tempImage = new ImageBuffer(thumbnailWidget.image.Width, thumbnailWidget.image.Height, 32, new BlenderBGRA()); Graphics2D partGraphics2D = tempImage.NewGraphics2D(); List nonManifoldEdges = loadedMesh.GetNonManifoldEdges(); if (nonManifoldEdges.Count > 0) { if (File.Exists("RunUnitTests.txt")) { partGraphics2D.Circle(4, 4, 4, RGBA_Bytes.Red); } } AxisAlignedBoundingBox aabb = loadedMesh.GetAxisAlignedBoundingBox(); double maxSize = Math.Max(aabb.XSize, aabb.YSize); double scale = thumbnailWidget.image.Width / (maxSize * 1.2); RectangleDouble bounds2D = new RectangleDouble(aabb.minXYZ.x, aabb.minXYZ.y, aabb.maxXYZ.x, aabb.maxXYZ.y); PolygonMesh.Rendering.OrthographicZProjection.DrawTo(partGraphics2D, loadedMesh, new Vector2((thumbnailWidget.image.Width / scale - bounds2D.Width) / 2 - bounds2D.Left, (thumbnailWidget.image.Height / scale - bounds2D.Height) / 2 - bounds2D.Bottom), scale, thumbnailWidget.FillColor); thumbnailWidget.image = new ImageBuffer(tempImage); } else { thumbnailWidget.image = new ImageBuffer(thumbnailWidget.noThumbnailImage); } } thumbnailWidget.Invalidate(); using (TimedLock.Lock(listOfWidgetsNeedingThumbnails, "CreateThumbnailsThread()")) { listOfWidgetsNeedingThumbnails.RemoveAt(0); foreach (PartThumbnailWidget part in listOfWidgetsNeedingThumbnails) { // mark them so we try to add them again if needed part.thumbNailHasBeenRequested = false; } listOfWidgetsNeedingThumbnails.Clear(); } } Thread.Sleep(100); } } private void onThemeChanged(object sender, EventArgs e) { //Set background color to new theme this.normalBackgroundColor = ActiveTheme.Instance.PrimaryAccentColor; this.BackgroundColor = ActiveTheme.Instance.PrimaryAccentColor; //Regenerate thumbnails // The thumbnail color is currently white and does not change with this change. // If we eventually change the thumbnail color with the theme we will need to change this. //this.thumbNailHasBeenRequested = false; this.Invalidate(); } private void onMouseClick(object sender, MouseEventArgs e) { if (printItem != null) { string pathAndFile = printItem.FileLocation; if (File.Exists(pathAndFile)) { new PartPreviewMainWindow(printItem); } else { PrintQueueItem.ShowCantFindFileMessage(printItem); } } } private void onEnter(object sender, EventArgs e) { HoverBorderColor = new RGBA_Bytes(255, 255, 255); this.Invalidate(); } private void onExit(object sender, EventArgs e) { HoverBorderColor = new RGBA_Bytes(); this.Invalidate(); } public override void OnDraw(Graphics2D graphics2D) { RoundedRect rectBorder = new RoundedRect(this.LocalBounds, 0); //Trigger thumbnail generation if neeeded if (!thumbNailHasBeenRequested) { thumbNailHasBeenRequested = true; using (TimedLock.Lock(listOfWidgetsNeedingThumbnails, "PrintQueueItem OnDraw")) { //Add to thumbnail generation queue listOfWidgetsNeedingThumbnails.Add(this); } } if (this.FirstWidgetUnderMouse) { graphics2D.Render(rectBorder, this.HoverBackgroundColor); } graphics2D.Render(image, Width / 2 - image.Width / 2, Height / 2 - image.Height / 2); base.OnDraw(graphics2D); RectangleDouble Bounds = LocalBounds; RoundedRect borderRect = new RoundedRect(this.LocalBounds, this.borderRadius); Stroke strokeRect = new Stroke(borderRect, BorderWidth); graphics2D.Render(strokeRect, HoverBorderColor); } private string GetImageLocation(string imageName) { return Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, imageName); } } }