Ejemplo n.º 1
0
            public CriteriaRow(string itemText, string fixitText, string errorText, bool succeeded, Action fixAction, ThemeConfig theme)
                : base(FlowDirection.LeftToRight)
            {
                HAnchor = HAnchor.Stretch;
                VAnchor = VAnchor.Absolute;

                ErrorText = errorText;

                base.Height = 40;

                base.AddChild(new TextWidget(string.Format("  {0}. {1}", criteriaCount + 1, itemText))
                {
                    TextColor = stillSuccessful ? Color.White : disabledTextColor,
                    VAnchor   = VAnchor.Center
                });

                if (stillSuccessful && !succeeded)
                {
                    ActiveErrorItem = this;
                }

                base.AddChild(new HorizontalSpacer());

                if (stillSuccessful)
                {
                    if (succeeded)
                    {
                        // Add checkmark image
                        AddSuccessIcon();
                    }
                    else
                    {
                        // Add Fix button
                        var button = theme.CreateDialogButton(fixitText);
                        button.VAnchor = VAnchor.Center;
                        button.Padding = new BorderDouble(3, 8);
                        button.Click  += (s, e) => fixAction?.Invoke();
                        base.AddChild(button);
                    }
                }

                if (stillSuccessful)
                {
                    this.BackgroundColor = (criteriaCount % 2 == 0) ? Color.Gray : toggleColor;
                }
                else
                {
                    this.BackgroundColor = disabledBackColor;
                }

                stillSuccessful &= succeeded;

                criteriaCount++;
            }
Ejemplo n.º 2
0
            public MessageBoxPage(Action <bool> callback, string message, string caption, MessageType messageType, GuiWidget[] extraWidgetsToAdd, double width, double height, string yesOk, string noCancel, ThemeConfig theme, bool useMarkdown = false)
                : base((noCancel == "") ? "No".Localize() : noCancel)
            {
                this.WindowSize = new Vector2(width * GuiWidget.DeviceScale, height * GuiWidget.DeviceScale);

                if (yesOk == "")
                {
                    yesOk = (messageType == MessageType.OK) ? "Ok".Localize() : "Yes".Localize();
                }

                this.HeaderText = caption;
                // this.IsModal = true;

                responseCallback = callback;
                unwrappedMessage = message;

                if (useMarkdown)
                {
                    contentRow.AddChild(messageContainer = new MarkdownWidget(theme)
                    {
                        Markdown = message,
                    });
                }
                else
                {
                    var scrollable = new ScrollableWidget(true);
                    scrollable.AnchorAll();
                    scrollable.ScrollArea.HAnchor = HAnchor.Stretch;
                    contentRow.AddChild(scrollable);

                    scrollable.AddChild(messageContainer = new TextWidget(message, textColor: theme.TextColor, pointSize: 12)
                    {
                        AutoExpandBoundsToText = true,
                        HAnchor = HAnchor.Left
                    });
                }

                if (extraWidgetsToAdd != null)
                {
                    foreach (GuiWidget widget in extraWidgetsToAdd)
                    {
                        contentRow.AddChild(widget);
                    }
                }

                var affirmativeButton = theme.CreateDialogButton(yesOk);

                affirmativeButton.Click += (s, e) =>
                {
                    // If applicable, invoke the callback
                    responseCallback?.Invoke(true);
                    haveResponded = true;

                    this.DialogWindow.Close();
                };

                this.AddPageAction(affirmativeButton, messageType != MessageType.YES_NO_WITHOUT_HIGHLIGHT);

                switch (messageType)
                {
                case MessageType.YES_NO_WITHOUT_HIGHLIGHT:
                case MessageType.YES_NO:
                    this.WindowTitle       = "MatterControl - " + "Please Confirm".Localize();
                    affirmativeButton.Name = "Yes Button";
                    this.SetCancelButtonName("No Button");
                    break;

                case MessageType.OK:
                    this.WindowTitle       = "MatterControl - " + "Alert".Localize();
                    affirmativeButton.Name = "Ok Button";
                    this.HideCancelButton();
                    break;

                default:
                    throw new NotImplementedException();
                }

                this.AdjustTextWrap();
            }
Ejemplo n.º 3
0
        public DialogPage(string cancelButtonText = null, bool useOverflowBar = false)
            : base(FlowDirection.TopToBottom)
        {
            theme = ApplicationController.Instance.Theme;

            this.HAnchor         = HAnchor.Stretch;
            this.VAnchor         = VAnchor.Stretch;
            this.BackgroundColor = theme.ActiveTabColor;

            if (cancelButtonText == null)
            {
                cancelButtonText = "Cancel".Localize();
            }

            cancelButton        = theme.CreateDialogButton(cancelButtonText);
            cancelButton.Margin = new BorderDouble(left: 3);
            cancelButton.Name   = "Cancel Wizard Button";

            // Create the header row for the widget
            if (useOverflowBar)
            {
                headerRow = new OverflowBar(theme)
                {
                    Name    = "HeaderRow",
                    Margin  = new BorderDouble(0, 3, 0, 0),
                    Padding = new BorderDouble(0, 12),
                    HAnchor = HAnchor.Stretch,
                    VAnchor = VAnchor.Fit
                };
            }
            else
            {
                headerRow = new FlowLayoutWidget(FlowDirection.LeftToRight)
                {
                    Name    = "HeaderRow",
                    Margin  = new BorderDouble(0, 3, 0, 0),
                    Padding = new BorderDouble(0, 12),
                    HAnchor = HAnchor.Stretch,
                    VAnchor = VAnchor.Fit
                };
            }

            this.AddChild(headerRow);

            headerLabel = new TextWidget("Setup Wizard".Localize(), pointSize: 24, textColor: theme.Colors.PrimaryAccentColor)
            {
                AutoExpandBoundsToText = true,
                EllipsisIfClipped      = true,
                HAnchor = HAnchor.Stretch
            };
            headerRow.AddChild(headerLabel);

            // Create the main control container
            contentRow = new FlowLayoutWidget(FlowDirection.TopToBottom)
            {
                Padding         = new BorderDouble(10),
                BackgroundColor = theme.MinimalShade,
                HAnchor         = HAnchor.Stretch,
                VAnchor         = VAnchor.Stretch
            };
            this.AddChild(contentRow);

            // Create the footer (button) container
            footerRow = new FlowLayoutWidget(FlowDirection.LeftToRight)
            {
                HAnchor = HAnchor.Fit | HAnchor.Right,
                VAnchor = VAnchor.Fit,
                Margin  = new BorderDouble(0, 6),
                Padding = new BorderDouble(top: 4, bottom: 2)
            };
            this.AddChild(footerRow);

#if !__ANDROID__
            headerRow.Padding = new BorderDouble(0, 3, 0, 3);

            headerLabel.PointSize = 14;
            headerLabel.TextColor = theme.Colors.PrimaryTextColor;
            contentRow.Padding    = new BorderDouble(5);

            footerRow.Padding = 0;
            footerRow.Margin  = new BorderDouble(top: theme.DefaultContainerPadding);
#endif
        }
Ejemplo n.º 4
0
        public TerminalWidget(PrinterConfig printer, ThemeConfig theme)
            : base(FlowDirection.TopToBottom)
        {
            this.printer = printer;
            this.Name    = "TerminalWidget";
            this.Padding = new BorderDouble(5, 0);

            // Header
            var headerRow = new FlowLayoutWidget(FlowDirection.LeftToRight)
            {
                HAnchor = HAnchor.Left | HAnchor.Stretch,
                Padding = new BorderDouble(0, 8)
            };

            this.AddChild(headerRow);

            headerRow.AddChild(CreateVisibilityOptions(theme));

            autoUppercase = new CheckBox("Auto Uppercase".Localize(), textSize: theme.DefaultFontSize)
            {
                Margin    = new BorderDouble(left: 25),
                Checked   = UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalAutoUppercase, true),
                TextColor = theme.TextColor,
                VAnchor   = VAnchor.Center
            };
            autoUppercase.CheckedStateChanged += (s, e) =>
            {
                UserSettings.Instance.Fields.SetBool(UserSettingsKey.TerminalAutoUppercase, autoUppercase.Checked);
            };
            headerRow.AddChild(autoUppercase);

            // Body
            var bodyRow = new FlowLayoutWidget()
            {
                Margin  = new BorderDouble(bottom: 4),
                HAnchor = HAnchor.Stretch,
                VAnchor = VAnchor.Stretch
            };

            this.AddChild(bodyRow);

            textScrollWidget = new TextScrollWidget(printer, printer.Connection.TerminalLog)
            {
                BackgroundColor = theme.MinimalShade,
                TextColor       = theme.TextColor,
                HAnchor         = HAnchor.Stretch,
                VAnchor         = VAnchor.Stretch,
                Margin          = 0,
                Padding         = new BorderDouble(3, 0)
            };
            bodyRow.AddChild(textScrollWidget);
            bodyRow.AddChild(new TextScrollBar(textScrollWidget, 15)
            {
                ThumbColor      = theme.AccentMimimalOverlay,
                BackgroundColor = theme.SlightShade,
                Margin          = 0
            });

            textScrollWidget.LineFilterFunction = lineData =>
            {
                var line       = lineData.Line;
                var output     = lineData.Direction == TerminalLine.MessageDirection.ToPrinter;
                var outputLine = line;

                var lineWithoutChecksum = GCodeFile.GetLineWithoutChecksum(line);

                // and set this as the output if desired
                if (output &&
                    !UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowChecksum, true))
                {
                    outputLine = lineWithoutChecksum;
                }

                if (!output &&
                    lineWithoutChecksum == "ok" &&
                    !UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowOks, true))
                {
                    return(null);
                }
                else if (output &&
                         lineWithoutChecksum.StartsWith("M105") &&
                         !UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowTempRequests, true))
                {
                    return(null);
                }
                else if (output &&
                         (lineWithoutChecksum.StartsWith("G0 ") || lineWithoutChecksum.StartsWith("G1 ")) &&
                         !UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowMovementRequests, true))
                {
                    return(null);
                }
                else if (!output &&
                         (lineWithoutChecksum.StartsWith("T") || lineWithoutChecksum.StartsWith("ok T")) &&
                         !UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowTempResponse, true))
                {
                    return(null);
                }
                else if (!output &&
                         lineWithoutChecksum == "wait" &&
                         !UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowWaitResponse, false))
                {
                    return(null);
                }

                if (UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalShowInputOutputMarks, true))
                {
                    switch (lineData.Direction)
                    {
                    case TerminalLine.MessageDirection.FromPrinter:
                        outputLine = "→ " + outputLine;
                        break;

                    case TerminalLine.MessageDirection.ToPrinter:
                        outputLine = "← " + outputLine;
                        break;

                    case TerminalLine.MessageDirection.ToTerminal:
                        outputLine = "* " + outputLine;
                        break;
                    }
                }

                return(outputLine);
            };

            // Input Row
            var inputRow = new FlowLayoutWidget(FlowDirection.LeftToRight)
            {
                BackgroundColor = this.BackgroundColor,
                HAnchor         = HAnchor.Stretch,
                Margin          = new BorderDouble(bottom: 2)
            };

            this.AddChild(inputRow);

            manualCommandTextEdit = new MHTextEditWidget("", theme, typeFace: ApplicationController.GetTypeFace(NamedTypeFace.Liberation_Mono))
            {
                Margin  = new BorderDouble(right: 3),
                HAnchor = HAnchor.Stretch,
                VAnchor = VAnchor.Bottom
            };
            manualCommandTextEdit.ActualTextEditWidget.EnterPressed += (s, e) =>
            {
                SendManualCommand();
            };
            manualCommandTextEdit.ActualTextEditWidget.KeyDown += (s, keyEvent) =>
            {
                bool changeToHistory = false;
                if (keyEvent.KeyCode == Keys.Up)
                {
                    commandHistoryIndex--;
                    if (commandHistoryIndex < 0)
                    {
                        commandHistoryIndex = 0;
                    }

                    changeToHistory = true;
                }
                else if (keyEvent.KeyCode == Keys.Down)
                {
                    commandHistoryIndex++;
                    if (commandHistoryIndex > commandHistory.Count - 1)
                    {
                        commandHistoryIndex = commandHistory.Count - 1;
                    }
                    else
                    {
                        changeToHistory = true;
                    }
                }
                else if (keyEvent.KeyCode == Keys.Escape)
                {
                    manualCommandTextEdit.Text = "";
                }

                if (changeToHistory && commandHistory.Count > 0)
                {
                    manualCommandTextEdit.Text = commandHistory[commandHistoryIndex];
                }
            };
            inputRow.AddChild(manualCommandTextEdit);

            // Footer
            var toolbarPadding = theme.ToolbarPadding;
            var footerRow      = new FlowLayoutWidget
            {
                HAnchor = HAnchor.Stretch,
                Padding = new BorderDouble(0, toolbarPadding.Bottom, toolbarPadding.Right, toolbarPadding.Top)
            };

            this.AddChild(footerRow);

            var sendButton = theme.CreateDialogButton("Send".Localize());

            sendButton.Margin = theme.ButtonSpacing;
            sendButton.Click += (s, e) =>
            {
                SendManualCommand();
            };
            footerRow.AddChild(sendButton);

            var clearButton = theme.CreateDialogButton("Clear".Localize());

            clearButton.Margin = theme.ButtonSpacing;
            clearButton.Click += (s, e) =>
            {
                printer.Connection.TerminalLog.Clear();
            };

            footerRow.AddChild(clearButton);

            var exportButton = theme.CreateDialogButton("Export".Localize());

            exportButton.Margin = theme.ButtonSpacing;
            exportButton.Click += (s, e) =>
            {
                UiThread.RunOnIdle(() =>
                {
                    AggContext.FileDialogs.SaveFileDialog(
                        new SaveFileDialogParams("Save as Text|*.txt")
                    {
                        Title             = "MatterControl: Terminal Log",
                        ActionButtonLabel = "Export",
                        FileName          = "print_log.txt"
                    },
                        (saveParams) =>
                    {
                        if (!string.IsNullOrEmpty(saveParams.FileName))
                        {
                            string filePathToSave = saveParams.FileName;

                            if (filePathToSave != null && filePathToSave != "")
                            {
                                try
                                {
                                    textScrollWidget.WriteToFile(filePathToSave);
                                }
                                catch (UnauthorizedAccessException ex)
                                {
                                    Debug.Print(ex.Message);

                                    printer.Connection.TerminalLog.WriteLine("");
                                    printer.Connection.TerminalLog.WriteLine("WARNING: Write Failed!".Localize());
                                    printer.Connection.TerminalLog.WriteLine("Can't access".Localize() + " " + filePathToSave);
                                    printer.Connection.TerminalLog.WriteLine("");

                                    UiThread.RunOnIdle(() =>
                                    {
                                        StyledMessageBox.ShowMessageBox(ex.Message, "Couldn't save file".Localize());
                                    });
                                }
                            }
                        }
                    });
                });
            };
            footerRow.AddChild(exportButton);

            footerRow.AddChild(new HorizontalSpacer());

            this.AnchorAll();
        }
Ejemplo n.º 5
0
        public EditLevelingSettingsPage(PrinterConfig printer, ThemeConfig theme)
        {
            this.printer = printer;

            this.WindowTitle = "Leveling Settings".Localize();
            this.HeaderText  = "Sampled Positions".Localize();

            var scrollableWidget = new ScrollableWidget()
            {
                AutoScroll = true,
                HAnchor    = HAnchor.Stretch,
                VAnchor    = VAnchor.Stretch,
            };

            scrollableWidget.ScrollArea.HAnchor = HAnchor.Stretch;
            contentRow.AddChild(scrollableWidget);

            // No right padding removes unexpected spacing to the right of scrollbar
            contentRow.Padding = contentRow.Padding.Clone(right: 0);

            var column = new FlowLayoutWidget(FlowDirection.TopToBottom)
            {
                HAnchor = HAnchor.Stretch,
                Padding = new BorderDouble(right: theme.DefaultContainerPadding + 4)
            };

            scrollableWidget.AddChild(column);

            var positions = new List <Vector3>();

            PrintLevelingData levelingData = printer.Settings.Helpers.GetPrintLevelingData();

            for (int i = 0; i < levelingData.SampledPositions.Count; i++)
            {
                positions.Add(levelingData.SampledPositions[i]);
            }

            int tab_index = 0;

            for (int row = 0; row < positions.Count; row++)
            {
                var leftRightEdit = new FlowLayoutWidget
                {
                    Padding = new BorderDouble(3),
                    HAnchor = HAnchor.Stretch
                };

                var positionLabel = new TextWidget("{0} {1,-5}".FormatWith("Position".Localize(), row + 1), textColor: theme.TextColor);

                positionLabel.VAnchor = VAnchor.Center;
                leftRightEdit.AddChild(positionLabel);

                for (int axis = 0; axis < 3; axis++)
                {
                    leftRightEdit.AddChild(new HorizontalSpacer());

                    string axisName = "x";
                    if (axis == 1)
                    {
                        axisName = "y";
                    }
                    else if (axis == 2)
                    {
                        axisName = "z";
                    }

                    leftRightEdit.AddChild(
                        new TextWidget($"  {axisName}: ", textColor: theme.TextColor)
                    {
                        VAnchor = VAnchor.Center
                    });

                    int linkCompatibleRow  = row;
                    int linkCompatibleAxis = axis;

                    MHNumberEdit valueEdit = new MHNumberEdit(positions[linkCompatibleRow][linkCompatibleAxis], theme, allowNegatives: true, allowDecimals: true, pixelWidth: 60, tabIndex: tab_index++)
                    {
                        Name = $"{axisName} Position {row}"
                    };
                    valueEdit.ActuallNumberEdit.InternalTextEditWidget.EditComplete += (sender, e) =>
                    {
                        Vector3 position = positions[linkCompatibleRow];
                        position[linkCompatibleAxis] = valueEdit.ActuallNumberEdit.Value;
                        positions[linkCompatibleRow] = position;
                    };

                    valueEdit.Margin = new BorderDouble(3);
                    leftRightEdit.AddChild(valueEdit);
                }

                column.AddChild(leftRightEdit);
            }

            var savePresetsButton = theme.CreateDialogButton("Save".Localize());

            savePresetsButton.Name   = "Save Leveling Button";
            savePresetsButton.Click += (s, e) => UiThread.RunOnIdle(() =>
            {
                PrintLevelingData newLevelingData = printer.Settings.Helpers.GetPrintLevelingData();

                for (int i = 0; i < newLevelingData.SampledPositions.Count; i++)
                {
                    newLevelingData.SampledPositions[i] = positions[i];
                }

                printer.Settings.Helpers.SetPrintLevelingData(newLevelingData);
                this.DialogWindow.Close();
            });
            this.AddPageAction(savePresetsButton);

            var exportButton = theme.CreateDialogButton("Export".Localize());

            exportButton.Click += (s, e) => {
                UiThread.RunOnIdle(this.ExportSettings, .1);
            };
            this.AddPageAction(exportButton);
        }
Ejemplo n.º 6
0
        public TerminalWidget(PrinterConfig printer, ThemeConfig theme)
            : base(FlowDirection.TopToBottom)
        {
            this.printer = printer;
            this.Name    = "TerminalWidget";
            this.Padding = new BorderDouble(5, 0);

            // Header
            var headerRow = new FlowLayoutWidget(FlowDirection.LeftToRight)
            {
                HAnchor = HAnchor.Left | HAnchor.Stretch,
                Padding = new BorderDouble(0, 8)
            };

            this.AddChild(headerRow);

            filterOutput = new CheckBox("Filter Output".Localize(), textSize: theme.DefaultFontSize)
            {
                TextColor = theme.TextColor,
                VAnchor   = VAnchor.Bottom,
            };
            filterOutput.CheckedStateChanged += (s, e) =>
            {
                if (filterOutput.Checked)
                {
                    textScrollWidget.SetLineStartFilter(new string[] { "<-wait", "<-ok", "<-T" });
                }
                else
                {
                    textScrollWidget.SetLineStartFilter(null);
                }

                UserSettings.Instance.Fields.SetBool(UserSettingsKey.TerminalFilterOutput, filterOutput.Checked);
            };
            headerRow.AddChild(filterOutput);

            autoUppercase = new CheckBox("Auto Uppercase".Localize(), textSize: theme.DefaultFontSize)
            {
                Margin    = new BorderDouble(left: 25),
                Checked   = UserSettings.Instance.Fields.GetBool(UserSettingsKey.TerminalAutoUppercase, true),
                TextColor = theme.TextColor,
                VAnchor   = VAnchor.Bottom
            };
            autoUppercase.CheckedStateChanged += (s, e) =>
            {
                UserSettings.Instance.Fields.SetBool(UserSettingsKey.TerminalAutoUppercase, autoUppercase.Checked);
            };
            headerRow.AddChild(autoUppercase);

            // Body
            var bodyRow = new FlowLayoutWidget()
            {
                Margin  = new BorderDouble(bottom: 4),
                HAnchor = HAnchor.Stretch,
                VAnchor = VAnchor.Stretch
            };

            this.AddChild(bodyRow);

            textScrollWidget = new TextScrollWidget(printer, printer.Connection.TerminalLog.PrinterLines)
            {
                BackgroundColor = theme.MinimalShade,
                TextColor       = theme.TextColor,
                HAnchor         = HAnchor.Stretch,
                VAnchor         = VAnchor.Stretch,
                Margin          = 0,
                Padding         = new BorderDouble(3, 0)
            };
            bodyRow.AddChild(textScrollWidget);
            bodyRow.AddChild(new TextScrollBar(textScrollWidget, 15)
            {
                ThumbColor      = theme.AccentMimimalOverlay,
                BackgroundColor = theme.SlightShade,
                Margin          = 0
            });

            // Input Row
            var inputRow = new FlowLayoutWidget(FlowDirection.LeftToRight)
            {
                BackgroundColor = this.BackgroundColor,
                HAnchor         = HAnchor.Stretch,
                Margin          = new BorderDouble(bottom: 2)
            };

            this.AddChild(inputRow);

            manualCommandTextEdit = new MHTextEditWidget("", theme, typeFace: ApplicationController.GetTypeFace(NamedTypeFace.Liberation_Mono))
            {
                Margin  = new BorderDouble(right: 3),
                HAnchor = HAnchor.Stretch,
                VAnchor = VAnchor.Bottom
            };
            manualCommandTextEdit.ActualTextEditWidget.EnterPressed += (s, e) =>
            {
                SendManualCommand();
            };
            manualCommandTextEdit.ActualTextEditWidget.KeyDown += (s, keyEvent) =>
            {
                bool changeToHistory = false;
                if (keyEvent.KeyCode == Keys.Up)
                {
                    commandHistoryIndex--;
                    if (commandHistoryIndex < 0)
                    {
                        commandHistoryIndex = 0;
                    }
                    changeToHistory = true;
                }
                else if (keyEvent.KeyCode == Keys.Down)
                {
                    commandHistoryIndex++;
                    if (commandHistoryIndex > commandHistory.Count - 1)
                    {
                        commandHistoryIndex = commandHistory.Count - 1;
                    }
                    else
                    {
                        changeToHistory = true;
                    }
                }
                else if (keyEvent.KeyCode == Keys.Escape)
                {
                    manualCommandTextEdit.Text = "";
                }

                if (changeToHistory && commandHistory.Count > 0)
                {
                    manualCommandTextEdit.Text = commandHistory[commandHistoryIndex];
                }
            };
            inputRow.AddChild(manualCommandTextEdit);

            // Footer
            var toolbarPadding = theme.ToolbarPadding;
            var footerRow      = new FlowLayoutWidget
            {
                HAnchor = HAnchor.Stretch,
                Padding = new BorderDouble(0, toolbarPadding.Bottom, toolbarPadding.Right, toolbarPadding.Top)
            };

            this.AddChild(footerRow);

            var sendButton = theme.CreateDialogButton("Send".Localize());

            sendButton.Margin = theme.ButtonSpacing;
            sendButton.Click += (s, e) =>
            {
                SendManualCommand();
            };
            footerRow.AddChild(sendButton);

            var clearButton = theme.CreateDialogButton("Clear".Localize());

            clearButton.Margin = theme.ButtonSpacing;
            clearButton.Click += (s, e) =>
            {
                printer.Connection.TerminalLog.Clear();
            };
            footerRow.AddChild(clearButton);

            var exportButton = theme.CreateDialogButton("Export".Localize());

            exportButton.Margin = theme.ButtonSpacing;
            exportButton.Click += (s, e) =>
            {
                UiThread.RunOnIdle(() =>
                {
                    AggContext.FileDialogs.SaveFileDialog(
                        new SaveFileDialogParams("Save as Text|*.txt")
                    {
                        Title             = "MatterControl: Terminal Log",
                        ActionButtonLabel = "Export",
                        FileName          = "print_log.txt"
                    },
                        (saveParams) =>
                    {
                        if (!string.IsNullOrEmpty(saveParams.FileName))
                        {
                            string filePathToSave = saveParams.FileName;
                            if (filePathToSave != null && filePathToSave != "")
                            {
                                try
                                {
                                    textScrollWidget.WriteToFile(filePathToSave);
                                }
                                catch (UnauthorizedAccessException ex)
                                {
                                    Debug.Print(ex.Message);

                                    printer.Connection.TerminalLog.PrinterLines.Add("");
                                    printer.Connection.TerminalLog.PrinterLines.Add(writeFaildeWaring);
                                    printer.Connection.TerminalLog.PrinterLines.Add(cantAccessPath.FormatWith(filePathToSave));
                                    printer.Connection.TerminalLog.PrinterLines.Add("");

                                    UiThread.RunOnIdle(() =>
                                    {
                                        StyledMessageBox.ShowMessageBox(ex.Message, "Couldn't save file".Localize());
                                    });
                                }
                            }
                        }
                    });
                });
            };
            footerRow.AddChild(exportButton);

            footerRow.AddChild(new HorizontalSpacer());

            this.AnchorAll();
        }