public static void ShowProbeCalibrationWizard(PrinterConfig printer, ThemeConfig theme) { // turn off print leveling PrintLevelingStream.AllowLeveling = false; var levelingContext = new ProbeCalibrationWizard(printer) { WindowTitle = $"{ApplicationController.Instance.ProductName} - " + "Probe Calibration Wizard".Localize() }; var probeCalibrationWizardWindow = DialogWindow.Show(new LevelingWizardRootPage(levelingContext) { WindowTitle = levelingContext.WindowTitle }); probeCalibrationWizardWindow.Closed += (s, e) => { // If leveling was on when we started, make sure it is on when we are done. PrintLevelingStream.AllowLeveling = true; probeCalibrationWizardWindow = null; // make sure we raise the probe on close if (printer.Settings.GetValue <bool>(SettingsKey.has_z_probe) && printer.Settings.GetValue <bool>(SettingsKey.use_z_probe) && printer.Settings.GetValue <bool>(SettingsKey.has_z_servo)) { // make sure the servo is retracted var servoRetract = printer.Settings.GetValue <double>(SettingsKey.z_servo_retracted_angle); printer.Connection.QueueLine($"M280 P0 S{servoRetract}"); } }; }
public static void ShowMessageBox(Action <bool> callback, string message, string caption, GuiWidget[] extraWidgetsToAdd, MessageType messageType, string yesOk = "", string noCancel = "", bool useMarkdown = false, int instanceIndex = 0) { DialogWindow.Show( new MessageBoxPage(callback, message, caption, messageType, extraWidgetsToAdd, 400, 300, yesOk, noCancel, ApplicationController.Instance.Theme, useMarkdown), instanceIndex); }
/// <summary> /// Validates printer satisfies all requirements. /// </summary> /// <param name="printer">The printer to validate.</param> /// <returns>A list of all warnings and errors.</returns> public static List <ValidationError> Validate(this PrinterConfig printer) { var errors = new List <ValidationError>(); var fffPrinter = printer.Settings.Slicer.PrinterType == PrinterType.FFF; if (!printer.Connection.IsConnected && fffPrinter) { errors.Add(new ValidationError(ValidationErrors.PrinterDisconnected) { Error = "Printer Disconnected".Localize(), Details = "Connect to your printer to continue".Localize(), FixAction = new NamedAction() { Title = "Connect".Localize(), Action = () => ApplicationController.Instance.ConnectToPrinter(printer) } }); } if (PrinterSetupRequired(printer)) { errors.Add(new ValidationError(ValidationErrors.PrinterSetupRequired) { Error = "Printer Setup Required".Localize(), Details = "Printer Setup must be run before printing".Localize(), FixAction = new NamedAction() { ID = "SetupPrinter", Title = "Setup".Localize() + "...", Action = () => { UiThread.RunOnIdle(() => { DialogWindow.Show( new PrinterCalibrationWizard(printer, AppContext.Theme), advanceToIncompleteStage: true); }); } } }); } // Concatenate printer and settings errors errors.AddRange(printer.ValidateSettings(validatePrintBed: !printer.Bed.EditContext.IsGGCodeSource)); return(errors); }
private void Connection_ConnectionSucceeded(object sender, EventArgs e) { if (sender is PrinterConfig printer) { if (PrinterCalibrationWizard.SetupRequired(printer)) { UiThread.RunOnIdle(() => { DialogWindow.Show( new PrinterCalibrationWizard(printer, AppContext.Theme), advanceToIncompleteStage: true); }); return; } } }
private void SetUpdateStatus(UpdateStatusStates updateStatus) { if (this.updateStatus != updateStatus) { this.updateStatus = updateStatus; OnUpdateStatusChanged(null); if (this.UpdateRequired && !haveShowUpdateRequired) { haveShowUpdateRequired = true; if (!GuiWidget.TouchScreenMode) { UiThread.RunOnIdle(() => DialogWindow.Show <CheckForUpdatesPage>()); } } } }
private void SetUpdateStatus(UpdateStatusStates updateStatus) { if (this.updateStatus != updateStatus) { this.updateStatus = updateStatus; OnUpdateStatusChanged(null); if (this.UpdateRequired && !haveShowUpdateRequired) { haveShowUpdateRequired = true; if (!UserSettings.Instance.IsTouchScreen) { #if !__ANDROID__ UiThread.RunOnIdle(() => DialogWindow.Show <CheckForUpdatesPage>()); #endif } } } }
public PrinterCalibrationWizard(PrinterConfig printer, ThemeConfig theme) { var stages = new List <ISetupWizard>() { new ZCalibrationWizard(printer), new PrintLevelingWizard(printer), new LoadFilamentWizard(printer, extruderIndex: 0, showAlreadyLoadedButton: true), new LoadFilamentWizard(printer, extruderIndex: 1, showAlreadyLoadedButton: true), new XyCalibrationWizard(printer, 1) }; this.Stages = stages; this.printer = printer; this.HomePageGenerator = () => { var homePage = new WizardSummaryPage() { HeaderText = "Printer Setup & Calibration".Localize() }; var contentRow = homePage.ContentRow; if (!this.ReturnedToHomePage) { contentRow.AddChild( new WrappedTextWidget( @"Select the calibration task on the left to continue".Replace("\r\n", "\n"), pointSize: theme.DefaultFontSize, textColor: theme.TextColor)); } contentRow.BackgroundColor = Color.Transparent; foreach (var stage in this.Stages.Where(s => s.Enabled && s.Visible)) { GuiWidget rightWidget = null; var widget = new GuiWidget(); if (stage is ZCalibrationWizard probeWizard) { var column = CreateColumn(theme); column.FlowDirection = FlowDirection.LeftToRight; var offset = printer.Settings.GetValue <Vector3>(SettingsKey.probe_offset); column.AddChild( new ValueTag( "Z Offset".Localize(), offset.Z.ToString("0.###"), new BorderDouble(12, 5, 2, 5), 5, 11) { Margin = new BorderDouble(bottom: 4), MinimumSize = new Vector2(125, 0) }); widget = column; } if (stage is PrintLevelingWizard levelingWizard) { PrintLevelingData levelingData = printer.Settings.Helpers.PrintLevelingData; // Always show leveling option if printer does not have hardware leveling if (!printer.Settings.GetValue <bool>(SettingsKey.has_hardware_leveling)) { var positions = levelingData.SampledPositions; var column = CreateColumn(theme); column.AddChild( new ValueTag( "Leveling Solution".Localize(), printer.Settings.GetValue(SettingsKey.print_leveling_solution), new BorderDouble(12, 5, 2, 5), 5, 11) { Margin = new BorderDouble(bottom: 4), MinimumSize = new Vector2(125, 0) }); var row = new FlowLayoutWidget() { VAnchor = VAnchor.Fit, HAnchor = HAnchor.Fit }; // Only show Edit button if data initialized if (levelingData?.SampledPositions.Count() > 0) { var editButton = new IconButton(AggContext.StaticData.LoadIcon("icon_edit.png", 16, 16, theme.InvertIcons), theme) { Name = "Edit Leveling Data Button", ToolTipText = "Edit Leveling Data".Localize(), }; editButton.Click += (s, e) => { DialogWindow.Show(new EditLevelingSettingsPage(printer, theme)); }; row.AddChild(editButton); } // only show the switch if leveling can be turned off (it can't if it is required). if (!printer.Settings.GetValue <bool>(SettingsKey.print_leveling_required_to_print)) { // put in the switch printLevelingSwitch = new RoundedToggleSwitch(theme) { VAnchor = VAnchor.Center, Margin = new BorderDouble(theme.DefaultContainerPadding, 0), Checked = printer.Settings.GetValue <bool>(SettingsKey.print_leveling_enabled), ToolTipText = "Enable Software Leveling".Localize() }; printLevelingSwitch.CheckedStateChanged += (sender, e) => { printer.Settings.Helpers.DoPrintLeveling(printLevelingSwitch.Checked); }; printLevelingSwitch.Closed += (s, e) => { // Unregister listeners printer.Settings.PrintLevelingEnabledChanged -= this.Settings_PrintLevelingEnabledChanged; }; // TODO: Why is this listener conditional? If the leveling changes somehow, shouldn't we be updated the UI to reflect that? // Register listeners printer.Settings.PrintLevelingEnabledChanged += this.Settings_PrintLevelingEnabledChanged; row.AddChild(printLevelingSwitch); } rightWidget = row; // Only visualize leveling data if initialized if (levelingData?.SampledPositions.Count() > 0) { var probeWidget = new ProbePositionsWidget(printer, positions.Select(v => new Vector2(v)).ToList(), theme) { HAnchor = HAnchor.Absolute, VAnchor = VAnchor.Absolute, Height = 200, Width = 200, RenderLevelingData = true, RenderProbePath = false, SimplePoints = true, }; column.AddChild(probeWidget); } widget = column; } } if (stage is XyCalibrationWizard xyWizard) { var column = CreateColumn(theme); column.FlowDirection = FlowDirection.LeftToRight; var hotendOffset = printer.Settings.Helpers.ExtruderOffset(1); var tool2Column = new FlowLayoutWidget(FlowDirection.TopToBottom); column.AddChild(tool2Column); tool2Column.AddChild( new TextWidget("Tool".Localize() + " 2", pointSize: theme.DefaultFontSize, textColor: theme.TextColor) { Margin = new BorderDouble(bottom: 4) }); tool2Column.AddChild( new ValueTag( "X Offset".Localize(), hotendOffset.X.ToString("0.###"), new BorderDouble(12, 5, 2, 5), 5, 11) { Margin = new BorderDouble(bottom: 4), MinimumSize = new Vector2(125, 0) }); tool2Column.AddChild( new ValueTag( "Y Offset".Localize(), hotendOffset.Y.ToString("0.###"), new BorderDouble(12, 5, 2, 5), 5, 11) { MinimumSize = new Vector2(125, 0) }); widget = column; } if (stage.SetupRequired) { var column = CreateColumn(theme); column.AddChild(new TextWidget("Setup Required".Localize(), pointSize: theme.DefaultFontSize, textColor: theme.TextColor)); widget = column; } else if (stage is LoadFilamentWizard filamentWizard) { widget.Margin = new BorderDouble(left: theme.DefaultContainerPadding); } var section = new SectionWidget(stage.Title, widget, theme, rightAlignedContent: rightWidget, expandingContent: false); theme.ApplyBoxStyle(section); section.Margin = section.Margin.Clone(left: 0); section.ShowExpansionIcon = false; if (stage.SetupRequired) { section.BackgroundColor = Color.Red.WithAlpha(30); } contentRow.AddChild(section); } return(homePage); }; }
private static PopupMenu CreatePopupMenu() { var menuTheme = ApplicationController.Instance.MenuTheme; var popupMenu = new PopupMenu(menuTheme) { MinimumSize = new Vector2(300, 0) }; var linkIcon = StaticData.Instance.LoadIcon("fa-link_16.png", 16, 16, menuTheme.InvertIcons); PopupMenu.MenuItem menuItem; menuItem = popupMenu.CreateMenuItem("Help".Localize(), StaticData.Instance.LoadIcon("help_page.png", 16, 16, menuTheme.InvertIcons)); menuItem.Click += (s, e) => ApplicationController.Instance.ShowApplicationHelp("Docs"); menuItem = popupMenu.CreateMenuItem("Interface Tour".Localize(), StaticData.Instance.LoadIcon("tour.png", 16, 16, menuTheme.InvertIcons)); menuItem.Click += (s, e) => { UiThread.RunOnIdle(() => { DialogWindow.Show <Tour.WelcomePage>(); }); }; if (Application.EnableNetworkTraffic) { popupMenu.CreateSeparator(); menuItem = popupMenu.CreateMenuItem("Check For Update".Localize(), StaticData.Instance.LoadIcon("update.png", 16, 16, menuTheme.InvertIcons)); menuItem.Click += (s, e) => UiThread.RunOnIdle(() => { UpdateControlData.Instance.CheckForUpdate(); DialogWindow.Show <CheckForUpdatesPage>(); }); } popupMenu.CreateSeparator(); menuItem = popupMenu.CreateMenuItem("Settings".Localize(), StaticData.Instance.LoadIcon("fa-cog_16.png", 16, 16, menuTheme.InvertIcons)); menuItem.Click += (s, e) => DialogWindow.Show <ApplicationSettingsPage>(); menuItem.Name = "Settings MenuItem"; popupMenu.CreateSeparator(); ImageBuffer indicatorIcon = null; if (IntPtr.Size == 8) { indicatorIcon = StaticData.Instance.LoadIcon("x64.png", 16, 16, menuTheme.InvertIcons); } popupMenu.CreateSubMenu("Community".Localize(), menuTheme, (modifyMenu) => { menuItem = modifyMenu.CreateMenuItem("Forums".Localize(), linkIcon); menuItem.Click += (s, e) => ApplicationController.LaunchBrowser("https://forums.matterhackers.com/category/20/mattercontrol"); menuItem = modifyMenu.CreateMenuItem("Guides and Articles".Localize(), linkIcon); menuItem.Click += (s, e) => ApplicationController.LaunchBrowser("https://www.matterhackers.com/topic/mattercontrol"); menuItem = modifyMenu.CreateMenuItem("Support".Localize(), linkIcon); menuItem.Click += (s, e) => ApplicationController.LaunchBrowser("https://www.matterhackers.com/mattercontrol/support"); menuItem = modifyMenu.CreateMenuItem("Release Notes".Localize(), linkIcon); menuItem.Click += (s, e) => ApplicationController.LaunchBrowser("https://www.matterhackers.com/mattercontrol/support/release-notes"); modifyMenu.CreateSeparator(); menuItem = modifyMenu.CreateMenuItem("Report a Bug".Localize(), StaticData.Instance.LoadIcon("feedback.png", 16, 16, menuTheme.InvertIcons)); menuItem.Click += (s, e) => ApplicationController.LaunchBrowser("https://github.com/MatterHackers/MatterControl/issues"); }, StaticData.Instance.LoadIcon("feedback.png", 16, 16, menuTheme.InvertIcons)); popupMenu.CreateSeparator(); var imageBuffer = new ImageBuffer(18, 18); // x64 indicator icon if (IntPtr.Size == 8) { var graphics = imageBuffer.NewGraphics2D(); graphics.Clear(menuTheme.BackgroundColor); graphics.Rectangle(imageBuffer.GetBoundingRect(), menuTheme.PrimaryAccentColor); graphics.DrawString("64", imageBuffer.Width / 2, imageBuffer.Height / 2, 8, Agg.Font.Justification.Center, Agg.Font.Baseline.BoundsCenter, color: menuTheme.PrimaryAccentColor); } menuItem = popupMenu.CreateMenuItem("About".Localize() + " MatterControl", imageBuffer); menuItem.Click += (s, e) => ApplicationController.Instance.ShowAboutPage(); return(popupMenu); }
private void AddAdvancedPannel(GuiWidget settingsColumn) { var advancedPanel = new FlowLayoutWidget(FlowDirection.TopToBottom); var advancedSection = new SectionWidget("Advanced".Localize(), advancedPanel, theme, serializationKey: "ApplicationSettings-Advanced", expanded: false) { Name = "Advanced Section", HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit, Margin = 0 }; settingsColumn.AddChild(advancedSection); theme.ApplyBoxStyle(advancedSection); // Touch Screen Mode this.AddSettingsRow( new SettingsItem( "Touch Screen Mode".Localize(), theme, new SettingsItem.ToggleSwitchConfig() { Checked = UserSettings.Instance.get(UserSettingsKey.ApplicationDisplayMode) == "touchscreen", ToggleAction = (itemChecked) => { string displayMode = itemChecked ? "touchscreen" : "responsive"; if (displayMode != UserSettings.Instance.get(UserSettingsKey.ApplicationDisplayMode)) { UserSettings.Instance.set(UserSettingsKey.ApplicationDisplayMode, displayMode); UiThread.RunOnIdle(() => ApplicationController.Instance.ReloadAll().ConfigureAwait(false)); } } }), advancedPanel); AddUserBoolToggle(advancedPanel, "Enable Socketeer Client".Localize(), UserSettingsKey.ApplicationUseSocketeer, true, false); AddUserBoolToggle(advancedPanel, "Utilize High Res Monitors".Localize(), UserSettingsKey.ApplicationUseHeigResDisplays, true, false); var openCacheButton = new IconButton(StaticData.Instance.LoadIcon("fa-link_16.png", 16, 16).SetToColor(theme.TextColor), theme) { ToolTipText = "Open Folder".Localize(), }; openCacheButton.Click += (s, e) => UiThread.RunOnIdle(() => { Process.Start(ApplicationDataStorage.ApplicationUserDataPath); }); this.AddSettingsRow( new SettingsItem( "Application Storage".Localize(), openCacheButton, theme), advancedPanel); var clearCacheButton = new HoverIconButton(StaticData.Instance.LoadIcon("remove.png", 16, 16).SetToColor(theme.TextColor), theme) { ToolTipText = "Clear Cache".Localize(), }; clearCacheButton.Click += (s, e) => UiThread.RunOnIdle(() => { CacheDirectory.DeleteCacheData(); }); this.AddSettingsRow( new SettingsItem( "Application Cache".Localize(), clearCacheButton, theme), advancedPanel); #if DEBUG var configureIcon = StaticData.Instance.LoadIcon("fa-cog_16.png", 16, 16).SetToColor(theme.TextColor); var configurePluginsButton = new IconButton(configureIcon, theme) { ToolTipText = "Configure Plugins".Localize(), Margin = 0 }; configurePluginsButton.Click += (s, e) => { UiThread.RunOnIdle(() => { DialogWindow.Show <PluginsPage>(); }); }; this.AddSettingsRow( new SettingsItem( "Plugins".Localize(), configurePluginsButton, theme), advancedPanel); #endif var gitHubPat = UserSettings.Instance.get("GitHubPat"); if (gitHubPat == null) { gitHubPat = ""; } var accessToken = new MHTextEditWidget(gitHubPat, theme, pixelWidth: 350, messageWhenEmptyAndNotSelected: "Enter Person Access Token".Localize()) { HAnchor = HAnchor.Absolute, Margin = new BorderDouble(5), Name = "GitHubPat Edit Field" }; accessToken.ActualTextEditWidget.EnterPressed += (s, e) => { UserSettings.Instance.set("GitHubPat", accessToken.ActualTextEditWidget.Text); }; accessToken.Closed += (s, e) => { UserSettings.Instance.set("GitHubPat", accessToken.ActualTextEditWidget.Text); }; this.AddSettingsRow( new SettingsItem( "GitHub Personal Access Token".Localize(), accessToken, theme) { ToolTipText = "This is used to increase the number of downloads allowed when browsing GitHub repositories".Localize(), }, advancedPanel); advancedPanel.Children <SettingsItem>().First().Border = new BorderDouble(0, 1); }
/// <summary> /// Validates the printer settings satisfy all requirements /// </summary> /// <param name="printer">The printer to validate</param> /// <returns>A list of all warnings and errors</returns> public static List <ValidationError> ValidateSettings(this PrinterConfig printer, SettingsContext settings = null) { if (settings == null) { settings = new SettingsContext(printer, null, NamedSettingsLayers.All); } var errors = new List <ValidationError>(); var extruderCount = settings.GetValue <int>(SettingsKey.extruder_count); // last let's check if there is any support in the scene and if it looks like it is needed var supportGenerator = new SupportGenerator(printer.Bed.Scene); if (supportGenerator.RequiresSupport()) { errors.Add(new ValidationError("UnsupportedParts") { Error = "Unsupported Parts Detected".Localize(), Details = "Some parts are unsupported and require support structures to print correctly".Localize(), ErrorLevel = ValidationErrorLevel.Warning, FixAction = new NamedAction() { Title = "Generate Supports".Localize(), Action = () => { // Find and InvokeClick on the Generate Supports toolbar button var sharedParent = ApplicationController.Instance.DragDropData.View3DWidget.Parents <GuiWidget>().FirstOrDefault(w => w.Name == "View3DContainerParent"); if (sharedParent != null) { var supportsPopup = sharedParent.FindDescendant("Support SplitButton"); supportsPopup.InvokeClick(); } } } }); } try { if (settings.GetValue <bool>(SettingsKey.validate_layer_height)) { if (settings.GetValue <double>(SettingsKey.layer_height) > settings.GetValue <double>(SettingsKey.nozzle_diameter)) { errors.Add( new SettingsValidationError(SettingsKey.layer_height) { Error = "{0} must be less than or equal to the {1}.".Localize().FormatWith( GetSettingsName(SettingsKey.layer_height), GetSettingsName(SettingsKey.nozzle_diameter)), ValueDetails = "{0} = {1}\n{2} = {3}".FormatWith( GetSettingsName(SettingsKey.layer_height), settings.GetValue <double>(SettingsKey.layer_height), GetSettingsName(SettingsKey.nozzle_diameter), settings.GetValue <double>(SettingsKey.nozzle_diameter)), }); } else if (settings.GetValue <double>(SettingsKey.layer_height) <= 0) { errors.Add( new SettingsValidationError(SettingsKey.layer_height) { Error = "{0} must be greater than 0.".Localize().FormatWith(GetSettingsName(SettingsKey.layer_height)), }); } if (settings.GetValue <double>(SettingsKey.first_layer_height) > settings.GetValue <double>(SettingsKey.nozzle_diameter)) { errors.Add( new SettingsValidationError(SettingsKey.first_layer_height) { Error = "{0} must be less than or equal to the {1}.".Localize().FormatWith( GetSettingsName(SettingsKey.first_layer_height), GetSettingsName(SettingsKey.nozzle_diameter)), ValueDetails = "{0} = {1}\n{2} = {3}".FormatWith( GetSettingsName(SettingsKey.first_layer_height), settings.GetValue <double>(SettingsKey.first_layer_height), GetSettingsName(SettingsKey.nozzle_diameter), settings.GetValue <double>(SettingsKey.nozzle_diameter)), }); } } string[] startGCode = settings.GetValue(SettingsKey.start_gcode).Replace("\\n", "\n").Split('\n'); // Print recovery is incompatible with firmware leveling - ensure not enabled in startGCode if (settings.GetValue <bool>(SettingsKey.recover_is_enabled)) { // Ensure we don't have hardware leveling commands in the start gcode. foreach (string startGCodeLine in startGCode) { if (startGCodeLine.StartsWith("G29")) { errors.Add( new SettingsValidationError(SettingsKey.start_gcode) { Error = "Start G-Code cannot contain G29 if Print Recovery is enabled.".Localize(), Details = "Your Start G-Code should not contain a G29 if you are planning on using Print Recovery. Change your start G-Code or turn off Print Recovery.".Localize(), }); } if (startGCodeLine.StartsWith("G30")) { errors.Add( new SettingsValidationError(SettingsKey.start_gcode) { Error = "Start G-Code cannot contain G30 if Print Leveling is enabled.".Localize(), Details = "Your Start G-Code should not contain a G30 if you are planning on using Print Recovery. Change your start G-Code or turn off Print Recovery.".Localize(), }); } } } var levelingEnabled = printer.Settings.GetValue <bool>(SettingsKey.print_leveling_enabled); var levelingRequired = printer.Settings.GetValue <bool>(SettingsKey.print_leveling_required_to_print); if (levelingEnabled || levelingRequired) { // Ensure we don't have hardware leveling commands in the start gcode. foreach (string startGCodeLine in startGCode) { if (startGCodeLine.StartsWith("G29")) { errors.Add( new SettingsValidationError(SettingsKey.start_gcode) { Error = "Start G-Code cannot contain G29 if Print Leveling is enabled.".Localize(), Details = "Your Start G-Code should not contain a G29 if you are planning on using print leveling. Change your start G-Code or turn off print leveling.".Localize(), }); } if (startGCodeLine.StartsWith("G30")) { errors.Add( new SettingsValidationError(SettingsKey.start_gcode) { Error = "Start G-Code cannot contain G30 if Print Leveling is enabled.".Localize(), Details = "Your Start G-Code should not contain a G30 if you are planning on using print leveling. Change your start G-Code or turn off print leveling.".Localize(), }); } } bool heatedBed = printer.Settings.GetValue <bool>(SettingsKey.has_heated_bed); double bedTemperature = printer.Settings.GetValue <double>(SettingsKey.bed_temperature); PrintLevelingData levelingData = printer.Settings.Helpers.GetPrintLevelingData(); if (heatedBed && !levelingData.IssuedLevelingTempWarning && Math.Abs(bedTemperature - levelingData.BedTemperature) > 10) { errors.Add( new ValidationError("BedLevelingTemperature") { Error = "Bed Leveling Temperature".Localize(), Details = string.Format( "Bed Leveling data created at {0}°C versus current {1}°C".Localize(), levelingData.BedTemperature, bedTemperature), ErrorLevel = ValidationErrorLevel.Warning, FixAction = new NamedAction() { Title = "Recalibrate", Action = () => { UiThread.RunOnIdle(() => { DialogWindow.Show(new PrintLevelingWizard(printer)); }); }, IsEnabled = () => printer.Connection.IsConnected } }); } } // Make sure the z offsets are not too big if (Math.Abs(settings.GetValue <double>(SettingsKey.baby_step_z_offset)) > 2) { // Static path generation for non-SliceSettings value var location = "Location".Localize() + ":" + "\n" + "Controls".Localize() + "\n • " + "Movement".Localize() + "\n • " + "Z Offset".Localize(); errors.Add( new ValidationError("ZOffset0TooLarge") { Error = "Z Offset is too large.".Localize(), Details = string.Format( "{0}\n\n{1}", "The Z Offset for your printer, sometimes called Baby Stepping, is greater than 2mm and invalid. Clear the value and re-level the bed.".Localize(), location) }); } if (extruderCount > 1 && Math.Abs(settings.GetValue <double>(SettingsKey.baby_step_z_offset_1)) > 2) { // Static path generation for non-SliceSettings value var location = "Location".Localize() + ":" + "\n" + "Controls".Localize() + "\n • " + "Movement".Localize() + "\n • " + "Z Offset 2".Localize(); errors.Add( new ValidationError("ZOffset1TooLarge") { Error = "Z Offset 2 is too large.".Localize(), Details = string.Format( "{0}\n\n{1}", "The Z Offset for your second extruder, is greater than 2mm and invalid. Clear the value and re-level the bed.".Localize(), location) }); } if (settings.GetValue <double>(SettingsKey.first_layer_extrusion_width) > settings.GetValue <double>(SettingsKey.nozzle_diameter) * 4) { errors.Add( new SettingsValidationError(SettingsKey.first_layer_extrusion_width) { Error = "{0} must be less than or equal to the {1} * 4.".Localize().FormatWith( GetSettingsName(SettingsKey.first_layer_extrusion_width), GetSettingsName(SettingsKey.nozzle_diameter)), ValueDetails = "{0} = {1}\n{2} = {3}".FormatWith( GetSettingsName(SettingsKey.first_layer_extrusion_width), settings.GetValue <double>(SettingsKey.first_layer_extrusion_width), GetSettingsName(SettingsKey.nozzle_diameter), settings.GetValue <double>(SettingsKey.nozzle_diameter)) }); } if (settings.GetValue <double>(SettingsKey.first_layer_extrusion_width) <= 0) { errors.Add( new SettingsValidationError(SettingsKey.first_layer_extrusion_width) { Error = "{0} must be greater than 0.".Localize().FormatWith( GetSettingsName(SettingsKey.first_layer_extrusion_width)), ValueDetails = "{0} = {1}".FormatWith( GetSettingsName(SettingsKey.first_layer_extrusion_width), settings.GetValue <double>(SettingsKey.first_layer_extrusion_width)), }); } if (settings.GetValue <double>(SettingsKey.external_perimeter_extrusion_width) > settings.GetValue <double>(SettingsKey.nozzle_diameter) * 4) { errors.Add( new SettingsValidationError(SettingsKey.external_perimeter_extrusion_width) { Error = "{0} must be less than or equal to the {1} * 4.".Localize().FormatWith( GetSettingsName(SettingsKey.external_perimeter_extrusion_width), GetSettingsName(SettingsKey.nozzle_diameter)), ValueDetails = "{0} = {1}\n{2} = {3}".FormatWith( GetSettingsName(SettingsKey.external_perimeter_extrusion_width), settings.GetValue <double>(SettingsKey.external_perimeter_extrusion_width), GetSettingsName(SettingsKey.nozzle_diameter), settings.GetValue <double>(SettingsKey.nozzle_diameter)), }); } if (settings.GetValue <double>(SettingsKey.external_perimeter_extrusion_width) <= 0) { errors.Add( new SettingsValidationError(SettingsKey.external_perimeter_extrusion_width) { Error = "{0} must be greater than 0.".Localize().FormatWith( GetSettingsName(SettingsKey.external_perimeter_extrusion_width)), ValueDetails = "{0} = {1}".FormatWith( GetSettingsName(SettingsKey.external_perimeter_extrusion_width), settings.GetValue <double>(SettingsKey.external_perimeter_extrusion_width)), }); } if (settings.GetValue <double>(SettingsKey.min_fan_speed) > 100) { errors.Add( new SettingsValidationError(SettingsKey.min_fan_speed) { Error = "The {0} can only go as high as 100%.".Localize().FormatWith( GetSettingsName(SettingsKey.min_fan_speed)), ValueDetails = "It is currently set to {0}.".Localize().FormatWith( settings.GetValue <double>(SettingsKey.min_fan_speed)), }); } if (settings.GetValue <double>(SettingsKey.max_fan_speed) > 100) { errors.Add( new SettingsValidationError(SettingsKey.max_fan_speed) { Error = "The {0} can only go as high as 100%.".Localize().FormatWith( GetSettingsName(SettingsKey.max_fan_speed)), ValueDetails = "It is currently set to {0}.".Localize().FormatWith( settings.GetValue <double>(SettingsKey.max_fan_speed)), }); } if (extruderCount < 1) { errors.Add( new SettingsValidationError(SettingsKey.extruder_count) { Error = "The {0} must be at least 1.".Localize().FormatWith( GetSettingsName(SettingsKey.extruder_count)), ValueDetails = "It is currently set to {0}.".Localize().FormatWith(extruderCount), }); } if (settings.GetValue <double>(SettingsKey.fill_density) < 0 || settings.GetValue <double>(SettingsKey.fill_density) > 1) { errors.Add( new SettingsValidationError(SettingsKey.fill_density) { Error = "The {0} must be between 0 and 1.".Localize().FormatWith( GetSettingsName(SettingsKey.fill_density)), ValueDetails = "It is currently set to {0}.".Localize().FormatWith( settings.GetValue <double>(SettingsKey.fill_density)), }); } // marlin firmware can only take a max of 128 bytes in a single instruction, make sure no lines are longer than that ValidateGCodeLinesShortEnough(SettingsKey.cancel_gcode, printer, errors); ValidateGCodeLinesShortEnough(SettingsKey.connect_gcode, printer, errors); ValidateGCodeLinesShortEnough(SettingsKey.end_gcode, printer, errors); ValidateGCodeLinesShortEnough(SettingsKey.layer_gcode, printer, errors); ValidateGCodeLinesShortEnough(SettingsKey.pause_gcode, printer, errors); ValidateGCodeLinesShortEnough(SettingsKey.resume_gcode, printer, errors); ValidateGCodeLinesShortEnough(SettingsKey.start_gcode, printer, errors); // If the given speed is part of the current slice engine then check that it is greater than 0. ValidateGoodSpeedSettingGreaterThan0(SettingsKey.bridge_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.air_gap_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.external_perimeter_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.first_layer_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.infill_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.perimeter_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.small_perimeter_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.solid_infill_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.support_material_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.top_solid_infill_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.travel_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.retract_speed, printer, errors); } catch (Exception e) { errors.Add( new ValidationError("ExceptionDuringSliceSettingsValidation") { Error = "Unexpected error validating settings".Localize(), Details = e.Message }); } return(errors); }
private static PopupMenu CreatePopupMenu() { var menuTheme = ApplicationController.Instance.MenuTheme; var popupMenu = new PopupMenu(menuTheme) { MinimumSize = new Vector2(300, 0) }; var linkIcon = AggContext.StaticData.LoadIcon("fa-link_16.png", 16, 16, menuTheme.InvertIcons); PopupMenu.MenuItem menuItem; menuItem = popupMenu.CreateMenuItem("Help".Localize(), AggContext.StaticData.LoadIcon("help_page.png", 16, 16, menuTheme.InvertIcons)); menuItem.Click += (s, e) => ApplicationController.Instance.ShowApplicationHelp(); popupMenu.CreateHorizontalLine(); menuItem = popupMenu.CreateMenuItem("Check For Update".Localize(), AggContext.StaticData.LoadIcon("update.png", 16, 16, menuTheme.InvertIcons)); menuItem.Click += (s, e) => UiThread.RunOnIdle(() => { UpdateControlData.Instance.CheckForUpdate(); DialogWindow.Show <CheckForUpdatesPage>(); }); popupMenu.CreateHorizontalLine(); menuItem = popupMenu.CreateMenuItem("Settings".Localize(), AggContext.StaticData.LoadIcon("fa-cog_16.png", 16, 16, menuTheme.InvertIcons)); menuItem.Click += (s, e) => DialogWindow.Show <ApplicationSettingsPage>(); menuItem.Name = "Settings MenuItem"; popupMenu.CreateHorizontalLine(); ImageBuffer indicatorIcon = null; if (IntPtr.Size == 8) { indicatorIcon = AggContext.StaticData.LoadIcon("x64.png", 16, 16, menuTheme.InvertIcons); } popupMenu.CreateSubMenu("Community".Localize(), menuTheme, (modifyMenu) => { menuItem = modifyMenu.CreateMenuItem("Forums".Localize(), linkIcon); menuItem.Click += (s, e) => ApplicationController.Instance.LaunchBrowser("https://forums.matterhackers.com/category/20/mattercontrol"); menuItem = modifyMenu.CreateMenuItem("Guides and Articles".Localize(), linkIcon); menuItem.Click += (s, e) => ApplicationController.Instance.LaunchBrowser("http://www.matterhackers.com/topic/mattercontrol"); menuItem = modifyMenu.CreateMenuItem("Support".Localize(), linkIcon); menuItem.Click += (s, e) => ApplicationController.Instance.LaunchBrowser("http://https://www.matterhackers.com/mattercontrol/support"); menuItem = modifyMenu.CreateMenuItem("Release Notes".Localize(), linkIcon); menuItem.Click += (s, e) => ApplicationController.Instance.LaunchBrowser("http://wiki.mattercontrol.com/Release_Notes"); modifyMenu.CreateHorizontalLine(); menuItem = modifyMenu.CreateMenuItem("Report a Bug".Localize(), AggContext.StaticData.LoadIcon("feedback.png", 16, 16, menuTheme.InvertIcons)); menuItem.Click += (s, e) => ApplicationController.Instance.LaunchBrowser("https://github.com/MatterHackers/MatterControl/issues"); }, AggContext.StaticData.LoadIcon("feedback.png", 16, 16, menuTheme.InvertIcons)); popupMenu.CreateHorizontalLine(); menuItem = popupMenu.CreateMenuItem("About".Localize() + " MatterControl", indicatorIcon); menuItem.Click += (s, e) => ApplicationController.Instance.ShowAboutPage(); return(popupMenu); }
public static async Task <GuiWidget> Initialize(SystemWindow systemWindow, Action <double, string> reporter) { var loading = "Loading..."; #if DEBUG loading = null; #endif reporter?.Invoke(0.01, (loading != null) ? loading : "PlatformInit"); AppContext.Platform.PlatformInit((status) => { reporter?.Invoke(0.01, (loading != null) ? loading : status); }); // TODO: Appears to be unused and should be removed // set this at startup so that we can tell next time if it got set to true in close UserSettings.Instance.Fields.StartCount = UserSettings.Instance.Fields.StartCount + 1; reporter?.Invoke(0.05, (loading != null) ? loading : "ApplicationController"); var applicationController = ApplicationController.Instance; // Accessing any property on ProfileManager will run the static constructor and spin up the ProfileManager instance reporter?.Invoke(0.2, (loading != null) ? loading : "ProfileManager"); bool na2 = ProfileManager.Instance.IsGuestProfile; await ProfileManager.Instance.Initialize(); reporter?.Invoke(0.25, (loading != null) ? loading : "Initialize printer"); reporter?.Invoke(0.3, (loading != null) ? loading : "Plugins"); ApplicationController.Plugins.InitializePlugins(systemWindow); reporter?.Invoke(0.4, (loading != null) ? loading : "MainView"); applicationController.MainView = new MainViewWidget(applicationController.Theme); reporter?.Invoke(0.91, (loading != null) ? loading : "OnLoadActions"); applicationController.OnLoadActions(); // Wired up to MainView.Load with the intent to fire startup actions and tasks in order with reporting async void InitialWindowLoad(object s, EventArgs e) { try { PrinterSettings.SliceEngines["MatterSlice"] = new EngineMappingsMatterSlice(); // Initial load builds UI elements, then constructs workspace tabs as they're encountered in RestoreUserTabs() await applicationController.RestoreUserTabs(); // Batch startup actions await applicationController.Tasks.Execute( "Finishing Startup".Localize(), null, (progress, cancellationToken) => { var status = new ProgressStatus(); int itemCount = ApplicationController.StartupActions.Count; double i = 1; foreach (var action in ApplicationController.StartupActions.OrderByDescending(t => t.Priority)) { status.Status = action.Title; progress.Report(status); action.Action?.Invoke(); status.Progress0To1 = i++ / itemCount; progress.Report(status); } return(Task.CompletedTask); }); // Batch execute startup tasks foreach (var task in ApplicationController.StartupTasks.OrderByDescending(t => t.Priority)) { await applicationController.Tasks.Execute(task.Title, null, task.Action); } if (UserSettings.Instance.get(UserSettingsKey.ShownWelcomeMessage) != "false") { UiThread.RunOnIdle(() => { DialogWindow.Show <WelcomePage>(); }); } } catch { } // Unhook after execution applicationController.MainView.Load -= InitialWindowLoad; } // Hook after first draw applicationController.MainView.Load += InitialWindowLoad; return(applicationController.MainView); }
/// <summary> /// Validates the printer settings satisfy all requirements. /// </summary> /// <param name="printer">The printer to validate.</param> /// <returns>A list of all warnings and errors.</returns> public static List <ValidationError> ValidateSettings(this PrinterConfig printer, SettingsContext settings = null, bool validatePrintBed = true) { var fffPrinter = printer.Settings.Slicer.PrinterType == PrinterType.FFF; if (settings == null) { settings = new SettingsContext(printer, null, NamedSettingsLayers.All); } var errors = new List <ValidationError>(); var extruderCount = settings.GetValue <int>(SettingsKey.extruder_count); // Check to see if supports are required if (!settings.GetValue <bool>(SettingsKey.create_per_layer_support)) { var supportGenerator = new SupportGenerator(printer.Bed.Scene, .05); if (supportGenerator.RequiresSupport()) { errors.Add(new ValidationError(ValidationErrors.UnsupportedParts) { Error = "Possible Unsupported Parts Detected".Localize(), Details = "Some parts may require support structures to print correctly".Localize(), ErrorLevel = ValidationErrorLevel.Warning, FixAction = new NamedAction() { Title = "Generate Supports".Localize(), Action = () => { // Find and InvokeClick on the Generate Supports toolbar button var sharedParent = ApplicationController.Instance.DragDropData.View3DWidget.Parents <GuiWidget>().FirstOrDefault(w => w.Name == "View3DContainerParent"); if (sharedParent != null) { var supportsPopup = sharedParent.FindDescendant("Support SplitButton"); supportsPopup.InvokeClick(); } } } }); } } if (!settings.GetValue <bool>(SettingsKey.extruder_offset)) { var t0Offset = printer.Settings.Helpers.ExtruderOffset(0); if (t0Offset != Vector3.Zero) { errors.Add( new SettingsValidationError(SettingsKey.extruder_offset) { Error = "Nozzle 1 should have offsets set to 0.".Localize(), ValueDetails = "{0} = {1}\n{2} = {3}".FormatWith( GetSettingsName(SettingsKey.extruder_offset), settings.GetValue <double>(SettingsKey.extruder_offset), GetSettingsName(SettingsKey.extruder_offset), settings.GetValue <double>(SettingsKey.extruder_offset)), ErrorLevel = ValidationErrorLevel.Warning, }); } } // Check to see if current OEM layer matches downloaded OEM layer { if (printer.Settings.GetValue(SettingsKey.make) != "Other" && ProfileManager.GetOemSettingsNeedingUpdate(printer).Any()) { errors.Add(new ValidationError(ValidationErrors.SettingsUpdateAvailable) { Error = "Settings Update Available".Localize(), Details = "The default settings for this printer have changed and can be updated".Localize(), ErrorLevel = ValidationErrorLevel.Warning, FixAction = new NamedAction() { Title = "Update Settings...".Localize(), Action = () => { DialogWindow.Show(new UpdateSettingsPage(printer)); } } }); } } if (printer.Connection.IsConnected && !PrinterSetupRequired(printer) && validatePrintBed && errors.Count(e => e.ErrorLevel == ValidationErrorLevel.Error) == 0 && !printer.PrintableItems(printer.Bed.Scene).Any()) { errors.Add(new ValidationError(ValidationErrors.NoPrintableParts) { Error = "Empty Bed".Localize(), Details = "No printable parts exists within the bounds of the printer bed. Add content to continue".Localize(), ErrorLevel = ValidationErrorLevel.Error, }); } try { if (settings.GetValue <bool>(SettingsKey.validate_layer_height)) { if (settings.GetValue <double>(SettingsKey.layer_height) > settings.GetValue <double>(SettingsKey.nozzle_diameter)) { errors.Add( new SettingsValidationError(SettingsKey.layer_height) { Error = "{0} must be less than or equal to the {1}.".Localize().FormatWith( GetSettingsName(SettingsKey.layer_height), GetSettingsName(SettingsKey.nozzle_diameter)), ValueDetails = "{0} = {1}\n{2} = {3}".FormatWith( GetSettingsName(SettingsKey.layer_height), settings.GetValue <double>(SettingsKey.layer_height), GetSettingsName(SettingsKey.nozzle_diameter), settings.GetValue <double>(SettingsKey.nozzle_diameter)), }); } else if (settings.GetValue <double>(SettingsKey.layer_height) <= 0) { errors.Add( new SettingsValidationError(SettingsKey.layer_height) { Error = "{0} must be greater than 0.".Localize().FormatWith(GetSettingsName(SettingsKey.layer_height)), }); } // make sure the first layer height is not too big if (settings.GetValue <double>(SettingsKey.first_layer_height) > settings.GetValue <double>(SettingsKey.nozzle_diameter)) { errors.Add( new SettingsValidationError(SettingsKey.first_layer_height) { Error = "{0} must be less than or equal to the {1}.".Localize().FormatWith( GetSettingsName(SettingsKey.first_layer_height), GetSettingsName(SettingsKey.nozzle_diameter)), ValueDetails = "{0} = {1}\n{2} = {3}".FormatWith( GetSettingsName(SettingsKey.first_layer_height), settings.GetValue <double>(SettingsKey.first_layer_height), GetSettingsName(SettingsKey.nozzle_diameter), settings.GetValue <double>(SettingsKey.nozzle_diameter)), }); } // make sure the first layer height is not too small else if (settings.GetValue <double>(SettingsKey.first_layer_height) < settings.GetValue <double>(SettingsKey.nozzle_diameter) / 2) { errors.Add( new SettingsValidationError(SettingsKey.first_layer_height) { Error = "{0} should be greater than or equal to 1/2 the {1}.".Localize().FormatWith( GetSettingsName(SettingsKey.first_layer_height), GetSettingsName(SettingsKey.nozzle_diameter)), ValueDetails = "{0} = {1}\n1/2 {2} = {3}".FormatWith( GetSettingsName(SettingsKey.first_layer_height), settings.GetValue <double>(SettingsKey.first_layer_height), GetSettingsName(SettingsKey.nozzle_diameter), settings.GetValue <double>(SettingsKey.nozzle_diameter) / 2), ErrorLevel = ValidationErrorLevel.Warning, }); } } string[] startGCode = settings.GetValue(SettingsKey.start_gcode).Replace("\\n", "\n").Split('\n'); // Print recovery is incompatible with firmware leveling - ensure not enabled in startGCode if (settings.GetValue <bool>(SettingsKey.recover_is_enabled) && !settings.GetValue <bool>(SettingsKey.has_hardware_leveling)) { // Ensure we don't have hardware leveling commands in the start gcode. foreach (string startGCodeLine in startGCode) { if (startGCodeLine.StartsWith("G29")) { errors.Add( new SettingsValidationError(SettingsKey.start_gcode) { Error = "Start G-Code cannot contain G29 if Print Recovery is enabled.".Localize(), Details = "Your Start G-Code should not contain a G29 if you are planning on using Print Recovery. Change your start G-Code or turn off Print Recovery.".Localize(), }); } if (startGCodeLine.StartsWith("G30")) { errors.Add( new SettingsValidationError(SettingsKey.start_gcode) { Error = "Start G-Code cannot contain G30 if Print Leveling is enabled.".Localize(), Details = "Your Start G-Code should not contain a G30 if you are planning on using Print Recovery. Change your start G-Code or turn off Print Recovery.".Localize(), }); } } } var levelingEnabled = printer.Settings.GetValue <bool>(SettingsKey.print_leveling_enabled) & !settings.GetValue <bool>(SettingsKey.has_hardware_leveling); var levelingRequired = printer.Settings.GetValue <bool>(SettingsKey.print_leveling_required_to_print); if (levelingEnabled || levelingRequired) { // Ensure we don't have hardware leveling commands in the start gcode. foreach (string startGCodeLine in startGCode) { if (startGCodeLine.StartsWith("G29")) { errors.Add( new SettingsValidationError(SettingsKey.start_gcode) { Error = "Start G-Code cannot contain G29 if Print Leveling is enabled.".Localize(), Details = "Your Start G-Code should not contain a G29 if you are planning on using print leveling. Change your start G-Code or turn off print leveling.".Localize(), }); } if (startGCodeLine.StartsWith("G30")) { errors.Add( new SettingsValidationError(SettingsKey.start_gcode) { Error = "Start G-Code cannot contain G30 if Print Leveling is enabled.".Localize(), Details = "Your Start G-Code should not contain a G30 if you are planning on using print leveling. Change your start G-Code or turn off print leveling.".Localize(), }); } } bool heatedBed = printer.Settings.GetValue <bool>(SettingsKey.has_heated_bed); double bedTemperature = printer.Settings.GetValue <double>(SettingsKey.bed_temperature); if (heatedBed && printer.Connection.IsConnected && !PrinterSetupRequired(printer) && printer.Settings.Helpers.PrintLevelingData is PrintLevelingData levelingData && !levelingData.IssuedLevelingTempWarning && Math.Abs(bedTemperature - levelingData.BedTemperature) > 10 && !printer.Settings.Helpers.ValidateLevelingWithProbe) { errors.Add( new ValidationError(ValidationErrors.BedLevelingTemperature) { Error = "Bed Leveling Temperature".Localize(), Details = string.Format( "Bed Leveling data created at {0}°C versus current {1}°C".Localize(), levelingData.BedTemperature, bedTemperature), ErrorLevel = ValidationErrorLevel.Warning, FixAction = new NamedAction() { Title = "Recalibrate", Action = () => { UiThread.RunOnIdle(() => { DialogWindow.Show(new PrintLevelingWizard(printer)); }); }, IsEnabled = () => printer.Connection.IsConnected } }); } if (levelingEnabled && !settings.GetValue <bool>(SettingsKey.has_hardware_leveling) && settings.GetValue <bool>(SettingsKey.has_z_probe) && settings.GetValue <bool>(SettingsKey.use_z_probe) && settings.GetValue <bool>(SettingsKey.validate_leveling) && (settings.GetValue <double>(SettingsKey.validation_threshold) < .001 || settings.GetValue <double>(SettingsKey.validation_threshold) > .5)) { var threshold = settings.GetValue <double>(SettingsKey.validation_threshold); errors.Add( new SettingsValidationError(SettingsKey.validation_threshold) { Error = "The Validation Threshold mush be greater than 0 and less than .5mm.".Localize().FormatWith(threshold), ValueDetails = "{0} = {1}".FormatWith(GetSettingsName(SettingsKey.validation_threshold), threshold), }); } // check if the leveling data has too large a range if (printer.Settings.Helpers.PrintLevelingData.SampledPositions.Count > 3) { var minLevelZ = double.MaxValue; var maxLevelZ = double.MinValue; foreach (var levelPosition in printer.Settings.Helpers.PrintLevelingData.SampledPositions) { minLevelZ = Math.Min(minLevelZ, levelPosition.Z); maxLevelZ = Math.Max(maxLevelZ, levelPosition.Z); } var delta = maxLevelZ - minLevelZ; var maxDelta = printer.Settings.GetValue <double>(SettingsKey.nozzle_diameter) * 10; if (delta > maxDelta) { errors.Add( new ValidationError(ValidationErrors.BedLevelingMesh) { Error = "Leveling Data Warning".Localize(), Details = "The leveling data might be invalid. It changes by as much as {0:0.##}mm. Leveling calibration should be re-run".Localize().FormatWith(delta), ErrorLevel = ValidationErrorLevel.Warning, FixAction = new NamedAction() { Title = "Recalibrate", Action = () => { UiThread.RunOnIdle(() => { DialogWindow.Show(new PrintLevelingWizard(printer)); }); }, IsEnabled = () => printer.Connection.IsConnected } }); } } } printer.Settings.ForTools <double>(SettingsKey.baby_step_z_offset, (key, value, i) => { // Make sure the z offsets are not too big if (Math.Abs(value) > 2) { // Static path generation for non-SliceSettings value var location = "Location".Localize() + ":" + "\n" + "Controls".Localize() + "\n • " + "Movement".Localize() + "\n • " + "Z Offset".Localize(); errors.Add( new ValidationError(ValidationErrors.ZOffset) { Error = "Z Offset is too large.".Localize(), Details = string.Format( "{0}\n\n{1}", "The Z Offset for your printer, sometimes called Baby Stepping, is greater than 2mm and invalid. Clear the value and re-level the bed.".Localize(), location) }); } }); if (settings.GetValue <double>(SettingsKey.first_layer_extrusion_width) > settings.GetValue <double>(SettingsKey.nozzle_diameter) * 4) { errors.Add( new SettingsValidationError(SettingsKey.first_layer_extrusion_width) { Error = "{0} must be less than or equal to the {1} * 4.".Localize().FormatWith( GetSettingsName(SettingsKey.first_layer_extrusion_width), GetSettingsName(SettingsKey.nozzle_diameter)), ValueDetails = "{0} = {1}\n{2} * 4 = {3}".FormatWith( GetSettingsName(SettingsKey.first_layer_extrusion_width), settings.GetValue <double>(SettingsKey.first_layer_extrusion_width), GetSettingsName(SettingsKey.nozzle_diameter), settings.GetValue <double>(SettingsKey.nozzle_diameter) * 4) }); } if (settings.GetValue <double>(SettingsKey.first_layer_extrusion_width) <= 0) { errors.Add( new SettingsValidationError(SettingsKey.first_layer_extrusion_width) { Error = "{0} must be greater than 0.".Localize().FormatWith( GetSettingsName(SettingsKey.first_layer_extrusion_width)), ValueDetails = "{0} = {1}".FormatWith( GetSettingsName(SettingsKey.first_layer_extrusion_width), settings.GetValue <double>(SettingsKey.first_layer_extrusion_width)), }); } if (settings.GetValue <double>(SettingsKey.fill_density) <= 0) { errors.Add( new SettingsValidationError(SettingsKey.fill_density) { Error = "{0} should be greater than 0.".Localize().FormatWith( GetSettingsName(SettingsKey.fill_density)), ErrorLevel = ValidationErrorLevel.Warning, ValueDetails = "{0} = {1}".FormatWith( GetSettingsName(SettingsKey.fill_density), settings.GetValue <double>(SettingsKey.fill_density)), }); } if (settings.GetValue <double>(SettingsKey.perimeters) <= 0) { errors.Add( new SettingsValidationError(SettingsKey.perimeters) { Error = "{0} should be greater than 0.".Localize().FormatWith( GetSettingsName(SettingsKey.perimeters)), ErrorLevel = ValidationErrorLevel.Warning, ValueDetails = "{0} = {1}".FormatWith( GetSettingsName(SettingsKey.perimeters), settings.GetValue <double>(SettingsKey.perimeters)), }); } if (settings.GetValue <int>(SettingsKey.extruder_count) > 1 && settings.GetValue <double>(SettingsKey.wipe_tower_perimeters_per_extruder) < 3) { errors.Add( new SettingsValidationError(SettingsKey.wipe_tower_perimeters_per_extruder) { Error = "{0} should be greater than 2.".Localize().FormatWith( GetSettingsName(SettingsKey.wipe_tower_perimeters_per_extruder)), ErrorLevel = ValidationErrorLevel.Warning, ValueDetails = "{0} = {1}".FormatWith( GetSettingsName(SettingsKey.wipe_tower_perimeters_per_extruder), settings.GetValue <double>(SettingsKey.wipe_tower_perimeters_per_extruder)), }); } if (settings.GetValue <double>(SettingsKey.infill_overlap_perimeter) < -settings.GetValue <double>(SettingsKey.nozzle_diameter) || settings.GetValue <double>(SettingsKey.infill_overlap_perimeter) > settings.GetValue <double>(SettingsKey.nozzle_diameter)) { errors.Add( new SettingsValidationError(SettingsKey.infill_overlap_perimeter) { Error = "{0} must be greater than 0 and less than your nozzle diameter. You may be missing a '%'.".Localize().FormatWith( GetSettingsName(SettingsKey.infill_overlap_perimeter)), ValueDetails = "{0} = {1}, {2} = {3}".FormatWith( GetSettingsName(SettingsKey.infill_overlap_perimeter), settings.GetValue <double>(SettingsKey.infill_overlap_perimeter), GetSettingsName(SettingsKey.nozzle_diameter), settings.GetValue <double>(SettingsKey.nozzle_diameter)), }); } if (printer.Connection.IsConnected && printer.Settings?.Helpers.ComPort() == "Emulator" && fffPrinter) { errors.Add( new SettingsValidationError(SettingsKey.com_port, "Connected to Emulator".Localize()) { Error = "You are connected to the Emulator not an actual printer.".Localize(), ErrorLevel = ValidationErrorLevel.Warning, FixAction = new NamedAction() { Title = "Switch".Localize(), IsEnabled = () => !printer.Connection.Printing && !printer.Connection.Paused, Action = () => UiThread.RunOnIdle(() => { // make sure we are not connected or we can't change the port printer.Connection.Disable(); // User initiated connect attempt failed, show port selection dialog DialogWindow.Show(new SetupStepComPortOne(printer)); }) } }); } if (settings.GetValue <double>(SettingsKey.external_perimeter_extrusion_width) <= 0) { errors.Add( new SettingsValidationError(SettingsKey.external_perimeter_extrusion_width) { Error = "{0} must be greater than 0.".Localize().FormatWith( GetSettingsName(SettingsKey.external_perimeter_extrusion_width)), ValueDetails = "{0} = {1}".FormatWith( GetSettingsName(SettingsKey.external_perimeter_extrusion_width), settings.GetValue <double>(SettingsKey.external_perimeter_extrusion_width)), }); } if (settings.GetValue <double>(SettingsKey.min_fan_speed) > 100) { errors.Add( new SettingsValidationError(SettingsKey.min_fan_speed) { Error = "The {0} can only go as high as 100%.".Localize().FormatWith( GetSettingsName(SettingsKey.min_fan_speed)), ValueDetails = "It is currently set to {0}.".Localize().FormatWith( settings.GetValue <double>(SettingsKey.min_fan_speed)), }); } if (settings.GetValue <double>(SettingsKey.max_fan_speed) > 100) { errors.Add( new SettingsValidationError(SettingsKey.max_fan_speed) { Error = "The {0} can only go as high as 100%.".Localize().FormatWith( GetSettingsName(SettingsKey.max_fan_speed)), ValueDetails = "It is currently set to {0}.".Localize().FormatWith( settings.GetValue <double>(SettingsKey.max_fan_speed)), }); } if (extruderCount < 1) { errors.Add( new SettingsValidationError(SettingsKey.extruder_count) { Error = "The {0} must be at least 1.".Localize().FormatWith( GetSettingsName(SettingsKey.extruder_count)), ValueDetails = "It is currently set to {0}.".Localize().FormatWith(extruderCount), }); } if (settings.GetValue <double>(SettingsKey.fill_density) < 0 || settings.GetValue <double>(SettingsKey.fill_density) > 1) { errors.Add( new SettingsValidationError(SettingsKey.fill_density) { Error = "The {0} must be between 0 and 1.".Localize().FormatWith( GetSettingsName(SettingsKey.fill_density)), ValueDetails = "It is currently set to {0}.".Localize().FormatWith( settings.GetValue <double>(SettingsKey.fill_density)), }); } // marlin firmware can only take a max of 128 bytes in a single instruction, make sure no lines are longer than that ValidateGCodeLinesShortEnough(SettingsKey.cancel_gcode, printer, errors); ValidateGCodeLinesShortEnough(SettingsKey.connect_gcode, printer, errors); ValidateGCodeLinesShortEnough(SettingsKey.end_gcode, printer, errors); ValidateGCodeLinesShortEnough(SettingsKey.layer_gcode, printer, errors); ValidateGCodeLinesShortEnough(SettingsKey.pause_gcode, printer, errors); ValidateGCodeLinesShortEnough(SettingsKey.resume_gcode, printer, errors); ValidateGCodeLinesShortEnough(SettingsKey.start_gcode, printer, errors); // If the given speed is part of the current slice engine then check that it is greater than 0. ValidateGoodSpeedSettingGreaterThan0(SettingsKey.bridge_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.air_gap_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.external_perimeter_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.first_layer_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.infill_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.perimeter_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.small_perimeter_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.solid_infill_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.support_material_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.top_solid_infill_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.travel_speed, printer, errors); ValidateGoodSpeedSettingGreaterThan0(SettingsKey.retract_speed, printer, errors); } catch (Exception e) { errors.Add( new ValidationError(ValidationErrors.ExceptionDuringSliceSettingsValidation) { Error = "Unexpected error validating settings".Localize(), Details = e.Message }); } return(errors); }
private void AddAdvancedPannel(GuiWidget settingsColumn) { var advancedPanel = new FlowLayoutWidget(FlowDirection.TopToBottom); var advancedSection = new SectionWidget("Advanced".Localize(), advancedPanel, theme, serializationKey: "ApplicationSettings-Advanced", expanded: false) { Name = "Advanced Section", HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit, Margin = 0 }; settingsColumn.AddChild(advancedSection); theme.ApplyBoxStyle(advancedSection); // Touch Screen Mode this.AddSettingsRow( new SettingsItem( "Touch Screen Mode".Localize(), theme, new SettingsItem.ToggleSwitchConfig() { Checked = UserSettings.Instance.get(UserSettingsKey.ApplicationDisplayMode) == "touchscreen", ToggleAction = (itemChecked) => { string displayMode = itemChecked ? "touchscreen" : "responsive"; if (displayMode != UserSettings.Instance.get(UserSettingsKey.ApplicationDisplayMode)) { UserSettings.Instance.set(UserSettingsKey.ApplicationDisplayMode, displayMode); UiThread.RunOnIdle(() => ApplicationController.Instance.ReloadAll().ConfigureAwait(false)); } } }), advancedPanel); AddUserBoolToggle(advancedPanel, "Utilize High Res Monitors".Localize(), UserSettingsKey.ApplicationUseHeigResDisplays, true, false); AddUserBoolToggle(advancedPanel, "Enable Socketeer Client".Localize(), UserSettingsKey.ApplicationUseSocketeer, true, false); var openCacheButton = new IconButton(AggContext.StaticData.LoadIcon("fa-link_16.png", 16, 16, theme.InvertIcons), theme) { ToolTipText = "Open Folder".Localize(), }; openCacheButton.Click += (s, e) => UiThread.RunOnIdle(() => { Process.Start(ApplicationDataStorage.ApplicationUserDataPath); }); this.AddSettingsRow( new SettingsItem( "Application Storage".Localize(), openCacheButton, theme), advancedPanel); var clearCacheButton = new HoverIconButton(AggContext.StaticData.LoadIcon("remove.png", 16, 16, theme.InvertIcons), theme) { ToolTipText = "Clear Cache".Localize(), }; clearCacheButton.Click += (s, e) => UiThread.RunOnIdle(() => { CacheDirectory.DeleteCacheData(); }); this.AddSettingsRow( new SettingsItem( "Application Cache".Localize(), clearCacheButton, theme), advancedPanel); #if DEBUG var configureIcon = AggContext.StaticData.LoadIcon("fa-cog_16.png", 16, 16, theme.InvertIcons); var configurePluginsButton = new IconButton(configureIcon, theme) { ToolTipText = "Configure Plugins".Localize(), Margin = 0 }; configurePluginsButton.Click += (s, e) => { UiThread.RunOnIdle(() => { DialogWindow.Show <PluginsPage>(); }); }; this.AddSettingsRow( new SettingsItem( "Plugins".Localize(), configurePluginsButton, theme), advancedPanel); #endif advancedPanel.Children <SettingsItem>().First().Border = new BorderDouble(0, 1); }
public static SystemWindow LoadRootWindow(int width, int height) { timer = Stopwatch.StartNew(); if (false) { // set the default font AggContext.DefaultFont = ApplicationController.GetTypeFace(NamedTypeFace.Nunito_Regular); AggContext.DefaultFontBold = ApplicationController.GetTypeFace(NamedTypeFace.Nunito_Bold); AggContext.DefaultFontItalic = ApplicationController.GetTypeFace(NamedTypeFace.Nunito_Italic); AggContext.DefaultFontBoldItalic = ApplicationController.GetTypeFace(NamedTypeFace.Nunito_Bold_Italic); } var systemWindow = new RootSystemWindow(width, height); var overlay = new GuiWidget() { BackgroundColor = AppContext.Theme.BackgroundColor, }; overlay.AnchorAll(); systemWindow.AddChild(overlay); var mutedAccentColor = AppContext.Theme.SplashAccentColor; var spinner = new LogoSpinner(overlay, rotateX: -0.05) { MeshColor = mutedAccentColor }; progressPanel = new FlowLayoutWidget(FlowDirection.TopToBottom) { Position = new Vector2(0, height * .25), HAnchor = HAnchor.Center | HAnchor.Fit, VAnchor = VAnchor.Fit, MinimumSize = new Vector2(400, 100), Margin = new BorderDouble(0, 0, 0, 200) }; overlay.AddChild(progressPanel); progressPanel.AddChild(statusText = new TextWidget("", textColor: AppContext.Theme.TextColor) { MinimumSize = new Vector2(200, 30), HAnchor = HAnchor.Center, AutoExpandBoundsToText = true }); progressPanel.AddChild(progressBar = new ProgressBar() { FillColor = mutedAccentColor, BorderColor = Color.Gray, // theme.BorderColor75, Height = 11 * GuiWidget.DeviceScale, Width = 230 * GuiWidget.DeviceScale, HAnchor = HAnchor.Center, VAnchor = VAnchor.Absolute }); AppContext.RootSystemWindow = systemWindow; // hook up a keyboard watcher to rout keys when not handled by children systemWindow.KeyPressed += SystemWindow_KeyPressed; systemWindow.KeyDown += (s, keyEvent) => { var view3D = systemWindow.Descendants <View3DWidget>().Where((v) => v.ActuallyVisibleOnScreen()).FirstOrDefault(); var printerTabPage = systemWindow.Descendants <PrinterTabPage>().Where((v) => v.ActuallyVisibleOnScreen()).FirstOrDefault(); var offsetDist = 50; var arrowKeyOperation = keyEvent.Shift ? TrackBallTransformType.Translation : TrackBallTransformType.Rotation; var gcode2D = systemWindow.Descendants <GCode2DWidget>().Where((v) => v.ActuallyVisibleOnScreen()).FirstOrDefault(); if (keyEvent.KeyCode == Keys.F1) { ApplicationController.Instance.ActivateHelpTab("Docs"); } if (EnableF5Collect && keyEvent.KeyCode == Keys.F5) { GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); systemWindow.Invalidate(); } if (!keyEvent.Handled && gcode2D != null) { switch (keyEvent.KeyCode) { case Keys.Oemplus: case Keys.Add: if (keyEvent.Control) { // Zoom out gcode2D.Zoom(1.2); keyEvent.Handled = true; } break; case Keys.OemMinus: case Keys.Subtract: if (keyEvent.Control) { // Zoom in gcode2D.Zoom(.8); keyEvent.Handled = true; } break; } } if (!keyEvent.Handled && view3D != null) { switch (keyEvent.KeyCode) { case Keys.C: if (keyEvent.Control) { view3D.Scene.Copy(); keyEvent.Handled = true; } break; case Keys.P: if (keyEvent.Control) { view3D.PushToPrinterAndPrint(); } break; case Keys.X: if (keyEvent.Control) { view3D.Scene.Cut(); keyEvent.Handled = true; } break; case Keys.Y: if (keyEvent.Control) { view3D.Scene.UndoBuffer.Redo(); keyEvent.Handled = true; } break; case Keys.A: if (keyEvent.Control) { view3D.SelectAll(); keyEvent.Handled = true; } break; case Keys.S: if (keyEvent.Control) { view3D.Save(); keyEvent.Handled = true; } break; case Keys.V: if (keyEvent.Control) { view3D.sceneContext.Paste(); keyEvent.Handled = true; } break; case Keys.Oemplus: case Keys.Add: if (keyEvent.Control) { // Zoom out Offset3DView(view3D, new Vector2(0, offsetDist), TrackBallTransformType.Scale); keyEvent.Handled = true; } break; case Keys.OemMinus: case Keys.Subtract: if (keyEvent.Control) { // Zoom in Offset3DView(view3D, new Vector2(0, -offsetDist), TrackBallTransformType.Scale); keyEvent.Handled = true; } break; case Keys.Z: if (keyEvent.Control) { if (keyEvent.Shift) { view3D.Scene.Redo(); } else { // undo last operation view3D.Scene.Undo(); } keyEvent.Handled = true; } break; case Keys.Insert: if (keyEvent.Shift) { view3D.sceneContext.Paste(); keyEvent.Handled = true; } break; case Keys.Delete: case Keys.Back: view3D.Scene.DeleteSelection(); keyEvent.Handled = true; keyEvent.SuppressKeyPress = true; break; case Keys.Escape: if (view3D.CurrentSelectInfo.DownOnPart) { view3D.CurrentSelectInfo.DownOnPart = false; view3D.Scene.SelectedItem.Matrix = view3D.TransformOnMouseDown; keyEvent.Handled = true; keyEvent.SuppressKeyPress = true; } foreach (var object3DControls in view3D.Object3DControlLayer.Object3DControls) { object3DControls.CancelOperation(); } break; case Keys.Left: if (keyEvent.Control && printerTabPage != null && !printerTabPage.sceneContext.ViewState.ModelView) { // Decrement slider printerTabPage.LayerFeaturesIndex -= 1; } else { if (view3D.sceneContext.Scene.SelectedItem is IObject3D object3D) { NudgeItem(view3D, object3D, ArrowDirection.Left, keyEvent); } else { // move or rotate view left Offset3DView(view3D, new Vector2(-offsetDist, 0), arrowKeyOperation); } } keyEvent.Handled = true; keyEvent.SuppressKeyPress = true; break; case Keys.Right: if (keyEvent.Control && printerTabPage != null && !printerTabPage.sceneContext.ViewState.ModelView) { // Increment slider printerTabPage.LayerFeaturesIndex += 1; } else { if (view3D.sceneContext.Scene.SelectedItem is IObject3D object3D) { NudgeItem(view3D, object3D, ArrowDirection.Right, keyEvent); } else { // move or rotate view right Offset3DView(view3D, new Vector2(offsetDist, 0), arrowKeyOperation); } } keyEvent.Handled = true; keyEvent.SuppressKeyPress = true; break; case Keys.Up: if (view3D.Printer != null && printerTabPage != null && view3D.Printer.ViewState.ViewMode != PartViewMode.Model) { printerTabPage.LayerScrollbar.Value += 1; } else { if (view3D.sceneContext.Scene.SelectedItem is IObject3D object3D) { NudgeItem(view3D, object3D, ArrowDirection.Up, keyEvent); } else { Offset3DView(view3D, new Vector2(0, offsetDist), arrowKeyOperation); } } keyEvent.Handled = true; keyEvent.SuppressKeyPress = true; break; case Keys.Down: if (view3D.Printer != null && printerTabPage != null && view3D.Printer.ViewState.ViewMode != PartViewMode.Model) { printerTabPage.LayerScrollbar.Value -= 1; } else { if (view3D.sceneContext.Scene.SelectedItem is IObject3D object3D) { NudgeItem(view3D, object3D, ArrowDirection.Down, keyEvent); } else { Offset3DView(view3D, new Vector2(0, -offsetDist), arrowKeyOperation); } } keyEvent.Handled = true; keyEvent.SuppressKeyPress = true; break; case Keys.F2: if (view3D.Printer == null || (view3D.Printer != null && view3D.Printer.ViewState.ViewMode == PartViewMode.Model)) { if (view3D.sceneContext.Scene.SelectedItem is IObject3D object3D) { DialogWindow.Show( new InputBoxPage( "Rename Item".Localize(), "Name".Localize(), object3D.Name, "Enter New Name Here".Localize(), "Rename".Localize(), (newName) => { // TODO: add undo data to this operation object3D.Name = newName; })); } } keyEvent.Handled = true; keyEvent.SuppressKeyPress = true; break; } } }; // Hook SystemWindow load and spin up MatterControl once we've hit first draw systemWindow.Load += (s, e) => { // Show the End User License Agreement if it has not been shown (on windows it is shown in the installer) if (AggContext.OperatingSystem != OSType.Windows && UserSettings.Instance.get(UserSettingsKey.SoftwareLicenseAccepted) != "true") { var eula = new LicenseAgreementPage(LoadMC) { Margin = new BorderDouble(5) }; systemWindow.AddChild(eula); } else { LoadMC(); } }; void LoadMC() { ReportStartupProgress(0.02, "First draw->RunOnIdle"); // UiThread.RunOnIdle(() => Task.Run(async() => { try { ReportStartupProgress(0.15, "MatterControlApplication.Initialize"); ApplicationController.LoadTranslationMap(); var mainView = await Initialize(systemWindow, (progress0To1, status) => { ReportStartupProgress(0.2 + progress0To1 * 0.7, status); }); ReportStartupProgress(0.9, "AddChild->MainView"); systemWindow.AddChild(mainView, 0); ReportStartupProgress(1, ""); systemWindow.BackgroundColor = Color.Transparent; overlay.Close(); } catch (Exception ex) { UiThread.RunOnIdle(() => { statusText.Visible = false; var errorTextColor = Color.White; progressPanel.Margin = 0; progressPanel.VAnchor = VAnchor.Center | VAnchor.Fit; progressPanel.BackgroundColor = Color.DarkGray; progressPanel.Padding = 20; progressPanel.Border = 1; progressPanel.BorderColor = Color.Red; var theme = new ThemeConfig(); progressPanel.AddChild( new TextWidget("Startup Failure".Localize() + ":", pointSize: theme.DefaultFontSize, textColor: errorTextColor)); progressPanel.AddChild( new TextWidget(ex.Message, pointSize: theme.FontSize9, textColor: errorTextColor)); var closeButton = new TextButton("Close", theme) { BackgroundColor = theme.SlightShade, HAnchor = HAnchor.Right, VAnchor = VAnchor.Absolute }; closeButton.Click += (s1, e1) => { systemWindow.Close(); }; spinner.SpinLogo = false; progressBar.Visible = false; progressPanel.AddChild(closeButton); }); } AppContext.IsLoading = false; }); } ReportStartupProgress(0, "ShowAsSystemWindow"); AddTextWidgetRightClickMenu(); return(systemWindow); }
public ApplicationSettingsPage() : base("Close".Localize()) { this.AlwaysOnTopOfMain = true; this.WindowTitle = this.HeaderText = "MatterControl " + "Settings".Localize(); this.WindowSize = new Vector2(700 * GuiWidget.DeviceScale, 600 * GuiWidget.DeviceScale); contentRow.Padding = theme.DefaultContainerPadding; contentRow.Padding = 0; contentRow.BackgroundColor = Color.Transparent; var generalPanel = new FlowLayoutWidget(FlowDirection.TopToBottom) { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit, }; var configureIcon = AggContext.StaticData.LoadIcon("fa-cog_16.png", 16, 16, theme.InvertIcons); var generalSection = new SectionWidget("General".Localize(), generalPanel, theme, expandingContent: false) { Name = "General Section", HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit, }; contentRow.AddChild(generalSection); theme.ApplyBoxStyle(generalSection); #if __ANDROID__ // Camera Monitoring bool hasCamera = true || ApplicationSettings.Instance.get(ApplicationSettingsKey.HardwareHasCamera) == "true"; var previewButton = new IconButton(configureIcon, theme) { ToolTipText = "Preview".Localize() }; previewButton.Click += (s, e) => { AppContext.Platform.OpenCameraPreview(); }; var printer = ApplicationController.Instance.ActivePrinters.FirstOrDefault() ?? PrinterConfig.EmptyPrinter; this.AddSettingsRow( new SettingsItem( "Camera Monitoring".Localize(), theme, new SettingsItem.ToggleSwitchConfig() { Checked = printer.Settings.GetValue <bool>(SettingsKey.publish_bed_image), ToggleAction = (itemChecked) => { printer.Settings.SetValue(SettingsKey.publish_bed_image, itemChecked ? "1" : "0"); } }, previewButton, AggContext.StaticData.LoadIcon("camera-24x24.png", 24, 24)) { Enabled = printer.Settings.PrinterSelected }, generalPanel ); #endif // Print Notifications var configureNotificationsButton = new IconButton(configureIcon, theme) { Name = "Configure Notification Settings Button", ToolTipText = "Configure Notifications".Localize(), Margin = new BorderDouble(left: 6), VAnchor = VAnchor.Center }; configureNotificationsButton.Click += (s, e) => { if (ApplicationController.ChangeToPrintNotification != null) { UiThread.RunOnIdle(() => { ApplicationController.ChangeToPrintNotification(this.DialogWindow); }); } }; this.AddSettingsRow( new SettingsItem( "Notifications".Localize(), theme, new SettingsItem.ToggleSwitchConfig() { Checked = UserSettings.Instance.get(UserSettingsKey.PrintNotificationsEnabled) == "true", ToggleAction = (itemChecked) => { UserSettings.Instance.set(UserSettingsKey.PrintNotificationsEnabled, itemChecked ? "true" : "false"); } }, configureNotificationsButton, AggContext.StaticData.LoadIcon("notify-24x24.png", 16, 16, theme.InvertIcons)), generalPanel); // LanguageControl var languageSelector = new LanguageSelector(theme); languageSelector.SelectionChanged += (s, e) => { UiThread.RunOnIdle(() => { string languageCode = languageSelector.SelectedValue; if (languageCode != UserSettings.Instance.get(UserSettingsKey.Language)) { UserSettings.Instance.set(UserSettingsKey.Language, languageCode); if (languageCode == "L10N") { #if DEBUG AppContext.Platform.GenerateLocalizationValidationFile(); #endif } ApplicationController.Instance.ResetTranslationMap(); ApplicationController.Instance.ReloadAll().ConfigureAwait(false); } }); }; this.AddSettingsRow(new SettingsItem("Language".Localize(), languageSelector, theme), generalPanel); #if !__ANDROID__ // ThumbnailRendering var thumbnailsModeDropList = new MHDropDownList("", theme, maxHeight: 200); thumbnailsModeDropList.AddItem("Flat".Localize(), "orthographic"); thumbnailsModeDropList.AddItem("3D".Localize(), "raytraced"); thumbnailsModeDropList.SelectedValue = UserSettings.Instance.ThumbnailRenderingMode; thumbnailsModeDropList.SelectionChanged += (s, e) => { string thumbnailRenderingMode = thumbnailsModeDropList.SelectedValue; if (thumbnailRenderingMode != UserSettings.Instance.ThumbnailRenderingMode) { UserSettings.Instance.ThumbnailRenderingMode = thumbnailRenderingMode; UiThread.RunOnIdle(() => { // Ask if the user they would like to rebuild their thumbnails StyledMessageBox.ShowMessageBox( (bool rebuildThumbnails) => { if (rebuildThumbnails) { string[] thumbnails = new string[] { ApplicationController.CacheablePath( Path.Combine("Thumbnails", "Content"), ""), ApplicationController.CacheablePath( Path.Combine("Thumbnails", "Library"), "") }; foreach (var directoryToRemove in thumbnails) { try { if (Directory.Exists(directoryToRemove)) { Directory.Delete(directoryToRemove, true); } } catch (Exception) { GuiWidget.BreakInDebugger(); } Directory.CreateDirectory(directoryToRemove); } ApplicationController.Instance.Library.NotifyContainerChanged(); } }, "You are switching to a different thumbnail rendering mode. If you want, your current thumbnails can be removed and recreated in the new style. You can switch back and forth at any time. There will be some processing overhead while the new thumbnails are created.\n\nDo you want to rebuild your existing thumbnails now?".Localize(), "Rebuild Thumbnails Now".Localize(), StyledMessageBox.MessageType.YES_NO, "Rebuild".Localize()); }); } }; this.AddSettingsRow( new SettingsItem( "Thumbnails".Localize(), thumbnailsModeDropList, theme), generalPanel); #endif // TextSize if (!double.TryParse(UserSettings.Instance.get(UserSettingsKey.ApplicationTextSize), out double currentTextSize)) { currentTextSize = 1.0; } double sliderThumbWidth = 10 * GuiWidget.DeviceScale; double sliderWidth = 100 * GuiWidget.DeviceScale; var textSizeSlider = new SolidSlider(new Vector2(), sliderThumbWidth, theme, .7, 1.4) { Name = "Text Size Slider", Margin = new BorderDouble(5, 0), Value = currentTextSize, HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Center, TotalWidthInPixels = sliderWidth, }; theme.ApplySliderStyle(textSizeSlider); var optionalContainer = new FlowLayoutWidget() { VAnchor = VAnchor.Center | VAnchor.Fit, HAnchor = HAnchor.Fit }; TextWidget sectionLabel = null; var textSizeApplyButton = new TextButton("Apply".Localize(), theme) { VAnchor = VAnchor.Center, BackgroundColor = theme.SlightShade, Visible = false, Margin = new BorderDouble(right: 6) }; textSizeApplyButton.Click += (s, e) => UiThread.RunOnIdle(() => { GuiWidget.DeviceScale = textSizeSlider.Value; ApplicationController.Instance.ReloadAll().ConfigureAwait(false); }); optionalContainer.AddChild(textSizeApplyButton); textSizeSlider.ValueChanged += (s, e) => { double textSizeNew = textSizeSlider.Value; UserSettings.Instance.set(UserSettingsKey.ApplicationTextSize, textSizeNew.ToString("0.0")); sectionLabel.Text = "Text Size".Localize() + $" : {textSizeNew:0.0}"; textSizeApplyButton.Visible = textSizeNew != currentTextSize; }; var textSizeRow = new SettingsItem( "Text Size".Localize() + $" : {currentTextSize:0.0}", textSizeSlider, theme, optionalContainer); sectionLabel = textSizeRow.Children <TextWidget>().FirstOrDefault(); this.AddSettingsRow(textSizeRow, generalPanel); var themeSection = CreateThemePanel(theme); contentRow.AddChild(themeSection); theme.ApplyBoxStyle(themeSection); var advancedPanel = new FlowLayoutWidget(FlowDirection.TopToBottom); var advancedSection = new SectionWidget("Advanced".Localize(), advancedPanel, theme, serializationKey: "ApplicationSettings-Advanced", expanded: false) { Name = "Advanced Section", HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit, Margin = 0 }; contentRow.AddChild(advancedSection); theme.ApplyBoxStyle(advancedSection); // Touch Screen Mode this.AddSettingsRow( new SettingsItem( "Touch Screen Mode".Localize(), theme, new SettingsItem.ToggleSwitchConfig() { Checked = UserSettings.Instance.get(UserSettingsKey.ApplicationDisplayMode) == "touchscreen", ToggleAction = (itemChecked) => { string displayMode = itemChecked ? "touchscreen" : "responsive"; if (displayMode != UserSettings.Instance.get(UserSettingsKey.ApplicationDisplayMode)) { UserSettings.Instance.set(UserSettingsKey.ApplicationDisplayMode, displayMode); UiThread.RunOnIdle(() => ApplicationController.Instance.ReloadAll().ConfigureAwait(false)); } } }), advancedPanel); var openCacheButton = new IconButton(AggContext.StaticData.LoadIcon("fa-link_16.png", 16, 16, theme.InvertIcons), theme) { ToolTipText = "Open Folder".Localize(), }; openCacheButton.Click += (s, e) => UiThread.RunOnIdle(() => { Process.Start(ApplicationDataStorage.ApplicationUserDataPath); }); this.AddSettingsRow( new SettingsItem( "Application Storage".Localize(), openCacheButton, theme), advancedPanel); var clearCacheButton = new HoverIconButton(AggContext.StaticData.LoadIcon("remove.png", 16, 16, theme.InvertIcons), theme) { ToolTipText = "Clear Cache".Localize(), }; clearCacheButton.Click += (s, e) => UiThread.RunOnIdle(() => { CacheDirectory.DeleteCacheData(); }); this.AddSettingsRow( new SettingsItem( "Application Cache".Localize(), clearCacheButton, theme), advancedPanel); #if DEBUG var configurePluginsButton = new IconButton(configureIcon, theme) { ToolTipText = "Configure Plugins".Localize(), Margin = 0 }; configurePluginsButton.Click += (s, e) => { UiThread.RunOnIdle(() => { DialogWindow.Show <PluginsPage>(); }); }; this.AddSettingsRow( new SettingsItem( "Plugins".Localize(), configurePluginsButton, theme), advancedPanel); #endif advancedPanel.Children <SettingsItem>().First().Border = new BorderDouble(0, 1); // Enforce consistent SectionWidget spacing and last child borders foreach (var section in contentRow.Children <SectionWidget>()) { section.Margin = new BorderDouble(0, 10, 0, 0); if (section.ContentPanel.Children.LastOrDefault() is SettingsItem lastRow) { // If we're in a contentPanel that has SettingsItems... // Clear the last items bottom border lastRow.Border = lastRow.Border.Clone(bottom: 0); // Set a common margin on the parent container section.ContentPanel.Margin = new BorderDouble(2, 0); } } }
public static void ShowPrintLevelWizard(PrinterConfig printer, ThemeConfig theme) { // turn off print leveling PrintLevelingStream.AllowLeveling = false; // clear any data that we are going to be acquiring (sampled positions, after z home offset) var levelingData = new PrintLevelingData() { LevelingSystem = printer.Settings.GetValue <LevelingSystem>(SettingsKey.print_leveling_solution) }; printer.Settings.SetValue(SettingsKey.baby_step_z_offset, "0"); LevelingPlan levelingPlan; switch (levelingData.LevelingSystem) { case LevelingSystem.Probe3Points: levelingPlan = new LevelWizard3Point(printer); break; case LevelingSystem.Probe7PointRadial: levelingPlan = new LevelWizard7PointRadial(printer); break; case LevelingSystem.Probe13PointRadial: levelingPlan = new LevelWizard13PointRadial(printer); break; case LevelingSystem.Probe100PointRadial: levelingPlan = new LevelWizard100PointRadial(printer); break; case LevelingSystem.Probe3x3Mesh: levelingPlan = new LevelWizardMesh(printer, 3, 3); break; case LevelingSystem.Probe5x5Mesh: levelingPlan = new LevelWizardMesh(printer, 5, 5); break; case LevelingSystem.Probe10x10Mesh: levelingPlan = new LevelWizardMesh(printer, 10, 10); break; default: throw new NotImplementedException(); } var levelingContext = new PrintLevelingWizard(levelingPlan, printer) { WindowTitle = $"{ApplicationController.Instance.ProductName} - " + "Print Leveling Wizard".Localize() }; var printLevelWizardWindow = DialogWindow.Show(new LevelingWizardRootPage(levelingContext) { WindowTitle = levelingContext.WindowTitle }); printLevelWizardWindow.Closed += (s, e) => { // If leveling was on when we started, make sure it is on when we are done. PrintLevelingStream.AllowLeveling = true; printLevelWizardWindow = null; // make sure we raise the probe on close if (printer.Settings.GetValue <bool>(SettingsKey.has_z_probe) && printer.Settings.GetValue <bool>(SettingsKey.use_z_probe) && printer.Settings.GetValue <bool>(SettingsKey.has_z_servo)) { // make sure the servo is retracted var servoRetract = printer.Settings.GetValue <double>(SettingsKey.z_servo_retracted_angle); printer.Connection.QueueLine($"M280 P0 S{servoRetract}"); } }; }
public PrinterCalibrationWizard(PrinterConfig printer, ThemeConfig theme) { var stages = new List <ISetupWizard>() { new ZCalibrationWizard(printer), new PrintLevelingWizard(printer), new LoadFilamentWizard(printer, extruderIndex: 0, showAlreadyLoadedButton: true), new LoadFilamentWizard(printer, extruderIndex: 1, showAlreadyLoadedButton: true), new XyCalibrationWizard(printer, 1) }; this.Stages = stages; this.printer = printer; this.HomePageGenerator = () => { var homePage = new WizardSummaryPage() { HeaderText = "Printer Setup & Calibration".Localize() }; var contentRow = homePage.ContentRow; if (!ReturnedToHomePage) { if (printer.Connection.IsConnected) { contentRow.AddChild( new WrappedTextWidget( @"Select the calibration task to continue".Replace("\r\n", "\n"), pointSize: theme.DefaultFontSize, textColor: theme.TextColor)); } else { contentRow.AddChild( new WrappedTextWidget( @"Connect the printer to complete the calibration tasks.".Replace("\r\n", "\n"), pointSize: theme.DefaultFontSize, textColor: theme.TextColor)); } } contentRow.BackgroundColor = Color.Transparent; foreach (var stage in this.Stages.Where(s => s.Visible)) { GuiWidget rightWidget = null; var widget = new GuiWidget(); if (stage is ZCalibrationWizard probeWizard) { var column = CreateColumn(theme); column.FlowDirection = FlowDirection.LeftToRight; var offset = printer.Settings.GetValue <Vector3>(SettingsKey.probe_offset); column.AddChild( new ValueTag( "Z Offset".Localize(), offset.Z.ToString("0.###"), new BorderDouble(12, 5, 2, 5), 5, 11) { Margin = new BorderDouble(bottom: 4), MinimumSize = new Vector2(125, 0) }); column.AddChild(new HorizontalSpacer()); AddRunStageButton("Run Z Calibration".Localize(), theme, stage, column); widget = column; } if (stage is LoadFilamentWizard loadWizard) { var column = CreateColumn(theme); column.FlowDirection = FlowDirection.LeftToRight; var lastRow = new FlowLayoutWidget() { HAnchor = HAnchor.Stretch }; column.AddChild(lastRow); lastRow.AddChild(new HorizontalSpacer()); AddRunStageButton("Load Filament".Localize(), theme, stage, lastRow).Margin = new BorderDouble(10); widget = column; } if (stage is PrintLevelingWizard levelingWizard) { PrintLevelingData levelingData = printer.Settings.Helpers.PrintLevelingData; var column = CreateColumn(theme); var lastRow = new FlowLayoutWidget() { HAnchor = HAnchor.Stretch }; if (levelingData != null && printer.Settings?.GetValue <bool>(SettingsKey.print_leveling_enabled) == true) { var positions = levelingData.SampledPositions; var levelingSolution = printer.Settings.GetValue(SettingsKey.print_leveling_solution); column.AddChild( new ValueTag( "Leveling Solution".Localize(), levelingSolution, new BorderDouble(12, 5, 2, 5), 5, 11) { Margin = new BorderDouble(bottom: 4), MinimumSize = new Vector2(125, 0) }); var editButton = new IconButton(StaticData.Instance.LoadIcon("icon_edit.png", 16, 16).SetToColor(theme.TextColor), theme) { Name = "Edit Leveling Data Button", ToolTipText = "Edit Leveling Data".Localize(), }; editButton.Click += (s, e) => { DialogWindow.Show(new EditLevelingSettingsPage(printer, theme)); }; var row = new FlowLayoutWidget() { VAnchor = VAnchor.Fit, HAnchor = HAnchor.Fit }; row.AddChild(editButton); // only show the switch if leveling can be turned off (it can't if it is required). if (!printer.Settings.GetValue <bool>(SettingsKey.print_leveling_required_to_print)) { // put in the switch printLevelingSwitch = new RoundedToggleSwitch(theme) { VAnchor = VAnchor.Center, Margin = new BorderDouble(theme.DefaultContainerPadding, 0), Checked = printer.Settings.GetValue <bool>(SettingsKey.print_leveling_enabled), ToolTipText = "Enable Software Leveling".Localize() }; printLevelingSwitch.CheckedStateChanged += (sender, e) => { printer.Settings.Helpers.DoPrintLeveling(printLevelingSwitch.Checked); }; printLevelingSwitch.Closed += (s, e) => { // Unregister listeners printer.Settings.PrintLevelingEnabledChanged -= Settings_PrintLevelingEnabledChanged; }; // TODO: Why is this listener conditional? If the leveling changes somehow, shouldn't we be updated the UI to reflect that? // Register listeners printer.Settings.PrintLevelingEnabledChanged += Settings_PrintLevelingEnabledChanged; row.AddChild(printLevelingSwitch); } rightWidget = row; column.AddChild(lastRow); var probeWidget = new ProbePositionsWidget(printer, positions.Select(v => new Vector2(v)).ToList(), theme) { HAnchor = HAnchor.Absolute, VAnchor = VAnchor.Absolute, Height = 200, Width = 200, RenderLevelingData = true, RenderProbePath = false, SimplePoints = true, }; lastRow.AddChild(probeWidget); } else { column.AddChild(lastRow); if (!printer.Settings.GetValue <bool>(SettingsKey.print_leveling_required_to_print)) { lastRow.AddChild(new WrappedTextWidget( @"Print Leveling is an optional feature for this printer that can help improve print quality. If the bed is uneven or cannot be mechanically leveled.".Localize(), pointSize: theme.DefaultFontSize, textColor: theme.TextColor)); } else if (printer.Settings.GetValue <bool>(SettingsKey.validate_leveling)) { lastRow.AddChild(new WrappedTextWidget( @"Print Leveling will run automatically at the start of each print.".Localize(), pointSize: theme.DefaultFontSize, textColor: theme.TextColor)); } else { lastRow.AddChild(new HorizontalSpacer()); } } lastRow.AddChild(new HorizontalSpacer()); AddRunStageButton("Run Print Leveling".Localize(), theme, stage, lastRow); widget = column; } if (stage is XyCalibrationWizard xyWizard) { var row = CreateColumn(theme); row.FlowDirection = FlowDirection.LeftToRight; var hotendOffset = printer.Settings.Helpers.ExtruderOffset(1); var tool2Column = new FlowLayoutWidget(FlowDirection.TopToBottom); row.AddChild(tool2Column); tool2Column.AddChild( new TextWidget("Tool".Localize() + " 2", pointSize: theme.DefaultFontSize, textColor: theme.TextColor) { Margin = new BorderDouble(bottom: 4) }); tool2Column.AddChild( new ValueTag( "X Offset".Localize(), hotendOffset.X.ToString("0.###"), new BorderDouble(12, 5, 2, 5), 5, 11) { Margin = new BorderDouble(bottom: 4), MinimumSize = new Vector2(125, 0) }); tool2Column.AddChild( new ValueTag( "Y Offset".Localize(), hotendOffset.Y.ToString("0.###"), new BorderDouble(12, 5, 2, 5), 5, 11) { MinimumSize = new Vector2(125, 0) }); row.AddChild(new HorizontalSpacer()); AddRunStageButton("Run Nozzle Alignment".Localize(), theme, stage, row); widget = row; } if (stage is LoadFilamentWizard filamentWizard) { widget.Margin = new BorderDouble(left: theme.DefaultContainerPadding); } var sectionName = stage.Title; if (stage.SetupRequired) { sectionName += " - " + "Required".Localize(); } else if (stage.Completed) { sectionName += " - " + "Completed".Localize(); } else { sectionName += " - " + "Optional".Localize(); } var section = new SectionWidget(sectionName, widget, theme, rightAlignedContent: rightWidget, expandingContent: false); theme.ApplyBoxStyle(section); section.Margin = section.Margin.Clone(left: 0); section.ShowExpansionIcon = false; if (stage.SetupRequired) { section.BackgroundColor = Color.Red.WithAlpha(30); } contentRow.AddChild(section); } return(homePage); }; }