// Copyright (c) Microsoft Corporation // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using Common; using Common.Utilities; using Microsoft.PowerToys.PreviewHandler.Gcode.Telemetry.Events; using Microsoft.PowerToys.Telemetry; namespace Microsoft.PowerToys.PreviewHandler.Gcode { /// /// Implementation of Control for Gcode Preview Handler. /// public class GcodePreviewHandlerControl : FormHandlerControl { /// /// Picture box control to display the G-code thumbnail. /// private PictureBox _pictureBox; /// /// Text box to display the information about blocked elements from Svg. /// private RichTextBox _textBox; /// /// Represent if an text box info bar is added for showing message. /// private bool _infoBarAdded; /// /// Initializes a new instance of the class. /// public GcodePreviewHandlerControl() { SetBackgroundColor(Settings.BackgroundColor); } /// /// Start the preview on the Control. /// /// Stream reference to access source file. public override void DoPreview(T dataSource) { if (global::PowerToys.GPOWrapper.GPOWrapper.GetConfiguredGcodePreviewEnabledValue() == global::PowerToys.GPOWrapper.GpoRuleConfigured.Disabled) { // GPO is disabling this utility. Show an error message instead. _infoBarAdded = true; AddTextBoxControl(Properties.Resource.GpoDisabledErrorText); Resize += FormResized; base.DoPreview(dataSource); return; } try { Bitmap thumbnail = null; if (!(dataSource is string filePath)) { throw new ArgumentException($"{nameof(dataSource)} for {nameof(GcodePreviewHandlerControl)} must be a string but was a '{typeof(T)}'"); } FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); using (var reader = new StreamReader(fs)) { var gcodeThumbnail = GcodeHelper.GetBestThumbnail(reader); thumbnail = gcodeThumbnail?.GetBitmap(); } _infoBarAdded = false; if (thumbnail == null) { _infoBarAdded = true; AddTextBoxControl(Properties.Resource.GcodeWithoutEmbeddedThumbnails); } else { AddPictureBoxControl(thumbnail); } Resize += FormResized; base.DoPreview(fs); try { PowerToysTelemetry.Log.WriteEvent(new GcodeFilePreviewed()); } catch { // Should not crash if sending telemetry is failing. Ignore the exception. } } catch (Exception ex) { PreviewError(ex, dataSource); } } /// /// Occurs when RichtextBox is resized. /// /// Reference to resized control. /// Provides data for the ContentsResized event. private void RTBContentsResized(object sender, ContentsResizedEventArgs e) { var richTextBox = sender as RichTextBox; richTextBox.Height = e.NewRectangle.Height + 5; } /// /// Occurs when form is resized. /// /// Reference to resized control. /// Provides data for the resize event. private void FormResized(object sender, EventArgs e) { if (_infoBarAdded) { _textBox.Width = Width; } } /// /// Adds a PictureBox Control to Control Collection. /// /// Image to display on PictureBox Control. private void AddPictureBoxControl(Image image) { _pictureBox = new PictureBox(); _pictureBox.BackgroundImage = image; _pictureBox.BackgroundImageLayout = Width >= image.Width && Height >= image.Height ? ImageLayout.Center : ImageLayout.Zoom; _pictureBox.Dock = DockStyle.Fill; Controls.Add(_pictureBox); } /// /// Adds a Text Box in Controls for showing information about blocked elements. /// /// Message to be displayed in textbox. private void AddTextBoxControl(string message) { _textBox = new RichTextBox(); _textBox.Text = message; _textBox.BackColor = Color.LightYellow; _textBox.Multiline = true; _textBox.Dock = DockStyle.Top; _textBox.ReadOnly = true; _textBox.ContentsResized += RTBContentsResized; _textBox.ScrollBars = RichTextBoxScrollBars.None; _textBox.BorderStyle = BorderStyle.None; Controls.Add(_textBox); } /// /// Called when an error occurs during preview. /// /// The exception which occurred. /// Stream reference to access source file. private void PreviewError(Exception exception, T dataSource) { try { PowerToysTelemetry.Log.WriteEvent(new GcodeFilePreviewError { Message = exception.Message }); } catch { // Should not crash if sending telemetry is failing. Ignore the exception. } Controls.Clear(); _infoBarAdded = true; AddTextBoxControl(Properties.Resource.GcodeNotPreviewedError); base.DoPreview(dataSource); } } }