public static GuiWidget PrintProgressWidget(PrinterConfig printer, ThemeConfig theme) { var bodyRow = new GuiWidget() { HAnchor = HAnchor.Fit | HAnchor.Center, VAnchor = VAnchor.Top | VAnchor.Fit, //BackgroundColor = new Color(theme.Colors.PrimaryBackgroundColor, 128), MinimumSize = new Vector2(275, 140), Selectable = false }; // Progress section var expandingContainer = new HorizontalSpacer() { VAnchor = VAnchor.Fit | VAnchor.Center }; bodyRow.AddChild(expandingContainer); var progressContainer = new FlowLayoutWidget(FlowDirection.TopToBottom) { Margin = new BorderDouble(50, 0), VAnchor = VAnchor.Center | VAnchor.Fit, HAnchor = HAnchor.Center | HAnchor.Fit, }; expandingContainer.AddChild(progressContainer); var progressDial = new ProgressDial() { HAnchor = HAnchor.Center, Height = 200 * DeviceScale, Width = 200 * DeviceScale }; progressContainer.AddChild(progressDial); var timeContainer = new FlowLayoutWidget() { HAnchor = HAnchor.Center | HAnchor.Fit, Margin = 3 }; progressContainer.AddChild(timeContainer); timeContainer.AddChild(new ImageWidget(AggContext.StaticData.LoadIcon("fa-clock_24.png", theme.InvertIcons)) { VAnchor = VAnchor.Center }); var timeWidget = new TextWidget("", pointSize: 22, textColor: theme.Colors.PrimaryTextColor) { 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) => runningInterval.Continue = false; 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 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); }