public override void OnClosed(EventArgs e) { // Unregister listeners UiThread.ClearInterval(runningInterval); base.OnClosed(e); }
private void ApplyVelocity() { if (HasBeenClosed || currentVelocityPerMs.LengthSquared <= 0) { UiThread.ClearInterval(runningInterval); } double msPerUpdate = 1000.0 / updatesPerSecond; if (currentVelocityPerMs.LengthSquared > 0) { if (TrackBallController.CurrentTrackingType == TrackBallTransformType.None) { Vector2 center = LocalBounds.Center; TrackBallController.OnMouseDown(center, Matrix4X4.Identity, TrackBallTransformType.Rotation); TrackBallController.OnMouseMove(center + currentVelocityPerMs * msPerUpdate); TrackBallController.OnMouseUp(); Invalidate(); currentVelocityPerMs *= .85; if (currentVelocityPerMs.LengthSquared < .01 / msPerUpdate) { currentVelocityPerMs = Vector2.Zero; } } } }
public override void OnClosed(EventArgs e) { // Unregister listeners printer.Connection.BedTemperatureRead -= Connection_BedTemperatureRead; UiThread.ClearInterval(runningInterval); base.OnClosed(e); }
public override void OnClosed(EventArgs e) { // Unregister listeners UiThread.ClearInterval(runningInterval); this.DialogWindow.KeyDown -= TopWindowKeyDown; base.OnClosed(e); }
public void ZeroVelocity() { motionQueue.Clear(); currentVelocityPerMs = Vector2.Zero; if (runningInterval != null) { UiThread.ClearInterval(runningInterval); } EndRotateAroundOrigin(); }
private void WaitToRefresh() { if (UiThread.CurrentTimerMs > lastTimeContentsChanged + 500 && waitingForRefresh != null) { UiThread.ClearInterval(waitingForRefresh); waitingForRefresh = null; this.ReloadContent(); } }
private void ConnectToWidget(object drawingWidget, DrawEventArgs e) { GuiWidget parent = drawingWidget as GuiWidget; while (parent.BackgroundColor.Alpha0To255 == 0) { parent = parent.Parent; } startColor = parent.BackgroundColor; timeSinceStart = Stopwatch.StartNew(); widgetToHighlight.AfterDraw -= ConnectToWidget; var runningInterval = UiThread.SetInterval(ChangeBackgroundColor, animationDelay); parent.Closed += (s, e2) => UiThread.ClearInterval(runningInterval); }
public MainViewWidget(ThemeConfig theme) : base(FlowDirection.TopToBottom) { this.AnchorAll(); this.theme = theme; this.Name = "PartPreviewContent"; this.BackgroundColor = theme.BackgroundColor; // Push TouchScreenMode into GuiWidget GuiWidget.TouchScreenMode = UserSettings.Instance.IsTouchScreen; var extensionArea = new LeftClipFlowLayoutWidget() { BackgroundColor = theme.TabBarBackground, VAnchor = VAnchor.Stretch, Padding = new BorderDouble(left: 8) }; tabControl = new ChromeTabs(extensionArea, theme) { VAnchor = VAnchor.Stretch, HAnchor = HAnchor.Stretch, BackgroundColor = theme.BackgroundColor, BorderColor = theme.MinimalShade, Border = new BorderDouble(left: 1), }; tabControl.PlusClicked += (s, e) => { UiThread.RunOnIdle(() => { this.CreatePartTab().ConfigureAwait(false); }); }; tabControl.ActiveTabChanged += (s, e) => { if (this.tabControl.ActiveTab?.TabContent is PartTabPage tabPage) { var dragDropData = ApplicationController.Instance.DragDropData; // Set reference on tab change dragDropData.View3DWidget = tabPage.view3DWidget; dragDropData.SceneContext = tabPage.sceneContext; ApplicationController.Instance.PrinterTabSelected = true; } else { ApplicationController.Instance.PrinterTabSelected = false; } ApplicationController.Instance.MainTabKey = tabControl.SelectedTabKey; }; // Force the ActionArea to be as high as ButtonHeight tabControl.TabBar.ActionArea.MinimumSize = new Vector2(0, theme.ButtonHeight); tabControl.TabBar.BackgroundColor = theme.TabBarBackground; tabControl.TabBar.BorderColor = theme.BackgroundColor; // Force common padding into top region tabControl.TabBar.Padding = theme.TabbarPadding.Clone(top: theme.TabbarPadding.Top * 2, bottom: 0); // add in a what's new button seeWhatsNewButton = new LinkLabel("What's New...".Localize(), theme) { Name = "What's New Link", ToolTipText = "See what's new in this version of MatterControl".Localize(), VAnchor = VAnchor.Center, Margin = new BorderDouble(10, 0), TextColor = theme.TextColor }; seeWhatsNewButton.Click += (s, e) => UiThread.RunOnIdle(() => { UserSettings.Instance.set(UserSettingsKey.LastReadWhatsNew, JsonConvert.SerializeObject(DateTime.Now)); DialogWindow.Show(new HelpPage("What's New")); }); tabControl.TabBar.ActionArea.AddChild(seeWhatsNewButton); // add in the update available button updateAvailableButton = new LinkLabel("Update Available".Localize(), theme) { Visible = false, Name = "Update Available Link", ToolTipText = "There is a new update available for download".Localize(), VAnchor = VAnchor.Center, Margin = new BorderDouble(10, 0) }; // Register listeners UserSettings.Instance.SettingChanged += SetLinkButtonsVisibility; RunningInterval showUpdateInterval = null; updateAvailableButton.VisibleChanged += (s, e) => { if (!updateAvailableButton.Visible) { if (showUpdateInterval != null) { UiThread.ClearInterval(showUpdateInterval); showUpdateInterval = null; } return; } showUpdateInterval = UiThread.SetInterval(() => { double displayTime = 1; double pulseTime = 1; double totalSeconds = 0; var textWidgets = updateAvailableButton.Descendants <TextWidget>().Where((w) => w.Visible == true).ToArray(); Color startColor = theme.TextColor; // Show a highlight on the button as the user did not click it Animation flashBackground = null; flashBackground = new Animation() { DrawTarget = updateAvailableButton, FramesPerSecond = 10, Update = (s1, updateEvent) => { totalSeconds += updateEvent.SecondsPassed; if (totalSeconds < displayTime) { double blend = AttentionGetter.GetFadeInOutPulseRatio(totalSeconds, pulseTime); var color = new Color(startColor, (int)((1 - blend) * 255)); foreach (var textWidget in textWidgets) { textWidget.TextColor = color; } } else { foreach (var textWidget in textWidgets) { textWidget.TextColor = startColor; } flashBackground.Stop(); } } }; flashBackground.Start(); }, 120); }; SetLinkButtonsVisibility(this, null); updateAvailableButton.Click += (s, e) => UiThread.RunOnIdle(() => { UpdateControlData.Instance.CheckForUpdate(); DialogWindow.Show <CheckForUpdatesPage>(); }); tabControl.TabBar.ActionArea.AddChild(updateAvailableButton); this.AddChild(tabControl); ApplicationController.Instance.NotifyPrintersTabRightElement(extensionArea); // Store tab tabControl.AddTab( new ChromeTab("Store", "Store".Localize(), tabControl, new StoreTabPage(theme), theme, hasClose: false) { MinimumSize = new Vector2(0, theme.TabButtonHeight), Name = "Store Tab", Padding = new BorderDouble(15, 0), }); // Library tab var libraryWidget = new LibraryWidget(this, theme) { BackgroundColor = theme.BackgroundColor }; tabControl.AddTab( new ChromeTab("Library", "Library".Localize(), tabControl, libraryWidget, theme, hasClose: false) { MinimumSize = new Vector2(0, theme.TabButtonHeight), Name = "Library Tab", Padding = new BorderDouble(15, 0), }); // Hardware tab tabControl.AddTab( new ChromeTab( "Hardware", "Hardware".Localize(), tabControl, new HardwareTabPage(theme) { BackgroundColor = theme.BackgroundColor }, theme, hasClose: false) { MinimumSize = new Vector2(0, theme.TabButtonHeight), Name = "Hardware Tab", Padding = new BorderDouble(15, 0), }); if (ApplicationController.Instance.Workspaces.Count == 0) { this.CreatePartTab().ConfigureAwait(false); } string tabKey = ApplicationController.Instance.MainTabKey; if (string.IsNullOrEmpty(tabKey)) { tabKey = "Hardware"; } // HACK: Restore to the first printer tab if PrinterTabSelected and tabKey not found. This allows sign in/out to remain on the printer tab across different users if (!tabControl.AllTabs.Any(t => t.Key == tabKey) && ApplicationController.Instance.PrinterTabSelected) { var key = tabControl.AllTabs.Where(t => t.TabContent is PrinterTabPage).FirstOrDefault()?.Key; if (key != null) { tabKey = key; } } var brandMenu = new BrandMenuButton(theme) { HAnchor = HAnchor.Fit, VAnchor = VAnchor.Fit, BackgroundColor = theme.TabBarBackground, Padding = theme.TabbarPadding.Clone(right: theme.DefaultContainerPadding) }; tabControl.TabBar.ActionArea.AddChild(brandMenu, 0); // Restore active tabs foreach (var workspace in ApplicationController.Instance.Workspaces) { this.CreatePartTab(workspace); } tabControl.SelectedTabKey = tabKey; statusBar = new Toolbar(theme) { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Absolute, Padding = 1, Height = 22, BackgroundColor = theme.BackgroundColor, Border = new BorderDouble(top: 1), BorderColor = theme.BorderColor20, }; this.AddChild(statusBar); statusBar.ActionArea.VAnchor = VAnchor.Stretch; tasksContainer = new FlowLayoutWidget(FlowDirection.LeftToRight) { HAnchor = HAnchor.Fit, VAnchor = VAnchor.Stretch, BackgroundColor = theme.MinimalShade, Name = "runningTasksPanel" }; statusBar.AddChild(tasksContainer); var tasks = ApplicationController.Instance.Tasks; tasks.TasksChanged += (s, e) => { RenderRunningTasks(theme, tasks); }; stretchStatusPanel = new GuiWidget() { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Stretch, Padding = new BorderDouble(right: 3), Margin = new BorderDouble(right: 2, top: 1, bottom: 1), Border = new BorderDouble(1), BackgroundColor = theme.MinimalShade.WithAlpha(10), BorderColor = theme.SlightShade, Width = 200 }; statusBar.AddChild(stretchStatusPanel); var panelBackgroundColor = theme.MinimalShade.WithAlpha(10); statusBar.AddChild( this.CreateThemeStatusPanel(theme, panelBackgroundColor)); statusBar.AddChild( this.CreateNetworkStatusPanel(theme)); this.RenderRunningTasks(theme, tasks); // Register listeners PrinterSettings.AnyPrinterSettingChanged += Printer_SettingChanged; ApplicationController.Instance.OpenPrintersChanged += OpenPrinters_Changed; UpdateControlData.Instance.UpdateStatusChanged.RegisterEvent((s, e) => { SetLinkButtonsVisibility(s, new StringEventArgs("Unknown")); }, ref unregisterEvents); ApplicationController.Instance.MainView = this; }
protected override IEnumerator <PrinterSetupWizardPage> GetWizardSteps() { var levelingStrings = new LevelingStrings(printer.Settings); var title = "Select Material".Localize(); var instructions = "Please select the material you will be printing with.".Localize(); if (onlyLoad) { title = "Load Material".Localize(); instructions = "Please select the material you want to load.".Localize(); } // select the material yield return(new SelectMaterialPage(this, title, instructions, onlyLoad ? "Load".Localize() : "Select".Localize(), onlyLoad)); var theme = ApplicationController.Instance.Theme; // show the trim filament message { PrinterSetupWizardPage trimFilamentPage = null; trimFilamentPage = new PrinterSetupWizardPage( this, "Trim Filament".Localize(), "") { BecomingActive = () => { // start heating up the extruder printer.Connection.SetTargetHotendTemperature(0, printer.Settings.GetValue <double>(SettingsKey.temperature)); var markdownText = printer.Settings.GetValue(SettingsKey.trim_filament_markdown); var markdownWidget = new MarkdownWidget(theme); markdownWidget.Markdown = markdownText = markdownText.Replace("\\n", "\n"); trimFilamentPage.ContentRow.AddChild(markdownWidget); } }; yield return(trimFilamentPage); } // show the insert filament page { RunningInterval runningGCodeCommands = null; PrinterSetupWizardPage insertFilamentPage = null; insertFilamentPage = new PrinterSetupWizardPage( this, "Insert Filament".Localize(), "") { BecomingActive = () => { var markdownText = printer.Settings.GetValue(SettingsKey.insert_filament_markdown2); var markdownWidget = new MarkdownWidget(theme); markdownWidget.Markdown = markdownText = markdownText.Replace("\\n", "\n"); insertFilamentPage.ContentRow.AddChild(markdownWidget); // turn off the fan printer.Connection.FanSpeed0To255 = 0; // Allow extrusion at any temperature. S0 only works on Marlin S1 works on repetier and marlin printer.Connection.QueueLine("M302 S1"); var runningTime = Stopwatch.StartNew(); runningGCodeCommands = UiThread.SetInterval(() => { if (printer.Connection.NumQueuedCommands == 0) { printer.Connection.MoveRelative(PrinterCommunication.PrinterConnection.Axis.E, .2, 80); int secondsToRun = 300; if (runningTime.ElapsedMilliseconds > secondsToRun * 1000) { UiThread.ClearInterval(runningGCodeCommands); } } }, .1); }, BecomingInactive = () => { if (runningGCodeCommands != null) { UiThread.ClearInterval(runningGCodeCommands); } } }; insertFilamentPage.Closed += (s, e) => { if (runningGCodeCommands != null) { UiThread.ClearInterval(runningGCodeCommands); } }; yield return(insertFilamentPage); } // show the loading filament progress bar { RunningInterval runningGCodeCommands = null; PrinterSetupWizardPage loadingFilamentPage = null; loadingFilamentPage = new PrinterSetupWizardPage( this, "Loading Filament".Localize(), "") { BecomingActive = () => { loadingFilamentPage.NextButton.Enabled = false; // add the progress bar var holder = new FlowLayoutWidget() { Margin = new BorderDouble(3, 0, 0, 10), }; var progressBar = new ProgressBar((int)(150 * GuiWidget.DeviceScale), (int)(15 * GuiWidget.DeviceScale)) { FillColor = theme.PrimaryAccentColor, BorderColor = theme.TextColor, BackgroundColor = Color.White, VAnchor = VAnchor.Center, }; var progressBarText = new TextWidget("", pointSize: 10, textColor: theme.TextColor) { AutoExpandBoundsToText = true, Margin = new BorderDouble(5, 0, 0, 0), VAnchor = VAnchor.Center, }; holder.AddChild(progressBar); holder.AddChild(progressBarText); loadingFilamentPage.ContentRow.AddChild(holder); // Allow extrusion at any temperature. S0 only works on Marlin S1 works on repetier and marlin printer.Connection.QueueLine("M302 S1"); // send a dwel to empty out the current move commands printer.Connection.QueueLine("G4 P1"); // put in a second one to use as a signal for the first being processed printer.Connection.QueueLine("G4 P1"); // start heating up the extruder printer.Connection.SetTargetHotendTemperature(0, printer.Settings.GetValue <double>(SettingsKey.temperature)); var loadingSpeedMmPerS = printer.Settings.GetValue <double>(SettingsKey.load_filament_speed); var loadLengthMm = Math.Max(1, printer.Settings.GetValue <double>(SettingsKey.load_filament_length)); var remainingLengthMm = loadLengthMm; var maxSingleExtrudeLength = 20; Stopwatch runningTime = null; var expectedTimeS = loadLengthMm / loadingSpeedMmPerS; runningGCodeCommands = UiThread.SetInterval(() => { if (printer.Connection.NumQueuedCommands == 0) { if (runningTime == null) { runningTime = Stopwatch.StartNew(); } if (progressBar.RatioComplete < 1) { var thisExtrude = Math.Min(remainingLengthMm, maxSingleExtrudeLength); var currentE = printer.Connection.CurrentExtruderDestination; printer.Connection.QueueLine("G1 E{0:0.###} F{1}".FormatWith(currentE + thisExtrude, loadingSpeedMmPerS * 60)); remainingLengthMm -= thisExtrude; var elapsedSeconds = runningTime.Elapsed.TotalSeconds; progressBar.RatioComplete = Math.Min(1, elapsedSeconds / expectedTimeS); progressBarText.Text = $"Loading Filament: {Math.Max(0, expectedTimeS - elapsedSeconds):0}"; } } if (progressBar.RatioComplete == 1 && remainingLengthMm <= .001) { UiThread.ClearInterval(runningGCodeCommands); loadingFilamentPage.NextButton.InvokeClick(); } }, .1); }, BecomingInactive = () => { UiThread.ClearInterval(runningGCodeCommands); } }; loadingFilamentPage.Closed += (s, e) => { UiThread.ClearInterval(runningGCodeCommands); }; yield return(loadingFilamentPage); } // wait for extruder to heat { double targetHotendTemp = printer.Settings.Helpers.ExtruderTemperature(0); yield return(new WaitForTempPage( this, "Waiting For Printer To Heat".Localize(), "Waiting for the hotend to heat to ".Localize() + targetHotendTemp + "°C.\n" + "This will ensure that filament is able to flow through the nozzle.".Localize() + "\n" + "\n" + "Warning! The tip of the nozzle will be HOT!".Localize() + "\n" + "Avoid contact with your skin.".Localize(), 0, targetHotendTemp)); } // extrude slowly so that we can prime the extruder { RunningInterval runningGCodeCommands = null; PrinterSetupWizardPage runningCleanPage = null; runningCleanPage = new PrinterSetupWizardPage( this, "Wait For Running Clean".Localize(), "") { BecomingActive = () => { var markdownText = printer.Settings.GetValue(SettingsKey.running_clean_markdown2); var markdownWidget = new MarkdownWidget(theme); markdownWidget.Markdown = markdownText = markdownText.Replace("\\n", "\n"); runningCleanPage.ContentRow.AddChild(markdownWidget); var runningTime = Stopwatch.StartNew(); runningGCodeCommands = UiThread.SetInterval(() => { if (printer.Connection.NumQueuedCommands == 0) { printer.Connection.MoveRelative(PrinterCommunication.PrinterConnection.Axis.E, .35, 140); int secondsToRun = 90; if (runningTime.ElapsedMilliseconds > secondsToRun * 1000) { UiThread.ClearInterval(runningGCodeCommands); } } }, .1); }, BecomingInactive = () => { UiThread.ClearInterval(runningGCodeCommands); } }; runningCleanPage.Closed += (s, e) => { UiThread.ClearInterval(runningGCodeCommands); printer.Settings.SetValue(SettingsKey.filament_has_been_loaded, "1"); }; yield return(runningCleanPage); } // put up a success message PrinterSetupWizardPage finalPage = null; finalPage = new PrinterSetupWizardPage(this, "Success".Localize(), "Success!\n\nYour filament should now be loaded".Localize()) { BecomingActive = () => { finalPage.ShowWizardFinished(); } }; yield return(finalPage); }
public RunningTaskRow(string title, RunningTaskDetails taskDetails, ThemeConfig theme) : base(FlowDirection.TopToBottom) { this.taskDetails = taskDetails; this.theme = theme; this.MinimumSize = new Vector2(100 * GuiWidget.DeviceScale, 20 * GuiWidget.DeviceScale); var detailsPanel = new GuiWidget() { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit, }; var rowContainer = new GuiWidget() { VAnchor = VAnchor.Fit, HAnchor = HAnchor.Stretch, }; this.AddChild(rowContainer); var topRow = new FlowLayoutWidget() { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit, Padding = 0, }; rowContainer.AddChild(topRow); progressBar = new ProgressBar() { HAnchor = HAnchor.Stretch, Height = 2 * GuiWidget.DeviceScale, VAnchor = VAnchor.Absolute | VAnchor.Bottom, FillColor = theme.PrimaryAccentColor, BorderColor = Color.Transparent, Margin = new BorderDouble(32, 7, theme.ButtonHeight * 2 + 14, 0), Visible = !taskDetails.IsExpanded }; rowContainer.AddChild(progressBar); expandButton = new ExpandCheckboxButton(!string.IsNullOrWhiteSpace(title) ? title : taskDetails.Title, theme, 10) { VAnchor = VAnchor.Center | VAnchor.Fit, HAnchor = HAnchor.Stretch, Checked = false, Padding = 0, AlwaysShowArrow = true }; expandButton.CheckedStateChanged += (s, e) => { taskDetails.IsExpanded = expandButton.Checked; SetExpansionMode(theme, detailsPanel, expandButton.Checked); }; topRow.AddChild(expandButton); IconButton resumeButton = null; var pauseButton = new IconButton(StaticData.Instance.LoadIcon("fa-pause_12.png", 12, 12, theme.InvertIcons), theme) { Margin = theme.ButtonSpacing, Enabled = taskDetails.Options?.PauseAction != null, ToolTipText = taskDetails.Options?.PauseToolTip ?? "Pause".Localize() }; if (taskDetails.Options?.IsPaused != null) { RunningInterval runningInterval = null; runningInterval = UiThread.SetInterval(() => { if (taskDetails.Options.IsPaused()) { pauseButton.Visible = false; resumeButton.Visible = true; } else { pauseButton.Visible = true; resumeButton.Visible = false; } if (this.HasBeenClosed) { UiThread.ClearInterval(runningInterval); } }, .2); } pauseButton.Click += (s, e) => { taskDetails.Options?.PauseAction(); pauseButton.Visible = false; resumeButton.Visible = true; }; topRow.AddChild(pauseButton); resumeButton = new IconButton(StaticData.Instance.LoadIcon("fa-play_12.png", 12, 12, theme.InvertIcons), theme) { Visible = false, Margin = theme.ButtonSpacing, ToolTipText = taskDetails.Options?.ResumeToolTip ?? "Resume".Localize(), Name = "Resume Task Button" }; resumeButton.Click += (s, e) => { taskDetails.Options?.ResumeAction(); pauseButton.Visible = true; resumeButton.Visible = false; }; topRow.AddChild(resumeButton); var stopButton = new IconButton(StaticData.Instance.LoadIcon("fa-stop_12.png", 12, 12, theme.InvertIcons), theme) { Margin = theme.ButtonSpacing, Name = "Stop Task Button", ToolTipText = taskDetails.Options?.StopToolTip ?? "Cancel".Localize() }; stopButton.Click += (s, e) => { var stopAction = taskDetails.Options?.StopAction; if (stopAction == null) { taskDetails.CancelTask(); } else { stopAction.Invoke(() => { stopButton.Enabled = true; }); } stopButton.Enabled = false; }; topRow.AddChild(stopButton); this.AddChild(detailsPanel); // Add rich progress controls if (taskDetails.Options?.RichProgressWidget?.Invoke() is GuiWidget guiWidget) { detailsPanel.AddChild(guiWidget); } else { expandButton.Expandable = false; } if (taskDetails.Options?.ReadOnlyReporting == true) { stopButton.Visible = false; pauseButton.Visible = false; resumeButton.Visible = false; // Ensure the top row is as big as it would be with buttons topRow.MinimumSize = new Vector2(0, resumeButton.Height); } SetExpansionMode(theme, detailsPanel, taskDetails.IsExpanded); taskDetails.ProgressChanged += TaskDetails_ProgressChanged; }
protected override IEnumerator <WizardPage> GetPages() { var extruderCount = printer.Settings.GetValue <int>(SettingsKey.extruder_count); var levelingStrings = new LevelingStrings(); var title = "Unload Material".Localize(); var instructions = "Please select the material you want to unload.".Localize(); if (extruderCount > 1) { instructions = "Please select the material you want to unload from extruder {0}.".Localize().FormatWith(extruderIndex + 1); } // select the material yield return(new SelectMaterialPage(this, title, instructions, "Unload".Localize(), extruderIndex, false, false) { WindowTitle = Title }); var theme = ApplicationController.Instance.Theme; // wait for extruder to heat { var targetHotendTemp = printer.Settings.Helpers.ExtruderTargetTemperature(extruderIndex); var temps = new double[4]; temps[extruderIndex] = targetHotendTemp; yield return(new WaitForTempPage( this, "Waiting For Printer To Heat".Localize(), (extruderCount > 1 ? "Waiting for hotend {0} to heat to ".Localize().FormatWith(extruderIndex + 1) : "Waiting for the hotend to heat to ".Localize()) + targetHotendTemp + "°C.\n" + "This will ensure that filament is able to flow through the nozzle.".Localize() + "\n" + "\n" + "Warning! The tip of the nozzle will be HOT!".Localize() + "\n" + "Avoid contact with your skin.".Localize(), 0, temps)); } // show the unloading filament progress bar { int extruderPriorToUnload = printer.Connection.ActiveExtruderIndex; RunningInterval runningGCodeCommands = null; var unloadingFilamentPage = new WizardPage(this, "Unloading Filament".Localize(), "") { PageLoad = (page) => { page.NextButton.Enabled = false; // add the progress bar var holder = new FlowLayoutWidget() { Margin = new BorderDouble(3, 0, 0, 10), }; var progressBar = new ProgressBar((int)(150 * GuiWidget.DeviceScale), (int)(15 * GuiWidget.DeviceScale)) { FillColor = theme.PrimaryAccentColor, BorderColor = theme.TextColor, BackgroundColor = Color.White, VAnchor = VAnchor.Center, }; var progressBarText = new TextWidget("", pointSize: 10, textColor: theme.TextColor) { AutoExpandBoundsToText = true, Margin = new BorderDouble(5, 0, 0, 0), VAnchor = VAnchor.Center, }; holder.AddChild(progressBar); holder.AddChild(progressBarText); page.ContentRow.AddChild(holder); if (extruderCount > 1) { // reset the extruder that was active printer.Connection.QueueLine($"T{extruderIndex}"); } // reset the extrusion amount so this is easier to debug printer.Connection.QueueLine("G92 E0"); // Allow extrusion at any temperature. S0 only works on Marlin S1 works on repetier and marlin printer.Connection.QueueLine("M302 S1"); // send a dwell to empty out the current move commands printer.Connection.QueueLine("G4 P1"); // put in a second one to use as a signal for the first being processed printer.Connection.QueueLine("G4 P1"); // start heating up the extruder if (extruderIndex == 0) { printer.Connection.SetTargetHotendTemperature(0, printer.Settings.GetValue <double>(SettingsKey.temperature)); } else { printer.Connection.SetTargetHotendTemperature(extruderIndex, printer.Settings.GetValue <double>(SettingsKey.temperature + extruderIndex.ToString())); } var loadingSpeedMmPerS = printer.Settings.GetValue <double>(SettingsKey.load_filament_speed); var loadLengthMm = Math.Max(1, printer.Settings.GetValue <double>(SettingsKey.unload_filament_length)); var remainingLengthMm = loadLengthMm; var maxSingleExtrudeLength = 20; Stopwatch runningTime = null; var expectedTimeS = loadLengthMm / loadingSpeedMmPerS; // push some out first var currentE = printer.Connection.CurrentExtruderDestination; printer.Connection.QueueLine("G1 E{0:0.###} F600".FormatWith(currentE + 15)); runningGCodeCommands = UiThread.SetInterval(() => { if (printer.Connection.NumQueuedCommands == 0) { if (runningTime == null) { runningTime = Stopwatch.StartNew(); } if (progressBar.RatioComplete < 1 || remainingLengthMm >= .001) { var thisExtrude = Math.Min(remainingLengthMm, maxSingleExtrudeLength); currentE = printer.Connection.CurrentExtruderDestination; printer.Connection.QueueLine("G1 E{0:0.###} F{1}".FormatWith(currentE - thisExtrude, loadingSpeedMmPerS * 60)); // make sure we wait for this command to finish so we can cancel the unload at any time without delay printer.Connection.QueueLine("G4 P1"); remainingLengthMm -= thisExtrude; var elapsedSeconds = runningTime.Elapsed.TotalSeconds; progressBar.RatioComplete = Math.Min(1, elapsedSeconds / expectedTimeS); progressBarText.Text = $"Unloading Filament: {Math.Max(0, expectedTimeS - elapsedSeconds):0}"; } } if (progressBar.RatioComplete == 1 && remainingLengthMm <= .001) { UiThread.ClearInterval(runningGCodeCommands); page.NextButton.InvokeClick(); } }, .1); }, PageClose = () => { UiThread.ClearInterval(runningGCodeCommands); } }; unloadingFilamentPage.Closed += (s, e) => { UiThread.ClearInterval(runningGCodeCommands); if (extruderCount > 1) { // reset the extruder that was active printer.Connection.QueueLine($"T{extruderPriorToUnload}"); } printer.Connection.QueueLine("G92 E0"); }; yield return(unloadingFilamentPage); } // put up a success message yield return(new DoneUnloadingPage(this, extruderIndex)); }
private IEnumerator <WizardPage> GetPages() { var extruderCount = printer.Settings.GetValue <int>(SettingsKey.extruder_count); var levelingStrings = new LevelingStrings(); var instructions = "Please select the material you want to load.".Localize(); if (extruderCount > 1) { instructions = "Please select the material you want to load into extruder {0}.".Localize().FormatWith(extruderIndex + 1); } // select the material yield return(new SelectMaterialPage(this, "Load Material".Localize(), instructions, "Select".Localize(), extruderIndex, true, showAlreadyLoadedButton) { WindowTitle = WindowTitle }); var theme = ApplicationController.Instance.Theme; // show the trim filament message { var trimFilamentPage = new WizardPage(this, "Trim Filament".Localize(), "") { PageLoad = (page) => { // start heating up the extruder printer.Connection.SetTargetHotendTemperature(extruderIndex, printer.Settings.GetValue <double>(SettingsKey.temperature)); var markdownText = printer.Settings.GetValue(SettingsKey.trim_filament_markdown); var markdownWidget = new MarkdownWidget(theme); markdownWidget.Markdown = markdownText = markdownText.Replace("\\n", "\n"); page.ContentRow.AddChild(markdownWidget); } }; yield return(trimFilamentPage); } if (extruderCount > 1) { // reset the extruder that was active printer.Connection.QueueLine($"T{extruderIndex}"); } // reset the extrusion amount so this is easier to debug printer.Connection.QueueLine("G92 E0"); // show the insert filament page { RunningInterval runningGCodeCommands = null; var insertFilamentPage = new WizardPage(this, "Insert Filament".Localize(), "") { PageLoad = (page) => { var markdownText = printer.Settings.GetValue(SettingsKey.insert_filament_markdown2); if (extruderIndex == 1) { markdownText = printer.Settings.GetValue(SettingsKey.insert_filament_1_markdown); } var markdownWidget = new MarkdownWidget(theme); markdownWidget.Markdown = markdownText = markdownText.Replace("\\n", "\n"); page.ContentRow.AddChild(markdownWidget); // turn off the fan printer.Connection.FanSpeed0To255 = 0; // Allow extrusion at any temperature. S0 only works on Marlin S1 works on repetier and marlin printer.Connection.QueueLine("M302 S1"); int maxSecondsToStartLoading = 300; var runningTime = Stopwatch.StartNew(); runningGCodeCommands = UiThread.SetInterval(() => { if (printer.Connection.NumQueuedCommands == 0) { printer.Connection.MoveRelative(PrinterCommunication.PrinterConnection.Axis.E, 1, 80); // send a dwell to empty out the current move commands printer.Connection.QueueLine("G4 P1"); if (runningTime.ElapsedMilliseconds > maxSecondsToStartLoading * 1000) { UiThread.ClearInterval(runningGCodeCommands); } } }, .1); }, PageClose = () => { if (runningGCodeCommands != null) { UiThread.ClearInterval(runningGCodeCommands); } } }; insertFilamentPage.Closed += (s, e) => { if (runningGCodeCommands != null) { UiThread.ClearInterval(runningGCodeCommands); } }; yield return(insertFilamentPage); } // show the loading filament progress bar { RunningInterval runningGCodeCommands = null; var loadingFilamentPage = new WizardPage(this, "Loading Filament".Localize(), "") { PageLoad = (page) => { page.NextButton.Enabled = false; // add the progress bar var holder = new FlowLayoutWidget() { Margin = new BorderDouble(3, 0, 0, 10), }; var progressBar = new ProgressBar((int)(150 * GuiWidget.DeviceScale), (int)(15 * GuiWidget.DeviceScale)) { FillColor = theme.PrimaryAccentColor, BorderColor = theme.TextColor, BackgroundColor = Color.White, VAnchor = VAnchor.Center, }; var progressBarText = new TextWidget("", pointSize: 10, textColor: theme.TextColor) { AutoExpandBoundsToText = true, Margin = new BorderDouble(5, 0, 0, 0), VAnchor = VAnchor.Center, }; holder.AddChild(progressBar); holder.AddChild(progressBarText); page.ContentRow.AddChild(holder); // Allow extrusion at any temperature. S0 only works on Marlin S1 works on repetier and marlin printer.Connection.QueueLine("M302 S1"); // send a dwell to empty out the current move commands printer.Connection.QueueLine("G4 P1"); // put in a second one to use as a signal for the first being processed printer.Connection.QueueLine("G4 P1"); // start heating up the extruder printer.Connection.SetTargetHotendTemperature(extruderIndex, printer.Settings.GetValue <double>(SettingsKey.temperature)); var loadingSpeedMmPerS = printer.Settings.GetValue <double>(SettingsKey.load_filament_speed); var loadLengthMm = Math.Max(1, printer.Settings.GetValue <double>(SettingsKey.load_filament_length)); var remainingLengthMm = loadLengthMm; var maxSingleExtrudeLength = 20; Stopwatch runningTime = null; var expectedTimeS = loadLengthMm / loadingSpeedMmPerS; runningGCodeCommands = UiThread.SetInterval(() => { if (printer.Connection.NumQueuedCommands == 0) { if (runningTime == null) { runningTime = Stopwatch.StartNew(); } if (progressBar.RatioComplete < 1 || remainingLengthMm >= .001) { var thisExtrude = Math.Min(remainingLengthMm, maxSingleExtrudeLength); var currentE = printer.Connection.CurrentExtruderDestination; printer.Connection.QueueLine("G1 E{0:0.###} F{1}".FormatWith(currentE + thisExtrude, loadingSpeedMmPerS * 60)); // make sure we wait for this command to finish so we can cancel the unload at any time without delay printer.Connection.QueueLine("G4 P1"); remainingLengthMm -= thisExtrude; var elapsedSeconds = runningTime.Elapsed.TotalSeconds; progressBar.RatioComplete = Math.Min(1, elapsedSeconds / expectedTimeS); progressBarText.Text = $"Loading Filament: {Math.Max(0, expectedTimeS - elapsedSeconds):0}"; } } if (progressBar.RatioComplete == 1 && remainingLengthMm <= .001) { UiThread.ClearInterval(runningGCodeCommands); page.NextButton.InvokeClick(); } }, .1); }, PageClose = () => { UiThread.ClearInterval(runningGCodeCommands); } }; loadingFilamentPage.Closed += (s, e) => { UiThread.ClearInterval(runningGCodeCommands); }; yield return(loadingFilamentPage); } // wait for extruder to heat { var targetHotendTemp = printer.Settings.Helpers.ExtruderTargetTemperature(extruderIndex); var temps = new double[4]; temps[extruderIndex] = targetHotendTemp; yield return(new WaitForTempPage( this, "Waiting For Printer To Heat".Localize(), "Waiting for the hotend to heat to ".Localize() + targetHotendTemp + "°C.\n" + "This will ensure that filament is able to flow through the nozzle.".Localize() + "\n" + "\n" + "Warning! The tip of the nozzle will be HOT!".Localize() + "\n" + "Avoid contact with your skin.".Localize(), 0, temps)); } // extrude slowly so that we can prime the extruder { RunningInterval runningGCodeCommands = null; var runningCleanPage = new WizardPage(this, "Wait For Running Clean".Localize(), "") { PageLoad = (page) => { var markdownText = printer.Settings.GetValue(SettingsKey.running_clean_markdown2); if (extruderIndex == 1) { markdownText = printer.Settings.GetValue(SettingsKey.running_clean_1_markdown); } var markdownWidget = new MarkdownWidget(theme); markdownWidget.Markdown = markdownText = markdownText.Replace("\\n", "\n"); page.ContentRow.AddChild(markdownWidget); var runningTime = Stopwatch.StartNew(); runningGCodeCommands = UiThread.SetInterval(() => { if (printer.Connection.NumQueuedCommands == 0) { printer.Connection.MoveRelative(PrinterCommunication.PrinterConnection.Axis.E, 2, 140); // make sure we wait for this command to finish so we can cancel the unload at any time without delay printer.Connection.QueueLine("G4 P1"); int secondsToRun = 90; if (runningTime.ElapsedMilliseconds > secondsToRun * 1000) { UiThread.ClearInterval(runningGCodeCommands); } } }, .1); }, PageClose = () => { UiThread.ClearInterval(runningGCodeCommands); } }; runningCleanPage.Closed += (s, e) => { switch (extruderIndex) { case 0: printer.Settings.SetValue(SettingsKey.filament_has_been_loaded, "1"); break; case 1: printer.Settings.SetValue(SettingsKey.filament_1_has_been_loaded, "1"); break; } printer.Settings.SetValue(SettingsKey.filament_has_been_loaded, "1"); }; yield return(runningCleanPage); } // put up a success message yield return(new DoneLoadingPage(this, extruderIndex)); }
public static GuiWidget PrintProgressWidget(PrinterConfig printer, ThemeConfig theme) { var bodyRow = new GuiWidget() { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Top | VAnchor.Fit, //BackgroundColor = new Color(theme.Colors.PrimaryBackgroundColor, 128), MinimumSize = new Vector2(275, 140), }; // Progress section var expandingContainer = new HorizontalSpacer() { VAnchor = VAnchor.Fit | VAnchor.Center }; bodyRow.AddChild(expandingContainer); var progressContainer = new FlowLayoutWidget(FlowDirection.TopToBottom) { VAnchor = VAnchor.Center | VAnchor.Fit, HAnchor = HAnchor.Stretch, }; expandingContainer.AddChild(progressContainer); var progressDial = new ProgressDial(theme) { HAnchor = HAnchor.Center, Height = 200 * DeviceScale, Width = 200 * DeviceScale }; progressContainer.AddChild(progressDial); var bottomRow = new GuiWidget() { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit }; progressContainer.AddChild(bottomRow); var resliceMessageRow = new FlowLayoutWidget(FlowDirection.TopToBottom) { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit, Visible = false }; progressContainer.AddChild(resliceMessageRow); var timeContainer = new FlowLayoutWidget() { HAnchor = HAnchor.Center | HAnchor.Fit, Margin = 3 }; bottomRow.AddChild(timeContainer); // we can only reslice on 64 bit, because in 64 bit we always have the gcode loaded if (IntPtr.Size == 8) { var resliceButton = new TextButton("Re-Slice", theme) { HAnchor = HAnchor.Right, VAnchor = VAnchor.Center, Margin = new BorderDouble(0, 0, 7, 0), Name = "Re-Slice Button" }; bool activelySlicing = false; resliceButton.Click += (s, e) => { resliceButton.Enabled = false; UiThread.RunOnIdle(async() => { bool doSlicing = !activelySlicing && printer.Bed.EditContext.SourceItem != null; if (doSlicing) { var errors = printer.ValidateSettings(); if (errors.Any(err => err.ErrorLevel == ValidationErrorLevel.Error)) { doSlicing = false; ApplicationController.Instance.ShowValidationErrors("Slicing Error".Localize(), errors); } } if (doSlicing) { activelySlicing = true; if (bottomRow.Name == null) { bottomRow.Name = printer.Bed.EditContext.GCodeFilePath(printer); } await ApplicationController.Instance.Tasks.Execute("Saving".Localize(), printer, printer.Bed.SaveChanges); // start up a new slice on a background thread await ApplicationController.Instance.SliceItemLoadOutput( printer, printer.Bed.Scene, printer.Bed.EditContext.GCodeFilePath(printer)); // Switch to the 3D layer view if on Model view if (printer.ViewState.ViewMode == PartViewMode.Model) { printer.ViewState.ViewMode = PartViewMode.Layers3D; } resliceMessageRow.Visible = true; resliceMessageRow.VAnchor = VAnchor.Absolute; resliceMessageRow.VAnchor = VAnchor.Fit; } else { resliceButton.Enabled = true; } }); }; bottomRow.AddChild(resliceButton); // setup the message row { // when it is done queue it to the change to gcode stream var switchMessage = "Switch to new G-Code?\n\nBefore you switch, check that your are seeing the changes you expect.".Localize(); resliceMessageRow.AddChild(new WrappedTextWidget(switchMessage, theme.DefaultFontSize, textColor: theme.TextColor) { Margin = new BorderDouble(7, 3) }); var switchButtonRow = new FlowLayoutWidget(FlowDirection.RightToLeft) { HAnchor = HAnchor.Stretch }; resliceMessageRow.AddChild(switchButtonRow); var switchButton = new TextButton("Switch", theme) { VAnchor = VAnchor.Center, Margin = new BorderDouble(5), Name = "Switch Button" }; switchButtonRow.AddChild(switchButton); switchButton.Click += (s, e) => { if (printer.Connection != null && (printer.Connection.Printing || printer.Connection.Paused)) { printer.Connection.SwitchToGCode(printer.Bed.EditContext.GCodeFilePath(printer)); bottomRow.Name = printer.Bed.EditContext.GCodeFilePath(printer); } activelySlicing = false; resliceButton.Enabled = true; resliceMessageRow.Visible = false; }; var cancelButton = new TextButton("Cancel", theme) { VAnchor = VAnchor.Center, Margin = new BorderDouble(5), Name = "Cancel Re-Slice Button" }; switchButtonRow.AddChild(cancelButton); cancelButton.Click += async(s, e) => { await ApplicationController.Instance.SliceItemLoadOutput( printer, printer.Bed.Scene, bottomRow.Name); activelySlicing = false; resliceButton.Enabled = true; resliceMessageRow.Visible = false; }; } } timeContainer.AddChild(new ImageWidget(AggContext.StaticData.LoadIcon("fa-clock_24.png", theme.InvertIcons)) { VAnchor = VAnchor.Center }); var timeWidget = new TextWidget("", pointSize: 22, textColor: theme.TextColor) { AutoExpandBoundsToText = true, Margin = new BorderDouble(10, 0, 0, 0), VAnchor = VAnchor.Center, }; timeContainer.AddChild(timeWidget); var runningInterval = UiThread.SetInterval( () => { int secondsPrinted = printer.Connection.SecondsPrinted; int hoursPrinted = (int)(secondsPrinted / (60 * 60)); int minutesPrinted = (secondsPrinted / 60 - hoursPrinted * 60); secondsPrinted = secondsPrinted % 60; // TODO: Consider if the consistency of a common time format would look and feel better than changing formats based on elapsed duration timeWidget.Text = (hoursPrinted <= 0) ? $"{minutesPrinted}:{secondsPrinted:00}" : $"{hoursPrinted}:{minutesPrinted:00}:{secondsPrinted:00}"; progressDial.LayerIndex = printer.Connection.CurrentlyPrintingLayer; progressDial.LayerCompletedRatio = printer.Connection.RatioIntoCurrentLayer; progressDial.CompletedRatio = printer.Connection.PercentComplete / 100; switch (printer.Connection.CommunicationState) { case CommunicationStates.PreparingToPrint: case CommunicationStates.Printing: case CommunicationStates.Paused: bodyRow.Visible = true; break; default: bodyRow.Visible = false; break; } }, 1); bodyRow.Closed += (s, e) => UiThread.ClearInterval(runningInterval); bodyRow.Visible = false; return(bodyRow); }
public static GuiWidget PrintProgressWidget(PrinterConfig printer, ThemeConfig theme) { var bodyRow = new GuiWidget() { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Top | VAnchor.Fit, // BackgroundColor = new Color(theme.Colors.PrimaryBackgroundColor, 128), MinimumSize = new Vector2(275, 140), }; // Progress section var expandingContainer = new HorizontalSpacer() { VAnchor = VAnchor.Fit | VAnchor.Center }; bodyRow.AddChild(expandingContainer); var topToBottom = new FlowLayoutWidget(FlowDirection.TopToBottom) { VAnchor = VAnchor.Center | VAnchor.Fit, HAnchor = HAnchor.Stretch, }; expandingContainer.AddChild(topToBottom); var progressRow = new GuiWidget() { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit }; topToBottom.AddChild(progressRow); var progressDial = new ProgressDial(theme) { HAnchor = HAnchor.Center, VAnchor = VAnchor.Center, Height = 200 * DeviceScale, Width = 200 * DeviceScale, Name = "Print Progress Dial" }; progressRow.AddChild(progressDial); // create a set of controls to do baby stepping on the first layer var babySteppingControls = new FlowLayoutWidget(FlowDirection.TopToBottom) { HAnchor = HAnchor.Right, VAnchor = VAnchor.Center | VAnchor.Fit, }; babySteppingControls.Width = 80 * GuiWidget.DeviceScale; progressRow.AddChild(babySteppingControls); // add in the move up button var babyStepAmount = .02; var upButton = babySteppingControls.AddChild(new IconButton(StaticData.Instance.LoadIcon("Up Arrow.png", 32, 32).SetToColor(theme.TextColor), theme) { HAnchor = HAnchor.Center, VAnchor = VAnchor.Absolute, Margin = 0, BackgroundRadius = theme.ButtonRadius, ToolTipText = "Raise extruder".Localize() + "\n\n*" + "First layer only".Localize() + "*", }); upButton.Click += (s, e) => { printer.Settings.ForTools <double>(SettingsKey.baby_step_z_offset, (key, value, i) => { if (printer.Connection.ActiveExtruderIndex == i) { var currentZ = value + babyStepAmount; printer.Settings.SetValue(key, currentZ.ToString("0.##")); } }); }; // add in the current position display var zTuning = babySteppingControls.AddChild(new ZTuningWidget(printer, theme, false) { HAnchor = HAnchor.Center | HAnchor.Fit, VAnchor = VAnchor.Fit, Margin = new BorderDouble(0, 3, 0, 0), Padding = 0, }); babySteppingControls.AddChild(new TextWidget("Z Offset".Localize(), pointSize: 8) { TextColor = theme.TextColor, Margin = new BorderDouble(0, 0, 0, 3), AutoExpandBoundsToText = true, HAnchor = HAnchor.Center, }); // add in the move down button var downButton = babySteppingControls.AddChild(new IconButton(StaticData.Instance.LoadIcon("Down Arrow.png", 32, 32).SetToColor(theme.TextColor), theme) { HAnchor = HAnchor.Center, VAnchor = VAnchor.Absolute, Margin = 0, BackgroundRadius = new RadiusCorners(theme.ButtonRadius, theme.ButtonRadius, 0, 0), ToolTipText = "Lower extruder".Localize() + "\n\n*" + "First layer only".Localize() + "*", }); downButton.Click += (s, e) => { printer.Settings.ForTools <double>(SettingsKey.baby_step_z_offset, (key, value, i) => { if (printer.Connection.ActiveExtruderIndex == i) { var currentZ = value - babyStepAmount; printer.Settings.SetValue(key, currentZ.ToString("0.##")); } }); }; // build the bottom row to hold re-slice var bottomRow = new GuiWidget() { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit }; topToBottom.AddChild(bottomRow); var resliceMessageRow = new FlowLayoutWidget(FlowDirection.TopToBottom) { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit, Visible = false }; topToBottom.AddChild(resliceMessageRow); var timeContainer = new FlowLayoutWidget() { HAnchor = HAnchor.Center | HAnchor.Fit, Margin = 3 }; bottomRow.AddChild(timeContainer); // we can only reslice on 64 bit, because in 64 bit we always have the gcode loaded if (IntPtr.Size == 8 || ApplicationController.Instance.Allow32BitReSlice) { var resliceButton = new TextButton("Re-Slice", theme) { VAnchor = VAnchor.Center, HAnchor = HAnchor.Right, Margin = new BorderDouble(0, 0, 7, 0), Name = "Re-Slice Button", ToolTipText = "Apply changes to this print".Localize() + "\n\n*" + "Plating and settings changes can be applied".Localize() + "*" }; theme.MakeRoundedButton(resliceButton); bool activelySlicing = false; resliceButton.Click += (s, e) => { resliceButton.Enabled = false; UiThread.RunOnIdle(async() => { bool doSlicing = !activelySlicing && printer.Bed.EditContext.SourceItem != null; if (doSlicing) { var errors = printer.ValidateSettings(); if (errors.Any(err => err.ErrorLevel == ValidationErrorLevel.Error)) { doSlicing = false; ApplicationController.Instance.ShowValidationErrors("Slicing Error".Localize(), errors); } } if (doSlicing) { activelySlicing = true; if (bottomRow.Name == null) { bottomRow.Name = await printer.Bed.EditContext.GCodeFilePath(printer); } await ApplicationController.Instance.Tasks.Execute("Saving".Localize(), printer, printer.Bed.SaveChanges); // start up a new slice on a background thread await ApplicationController.Instance.SliceItemLoadOutput( printer, printer.Bed.Scene, await printer.Bed.EditContext.GCodeFilePath(printer)); // Switch to the 3D layer view if on Model view if (printer.ViewState.ViewMode == PartViewMode.Model) { printer.ViewState.ViewMode = PartViewMode.Layers3D; } resliceMessageRow.Visible = true; resliceMessageRow.VAnchor = VAnchor.Absolute; resliceMessageRow.VAnchor = VAnchor.Fit; } else { resliceButton.Enabled = true; } }); }; bottomRow.AddChild(resliceButton); // setup the message row { // when it is done queue it to the change to gcode stream var switchMessage = "Switch to new G-Code?\n\nBefore you switch, check that you are seeing the changes you expect.".Localize(); resliceMessageRow.AddChild(new WrappedTextWidget(switchMessage, theme.DefaultFontSize, textColor: theme.TextColor) { Margin = new BorderDouble(7, 3) }); var switchButtonRow = new FlowLayoutWidget(FlowDirection.RightToLeft) { HAnchor = HAnchor.Stretch }; resliceMessageRow.AddChild(switchButtonRow); var switchButton = new TextButton("Switch", theme) { VAnchor = VAnchor.Center, Margin = new BorderDouble(5), Name = "Switch Button" }; theme.MakeRoundedButton(switchButton); switchButtonRow.AddChild(switchButton); switchButton.Click += async(s, e) => { if (printer.Connection != null && (printer.Connection.Printing || printer.Connection.Paused)) { printer.Connection.SwitchToGCode(await printer.Bed.EditContext.GCodeFilePath(printer)); bottomRow.Name = await printer.Bed.EditContext.GCodeFilePath(printer); } activelySlicing = false; resliceButton.Enabled = true; resliceMessageRow.Visible = false; }; var cancelButton = new TextButton("Cancel", theme) { VAnchor = VAnchor.Center, Margin = new BorderDouble(0, 5), Name = "Cancel Re-Slice Button" }; theme.MakeRoundedButton(cancelButton); switchButtonRow.AddChild(cancelButton); cancelButton.Click += async(s, e) => { await ApplicationController.Instance.SliceItemLoadOutput( printer, printer.Bed.Scene, bottomRow.Name); activelySlicing = false; resliceButton.Enabled = true; resliceMessageRow.Visible = false; }; } } timeContainer.AddChild(new ImageWidget(StaticData.Instance.LoadIcon("fa-clock_24.png", 24, 24).SetToColor(theme.TextColor)) { VAnchor = VAnchor.Center }); var timeStack = new FlowLayoutWidget(FlowDirection.TopToBottom) { Margin = new BorderDouble(10, 0, 0, 0), Padding = new BorderDouble(5, 0, 0, 0), VAnchor = VAnchor.Center | VAnchor.Fit }; timeContainer.AddChild(timeStack); var timePrinted = new TextWidget("", pointSize: 16, textColor: theme.TextColor) { AutoExpandBoundsToText = true, HAnchor = HAnchor.Center, }; timeStack.AddChild(timePrinted); var timeToEnd = new TextWidget("", pointSize: 9, textColor: theme.TextColor) { AutoExpandBoundsToText = true, HAnchor = HAnchor.Center, }; timeStack.AddChild(timeToEnd); var runningInterval = UiThread.SetInterval(() => { int totalSecondsPrinted = printer.Connection.SecondsPrinted; int hoursPrinted = totalSecondsPrinted / (60 * 60); int minutesPrinted = totalSecondsPrinted / 60 - hoursPrinted * 60; var secondsPrinted = totalSecondsPrinted % 60; // TODO: Consider if the consistency of a common time format would look and feel better than changing formats based on elapsed duration timePrinted.Text = GetFormatedTime(hoursPrinted, minutesPrinted, secondsPrinted); int totalSecondsToEnd = printer.Connection.SecondsToEnd; int hoursToEnd = totalSecondsToEnd / (60 * 60); int minutesToEnd = totalSecondsToEnd / 60 - hoursToEnd * 60; var secondsToEnd = totalSecondsToEnd % 60; timeToEnd.Text = GetFormatedTime(hoursToEnd, minutesToEnd, secondsToEnd); progressDial.LayerIndex = printer.Connection.CurrentlyPrintingLayer; if (progressDial.LayerIndex > 0) { babySteppingControls.Visible = false; } progressDial.LayerCompletedRatio = printer.Connection.RatioIntoCurrentLayerSeconds; progressDial.CompletedRatio = printer.Connection.PercentComplete / 100; switch (printer.Connection.CommunicationState) { case CommunicationStates.PreparingToPrint: case CommunicationStates.Printing: case CommunicationStates.Paused: bodyRow.Visible = true; break; default: bodyRow.Visible = false; break; } }, 1); bodyRow.Closed += (s, e) => UiThread.ClearInterval(runningInterval); bodyRow.Visible = false; return(bodyRow); }