public override void OnMouseUp(MouseEventArgs mouseEvent) { if (CurrentTrackingType != TrackBallTransformType.None) { if (CurrentTrackingType == TrackBallTransformType.Rotation) { EndRotateAroundOrigin(); // try and preserve some of the velocity motionQueue.AddMoveToMotionQueue(mouseEvent.Position, UiThread.CurrentTimerMs); if (!Keyboard.IsKeyDown(Keys.ShiftKey)) { currentVelocityPerMs = motionQueue.GetVelocityPixelsPerMs(); if (currentVelocityPerMs.LengthSquared > 0) { Vector2 center = LocalBounds.Center; StartRotateAroundOrigin(center); runningInterval = UiThread.SetInterval(ApplyVelocity, 1.0 / updatesPerSecond); } } } CurrentTrackingType = TrackBallTransformType.None; } base.OnMouseUp(mouseEvent); }
public override void PageIsBecomingActive() { bedStartingTemp = printer.Connection.ActualBedTemperature; runningInterval = UiThread.SetInterval(ShowTempChangeProgress, 1); if (bedTargetTemp > 0) { // start heating the bed and show our progress printer.Connection.TargetBedTemperature = bedTargetTemp; } if (hotEndTargetTemp > 0) { // start heating the hot end and show our progress printer.Connection.SetTargetHotendTemperature(0, hotEndTargetTemp); } NextButton.Enabled = false; // if we are trying to go to a temp of 0 than just move on to next window if (bedTargetTemp == 0 && hotEndTargetTemp == 0) { // advance to the next page UiThread.RunOnIdle(() => NextButton.InvokeClick()); } base.PageIsBecomingActive(); }
public GamePlatform(int framesPerSecond, int maxUpdatesPerDraw, double width, double height) : base(width, height) { AnchorAll(); showFrameRate = true; secondsPerUpdate = 1.0 / (double)framesPerSecond; this.maxUpdatesPerDraw = maxUpdatesPerDraw; AudioSystem.Startup(); UiThread.SetInterval(OnIdle, secondsPerUpdate); }
private void DirectoryContentsChanged(object sender, EventArgs e) { // Flag for reload isDirty = true; lastTimeContentsChanged = UiThread.CurrentTimerMs; // Only refresh content if we're the active container if (isActiveContainer && waitingForRefresh == null) { waitingForRefresh = UiThread.SetInterval(WaitToRefresh, .5); } }
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) => runningInterval.Continue = false; }
public FindBedHeight(ISetupWizard setupWizard, string pageDescription, string setZHeightCoarseInstruction1, string setZHeightCoarseInstruction2, double moveDistance, List <PrintLevelingWizard.ProbePosition> probePositions, int probePositionsBeingEditedIndex) : base(setupWizard, pageDescription, setZHeightCoarseInstruction1) { this.probePositions = probePositions; this.moveAmount = moveDistance; this.lastReportedPosition = printer.Connection.LastReportedPosition; this.probePositionsBeingEditedIndex = probePositionsBeingEditedIndex; GuiWidget spacer = new GuiWidget(15, 15); contentRow.AddChild(spacer); FlowLayoutWidget zButtonsAndInfo = new FlowLayoutWidget(); zButtonsAndInfo.HAnchor |= Agg.UI.HAnchor.Center; FlowLayoutWidget zButtons = CreateZButtons(); zButtonsAndInfo.AddChild(zButtons); zButtonsAndInfo.AddChild(new GuiWidget(15, 10)); // textFields TextWidget zPosition = new TextWidget("Z: 0.0 ", pointSize: 12, textColor: theme.TextColor) { VAnchor = VAnchor.Center, Margin = new BorderDouble(10, 0), }; runningInterval = UiThread.SetInterval(() => { Vector3 destinationPosition = printer.Connection.CurrentDestination; zPosition.Text = "Z: {0:0.00}".FormatWith(destinationPosition.Z); }, .3); zButtonsAndInfo.AddChild(zPosition); contentRow.AddChild(zButtonsAndInfo); contentRow.AddChild( this.CreateTextField(setZHeightCoarseInstruction2)); }
public InlineEditControl(string defaultSizeString = "-0000.00", Agg.Font.Justification justification = Agg.Font.Justification.Left) { base.Visible = false; double pointSize = 12; numberDisplay = new TextWidget(defaultSizeString, 0, 0, pointSize, justification: justification) { Visible = false, VAnchor = VAnchor.Bottom, HAnchor = HAnchor.Left, Text = "0", }; AddChild(numberDisplay); numberEdit = new NumberEdit(0, 50, 50, pointSize, pixelWidth: numberDisplay.Width, allowNegatives: true, allowDecimals: true) { Visible = false, VAnchor = VAnchor.Bottom, HAnchor = HAnchor.Left, SelectAllOnFocus = true, }; numberEdit.InternalNumberEdit.TextChanged += (s, e) => { numberDisplay.Text = GetDisplayString == null ? "None" : GetDisplayString.Invoke(Value); base.OnTextChanged(e); }; numberEdit.InternalNumberEdit.MaxDecimalsPlaces = 2; numberEdit.EditComplete += (s, e) => { EditComplete?.Invoke(this, e); timeSinceMouseUp.Restart(); numberEdit.Visible = false; numberDisplay.Visible = true; }; AddChild(numberEdit); VAnchor = VAnchor.Fit; HAnchor = HAnchor.Fit; var runningInterval = UiThread.SetInterval(HideIfApplicable, .1); this.Closed += (s, e) => runningInterval.Continue = false; }
private void LookForTempRequest(object sender, EventArgs e) { var stringEvent = e as StringEventArgs; if (stringEvent != null && stringEvent.Data.Contains("M104")) { startingTemp = printer.Connection.GetActualHotendTemperature(0); RunningInterval runningInterval = null; runningInterval = UiThread.SetInterval(() => { runningInterval.Continue = !HasBeenClosed && progressBar.RatioComplete < 1; progressBar.Visible = true; double targetTemp = printer.Connection.GetTargetHotendTemperature(0); double actualTemp = printer.Connection.GetActualHotendTemperature(0); double totalDelta = targetTemp - startingTemp; double currentDelta = actualTemp - startingTemp; double ratioDone = totalDelta != 0 ? (currentDelta / totalDelta) : 1; progressBar.RatioComplete = Math.Min(Math.Max(0, ratioDone), 1); progressBarText.Text = $"Temperature: {actualTemp:0} / {targetTemp:0}"; }, 1); } }
public override void OnMouseUp(MouseEventArgs mouseEvent) { if (!LockTrackBall && TrackBallController.CurrentTrackingType != TrackBallTransformType.None) { if (TrackBallController.CurrentTrackingType == TrackBallTransformType.Rotation) { // try and preserve some of the velocity motionQueue.AddMoveToMotionQueue(mouseEvent.Position, UiThread.CurrentTimerMs); if (!Keyboard.IsKeyDown(Keys.ShiftKey)) { currentVelocityPerMs = motionQueue.GetVelocityPixelsPerMs(); if (currentVelocityPerMs.LengthSquared > 0) { runningInterval = UiThread.SetInterval(ApplyVelocity, 1.0 / updatesPerSecond); } } } TrackBallController.OnMouseUp(); } base.OnMouseUp(mouseEvent); }
public override void OnLoad(EventArgs args) { // hook our parent so we can turn off the bed when we are done with leveling this.DialogWindow.Closed += WizardWindow_Closed; bedStartingTemp = printer.Connection.ActualBedTemperature; runningInterval = UiThread.SetInterval(ShowTempChangeProgress, 1); if (bedTargetTemp > 0) { // start heating the bed and show our progress printer.Connection.TargetBedTemperature = bedTargetTemp; } for (int i = 0; i < targetHotendTemps.Length; i++) { if (targetHotendTemps[i] > 0) { // start heating the hot end and show our progress printer.Connection.SetTargetHotendTemperature(i, targetHotendTemps[i]); } } NextButton.Enabled = false; // if we are trying to go to a temp of 0 than just move on to next window if (bedTargetTemp == 0 && targetHotendTemps.All(i => i == 0)) { // advance to the next page UiThread.RunOnIdle(() => NextButton.InvokeClick()); } base.OnLoad(args); }
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 RunningMacroPage(PrinterConfig printer, MacroCommandData macroData, ThemeConfig theme) : base("Cancel") { this.printer = printer; this.WindowTitle = "Running Macro".Localize(); this.HeaderText = macroData.title; if (macroData.showMaterialSelector) { contentRow.AddChild(new PresetSelectorWidget(printer, "Material".Localize(), Color.Transparent, NamedSettingsLayers.Material, theme) { BackgroundColor = Color.Transparent, Margin = new BorderDouble(0, 0, 0, 15) }); } printer.Connection.LineSent.RegisterEvent(LookForTempRequest, ref unregisterEvents); if (macroData.waitOk | macroData.expireTime > 0) { var okButton = theme.CreateDialogButton("Continue".Localize()); okButton.Click += (s, e) => { printer.Connection.MacroContinue(); }; this.AddPageAction(okButton); } if (macroData.image != null) { var imageWidget = new ImageWidget(macroData.image) { HAnchor = HAnchor.Center, Margin = new BorderDouble(5, 15), }; contentRow.AddChild(imageWidget); } var holder = new FlowLayoutWidget(); progressBar = new ProgressBar((int)(150 * GuiWidget.DeviceScale), (int)(15 * GuiWidget.DeviceScale)) { FillColor = ActiveTheme.Instance.PrimaryAccentColor, BorderColor = ActiveTheme.Instance.PrimaryTextColor, BackgroundColor = Color.White, Margin = new BorderDouble(3, 0, 0, 10), }; progressBarText = new TextWidget("", pointSize: 10, textColor: ActiveTheme.Instance.PrimaryTextColor) { AutoExpandBoundsToText = true, Margin = new BorderDouble(5, 0, 0, 0), }; holder.AddChild(progressBar); holder.AddChild(progressBarText); contentRow.AddChild(holder); progressBar.Visible = false; if (macroData.countDown > 0) { timeToWaitMs = (long)(macroData.countDown * 1000); startTimeMs = UiThread.CurrentTimerMs; runningInterval = UiThread.SetInterval(CountDownTime, .2); } }
private GuiWidget GetPopupContent(ThemeConfig theme) { var widget = new IgnoredPopupWidget() { Width = 300, HAnchor = HAnchor.Absolute, VAnchor = VAnchor.Fit, BackgroundColor = theme.Colors.PrimaryBackgroundColor, Padding = new BorderDouble(12, 0) }; var container = new FlowLayoutWidget(FlowDirection.TopToBottom) { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit | VAnchor.Top, }; widget.AddChild(container); GuiWidget hotendRow; container.AddChild(hotendRow = new SettingsItem( "Heated Bed".Localize(), theme, new SettingsItem.ToggleSwitchConfig() { Checked = false, ToggleAction = (itemChecked) => { var goalTemp = itemChecked ? printer.Settings.GetValue <double>(SettingsKey.bed_temperature) : 0; if (itemChecked) { SetTargetTemperature(goalTemp); } else { SetTargetTemperature(0); } } }, enforceGutter: false)); var toggleWidget = hotendRow.Children.Where(o => o is ICheckbox).FirstOrDefault(); toggleWidget.Name = "Toggle Heater"; heatToggle = toggleWidget as ICheckbox; int tabIndex = 0; var settingsContext = new SettingsContext(printer, null, NamedSettingsLayers.All); var settingsData = SettingsOrganizer.Instance.GetSettingsData(SettingsKey.bed_temperature); var temperatureRow = SliceSettingsTabView.CreateItemRow(settingsData, settingsContext, printer, theme, ref tabIndex); SliceSettingsRow.AddBordersToEditFields(temperatureRow); container.AddChild(temperatureRow); alwaysEnabled.Add(hotendRow); // add in the temp graph var graph = new DataViewGraph() { DynamiclyScaleRange = false, MinValue = 0, ShowGoal = true, GoalColor = ActiveTheme.Instance.PrimaryAccentColor, GoalValue = printer.Settings.GetValue <double>(SettingsKey.bed_temperature), MaxValue = 150, // could come from some profile value in the future Width = widget.Width - 20, Height = 35, // this works better if it is a common multiple of the Width Margin = new BorderDouble(0, 5, 0, 0), }; var runningInterval = UiThread.SetInterval(() => { graph.AddData(this.ActualTemperature); }, 1); this.Closed += (s, e) => runningInterval.Continue = false; var valueField = temperatureRow.Descendants <MHNumberEdit>().FirstOrDefault(); var settingsRow = temperatureRow.DescendantsAndSelf <SliceSettingsRow>().FirstOrDefault(); ActiveSliceSettings.SettingChanged.RegisterEvent((s, e) => { if (e is StringEventArgs stringEvent) { var temp = printer.Settings.GetValue <double>(SettingsKey.bed_temperature); valueField.Value = temp; graph.GoalValue = temp; settingsRow.UpdateStyle(); if (stringEvent.Data == SettingsKey.bed_temperature && heatToggle.Checked) { SetTargetTemperature(temp); } } ; }, ref unregisterEvents); container.AddChild(graph); return(widget); }
private GuiWidget GetPopupContent(ThemeConfig menuTheme) { var widget = new IgnoredPopupWidget() { Width = 300, HAnchor = HAnchor.Absolute, VAnchor = VAnchor.Fit, Padding = new BorderDouble(12, 0), BackgroundColor = menuTheme.BackgroundColor }; var container = new FlowLayoutWidget(FlowDirection.TopToBottom) { HAnchor = HAnchor.Stretch, VAnchor = VAnchor.Fit | VAnchor.Top, }; widget.AddChild(container); GuiWidget hotendRow; container.AddChild(hotendRow = new SettingsItem( "Heated Bed".Localize(), menuTheme, new SettingsItem.ToggleSwitchConfig() { Checked = false, ToggleAction = (itemChecked) => { var goalTemp = itemChecked ? printer.Settings.GetValue <double>(SettingsKey.bed_temperature) : 0; if (itemChecked) { SetTargetTemperature(goalTemp); } else { SetTargetTemperature(0); } } }, enforceGutter: false)); var toggleWidget = hotendRow.Children.Where(o => o is ICheckbox).FirstOrDefault(); toggleWidget.Name = "Toggle Heater"; heatToggle = toggleWidget as ICheckbox; int tabIndex = 0; var settingsContext = new SettingsContext(printer, null, NamedSettingsLayers.All); var settingsData = PrinterSettings.SettingsData[SettingsKey.bed_temperature]; var temperatureRow = SliceSettingsTabView.CreateItemRow(settingsData, settingsContext, printer, menuTheme, ref tabIndex, allUiFields); container.AddChild(temperatureRow); // Add the temperature row to the always enabled list ensuring the field can be set when disconnected alwaysEnabled.Add(temperatureRow); // add in the temp graph var graph = new DataViewGraph() { DynamicallyScaleRange = false, MinValue = 0, ShowGoal = true, GoalColor = menuTheme.PrimaryAccentColor, GoalValue = printer.Settings.GetValue <double>(SettingsKey.bed_temperature), MaxValue = 150, // could come from some profile value in the future Width = widget.Width - 20, Height = 35, // this works better if it is a common multiple of the Width Margin = new BorderDouble(0, 5, 0, 0), }; runningInterval = UiThread.SetInterval(() => { graph.AddData(this.ActualTemperature); }, 1); var settingsRow = temperatureRow.DescendantsAndSelf <SliceSettingsRow>().FirstOrDefault(); void Printer_SettingChanged(object s, StringEventArgs stringEvent) { if (stringEvent != null) { string settingsKey = stringEvent.Data; if (this.allUiFields.TryGetValue(settingsKey, out UIField uifield)) { string currentValue = settingsContext.GetValue(settingsKey); if (uifield.Value != currentValue) { uifield.SetValue( currentValue, userInitiated: false); } } if (stringEvent.Data == SettingsKey.bed_temperature) { var temp = printer.Settings.GetValue <double>(SettingsKey.bed_temperature); graph.GoalValue = temp; // TODO: Why is this only when enabled? How does it get set to if (heatToggle.Checked) { // TODO: Why is a UI widget who is listening to model events driving this behavior? What when it's not loaded? SetTargetTemperature(temp); } settingsRow.UpdateStyle(); } } } printer.Settings.SettingChanged += Printer_SettingChanged; printer.Disposed += (s, e) => printer.Settings.SettingChanged -= Printer_SettingChanged; container.AddChild(graph); return(widget); }
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); GuiWidget resumeButton = null; GuiWidget pauseButton = CreateIconOrTextButton("fa-pause_12.png", taskDetails.Options?.PauseText, taskDetails.Options?.PauseAction, taskDetails.Options?.PauseToolTip ?? "Pause".Localize(), "", theme, 0); 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 = CreateIconOrTextButton("fa-play_12.png", taskDetails.Options?.ResumeText, taskDetails.Options?.ResumeAction, taskDetails.Options?.ResumeToolTip ?? "Resume".Localize(), "Resume Task Button", theme, 0); // start with it hidden resumeButton.Visible = false; resumeButton.Click += (s, e) => { taskDetails.Options?.ResumeAction(); pauseButton.Visible = true; resumeButton.Visible = false; }; topRow.AddChild(resumeButton); var stopButton = CreateIconOrTextButton("fa-stop_12.png", taskDetails.Options?.StopText, taskDetails.Options?.StopAction, taskDetails.Options?.StopToolTip ?? "Cancel".Localize(), "Stop Task Button", theme, 5); stopButton.Enabled = true; 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; }
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); }
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 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 RunningTaskRow(string title, RunningTaskDetails taskDetails, ThemeConfig theme) : base(FlowDirection.TopToBottom) { this.taskDetails = taskDetails; this.theme = theme; this.MinimumSize = new Vector2(100, 20); 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, VAnchor = VAnchor.Absolute | VAnchor.Bottom, FillColor = ActiveTheme.Instance.PrimaryAccentColor, BorderColor = Color.Transparent, BackgroundColor = ActiveTheme.Instance.TertiaryBackgroundColor, Margin = new BorderDouble(32, 7, theme.ButtonHeight * 2 + 14, 0), }; 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 }; expandButton.CheckedStateChanged += (s, e) => { taskDetails.IsExpanded = expandButton.Checked; SetExpansionMode(theme, detailsPanel, expandButton.Checked); }; topRow.AddChild(expandButton); IconButton resumeButton = null; var pauseButton = new IconButton(AggContext.StaticData.LoadIcon("fa-pause_12.png", 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) { runningInterval.Continue = false; } }, .2); } pauseButton.Click += (s, e) => { taskDetails.Options?.PauseAction(); pauseButton.Visible = false; resumeButton.Visible = true; }; topRow.AddChild(pauseButton); resumeButton = new IconButton(AggContext.StaticData.LoadIcon("fa-play_12.png", 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(AggContext.StaticData.LoadIcon("fa-stop_12.png", 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(); } }; topRow.AddChild(stopButton); this.AddChild(detailsPanel); // Add rich progress controls if (taskDetails.Options?.RichProgressWidget?.Invoke() is GuiWidget guiWidget) { detailsPanel.AddChild(guiWidget); } 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; }
public PartPreviewContent(ThemeConfig theme) : base(FlowDirection.TopToBottom) { this.AnchorAll(); 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 = ActiveTheme.Instance.PrimaryBackgroundColor, BorderColor = theme.MinimalShade, Border = new BorderDouble(left: 1), NewTabPage = () => { return(new StartTabPage(this, theme)); } }; 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; } }; // 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.ActiveTabColor; // 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 var 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.Colors.PrimaryTextColor }; 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 var updateAvailableButton = new LinkLabel("Update Available".Localize(), theme) { Visible = false, }; // make the function inline so we don't have to create members for the buttons EventHandler SetLinkButtonsVisibility = (s, e) => { if (UserSettings.Instance.HasLookedAtWhatsNew()) { // hide it seeWhatsNewButton.Visible = false; } if (UpdateControlData.Instance.UpdateStatus == UpdateControlData.UpdateStatusStates.UpdateAvailable) { updateAvailableButton.Visible = true; // if we are going to show the update link hide the whats new link no matter what seeWhatsNewButton.Visible = false; } else { updateAvailableButton.Visible = false; } }; UserSettings.Instance.Changed += SetLinkButtonsVisibility; Closed += (s, e) => UserSettings.Instance.Changed -= SetLinkButtonsVisibility; RunningInterval showUpdateInterval = null; updateAvailableButton.VisibleChanged += (s, e) => { if (!updateAvailableButton.Visible) { if (showUpdateInterval != null) { showUpdateInterval.Continue = false; 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.Colors.PrimaryTextColor; // 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); }; updateAvailableButton.Name = "Update Available Link"; SetLinkButtonsVisibility(this, null); updateAvailableButton.ToolTipText = "There is a new update available for download".Localize(); updateAvailableButton.VAnchor = VAnchor.Center; updateAvailableButton.Margin = new BorderDouble(10, 0); updateAvailableButton.Click += (s, e) => UiThread.RunOnIdle(() => { UiThread.RunOnIdle(() => { UpdateControlData.Instance.CheckForUpdate(); DialogWindow.Show <CheckForUpdatesPage>(); }); }); tabControl.TabBar.ActionArea.AddChild(updateAvailableButton); UpdateControlData.Instance.UpdateStatusChanged.RegisterEvent(SetLinkButtonsVisibility, ref unregisterEvents); this.AddChild(tabControl); ActiveSliceSettings.SettingChanged.RegisterEvent((s, e) => { if (e is StringEventArgs stringEvent && stringEvent.Data == SettingsKey.printer_name && printerTab != null) { printerTab.Text = ActiveSliceSettings.Instance.GetValue(SettingsKey.printer_name); } }, ref unregisterEvents); ActiveSliceSettings.ActivePrinterChanged.RegisterEvent((s, e) => { var activePrinter = ApplicationController.Instance.ActivePrinter; // If ActivePrinter has been nulled and a printer tab is open, close it var tab1 = tabControl.AllTabs.Skip(1).FirstOrDefault(); if ((activePrinter == null || !activePrinter.Settings.PrinterSelected) && tab1?.TabContent is PrinterTabPage) { tabControl.RemoveTab(tab1); } else { this.CreatePrinterTab(activePrinter, theme); } }, ref unregisterEvents); ApplicationController.Instance.NotifyPrintersTabRightElement(extensionArea); // Show fixed start page tabControl.AddTab( new ChromeTab("Start".Localize(), tabControl, tabControl.NewTabPage(), theme, hasClose: false) { MinimumSize = new Vector2(0, theme.TabButtonHeight), Name = "Start Tab", Padding = new BorderDouble(15, 0) }); // Add a tab for the current printer if (ActiveSliceSettings.Instance.PrinterSelected) { this.CreatePrinterTab(ApplicationController.Instance.ActivePrinter, theme); } // Restore active tabs foreach (var bed in ApplicationController.Instance.Workspaces) { this.CreatePartTab("New Part", bed, theme); } }
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 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; }
public InlineEditControl(string defaultSizeString = "-0000.00") { theme = AppContext.Theme; base.Visible = false; double pointSize = 10; this.Padding = new BorderDouble(3); numberDisplay = new TextWidget(defaultSizeString, 0, 0, pointSize, justification: Agg.Font.Justification.Center, textColor: theme.TextColor) { Visible = false, VAnchor = VAnchor.Bottom, HAnchor = HAnchor.Left, Text = "0", AutoExpandBoundsToText = true, }; this.BeforeDraw += (s, e) => { if (s is GuiWidget widget) { var test = true; if (test) { // return; } var bounds = widget.LocalBounds; e.Graphics2D.Render(new RoundedRect(bounds, 3 * GuiWidget.DeviceScale), theme.BackgroundColor.WithAlpha(200)); } }; AddChild(numberDisplay); numberEdit = new MHNumberEdit(0, theme, pixelWidth: numberDisplay.Width, allowNegatives: true, allowDecimals: true) { Visible = false, VAnchor = VAnchor.Bottom, HAnchor = HAnchor.Left, SelectAllOnFocus = true, }; numberEdit.ActuallNumberEdit.InternalNumberEdit.TextChanged += (s, e) => { numberDisplay.Text = GetDisplayString == null ? "None" : GetDisplayString.Invoke(Value); this.OnTextChanged(e); }; numberEdit.ActuallNumberEdit.InternalNumberEdit.MaxDecimalsPlaces = 2; numberEdit.ActuallNumberEdit.EditComplete += (s, e) => { EditComplete?.Invoke(this, e); timeSinceMouseUp.Restart(); numberEdit.Visible = false; numberDisplay.Visible = true; }; AddChild(numberEdit); VAnchor = VAnchor.Fit; HAnchor = HAnchor.Fit; runningInterval = UiThread.SetInterval(HideIfApplicable, .1); }