public override void OnClosed(EventArgs e)
        {
            // Unregister listeners
            UiThread.ClearInterval(runningInterval);

            base.OnClosed(e);
        }
        private void ApplyVelocity()
        {
            if (HasBeenClosed || currentVelocityPerMs.LengthSquared <= 0)
            {
                UiThread.ClearInterval(runningInterval);
            }

            double msPerUpdate = 1000.0 / updatesPerSecond;

            if (currentVelocityPerMs.LengthSquared > 0)
            {
                if (TrackBallController.CurrentTrackingType == TrackBallTransformType.None)
                {
                    Vector2 center = LocalBounds.Center;
                    TrackBallController.OnMouseDown(center, Matrix4X4.Identity, TrackBallTransformType.Rotation);
                    TrackBallController.OnMouseMove(center + currentVelocityPerMs * msPerUpdate);
                    TrackBallController.OnMouseUp();
                    Invalidate();

                    currentVelocityPerMs *= .85;
                    if (currentVelocityPerMs.LengthSquared < .01 / msPerUpdate)
                    {
                        currentVelocityPerMs = Vector2.Zero;
                    }
                }
            }
        }
Example #3
0
        public override void OnClosed(EventArgs e)
        {
            // Unregister listeners
            printer.Connection.BedTemperatureRead -= Connection_BedTemperatureRead;
            UiThread.ClearInterval(runningInterval);

            base.OnClosed(e);
        }
Example #4
0
        public override void OnClosed(EventArgs e)
        {
            // Unregister listeners
            UiThread.ClearInterval(runningInterval);
            this.DialogWindow.KeyDown -= TopWindowKeyDown;

            base.OnClosed(e);
        }
 public void ZeroVelocity()
 {
     motionQueue.Clear();
     currentVelocityPerMs = Vector2.Zero;
     if (runningInterval != null)
     {
         UiThread.ClearInterval(runningInterval);
     }
     EndRotateAroundOrigin();
 }
        private void WaitToRefresh()
        {
            if (UiThread.CurrentTimerMs > lastTimeContentsChanged + 500 &&
                waitingForRefresh != null)
            {
                UiThread.ClearInterval(waitingForRefresh);

                waitingForRefresh = null;
                this.ReloadContent();
            }
        }
        private void ConnectToWidget(object drawingWidget, DrawEventArgs e)
        {
            GuiWidget parent = drawingWidget as GuiWidget;

            while (parent.BackgroundColor.Alpha0To255 == 0)
            {
                parent = parent.Parent;
            }
            startColor     = parent.BackgroundColor;
            timeSinceStart = Stopwatch.StartNew();
            widgetToHighlight.AfterDraw -= ConnectToWidget;
            var runningInterval = UiThread.SetInterval(ChangeBackgroundColor, animationDelay);

            parent.Closed += (s, e2) => UiThread.ClearInterval(runningInterval);
        }
        public MainViewWidget(ThemeConfig theme)
            : base(FlowDirection.TopToBottom)
        {
            this.AnchorAll();
            this.theme           = theme;
            this.Name            = "PartPreviewContent";
            this.BackgroundColor = theme.BackgroundColor;

            // Push TouchScreenMode into GuiWidget
            GuiWidget.TouchScreenMode = UserSettings.Instance.IsTouchScreen;

            var extensionArea = new LeftClipFlowLayoutWidget()
            {
                BackgroundColor = theme.TabBarBackground,
                VAnchor         = VAnchor.Stretch,
                Padding         = new BorderDouble(left: 8)
            };

            tabControl = new ChromeTabs(extensionArea, theme)
            {
                VAnchor         = VAnchor.Stretch,
                HAnchor         = HAnchor.Stretch,
                BackgroundColor = theme.BackgroundColor,
                BorderColor     = theme.MinimalShade,
                Border          = new BorderDouble(left: 1),
            };

            tabControl.PlusClicked += (s, e) =>
            {
                UiThread.RunOnIdle(() =>
                {
                    this.CreatePartTab().ConfigureAwait(false);
                });
            };

            tabControl.ActiveTabChanged += (s, e) =>
            {
                if (this.tabControl.ActiveTab?.TabContent is PartTabPage tabPage)
                {
                    var dragDropData = ApplicationController.Instance.DragDropData;

                    // Set reference on tab change
                    dragDropData.View3DWidget = tabPage.view3DWidget;
                    dragDropData.SceneContext = tabPage.sceneContext;

                    ApplicationController.Instance.PrinterTabSelected = true;
                }
                else
                {
                    ApplicationController.Instance.PrinterTabSelected = false;
                }

                ApplicationController.Instance.MainTabKey = tabControl.SelectedTabKey;
            };

            // Force the ActionArea to be as high as ButtonHeight
            tabControl.TabBar.ActionArea.MinimumSize = new Vector2(0, theme.ButtonHeight);
            tabControl.TabBar.BackgroundColor        = theme.TabBarBackground;
            tabControl.TabBar.BorderColor            = theme.BackgroundColor;

            // Force common padding into top region
            tabControl.TabBar.Padding = theme.TabbarPadding.Clone(top: theme.TabbarPadding.Top * 2, bottom: 0);

            // add in a what's new button
            seeWhatsNewButton = new LinkLabel("What's New...".Localize(), theme)
            {
                Name        = "What's New Link",
                ToolTipText = "See what's new in this version of MatterControl".Localize(),
                VAnchor     = VAnchor.Center,
                Margin      = new BorderDouble(10, 0),
                TextColor   = theme.TextColor
            };
            seeWhatsNewButton.Click += (s, e) => UiThread.RunOnIdle(() =>
            {
                UserSettings.Instance.set(UserSettingsKey.LastReadWhatsNew, JsonConvert.SerializeObject(DateTime.Now));
                DialogWindow.Show(new HelpPage("What's New"));
            });

            tabControl.TabBar.ActionArea.AddChild(seeWhatsNewButton);

            // add in the update available button
            updateAvailableButton = new LinkLabel("Update Available".Localize(), theme)
            {
                Visible     = false,
                Name        = "Update Available Link",
                ToolTipText = "There is a new update available for download".Localize(),
                VAnchor     = VAnchor.Center,
                Margin      = new BorderDouble(10, 0)
            };

            // Register listeners
            UserSettings.Instance.SettingChanged += SetLinkButtonsVisibility;

            RunningInterval showUpdateInterval = null;

            updateAvailableButton.VisibleChanged += (s, e) =>
            {
                if (!updateAvailableButton.Visible)
                {
                    if (showUpdateInterval != null)
                    {
                        UiThread.ClearInterval(showUpdateInterval);
                        showUpdateInterval = null;
                    }
                    return;
                }

                showUpdateInterval = UiThread.SetInterval(() =>
                {
                    double displayTime  = 1;
                    double pulseTime    = 1;
                    double totalSeconds = 0;
                    var textWidgets     = updateAvailableButton.Descendants <TextWidget>().Where((w) => w.Visible == true).ToArray();
                    Color startColor    = theme.TextColor;
                    // Show a highlight on the button as the user did not click it
                    Animation flashBackground = null;
                    flashBackground           = new Animation()
                    {
                        DrawTarget      = updateAvailableButton,
                        FramesPerSecond = 10,
                        Update          = (s1, updateEvent) =>
                        {
                            totalSeconds += updateEvent.SecondsPassed;
                            if (totalSeconds < displayTime)
                            {
                                double blend = AttentionGetter.GetFadeInOutPulseRatio(totalSeconds, pulseTime);
                                var color    = new Color(startColor, (int)((1 - blend) * 255));
                                foreach (var textWidget in textWidgets)
                                {
                                    textWidget.TextColor = color;
                                }
                            }
                            else
                            {
                                foreach (var textWidget in textWidgets)
                                {
                                    textWidget.TextColor = startColor;
                                }
                                flashBackground.Stop();
                            }
                        }
                    };
                    flashBackground.Start();
                }, 120);
            };

            SetLinkButtonsVisibility(this, null);
            updateAvailableButton.Click += (s, e) => UiThread.RunOnIdle(() =>
            {
                UpdateControlData.Instance.CheckForUpdate();
                DialogWindow.Show <CheckForUpdatesPage>();
            });

            tabControl.TabBar.ActionArea.AddChild(updateAvailableButton);

            this.AddChild(tabControl);

            ApplicationController.Instance.NotifyPrintersTabRightElement(extensionArea);

            // Store tab
            tabControl.AddTab(
                new ChromeTab("Store", "Store".Localize(), tabControl, new StoreTabPage(theme), theme, hasClose: false)
            {
                MinimumSize = new Vector2(0, theme.TabButtonHeight),
                Name        = "Store Tab",
                Padding     = new BorderDouble(15, 0),
            });

            // Library tab
            var libraryWidget = new LibraryWidget(this, theme)
            {
                BackgroundColor = theme.BackgroundColor
            };

            tabControl.AddTab(
                new ChromeTab("Library", "Library".Localize(), tabControl, libraryWidget, theme, hasClose: false)
            {
                MinimumSize = new Vector2(0, theme.TabButtonHeight),
                Name        = "Library Tab",
                Padding     = new BorderDouble(15, 0),
            });

            // Hardware tab
            tabControl.AddTab(
                new ChromeTab(
                    "Hardware",
                    "Hardware".Localize(),
                    tabControl,
                    new HardwareTabPage(theme)
            {
                BackgroundColor = theme.BackgroundColor
            },
                    theme,
                    hasClose: false)
            {
                MinimumSize = new Vector2(0, theme.TabButtonHeight),
                Name        = "Hardware Tab",
                Padding     = new BorderDouble(15, 0),
            });

            if (ApplicationController.Instance.Workspaces.Count == 0)
            {
                this.CreatePartTab().ConfigureAwait(false);
            }

            string tabKey = ApplicationController.Instance.MainTabKey;

            if (string.IsNullOrEmpty(tabKey))
            {
                tabKey = "Hardware";
            }

            // HACK: Restore to the first printer tab if PrinterTabSelected and tabKey not found. This allows sign in/out to remain on the printer tab across different users
            if (!tabControl.AllTabs.Any(t => t.Key == tabKey) &&
                ApplicationController.Instance.PrinterTabSelected)
            {
                var key = tabControl.AllTabs.Where(t => t.TabContent is PrinterTabPage).FirstOrDefault()?.Key;
                if (key != null)
                {
                    tabKey = key;
                }
            }

            var brandMenu = new BrandMenuButton(theme)
            {
                HAnchor         = HAnchor.Fit,
                VAnchor         = VAnchor.Fit,
                BackgroundColor = theme.TabBarBackground,
                Padding         = theme.TabbarPadding.Clone(right: theme.DefaultContainerPadding)
            };

            tabControl.TabBar.ActionArea.AddChild(brandMenu, 0);

            // Restore active tabs
            foreach (var workspace in ApplicationController.Instance.Workspaces)
            {
                this.CreatePartTab(workspace);
            }

            tabControl.SelectedTabKey = tabKey;

            statusBar = new Toolbar(theme)
            {
                HAnchor         = HAnchor.Stretch,
                VAnchor         = VAnchor.Absolute,
                Padding         = 1,
                Height          = 22,
                BackgroundColor = theme.BackgroundColor,
                Border          = new BorderDouble(top: 1),
                BorderColor     = theme.BorderColor20,
            };
            this.AddChild(statusBar);

            statusBar.ActionArea.VAnchor = VAnchor.Stretch;

            tasksContainer = new FlowLayoutWidget(FlowDirection.LeftToRight)
            {
                HAnchor         = HAnchor.Fit,
                VAnchor         = VAnchor.Stretch,
                BackgroundColor = theme.MinimalShade,
                Name            = "runningTasksPanel"
            };
            statusBar.AddChild(tasksContainer);

            var tasks = ApplicationController.Instance.Tasks;

            tasks.TasksChanged += (s, e) =>
            {
                RenderRunningTasks(theme, tasks);
            };

            stretchStatusPanel = new GuiWidget()
            {
                HAnchor         = HAnchor.Stretch,
                VAnchor         = VAnchor.Stretch,
                Padding         = new BorderDouble(right: 3),
                Margin          = new BorderDouble(right: 2, top: 1, bottom: 1),
                Border          = new BorderDouble(1),
                BackgroundColor = theme.MinimalShade.WithAlpha(10),
                BorderColor     = theme.SlightShade,
                Width           = 200
            };
            statusBar.AddChild(stretchStatusPanel);

            var panelBackgroundColor = theme.MinimalShade.WithAlpha(10);

            statusBar.AddChild(
                this.CreateThemeStatusPanel(theme, panelBackgroundColor));

            statusBar.AddChild(
                this.CreateNetworkStatusPanel(theme));

            this.RenderRunningTasks(theme, tasks);

            // Register listeners
            PrinterSettings.AnyPrinterSettingChanged           += Printer_SettingChanged;
            ApplicationController.Instance.OpenPrintersChanged += OpenPrinters_Changed;

            UpdateControlData.Instance.UpdateStatusChanged.RegisterEvent((s, e) =>
            {
                SetLinkButtonsVisibility(s, new StringEventArgs("Unknown"));
            }, ref unregisterEvents);

            ApplicationController.Instance.MainView = this;
        }
Example #9
0
        protected override IEnumerator <PrinterSetupWizardPage> GetWizardSteps()
        {
            var levelingStrings = new LevelingStrings(printer.Settings);

            var title        = "Select Material".Localize();
            var instructions = "Please select the material you will be printing with.".Localize();

            if (onlyLoad)
            {
                title        = "Load Material".Localize();
                instructions = "Please select the material you want to load.".Localize();
            }

            // select the material
            yield return(new SelectMaterialPage(this, title, instructions, onlyLoad ? "Load".Localize() : "Select".Localize(), onlyLoad));

            var theme = ApplicationController.Instance.Theme;

            // show the trim filament message
            {
                PrinterSetupWizardPage trimFilamentPage = null;
                trimFilamentPage = new PrinterSetupWizardPage(
                    this,
                    "Trim Filament".Localize(),
                    "")
                {
                    BecomingActive = () =>
                    {
                        // start heating up the extruder
                        printer.Connection.SetTargetHotendTemperature(0, printer.Settings.GetValue <double>(SettingsKey.temperature));

                        var markdownText   = printer.Settings.GetValue(SettingsKey.trim_filament_markdown);
                        var markdownWidget = new MarkdownWidget(theme);
                        markdownWidget.Markdown = markdownText = markdownText.Replace("\\n", "\n");
                        trimFilamentPage.ContentRow.AddChild(markdownWidget);
                    }
                };
                yield return(trimFilamentPage);
            }

            // show the insert filament page
            {
                RunningInterval        runningGCodeCommands = null;
                PrinterSetupWizardPage insertFilamentPage   = null;
                insertFilamentPage = new PrinterSetupWizardPage(
                    this,
                    "Insert Filament".Localize(),
                    "")
                {
                    BecomingActive = () =>
                    {
                        var markdownText   = printer.Settings.GetValue(SettingsKey.insert_filament_markdown2);
                        var markdownWidget = new MarkdownWidget(theme);
                        markdownWidget.Markdown = markdownText = markdownText.Replace("\\n", "\n");
                        insertFilamentPage.ContentRow.AddChild(markdownWidget);

                        // turn off the fan
                        printer.Connection.FanSpeed0To255 = 0;
                        // Allow extrusion at any temperature. S0 only works on Marlin S1 works on repetier and marlin
                        printer.Connection.QueueLine("M302 S1");

                        var runningTime = Stopwatch.StartNew();
                        runningGCodeCommands = UiThread.SetInterval(() =>
                        {
                            if (printer.Connection.NumQueuedCommands == 0)
                            {
                                printer.Connection.MoveRelative(PrinterCommunication.PrinterConnection.Axis.E, .2, 80);
                                int secondsToRun = 300;
                                if (runningTime.ElapsedMilliseconds > secondsToRun * 1000)
                                {
                                    UiThread.ClearInterval(runningGCodeCommands);
                                }
                            }
                        },
                                                                    .1);
                    },
                    BecomingInactive = () =>
                    {
                        if (runningGCodeCommands != null)
                        {
                            UiThread.ClearInterval(runningGCodeCommands);
                        }
                    }
                };
                insertFilamentPage.Closed += (s, e) =>
                {
                    if (runningGCodeCommands != null)
                    {
                        UiThread.ClearInterval(runningGCodeCommands);
                    }
                };

                yield return(insertFilamentPage);
            }

            // show the loading filament progress bar
            {
                RunningInterval        runningGCodeCommands = null;
                PrinterSetupWizardPage loadingFilamentPage  = null;
                loadingFilamentPage = new PrinterSetupWizardPage(
                    this,
                    "Loading Filament".Localize(),
                    "")
                {
                    BecomingActive = () =>
                    {
                        loadingFilamentPage.NextButton.Enabled = false;

                        // add the progress bar
                        var holder = new FlowLayoutWidget()
                        {
                            Margin = new BorderDouble(3, 0, 0, 10),
                        };
                        var progressBar = new ProgressBar((int)(150 * GuiWidget.DeviceScale), (int)(15 * GuiWidget.DeviceScale))
                        {
                            FillColor       = theme.PrimaryAccentColor,
                            BorderColor     = theme.TextColor,
                            BackgroundColor = Color.White,
                            VAnchor         = VAnchor.Center,
                        };
                        var progressBarText = new TextWidget("", pointSize: 10, textColor: theme.TextColor)
                        {
                            AutoExpandBoundsToText = true,
                            Margin  = new BorderDouble(5, 0, 0, 0),
                            VAnchor = VAnchor.Center,
                        };
                        holder.AddChild(progressBar);
                        holder.AddChild(progressBarText);
                        loadingFilamentPage.ContentRow.AddChild(holder);

                        // Allow extrusion at any temperature. S0 only works on Marlin S1 works on repetier and marlin
                        printer.Connection.QueueLine("M302 S1");
                        // send a dwel to empty out the current move commands
                        printer.Connection.QueueLine("G4 P1");
                        // put in a second one to use as a signal for the first being processed
                        printer.Connection.QueueLine("G4 P1");
                        // start heating up the extruder
                        printer.Connection.SetTargetHotendTemperature(0, printer.Settings.GetValue <double>(SettingsKey.temperature));

                        var loadingSpeedMmPerS     = printer.Settings.GetValue <double>(SettingsKey.load_filament_speed);
                        var loadLengthMm           = Math.Max(1, printer.Settings.GetValue <double>(SettingsKey.load_filament_length));
                        var remainingLengthMm      = loadLengthMm;
                        var maxSingleExtrudeLength = 20;

                        Stopwatch runningTime   = null;
                        var       expectedTimeS = loadLengthMm / loadingSpeedMmPerS;

                        runningGCodeCommands = UiThread.SetInterval(() =>
                        {
                            if (printer.Connection.NumQueuedCommands == 0)
                            {
                                if (runningTime == null)
                                {
                                    runningTime = Stopwatch.StartNew();
                                }

                                if (progressBar.RatioComplete < 1)
                                {
                                    var thisExtrude = Math.Min(remainingLengthMm, maxSingleExtrudeLength);
                                    var currentE    = printer.Connection.CurrentExtruderDestination;
                                    printer.Connection.QueueLine("G1 E{0:0.###} F{1}".FormatWith(currentE + thisExtrude, loadingSpeedMmPerS * 60));
                                    remainingLengthMm        -= thisExtrude;
                                    var elapsedSeconds        = runningTime.Elapsed.TotalSeconds;
                                    progressBar.RatioComplete = Math.Min(1, elapsedSeconds / expectedTimeS);
                                    progressBarText.Text      = $"Loading Filament: {Math.Max(0, expectedTimeS - elapsedSeconds):0}";
                                }
                            }

                            if (progressBar.RatioComplete == 1 &&
                                remainingLengthMm <= .001)
                            {
                                UiThread.ClearInterval(runningGCodeCommands);
                                loadingFilamentPage.NextButton.InvokeClick();
                            }
                        },
                                                                    .1);
                    },
                    BecomingInactive = () =>
                    {
                        UiThread.ClearInterval(runningGCodeCommands);
                    }
                };
                loadingFilamentPage.Closed += (s, e) =>
                {
                    UiThread.ClearInterval(runningGCodeCommands);
                };

                yield return(loadingFilamentPage);
            }

            // wait for extruder to heat
            {
                double targetHotendTemp = printer.Settings.Helpers.ExtruderTemperature(0);
                yield return(new WaitForTempPage(
                                 this,
                                 "Waiting For Printer To Heat".Localize(),
                                 "Waiting for the hotend to heat to ".Localize() + targetHotendTemp + "°C.\n"
                                 + "This will ensure that filament is able to flow through the nozzle.".Localize() + "\n"
                                 + "\n"
                                 + "Warning! The tip of the nozzle will be HOT!".Localize() + "\n"
                                 + "Avoid contact with your skin.".Localize(),
                                 0,
                                 targetHotendTemp));
            }

            // extrude slowly so that we can prime the extruder
            {
                RunningInterval        runningGCodeCommands = null;
                PrinterSetupWizardPage runningCleanPage     = null;
                runningCleanPage = new PrinterSetupWizardPage(
                    this,
                    "Wait For Running Clean".Localize(),
                    "")
                {
                    BecomingActive = () =>
                    {
                        var markdownText   = printer.Settings.GetValue(SettingsKey.running_clean_markdown2);
                        var markdownWidget = new MarkdownWidget(theme);
                        markdownWidget.Markdown = markdownText = markdownText.Replace("\\n", "\n");
                        runningCleanPage.ContentRow.AddChild(markdownWidget);

                        var runningTime = Stopwatch.StartNew();
                        runningGCodeCommands = UiThread.SetInterval(() =>
                        {
                            if (printer.Connection.NumQueuedCommands == 0)
                            {
                                printer.Connection.MoveRelative(PrinterCommunication.PrinterConnection.Axis.E, .35, 140);
                                int secondsToRun = 90;
                                if (runningTime.ElapsedMilliseconds > secondsToRun * 1000)
                                {
                                    UiThread.ClearInterval(runningGCodeCommands);
                                }
                            }
                        },
                                                                    .1);
                    },
                    BecomingInactive = () =>
                    {
                        UiThread.ClearInterval(runningGCodeCommands);
                    }
                };
                runningCleanPage.Closed += (s, e) =>
                {
                    UiThread.ClearInterval(runningGCodeCommands);
                    printer.Settings.SetValue(SettingsKey.filament_has_been_loaded, "1");
                };

                yield return(runningCleanPage);
            }

            // put up a success message
            PrinterSetupWizardPage finalPage = null;

            finalPage = new PrinterSetupWizardPage(this, "Success".Localize(), "Success!\n\nYour filament should now be loaded".Localize())
            {
                BecomingActive = () =>
                {
                    finalPage.ShowWizardFinished();
                }
            };

            yield return(finalPage);
        }
        public RunningTaskRow(string title, RunningTaskDetails taskDetails, ThemeConfig theme)
            : base(FlowDirection.TopToBottom)
        {
            this.taskDetails = taskDetails;
            this.theme       = theme;

            this.MinimumSize = new Vector2(100 * GuiWidget.DeviceScale, 20 * GuiWidget.DeviceScale);

            var detailsPanel = new GuiWidget()
            {
                HAnchor = HAnchor.Stretch,
                VAnchor = VAnchor.Fit,
            };

            var rowContainer = new GuiWidget()
            {
                VAnchor = VAnchor.Fit,
                HAnchor = HAnchor.Stretch,
            };

            this.AddChild(rowContainer);

            var topRow = new FlowLayoutWidget()
            {
                HAnchor = HAnchor.Stretch,
                VAnchor = VAnchor.Fit,
                Padding = 0,
            };

            rowContainer.AddChild(topRow);

            progressBar = new ProgressBar()
            {
                HAnchor     = HAnchor.Stretch,
                Height      = 2 * GuiWidget.DeviceScale,
                VAnchor     = VAnchor.Absolute | VAnchor.Bottom,
                FillColor   = theme.PrimaryAccentColor,
                BorderColor = Color.Transparent,
                Margin      = new BorderDouble(32, 7, theme.ButtonHeight * 2 + 14, 0),
                Visible     = !taskDetails.IsExpanded
            };
            rowContainer.AddChild(progressBar);

            expandButton = new ExpandCheckboxButton(!string.IsNullOrWhiteSpace(title) ? title : taskDetails.Title, theme, 10)
            {
                VAnchor         = VAnchor.Center | VAnchor.Fit,
                HAnchor         = HAnchor.Stretch,
                Checked         = false,
                Padding         = 0,
                AlwaysShowArrow = true
            };
            expandButton.CheckedStateChanged += (s, e) =>
            {
                taskDetails.IsExpanded = expandButton.Checked;
                SetExpansionMode(theme, detailsPanel, expandButton.Checked);
            };
            topRow.AddChild(expandButton);

            IconButton resumeButton = null;

            var pauseButton = new IconButton(StaticData.Instance.LoadIcon("fa-pause_12.png", 12, 12, theme.InvertIcons), theme)
            {
                Margin      = theme.ButtonSpacing,
                Enabled     = taskDetails.Options?.PauseAction != null,
                ToolTipText = taskDetails.Options?.PauseToolTip ?? "Pause".Localize()
            };

            if (taskDetails.Options?.IsPaused != null)
            {
                RunningInterval runningInterval = null;
                runningInterval = UiThread.SetInterval(() =>
                {
                    if (taskDetails.Options.IsPaused())
                    {
                        pauseButton.Visible  = false;
                        resumeButton.Visible = true;
                    }
                    else
                    {
                        pauseButton.Visible  = true;
                        resumeButton.Visible = false;
                    }
                    if (this.HasBeenClosed)
                    {
                        UiThread.ClearInterval(runningInterval);
                    }
                }, .2);
            }
            pauseButton.Click += (s, e) =>
            {
                taskDetails.Options?.PauseAction();
                pauseButton.Visible  = false;
                resumeButton.Visible = true;
            };
            topRow.AddChild(pauseButton);

            resumeButton = new IconButton(StaticData.Instance.LoadIcon("fa-play_12.png", 12, 12, theme.InvertIcons), theme)
            {
                Visible     = false,
                Margin      = theme.ButtonSpacing,
                ToolTipText = taskDetails.Options?.ResumeToolTip ?? "Resume".Localize(),
                Name        = "Resume Task Button"
            };
            resumeButton.Click += (s, e) =>
            {
                taskDetails.Options?.ResumeAction();
                pauseButton.Visible  = true;
                resumeButton.Visible = false;
            };
            topRow.AddChild(resumeButton);

            var stopButton = new IconButton(StaticData.Instance.LoadIcon("fa-stop_12.png", 12, 12, theme.InvertIcons), theme)
            {
                Margin      = theme.ButtonSpacing,
                Name        = "Stop Task Button",
                ToolTipText = taskDetails.Options?.StopToolTip ?? "Cancel".Localize()
            };

            stopButton.Click += (s, e) =>
            {
                var stopAction = taskDetails.Options?.StopAction;
                if (stopAction == null)
                {
                    taskDetails.CancelTask();
                }
                else
                {
                    stopAction.Invoke(() =>
                    {
                        stopButton.Enabled = true;
                    });
                }

                stopButton.Enabled = false;
            };
            topRow.AddChild(stopButton);

            this.AddChild(detailsPanel);

            // Add rich progress controls
            if (taskDetails.Options?.RichProgressWidget?.Invoke() is GuiWidget guiWidget)
            {
                detailsPanel.AddChild(guiWidget);
            }
            else
            {
                expandButton.Expandable = false;
            }

            if (taskDetails.Options?.ReadOnlyReporting == true)
            {
                stopButton.Visible   = false;
                pauseButton.Visible  = false;
                resumeButton.Visible = false;

                // Ensure the top row is as big as it would be with buttons
                topRow.MinimumSize = new Vector2(0, resumeButton.Height);
            }

            SetExpansionMode(theme, detailsPanel, taskDetails.IsExpanded);

            taskDetails.ProgressChanged += TaskDetails_ProgressChanged;
        }
        protected override IEnumerator <WizardPage> GetPages()
        {
            var extruderCount = printer.Settings.GetValue <int>(SettingsKey.extruder_count);

            var levelingStrings = new LevelingStrings();

            var title        = "Unload Material".Localize();
            var instructions = "Please select the material you want to unload.".Localize();

            if (extruderCount > 1)
            {
                instructions = "Please select the material you want to unload from extruder {0}.".Localize().FormatWith(extruderIndex + 1);
            }

            // select the material
            yield return(new SelectMaterialPage(this, title, instructions, "Unload".Localize(), extruderIndex, false, false)
            {
                WindowTitle = Title
            });

            var theme = ApplicationController.Instance.Theme;

            // wait for extruder to heat
            {
                var targetHotendTemp = printer.Settings.Helpers.ExtruderTargetTemperature(extruderIndex);
                var temps            = new double[4];
                temps[extruderIndex] = targetHotendTemp;
                yield return(new WaitForTempPage(
                                 this,
                                 "Waiting For Printer To Heat".Localize(),
                                 (extruderCount > 1 ? "Waiting for hotend {0} to heat to ".Localize().FormatWith(extruderIndex + 1) : "Waiting for the hotend to heat to ".Localize()) + targetHotendTemp + "°C.\n"
                                 + "This will ensure that filament is able to flow through the nozzle.".Localize() + "\n"
                                 + "\n"
                                 + "Warning! The tip of the nozzle will be HOT!".Localize() + "\n"
                                 + "Avoid contact with your skin.".Localize(),
                                 0,
                                 temps));
            }

            // show the unloading filament progress bar
            {
                int extruderPriorToUnload = printer.Connection.ActiveExtruderIndex;

                RunningInterval runningGCodeCommands  = null;
                var             unloadingFilamentPage = new WizardPage(this, "Unloading Filament".Localize(), "")
                {
                    PageLoad = (page) =>
                    {
                        page.NextButton.Enabled = false;

                        // add the progress bar
                        var holder = new FlowLayoutWidget()
                        {
                            Margin = new BorderDouble(3, 0, 0, 10),
                        };
                        var progressBar = new ProgressBar((int)(150 * GuiWidget.DeviceScale), (int)(15 * GuiWidget.DeviceScale))
                        {
                            FillColor       = theme.PrimaryAccentColor,
                            BorderColor     = theme.TextColor,
                            BackgroundColor = Color.White,
                            VAnchor         = VAnchor.Center,
                        };
                        var progressBarText = new TextWidget("", pointSize: 10, textColor: theme.TextColor)
                        {
                            AutoExpandBoundsToText = true,
                            Margin  = new BorderDouble(5, 0, 0, 0),
                            VAnchor = VAnchor.Center,
                        };
                        holder.AddChild(progressBar);
                        holder.AddChild(progressBarText);
                        page.ContentRow.AddChild(holder);

                        if (extruderCount > 1)
                        {
                            // reset the extruder that was active
                            printer.Connection.QueueLine($"T{extruderIndex}");
                        }

                        // reset the extrusion amount so this is easier to debug
                        printer.Connection.QueueLine("G92 E0");

                        // Allow extrusion at any temperature. S0 only works on Marlin S1 works on repetier and marlin
                        printer.Connection.QueueLine("M302 S1");
                        // send a dwell to empty out the current move commands
                        printer.Connection.QueueLine("G4 P1");
                        // put in a second one to use as a signal for the first being processed
                        printer.Connection.QueueLine("G4 P1");
                        // start heating up the extruder
                        if (extruderIndex == 0)
                        {
                            printer.Connection.SetTargetHotendTemperature(0, printer.Settings.GetValue <double>(SettingsKey.temperature));
                        }
                        else
                        {
                            printer.Connection.SetTargetHotendTemperature(extruderIndex, printer.Settings.GetValue <double>(SettingsKey.temperature + extruderIndex.ToString()));
                        }

                        var loadingSpeedMmPerS     = printer.Settings.GetValue <double>(SettingsKey.load_filament_speed);
                        var loadLengthMm           = Math.Max(1, printer.Settings.GetValue <double>(SettingsKey.unload_filament_length));
                        var remainingLengthMm      = loadLengthMm;
                        var maxSingleExtrudeLength = 20;

                        Stopwatch runningTime   = null;
                        var       expectedTimeS = loadLengthMm / loadingSpeedMmPerS;

                        // push some out first
                        var currentE = printer.Connection.CurrentExtruderDestination;
                        printer.Connection.QueueLine("G1 E{0:0.###} F600".FormatWith(currentE + 15));

                        runningGCodeCommands = UiThread.SetInterval(() =>
                        {
                            if (printer.Connection.NumQueuedCommands == 0)
                            {
                                if (runningTime == null)
                                {
                                    runningTime = Stopwatch.StartNew();
                                }

                                if (progressBar.RatioComplete < 1 ||
                                    remainingLengthMm >= .001)
                                {
                                    var thisExtrude = Math.Min(remainingLengthMm, maxSingleExtrudeLength);
                                    currentE        = printer.Connection.CurrentExtruderDestination;
                                    printer.Connection.QueueLine("G1 E{0:0.###} F{1}".FormatWith(currentE - thisExtrude, loadingSpeedMmPerS * 60));
                                    // make sure we wait for this command to finish so we can cancel the unload at any time without delay
                                    printer.Connection.QueueLine("G4 P1");
                                    remainingLengthMm        -= thisExtrude;
                                    var elapsedSeconds        = runningTime.Elapsed.TotalSeconds;
                                    progressBar.RatioComplete = Math.Min(1, elapsedSeconds / expectedTimeS);
                                    progressBarText.Text      = $"Unloading Filament: {Math.Max(0, expectedTimeS - elapsedSeconds):0}";
                                }
                            }

                            if (progressBar.RatioComplete == 1 &&
                                remainingLengthMm <= .001)
                            {
                                UiThread.ClearInterval(runningGCodeCommands);
                                page.NextButton.InvokeClick();
                            }
                        },
                                                                    .1);
                    },
                    PageClose = () =>
                    {
                        UiThread.ClearInterval(runningGCodeCommands);
                    }
                };
                unloadingFilamentPage.Closed += (s, e) =>
                {
                    UiThread.ClearInterval(runningGCodeCommands);
                    if (extruderCount > 1)
                    {
                        // reset the extruder that was active
                        printer.Connection.QueueLine($"T{extruderPriorToUnload}");
                    }
                    printer.Connection.QueueLine("G92 E0");
                };

                yield return(unloadingFilamentPage);
            }

            // put up a success message
            yield return(new DoneUnloadingPage(this, extruderIndex));
        }
Example #12
0
        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));
        }
Example #13
0
        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);
        }
Example #14
0
        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);
        }