예제 #1
0
        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}");
                }
            };
        }
예제 #2
0
 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);
 }
예제 #3
0
        /// <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);
        }
예제 #4
0
        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;
                }
            }
        }
예제 #5
0
        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>());
                    }
                }
            }
        }
예제 #6
0
        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);
            };
        }
예제 #8
0
        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);
        }
예제 #10
0
        /// <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);
        }
예제 #11
0
        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);
        }
예제 #12
0
        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);
        }
예제 #13
0
        /// <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);
        }
예제 #15
0
        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);
                }
            }
        }
예제 #17
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}");
                }
            };
        }
예제 #18
0
        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);
            };
        }