diff --git a/AboutPage/AboutPage.cs b/AboutPage/AboutPage.cs index 34af95d3c..226f45ce9 100644 --- a/AboutPage/AboutPage.cs +++ b/AboutPage/AboutPage.cs @@ -41,7 +41,6 @@ using MatterHackers.MatterControl.HtmlParsing; namespace MatterHackers.MatterControl { - public class AboutWindow : SystemWindow { public AboutWindow() diff --git a/ActionBar/PrintActionRow.cs b/ActionBar/PrintActionRow.cs index 3d8b23ed0..97b5a0d3d 100644 --- a/ActionBar/PrintActionRow.cs +++ b/ActionBar/PrintActionRow.cs @@ -284,7 +284,10 @@ namespace MatterHackers.MatterControl.ActionBar void onStartButton_Click(object sender, MouseEventArgs mouseEvent) { - PrintActivePart(); + UiThread.RunOnIdle((state) => + { + PrintActivePart(); + }); } void onSkipButton_Click(object sender, MouseEventArgs mouseEvent) diff --git a/ActionBar/PrintStatusRow.cs b/ActionBar/PrintStatusRow.cs index 6be40b45c..f3aef9425 100644 --- a/ActionBar/PrintStatusRow.cs +++ b/ActionBar/PrintStatusRow.cs @@ -37,6 +37,7 @@ using MatterHackers.Agg.VertexSource; using MatterHackers.Localizations; using MatterHackers.MatterControl.PrintQueue; using MatterHackers.MatterControl.CustomWidgets; +using MatterHackers.MatterControl.SlicerConfiguration; using MatterHackers.VectorMath; using MatterHackers.MatterControl.PrinterCommunication; @@ -181,7 +182,7 @@ namespace MatterHackers.MatterControl.ActionBar { if (ActivePrinterProfile.Instance.ActivePrinter != null) { - if (ActivePrinterProfile.Instance.ActivePrinter.GetFeatures().HasHeatedBed()) + if (ActiveSliceSettings.Instance.HasHeatedBed()) { bedTemperatureWidget.Visible = true; } @@ -196,8 +197,8 @@ namespace MatterHackers.MatterControl.ActionBar { ImageButtonFactory imageButtonFactory = new ImageButtonFactory(); imageButtonFactory.invertImageColor = false; - string notifyIconPath = Path.Combine("Icons", "PrintStatusControls", "leveling-16x16.png"); - string notifyHoverIconPath = Path.Combine("Icons", "PrintStatusControls", "leveling-16x16.png"); + string notifyIconPath = Path.Combine("PrintStatusControls", "leveling-16x16.png"); + string notifyHoverIconPath = Path.Combine("PrintStatusControls", "leveling-16x16.png"); Button autoLevelButton = imageButtonFactory.Generate(notifyIconPath, notifyHoverIconPath); autoLevelButton.Cursor = Cursors.Hand; autoLevelButton.Margin = new Agg.BorderDouble(top: 3); diff --git a/ControlElements/ImageButtonFactory.cs b/ControlElements/ImageButtonFactory.cs index c5c2c101d..d4080975e 100644 --- a/ControlElements/ImageButtonFactory.cs +++ b/ControlElements/ImageButtonFactory.cs @@ -71,7 +71,7 @@ namespace MatterHackers.MatterControl private string GetImageLocation(string imageName) { - return Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, imageName); + return Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, "Icons", imageName); } } diff --git a/ControlElements/TextImageButtonFactory.cs b/ControlElements/TextImageButtonFactory.cs index 68b1458b0..6d6b0a7ff 100644 --- a/ControlElements/TextImageButtonFactory.cs +++ b/ControlElements/TextImageButtonFactory.cs @@ -180,7 +180,7 @@ namespace MatterHackers.MatterControl ImageBuffer LoadUpButtonImage(string imageName) { - string path = Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, imageName); + string path = Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, "Icons", imageName); ImageBuffer buffer = new ImageBuffer(10, 10, 32, new BlenderBGRA()); ImageIO.LoadImageData(path, buffer); @@ -253,7 +253,7 @@ namespace MatterHackers.MatterControl private string GetImageLocation(string imageName) { - return Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, imageName); + return Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, "Icons", imageName); } private ButtonViewStates getButtonView(string label, string normalImageName = null, string hoverImageName = null, string pressedImageName = null, string disabledImageName = null, bool centerText = false) diff --git a/CustomWidgets/PanelSeparator.cs b/CustomWidgets/PanelSeparator.cs index df2a5958a..8fa546131 100644 --- a/CustomWidgets/PanelSeparator.cs +++ b/CustomWidgets/PanelSeparator.cs @@ -51,7 +51,7 @@ namespace MatterHackers.MatterControl.CustomWidgets hoverBackgroundColor = new RGBA_Bytes(100, 100, 100); Agg.Image.ImageBuffer arrowImage = new Agg.Image.ImageBuffer(); - ImageIO.LoadImageData(Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, "icon_arrow_left_16x16.png"), arrowImage); + ImageIO.LoadImageData(Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, "Icons", "icon_arrow_left_16x16.png"), arrowImage); arrowIndicator = new ImageWidget(arrowImage); arrowIndicator.HAnchor = Agg.UI.HAnchor.ParentCenter; arrowIndicator.VAnchor = Agg.UI.VAnchor.ParentCenter; diff --git a/CustomWidgets/PartThumbnailWidget.cs b/CustomWidgets/PartThumbnailWidget.cs index 465d254d6..378338025 100644 --- a/CustomWidgets/PartThumbnailWidget.cs +++ b/CustomWidgets/PartThumbnailWidget.cs @@ -43,6 +43,7 @@ using MatterHackers.Agg.UI; using MatterHackers.VectorMath; using MatterHackers.MatterControl.PartPreviewWindow; using MatterHackers.MatterControl.DataStorage; +using MatterHackers.Agg.VertexSource; using MatterHackers.PolygonMesh; using MatterHackers.PolygonMesh.Processors; @@ -170,6 +171,38 @@ namespace MatterHackers.MatterControl thumbnailWidget.Invalidate(); return; } + + if (thumbnailWidget.PrintItem.FileLocation == QueueData.SdCardFileName) + { + switch (thumbnailWidget.Size) + { + case ImageSizes.Size115x115: + { + ImageIO.LoadImageData(this.GetImageLocation("icon_sd_card_115x115.png"), thumbnailWidget.tumbnailImage); + thumbnailWidget.tumbnailImage.SetRecieveBlender(new BlenderPreMultBGRA()); + Graphics2D graphics = thumbnailWidget.tumbnailImage.NewGraphics2D(); + Ellipse outline = new Ellipse(new Vector2(115 / 2.0, 115 / 2.0), 50); + graphics.Render(new Stroke(outline, 4), RGBA_Bytes.White); + } + break; + + case ImageSizes.Size50x50: + { + ImageIO.LoadImageData(this.GetImageLocation("icon_sd_card_50x50.png"), thumbnailWidget.tumbnailImage); + thumbnailWidget.tumbnailImage.SetRecieveBlender(new BlenderPreMultBGRA()); + Graphics2D graphics = thumbnailWidget.tumbnailImage.NewGraphics2D(); + Ellipse outline = new Ellipse(new Vector2(50 / 2.0, 50 / 2.0), 22); + graphics.Render(new Stroke(outline, 1.5), RGBA_Bytes.White); + } + break; + + default: + throw new NotImplementedException(); + } + + UiThread.RunOnIdle(thumbnailWidget.EnsureImageUpdated); + return; + } string stlHashCode = thumbnailWidget.PrintItem.StlFileHashCode.ToString(); @@ -403,7 +436,7 @@ namespace MatterHackers.MatterControl string GetImageLocation(string imageName) { - return Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, imageName); + return Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, "Icons", imageName); } } } diff --git a/CustomWidgets/PluginChooserWindow.cs b/CustomWidgets/PluginChooserWindow.cs index 06ad0d78e..7afd4c6a5 100644 --- a/CustomWidgets/PluginChooserWindow.cs +++ b/CustomWidgets/PluginChooserWindow.cs @@ -50,7 +50,7 @@ namespace MatterHackers.MatterControl.CreatorPlugins ImageBuffer LoadImage(string imageName) { - string path = Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, imageName); + string path = Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, "Icons", imageName); ImageBuffer buffer = new ImageBuffer(10, 10, 32, new BlenderBGRA()); ImageIO.LoadImageData(path, buffer); return buffer; diff --git a/DataStorage/Models.cs b/DataStorage/Models.cs index a3f639bd1..0a60b9a0b 100644 --- a/DataStorage/Models.cs +++ b/DataStorage/Models.cs @@ -291,80 +291,6 @@ namespace MatterHackers.MatterControl.DataStorage } } - public class PrinterFeatures - { - Dictionary features = new Dictionary(); - public PrinterFeatures(string features) - { - if (features != null) - { - string[] featuresArray = features.Split(','); - for (int i = 0; i < features.Length / 2; i++) - { - this.features.Add(featuresArray[i * 2], featuresArray[i * 2 + 1]); - } - } - } - - public string GetFeatuersString() - { - StringBuilder output = new StringBuilder(); - - bool first = true; - foreach (KeyValuePair feature in features) - { - if (!first) - { - output.Append(","); - } - output.Append(feature.Key + "," + feature.Value); - first = false; - } - - return output.ToString(); - } - - public bool HasFan() - { - if (features.ContainsKey("HasFan")) - { - return features["HasFan"] == "true"; - } - - return true; - } - - public bool HasSdCard() - { - if (features.ContainsKey("HasSdCard")) - { - return features["HasSdCard"] == "true"; - } - - return true; - } - - public bool HasHeatedBed() - { - if (features.ContainsKey("HasHeatedBed")) - { - return features["HasHeatedBed"] == "true"; - } - - return true; - } - - public int ExtruderCount() - { - if (features.ContainsKey("ExtruderCount")) - { - return int.Parse(features["ExtruderCount"]); - } - - return 1; - } - } - public class Printer : Entity { public int DefaultSettingsCollectionId { get; set; } @@ -390,27 +316,6 @@ namespace MatterHackers.MatterControl.DataStorage public string MaterialCollectionIds { get; set; } // store id1,id2... (for N extruders) public int QualityCollectionId { get; set; } - protected PrinterFeatures printerFeatures; - public PrinterFeatures GetFeatures() - { - if (printerFeatures == null) - { - printerFeatures = new PrinterFeatures(_features); - } - - return printerFeatures; - } - - public override void Commit() - { - if (printerFeatures != null) - { - _features = printerFeatures.GetFeatuersString(); - } - - base.Commit(); - } - public Printer() : base() { diff --git a/MatterControl.sln b/MatterControl.sln index 8a0e3fba3..d1c4c5973 100644 --- a/MatterControl.sln +++ b/MatterControl.sln @@ -64,6 +64,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PictureCreator", "..\Matter EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "X3GCommunication", "..\MatterControlX3GCommunication\X3GCommunication.csproj", "{A3680C51-A549-4D1F-AEA5-3931EA755E9A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatterRepair", "..\MatterRepair\MatterRepair\MatterRepair.csproj", "{DA4A9C04-C54A-4571-B6B0-957C7E6E868B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -452,6 +454,18 @@ Global {A3680C51-A549-4D1F-AEA5-3931EA755E9A}.Release64|Any CPU.Build.0 = Release64|Any CPU {A3680C51-A549-4D1F-AEA5-3931EA755E9A}.Release64|x64.ActiveCfg = Release64|Any CPU {A3680C51-A549-4D1F-AEA5-3931EA755E9A}.Release64|x86.ActiveCfg = Release64|Any CPU + {DA4A9C04-C54A-4571-B6B0-957C7E6E868B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DA4A9C04-C54A-4571-B6B0-957C7E6E868B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DA4A9C04-C54A-4571-B6B0-957C7E6E868B}.Debug|x64.ActiveCfg = Debug|Any CPU + {DA4A9C04-C54A-4571-B6B0-957C7E6E868B}.Debug|x86.ActiveCfg = Debug|Any CPU + {DA4A9C04-C54A-4571-B6B0-957C7E6E868B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DA4A9C04-C54A-4571-B6B0-957C7E6E868B}.Release|Any CPU.Build.0 = Release|Any CPU + {DA4A9C04-C54A-4571-B6B0-957C7E6E868B}.Release|x64.ActiveCfg = Release|Any CPU + {DA4A9C04-C54A-4571-B6B0-957C7E6E868B}.Release|x86.ActiveCfg = Release|Any CPU + {DA4A9C04-C54A-4571-B6B0-957C7E6E868B}.Release64|Any CPU.ActiveCfg = Release64|Any CPU + {DA4A9C04-C54A-4571-B6B0-957C7E6E868B}.Release64|Any CPU.Build.0 = Release64|Any CPU + {DA4A9C04-C54A-4571-B6B0-957C7E6E868B}.Release64|x64.ActiveCfg = Release64|Any CPU + {DA4A9C04-C54A-4571-B6B0-957C7E6E868B}.Release64|x86.ActiveCfg = Release64|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -462,6 +476,7 @@ Global {239CC6B1-537C-4998-9AA9-3372A3464498} = {DA2BE4E5-5FB2-4C74-9170-0D2513AAFC84} {BEC6FD13-C765-4B90-836B-53823AC12E20} = {DA2BE4E5-5FB2-4C74-9170-0D2513AAFC84} {A3680C51-A549-4D1F-AEA5-3931EA755E9A} = {DA2BE4E5-5FB2-4C74-9170-0D2513AAFC84} + {DA4A9C04-C54A-4571-B6B0-957C7E6E868B} = {DA2BE4E5-5FB2-4C74-9170-0D2513AAFC84} EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = MatterControl.csproj diff --git a/PartPreviewWindow/ViewControls2D.cs b/PartPreviewWindow/ViewControls2D.cs index 894301058..688758472 100644 --- a/PartPreviewWindow/ViewControls2D.cs +++ b/PartPreviewWindow/ViewControls2D.cs @@ -24,12 +24,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow iconTextImageButtonFactory.FixedHeight = 20; iconTextImageButtonFactory.FixedWidth = 20; - string translateIconPath = Path.Combine("Icons", "ViewTransformControls", "translate.png"); + string translateIconPath = Path.Combine("ViewTransformControls", "translate.png"); translateButton = iconTextImageButtonFactory.GenerateRadioButton("", translateIconPath); translateButton.Margin = new BorderDouble(3); AddChild(translateButton); - string scaleIconPath = Path.Combine("Icons", "ViewTransformControls", "scale.png"); + string scaleIconPath = Path.Combine("ViewTransformControls", "scale.png"); scaleButton = iconTextImageButtonFactory.GenerateRadioButton("", scaleIconPath); scaleButton.Margin = new BorderDouble(3); AddChild(scaleButton); diff --git a/PartPreviewWindow/ViewControls3D.cs b/PartPreviewWindow/ViewControls3D.cs index b577a130d..e1d30f61f 100644 --- a/PartPreviewWindow/ViewControls3D.cs +++ b/PartPreviewWindow/ViewControls3D.cs @@ -47,7 +47,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow textImageButtonFactory.FixedWidth = 20; textImageButtonFactory.AllowThemeToAdjustImage = false; - string rotateIconPath = Path.Combine("Icons", "ViewTransformControls", "rotate.png"); + string rotateIconPath = Path.Combine("ViewTransformControls", "rotate.png"); rotateButton = textImageButtonFactory.GenerateRadioButton("", rotateIconPath); rotateButton.Margin = new BorderDouble(3); AddChild(rotateButton); @@ -56,7 +56,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow meshViewerWidget.TrackballTumbleWidget.TransformState = TrackBallController.MouseDownType.Rotation; }; - string translateIconPath = Path.Combine("Icons", "ViewTransformControls", "translate.png"); + string translateIconPath = Path.Combine("ViewTransformControls", "translate.png"); translateButton = textImageButtonFactory.GenerateRadioButton("", translateIconPath); translateButton.Margin = new BorderDouble(3); AddChild(translateButton); @@ -65,7 +65,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow meshViewerWidget.TrackballTumbleWidget.TransformState = TrackBallController.MouseDownType.Translation; }; - string scaleIconPath = Path.Combine("Icons", "ViewTransformControls", "scale.png"); + string scaleIconPath = Path.Combine("ViewTransformControls", "scale.png"); RadioButton scaleButton = textImageButtonFactory.GenerateRadioButton("", scaleIconPath); scaleButton.Margin = new BorderDouble(3); AddChild(scaleButton); @@ -79,7 +79,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow partSelectSeparator.Margin = new BorderDouble(3); AddChild(partSelectSeparator); - string partSelectIconPath = Path.Combine("Icons", "ViewTransformControls", "partSelect.png"); + string partSelectIconPath = Path.Combine("ViewTransformControls", "partSelect.png"); partSelectButton = textImageButtonFactory.GenerateRadioButton("", partSelectIconPath); partSelectButton.Margin = new BorderDouble(3); AddChild(partSelectButton); diff --git a/PrintQueue/OptionsMenu/QueueOptionsMenu.cs b/PrintQueue/OptionsMenu/QueueOptionsMenu.cs index 9a944d07a..1f1c00db7 100644 --- a/PrintQueue/OptionsMenu/QueueOptionsMenu.cs +++ b/PrintQueue/OptionsMenu/QueueOptionsMenu.cs @@ -39,10 +39,12 @@ using System.Threading; using MatterHackers.Agg.Image; using MatterHackers.Agg.VertexSource; using MatterHackers.Agg; +using MatterHackers.MatterControl.SlicerConfiguration; using MatterHackers.Agg.UI; using MatterHackers.VectorMath; using MatterHackers.MatterControl.DataStorage; using MatterHackers.Localizations; +using MatterHackers.MatterControl.PrinterCommunication; namespace MatterHackers.MatterControl.PrintQueue { @@ -85,36 +87,33 @@ namespace MatterHackers.MatterControl.PrintQueue void SetMenuItems() { + menuItems = new TupleList>(); + menuItems.Add(new Tuple>("STL", null)); + menuItems.Add(new Tuple>(LocalizedString.Get(" Import from Zip"), importQueueFromZipMenu_Click)); + menuItems.Add(new Tuple>(LocalizedString.Get(" Export to Zip"), exportQueueToZipMenu_Click)); + menuItems.Add(new Tuple>("GCode", null)); + menuItems.Add(new Tuple>(LocalizedString.Get(" Export to Folder"), exportGCodeToFolderButton_Click)); + + if (ActiveSliceSettings.Instance.HasSdCardReader()) + { + menuItems.Add(new Tuple>("SD Card", null)); + menuItems.Add(new Tuple>(LocalizedString.Get(" Load Files"), loadFilesFromSDButton_Click)); + menuItems.Add(new Tuple>(LocalizedString.Get(" Eject SD Card"), ejectSDCardButton_Click)); + } + // The pdf export library is not working on the mac at the moment so we don't include the // part sheet export option on mac. if (MatterHackers.Agg.UI.WindowsFormsAbstract.GetOSType() == WindowsFormsAbstract.OSType.Mac) { - //Set the name and callback function of the menu items - menuItems = new TupleList> - { - {"STL", null}, - {LocalizedString.Get(" Import from Zip"), importQueueFromZipMenu_Click}, - {LocalizedString.Get(" Export to Zip"), exportQueueToZipMenu_Click}, - {"GCode", null}, - {LocalizedString.Get(" Export to Folder"), exportGCodeToFolderButton_Click}, - {LocalizedString.Get("Other"), null}, - {LocalizedString.Get(" Remove All"), removeAllFromQueueButton_Click}, - }; + // mac cannot export to pdf + menuItems.Add(new Tuple>(LocalizedString.Get("Other"), null)); + menuItems.Add(new Tuple>(LocalizedString.Get(" Remove All"), removeAllFromQueueButton_Click)); } else { - //Set the name and callback function of the menu items - menuItems = new TupleList> - { - {"STL", null}, - {LocalizedString.Get(" Import from Zip"), importQueueFromZipMenu_Click}, - {LocalizedString.Get(" Export to Zip"), exportQueueToZipMenu_Click}, - {"GCode", null}, - {LocalizedString.Get(" Export to Folder"), exportGCodeToFolderButton_Click}, - {LocalizedString.Get("Other"), null}, - {LocalizedString.Get(" Create Part Sheet"), createPartsSheetsButton_Click}, - {LocalizedString.Get(" Remove All"), removeAllFromQueueButton_Click}, - }; + menuItems.Add(new Tuple>(LocalizedString.Get("Other"), null)); + menuItems.Add(new Tuple>(LocalizedString.Get(" Create Part Sheet"), createPartsSheetsButton_Click)); + menuItems.Add(new Tuple>(LocalizedString.Get(" Remove All"), removeAllFromQueueButton_Click)); } BorderDouble padding = MenuDropList.MenuItemsPadding; @@ -251,7 +250,64 @@ namespace MatterHackers.MatterControl.PrintQueue UiThread.RunOnIdle(ImportQueueFromZipMenuOnIdle); return true; } - + + event EventHandler unregisterEvents; + public override void OnClosed(EventArgs e) + { + if (unregisterEvents != null) + { + unregisterEvents(this, null); + } + base.OnClosed(e); + } + + bool loadFilesFromSDButton_Click() + { + if (PrinterConnectionAndCommunication.Instance.PrinterIsConnected + && !(PrinterConnectionAndCommunication.Instance.PrinterIsPrinting + || PrinterConnectionAndCommunication.Instance.PrinterIsPaused)) + { + PrinterConnectionAndCommunication.Instance.ReadLine.RegisterEvent(GetSdCardList, ref unregisterEvents); + StringBuilder commands = new StringBuilder(); + commands.AppendLine("M21"); // Init SD card + commands.AppendLine("M20"); // List SD card + PrinterConnectionAndCommunication.Instance.SendLineToPrinterNow(commands.ToString()); + } + return true; + } + + void GetSdCardList(object sender, EventArgs e) + { + StringEventArgs currentEvent = e as StringEventArgs; + if (currentEvent != null) + { + if (!currentEvent.Data.StartsWith("echo:")) + { + switch (currentEvent.Data) + { + case "Begin file list": + break; + + default: + QueueData.Instance.AddItem(new PrintItemWrapper(new PrintItem(currentEvent.Data, QueueData.SdCardFileName))); + break; + + case "End file list": + PrinterConnectionAndCommunication.Instance.ReadLine.UnregisterEvent(GetSdCardList, ref unregisterEvents); + break; + } + } + } + } + + bool ejectSDCardButton_Click() + { + // Remove all the QueueData.SdCardFileName parts from the queue + QueueData.Instance.RemoveAllSdCardFiles(); + PrinterConnectionAndCommunication.Instance.SendLineToPrinterNow("M22"); // (Release SD card) + return true; + } + void ImportQueueFromZipMenuOnIdle(object state) { ProjectFileHandler project = new ProjectFileHandler(null); diff --git a/PrintQueue/QueueData.cs b/PrintQueue/QueueData.cs index 2f9f67a12..c75a9c460 100644 --- a/PrintQueue/QueueData.cs +++ b/PrintQueue/QueueData.cs @@ -68,6 +68,8 @@ namespace MatterHackers.MatterControl.PrintQueue public class QueueData { + public static readonly string SdCardFileName = "SD_CARD"; + private List printItems = new List(); private List PrintItems { @@ -216,6 +218,19 @@ namespace MatterHackers.MatterControl.PrintQueue AddItem(new PrintItemWrapper(item)); } } + RemoveAllSdCardFiles(); + } + + public void RemoveAllSdCardFiles() + { + for (int i = Count - 1; i >= 0; i--) + { + PrintItem printItem = PrintItems[i].PrintItem; + if (printItem.FileLocation == QueueData.SdCardFileName) + { + RemoveAt(i); + } + } } public void OnItemAdded(EventArgs e) diff --git a/PrinterControls/EditMacrosWindow.cs b/PrinterControls/EditMacrosWindow.cs index 256164b43..fa96ca7c1 100644 --- a/PrinterControls/EditMacrosWindow.cs +++ b/PrinterControls/EditMacrosWindow.cs @@ -196,7 +196,7 @@ namespace MatterHackers.MatterControl FormField.ValidationHandler[] stringValidationHandlers = new FormField.ValidationHandler[] { validationMethods.StringIsNotEmpty }; FormField.ValidationHandler[] nameValidationHandlers = new FormField.ValidationHandler[] { validationMethods.StringIsNotEmpty, validationMethods.StringHasNoSpecialChars }; - formFields.Add(new FormField(macroNameInput, macroNameError, nameValidationHandlers)); + formFields.Add(new FormField(macroNameInput, macroNameError, stringValidationHandlers)); formFields.Add(new FormField(macroCommandInput, macroCommandError, stringValidationHandlers)); bool formIsValid = true; diff --git a/PrinterControls/ManualPrinterControls.cs b/PrinterControls/ManualPrinterControls.cs index 474701d9b..715d348fc 100644 --- a/PrinterControls/ManualPrinterControls.cs +++ b/PrinterControls/ManualPrinterControls.cs @@ -37,6 +37,7 @@ using MatterHackers.Agg; using MatterHackers.Agg.UI; using MatterHackers.VectorMath; using MatterHackers.Agg.Image; +using MatterHackers.MatterControl.SlicerConfiguration; using MatterHackers.MatterControl.DataStorage; using MatterHackers.MatterControl.CustomWidgets; using MatterHackers.Localizations; @@ -227,8 +228,7 @@ namespace MatterHackers.MatterControl fanControlsContainer.HAnchor = Agg.UI.HAnchor.ParentLeftRight; fanControlsContainer.AddChild(fanControlsGroupBox); - if (ActivePrinterProfile.Instance.ActivePrinter == null - || ActivePrinterProfile.Instance.ActivePrinter.GetFeatures().HasFan()) + if (ActiveSliceSettings.Instance.HasFan()) { controlsTopToBottomLayout.AddChild(fanControlsContainer); } @@ -253,7 +253,7 @@ namespace MatterHackers.MatterControl eePromControlsLayout.Padding = new BorderDouble(0); { Agg.Image.ImageBuffer eePromImage = new Agg.Image.ImageBuffer(); - ImageIO.LoadImageData(Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath,"Icons", "PrintStatusControls", "leveling-24x24.png"), eePromImage); + ImageIO.LoadImageData(Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, "Icons", "PrintStatusControls", "leveling-24x24.png"), eePromImage); ImageWidget eePromIcon = new ImageWidget(eePromImage); eePromIcon.Margin = new BorderDouble (right: 6); @@ -354,8 +354,7 @@ namespace MatterHackers.MatterControl bedTemperatureControlWidget = new DisableableWidget(); bedTemperatureControlWidget.AddChild(new BedTemperatureControlWidget()); - if (ActivePrinterProfile.Instance.ActivePrinter == null - || ActivePrinterProfile.Instance.ActivePrinter.GetFeatures().HasHeatedBed()) + if (ActiveSliceSettings.Instance.HasHeatedBed()) { temperatureControlContainer.AddChild(bedTemperatureControlWidget); } @@ -676,7 +675,7 @@ namespace MatterHackers.MatterControl homeButtonBar.Padding = new BorderDouble(0); string homeIconFile = "icon_home_white_24x24.png"; - string fileAndPath = Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, homeIconFile); + string fileAndPath = Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, "Icons", homeIconFile); ImageBuffer helpIconImage = new ImageBuffer(); ImageIO.LoadImageData(fileAndPath, helpIconImage); ImageWidget homeIconImageWidget = new ImageWidget(helpIconImage); diff --git a/SlicerConfiguration/ActiveSliceSettings.cs b/SlicerConfiguration/ActiveSliceSettings.cs index 2a14f9bf9..83601489d 100644 --- a/SlicerConfiguration/ActiveSliceSettings.cs +++ b/SlicerConfiguration/ActiveSliceSettings.cs @@ -190,6 +190,21 @@ namespace MatterHackers.MatterControl.SlicerConfiguration } + public bool HasFan() + { + return GetActiveValue("has_fan") == "1"; + } + + public bool HasSdCardReader() + { + return GetActiveValue("has_sd_card_reader") == "1"; + } + + public bool HasHeatedBed() + { + return GetActiveValue("has_heated_bed") == "1"; + } + public Dictionary DefaultSettings { get diff --git a/SlicerConfiguration/SlicePresetsWindow/SlicePresetDetailWidget.cs b/SlicerConfiguration/SlicePresetsWindow/SlicePresetDetailWidget.cs index dc885e37c..44fd26332 100644 --- a/SlicerConfiguration/SlicePresetsWindow/SlicePresetDetailWidget.cs +++ b/SlicerConfiguration/SlicePresetsWindow/SlicePresetDetailWidget.cs @@ -687,6 +687,10 @@ namespace MatterHackers.MatterControl.SlicerConfiguration } break; + case OrganizerSettingsData.DataEditTypes.HARDWARE_PRESENT: + // this is not editable for a detail setting (quality or material) + break; + case OrganizerSettingsData.DataEditTypes.VECTOR2: { string[] xyValueStrings = sliceSettingValue.Split(','); diff --git a/SlicerConfiguration/SliceSettingsOrganizer.cs b/SlicerConfiguration/SliceSettingsOrganizer.cs index 9f0a05eed..89f0849b8 100644 --- a/SlicerConfiguration/SliceSettingsOrganizer.cs +++ b/SlicerConfiguration/SliceSettingsOrganizer.cs @@ -39,7 +39,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration public class OrganizerSettingsData { [JsonConverter(typeof(StringEnumConverter))] - public enum DataEditTypes { STRING, INT, DOUBLE, POSITIVE_DOUBLE, OFFSET, DOUBLE_OR_PERCENT, VECTOR2, OFFSET2, CHECK_BOX, LIST, MULTI_LINE_TEXT }; + public enum DataEditTypes { STRING, INT, DOUBLE, POSITIVE_DOUBLE, OFFSET, DOUBLE_OR_PERCENT, VECTOR2, OFFSET2, CHECK_BOX, LIST, MULTI_LINE_TEXT, HARDWARE_PRESENT }; public string SlicerConfigName { get; set; } diff --git a/SlicerConfiguration/SliceSettingsWidget.cs b/SlicerConfiguration/SliceSettingsWidget.cs index 7eb04e67d..021c0bc5c 100644 --- a/SlicerConfiguration/SliceSettingsWidget.cs +++ b/SlicerConfiguration/SliceSettingsWidget.cs @@ -664,6 +664,29 @@ namespace MatterHackers.MatterControl.SlicerConfiguration } break; + case OrganizerSettingsData.DataEditTypes.HARDWARE_PRESENT: + { + CheckBox checkBoxWidget = new CheckBox(""); + checkBoxWidget.VAnchor = Agg.UI.VAnchor.ParentBottom; + checkBoxWidget.TextColor = ActiveTheme.Instance.PrimaryTextColor; + checkBoxWidget.Checked = (sliceSettingValue == "1"); + checkBoxWidget.CheckedStateChanged += (sender, e) => + { + if (((CheckBox)sender).Checked) + { + SaveSetting(settingData.SlicerConfigName, "1"); + // Now show all of the settings that this control is associated with. + } + else + { + SaveSetting(settingData.SlicerConfigName, "0"); + // Now hide all of the settings that this control is associated with. + } + }; + leftToRightLayout.AddChild(checkBoxWidget); + } + break; + case OrganizerSettingsData.DataEditTypes.VECTOR2: { string[] xyValueStrings = sliceSettingValue.Split(','); diff --git a/SlicerConfiguration/SlicerMapping/EngineMappingCura.cs b/SlicerConfiguration/SlicerMapping/EngineMappingCura.cs index da9f69a8c..b9ccea6de 100644 --- a/SlicerConfiguration/SlicerMapping/EngineMappingCura.cs +++ b/SlicerConfiguration/SlicerMapping/EngineMappingCura.cs @@ -96,6 +96,9 @@ namespace MatterHackers.MatterControl.SlicerConfiguration new NotPassedItem("", "bed_temperature"), new NotPassedItem("", "bed_shape"), + new NotPassedItem("", "has_fan"), + new NotPassedItem("", "has_heated_bed"), + new NotPassedItem("", "has_sd_card_reader"), new ScaledSingleNumber("objectSink", "bottom_clip_amount", 1000), diff --git a/SlicerConfiguration/SlicerMapping/EngineMappingMatterSlice.cs b/SlicerConfiguration/SlicerMapping/EngineMappingMatterSlice.cs index a2dedb7ab..214510c3a 100644 --- a/SlicerConfiguration/SlicerMapping/EngineMappingMatterSlice.cs +++ b/SlicerConfiguration/SlicerMapping/EngineMappingMatterSlice.cs @@ -190,6 +190,10 @@ namespace MatterHackers.MatterControl.SlicerConfiguration new MapRepairOutlines("repairOutlines", "repair_outlines_extensive_stitching"), new NotPassedItem("", "repair_outlines_keep_open"), + new NotPassedItem("", "has_fan"), + new NotPassedItem("", "has_heated_bed"), + new NotPassedItem("", "has_sd_card_reader"), + //repairOverlaps=NONE # Available Values: NONE, REVERSE_ORIENTATION, UNION_ALL_TOGETHER # You can or them together using '|'. new MapRepairOverlaps("repairOverlaps", "repair_overlaps_reverse_orientation"), new NotPassedItem("", "repair_overlaps_union_all_together"), diff --git a/StaticData/140.png b/StaticData/Icons/140.png similarity index 100% rename from StaticData/140.png rename to StaticData/Icons/140.png diff --git a/StaticData/259.png b/StaticData/Icons/259.png similarity index 100% rename from StaticData/259.png rename to StaticData/Icons/259.png diff --git a/StaticData/402.png b/StaticData/Icons/402.png similarity index 100% rename from StaticData/402.png rename to StaticData/Icons/402.png diff --git a/StaticData/403.png b/StaticData/Icons/403.png similarity index 100% rename from StaticData/403.png rename to StaticData/Icons/403.png diff --git a/StaticData/404.png b/StaticData/Icons/404.png similarity index 100% rename from StaticData/404.png rename to StaticData/Icons/404.png diff --git a/StaticData/405.png b/StaticData/Icons/405.png similarity index 100% rename from StaticData/405.png rename to StaticData/Icons/405.png diff --git a/StaticData/406.png b/StaticData/Icons/406.png similarity index 100% rename from StaticData/406.png rename to StaticData/Icons/406.png diff --git a/StaticData/426.png b/StaticData/Icons/426.png similarity index 100% rename from StaticData/426.png rename to StaticData/Icons/426.png diff --git a/StaticData/building_thumbnail_100x100.png b/StaticData/Icons/building_thumbnail_100x100.png similarity index 100% rename from StaticData/building_thumbnail_100x100.png rename to StaticData/Icons/building_thumbnail_100x100.png diff --git a/StaticData/building_thumbnail_40x40.png b/StaticData/Icons/building_thumbnail_40x40.png similarity index 100% rename from StaticData/building_thumbnail_40x40.png rename to StaticData/Icons/building_thumbnail_40x40.png diff --git a/StaticData/gear_icon.png b/StaticData/Icons/gear_icon.png similarity index 100% rename from StaticData/gear_icon.png rename to StaticData/Icons/gear_icon.png diff --git a/StaticData/gear_icon_hover.png b/StaticData/Icons/gear_icon_hover.png similarity index 100% rename from StaticData/gear_icon_hover.png rename to StaticData/Icons/gear_icon_hover.png diff --git a/StaticData/icon_arrow_down_no_border_32x32.png b/StaticData/Icons/icon_arrow_down_no_border_32x32.png similarity index 100% rename from StaticData/icon_arrow_down_no_border_32x32.png rename to StaticData/Icons/icon_arrow_down_no_border_32x32.png diff --git a/StaticData/icon_arrow_left_16x16.png b/StaticData/Icons/icon_arrow_left_16x16.png similarity index 100% rename from StaticData/icon_arrow_left_16x16.png rename to StaticData/Icons/icon_arrow_left_16x16.png diff --git a/StaticData/icon_arrow_left_32x32.png b/StaticData/Icons/icon_arrow_left_32x32.png similarity index 100% rename from StaticData/icon_arrow_left_32x32.png rename to StaticData/Icons/icon_arrow_left_32x32.png diff --git a/StaticData/icon_arrow_right_32x32.png b/StaticData/Icons/icon_arrow_right_32x32.png similarity index 100% rename from StaticData/icon_arrow_right_32x32.png rename to StaticData/Icons/icon_arrow_right_32x32.png diff --git a/StaticData/icon_arrow_right_no_border_32x32.png b/StaticData/Icons/icon_arrow_right_no_border_32x32.png similarity index 100% rename from StaticData/icon_arrow_right_no_border_32x32.png rename to StaticData/Icons/icon_arrow_right_no_border_32x32.png diff --git a/StaticData/icon_box_16x16.png b/StaticData/Icons/icon_box_16x16.png similarity index 100% rename from StaticData/icon_box_16x16.png rename to StaticData/Icons/icon_box_16x16.png diff --git a/StaticData/icon_check_16x16.png b/StaticData/Icons/icon_check_16x16.png similarity index 100% rename from StaticData/icon_check_16x16.png rename to StaticData/Icons/icon_check_16x16.png diff --git a/StaticData/icon_check_32x32.png b/StaticData/Icons/icon_check_32x32.png similarity index 100% rename from StaticData/icon_check_32x32.png rename to StaticData/Icons/icon_check_32x32.png diff --git a/StaticData/icon_circle_plus.png b/StaticData/Icons/icon_circle_plus.png similarity index 100% rename from StaticData/icon_circle_plus.png rename to StaticData/Icons/icon_circle_plus.png diff --git a/StaticData/icon_connect_black.png b/StaticData/Icons/icon_connect_black.png similarity index 100% rename from StaticData/icon_connect_black.png rename to StaticData/Icons/icon_connect_black.png diff --git a/StaticData/icon_connect_white.png b/StaticData/Icons/icon_connect_white.png similarity index 100% rename from StaticData/icon_connect_white.png rename to StaticData/Icons/icon_connect_white.png diff --git a/StaticData/icon_creator_white_32x32.png b/StaticData/Icons/icon_creator_white_32x32.png similarity index 100% rename from StaticData/icon_creator_white_32x32.png rename to StaticData/Icons/icon_creator_white_32x32.png diff --git a/StaticData/icon_disconnect_black.png b/StaticData/Icons/icon_disconnect_black.png similarity index 100% rename from StaticData/icon_disconnect_black.png rename to StaticData/Icons/icon_disconnect_black.png diff --git a/StaticData/icon_disconnect_white.png b/StaticData/Icons/icon_disconnect_white.png similarity index 100% rename from StaticData/icon_disconnect_white.png rename to StaticData/Icons/icon_disconnect_white.png diff --git a/StaticData/icon_edit_black.png b/StaticData/Icons/icon_edit_black.png similarity index 100% rename from StaticData/icon_edit_black.png rename to StaticData/Icons/icon_edit_black.png diff --git a/StaticData/icon_edit_gray.png b/StaticData/Icons/icon_edit_gray.png similarity index 100% rename from StaticData/icon_edit_gray.png rename to StaticData/Icons/icon_edit_gray.png diff --git a/StaticData/icon_edit_white.png b/StaticData/Icons/icon_edit_white.png similarity index 100% rename from StaticData/icon_edit_white.png rename to StaticData/Icons/icon_edit_white.png diff --git a/StaticData/icon_home_blk_24x24.png b/StaticData/Icons/icon_home_blk_24x24.png similarity index 100% rename from StaticData/icon_home_blk_24x24.png rename to StaticData/Icons/icon_home_blk_24x24.png diff --git a/StaticData/icon_home_inverted_32x32.png b/StaticData/Icons/icon_home_inverted_32x32.png similarity index 100% rename from StaticData/icon_home_inverted_32x32.png rename to StaticData/Icons/icon_home_inverted_32x32.png diff --git a/StaticData/icon_home_white_24x24.png b/StaticData/Icons/icon_home_white_24x24.png similarity index 100% rename from StaticData/icon_home_white_24x24.png rename to StaticData/Icons/icon_home_white_24x24.png diff --git a/StaticData/icon_import_white_32x32.png b/StaticData/Icons/icon_import_white_32x32.png similarity index 100% rename from StaticData/icon_import_white_32x32.png rename to StaticData/Icons/icon_import_white_32x32.png diff --git a/StaticData/icon_notification_32x32.png b/StaticData/Icons/icon_notification_32x32.png similarity index 100% rename from StaticData/icon_notification_32x32.png rename to StaticData/Icons/icon_notification_32x32.png diff --git a/StaticData/icon_pause_32x32.png b/StaticData/Icons/icon_pause_32x32.png similarity index 100% rename from StaticData/icon_pause_32x32.png rename to StaticData/Icons/icon_pause_32x32.png diff --git a/StaticData/icon_play_32x32.png b/StaticData/Icons/icon_play_32x32.png similarity index 100% rename from StaticData/icon_play_32x32.png rename to StaticData/Icons/icon_play_32x32.png diff --git a/StaticData/icon_power_2_32x32.png b/StaticData/Icons/icon_power_2_32x32.png similarity index 100% rename from StaticData/icon_power_2_32x32.png rename to StaticData/Icons/icon_power_2_32x32.png diff --git a/StaticData/icon_power_32x32.png b/StaticData/Icons/icon_power_32x32.png similarity index 100% rename from StaticData/icon_power_32x32.png rename to StaticData/Icons/icon_power_32x32.png diff --git a/StaticData/icon_rotate_32x32.png b/StaticData/Icons/icon_rotate_32x32.png similarity index 100% rename from StaticData/icon_rotate_32x32.png rename to StaticData/Icons/icon_rotate_32x32.png diff --git a/StaticData/Icons/icon_sd_card_115x115.png b/StaticData/Icons/icon_sd_card_115x115.png new file mode 100644 index 000000000..2f7e7391c Binary files /dev/null and b/StaticData/Icons/icon_sd_card_115x115.png differ diff --git a/StaticData/Icons/icon_sd_card_50x50.png b/StaticData/Icons/icon_sd_card_50x50.png new file mode 100644 index 000000000..633c6053e Binary files /dev/null and b/StaticData/Icons/icon_sd_card_50x50.png differ diff --git a/StaticData/icon_shopping_cart_32x32.png b/StaticData/Icons/icon_shopping_cart_32x32.png similarity index 100% rename from StaticData/icon_shopping_cart_32x32.png rename to StaticData/Icons/icon_shopping_cart_32x32.png diff --git a/StaticData/icon_stop_32x32.png b/StaticData/Icons/icon_stop_32x32.png similarity index 100% rename from StaticData/icon_stop_32x32.png rename to StaticData/Icons/icon_stop_32x32.png diff --git a/StaticData/part_icon_transparent_100x100.png b/StaticData/Icons/part_icon_transparent_100x100.png similarity index 100% rename from StaticData/part_icon_transparent_100x100.png rename to StaticData/Icons/part_icon_transparent_100x100.png diff --git a/StaticData/part_icon_transparent_40x40.png b/StaticData/Icons/part_icon_transparent_40x40.png similarity index 100% rename from StaticData/part_icon_transparent_40x40.png rename to StaticData/Icons/part_icon_transparent_40x40.png diff --git a/StaticData/part_thumbnail_default.png b/StaticData/Icons/part_thumbnail_default.png similarity index 100% rename from StaticData/part_thumbnail_default.png rename to StaticData/Icons/part_thumbnail_default.png diff --git a/StaticData/repair.png b/StaticData/Icons/repair.png similarity index 100% rename from StaticData/repair.png rename to StaticData/Icons/repair.png diff --git a/StaticData/PrinterSettings/config.ini b/StaticData/PrinterSettings/config.ini index 6853397a7..adb0ae0c2 100644 --- a/StaticData/PrinterSettings/config.ini +++ b/StaticData/PrinterSettings/config.ini @@ -48,6 +48,9 @@ gcode_arcs = 0 gcode_comments = 0 gcode_flavor = reprap gcode_output_type = REPRAP +has_fan = 1 +has_heated_bed = 1 +has_sd_card_reader = 0 infill_acceleration = 0 infill_every_layers = 1 infill_extruder = 1 diff --git a/StaticData/SliceSettings/Layouts.txt b/StaticData/SliceSettings/Layouts.txt index ea97bf1a5..16a8be1c7 100644 --- a/StaticData/SliceSettings/Layouts.txt +++ b/StaticData/SliceSettings/Layouts.txt @@ -209,6 +209,9 @@ Advanced build_height z_offset bed_shape + has_fan + has_heated_bed + has_sd_card_reader Firmware gcode_flavor gcode_output_type diff --git a/StaticData/SliceSettings/Properties.txt b/StaticData/SliceSettings/Properties.txt index 299bb80c6..da6a577fa 100644 --- a/StaticData/SliceSettings/Properties.txt +++ b/StaticData/SliceSettings/Properties.txt @@ -48,6 +48,9 @@ gcode_arcs|Use Arcs|CHECK_BOX||Use firmware arcs rather than multiple segments f gcode_comments|Verbose G-Code|CHECK_BOX||Include detailed comments in the gcode. gcode_flavor|G-Code Flavor|LIST|reprap,teacup,makerbot,sailfish,mach3_ecm,no_extrusion|Some firmware use different g and m codes. Setting this ensures that the output gcode will use the correct commands. gcode_output_type|G-Code Output|LIST|REPRAP,ULTIGCODE,MAKERBOT,BFB,MACH3|Some firmware use different g and m codes. Setting this ensures that the output gcode will use the correct commands. +has_fan|Has Fan|HARDWARE_PRESENT|bridge_fan_speed,disable_fan_first_layers,fan_always_on,fan_below_layer_time,max_fan_speed,min_fan_speed|Specify if your printer has a fan. +has_heated_bed|Has Heated Bed|HARDWARE_PRESENT||Specify if your printer has a heated bed. +has_sd_card_reader|Has SD Card Reader|HARDWARE_PRESENT|bed_temperature,first_layer_bed_temperature|Specify if your printer has the ability to plug in an SD card. infill_acceleration|Infill|POSITIVE_DOUBLE|mm/sē|Acceleration to use while infilling. Set to 0 to disable changing the printer's acceleration. infill_every_layers|Infill Every|INT|layers|Sets which layers will receive infill. This should normally stay set to 1 to make strong parts. infill_extruder|Infill Extruder|INT||The index of the extruder to use for infill. diff --git a/StaticData/Translations/Master.txt b/StaticData/Translations/Master.txt index 1b46d0fb0..a8a27e5f3 100644 --- a/StaticData/Translations/Master.txt +++ b/StaticData/Translations/Master.txt @@ -2373,3 +2373,36 @@ Translated:About MatterControl English:Oops! Printer could not be detected Translated:Oops! Printer could not be detected +English: Load Files +Translated: Load Files + +English: Eject SD Card +Translated: Eject SD Card + +English:Show Voxels +Translated:Show Voxels + +English:Show Mesh +Translated:Show Mesh + +English:Do Subtract +Translated:Do Subtract + +English:Specify if your printer has a fan. +Translated:Specify if your printer has a fan. + +English:Specify if your printer has a heated bed. +Translated:Specify if your printer has a heated bed. + +English:Specify if your printer has the ability to plug in an SD card. +Translated:Specify if your printer has the ability to plug in an SD card. + +English:Has Fan +Translated:Has Fan + +English:Has Heated Bed +Translated:Has Heated Bed + +English:Has SD Card Reader +Translated:Has SD Card Reader +