public ViewControls3D(PartWorkspace workspace, ThemeConfig theme, UndoBuffer undoBuffer, bool isPrinterType, bool showPrintButton)
            : base(theme)
        {
            this.theme             = theme;
            this.undoBuffer        = undoBuffer;
            this.ActionArea.Click += (s, e) =>
            {
                view3DWidget.Object3DControlLayer.Focus();
            };

            this.OverflowButton.ToolTipText = "Tool Bar Overflow".Localize();

            this.OverflowButton.DynamicPopupContent = () =>
            {
                bool IncludeInMenu(SceneOperation operation)
                {
                    foreach (var widget in this.ActionArea.Children.Where(c => !c.Visible && !ignoredInMenuTypes.Contains(c.GetType())))
                    {
                        if (operationButtons.TryGetValue(widget, out SceneOperation buttonOperation) &&
                            buttonOperation == operation)
                        {
                            return(true);
                        }
                    }

                    return(false);
                }

                return(SceneOperations.GetToolbarOverflowMenu(AppContext.MenuTheme, sceneContext, IncludeInMenu));
            };

            this.IsPrinterMode = isPrinterType;
            this.sceneContext  = workspace.SceneContext;
            this.workspace     = workspace;

            string iconPath;

            this.AddChild(CreateAddButton(sceneContext, theme));

            this.AddChild(new ToolbarSeparator(theme.GetBorderColor(50), theme.SeparatorMargin));

            bedMenuButton = new PopupMenuButton(StaticData.Instance.LoadIcon("bed.png", 16, 16, theme.InvertIcons), theme)
            {
                Name        = "Bed Options Menu",
                ToolTipText = "Bed",
                Enabled     = true,
                Margin      = theme.ButtonSpacing,
                VAnchor     = VAnchor.Center,
                DrawArrow   = true
            };

            this.AddChild(bedMenuButton);

            this.AddChild(new ToolbarSeparator(theme.GetBorderColor(50), theme.SeparatorMargin));

            this.AddChild(CreateOpenButton(theme));

            this.AddChild(CreateSaveButton(theme));

            this.AddChild(new ToolbarSeparator(theme.GetBorderColor(50), theme.SeparatorMargin));

            undoButton = new IconButton(StaticData.Instance.LoadIcon("Undo_grey_16x.png", 16, 16, theme.InvertIcons), theme)
            {
                Name        = "3D View Undo",
                ToolTipText = "Undo".Localize(),
                Enabled     = false,
                Margin      = theme.ButtonSpacing,
                VAnchor     = VAnchor.Center
            };
            undoButton.Click += (sender, e) =>
            {
                sceneContext.Scene.Undo();
                view3DWidget.Object3DControlLayer.Focus();
            };
            this.AddChild(undoButton);

            redoButton = new IconButton(StaticData.Instance.LoadIcon("Redo_grey_16x.png", 16, 16, theme.InvertIcons), theme)
            {
                Name        = "3D View Redo",
                Margin      = theme.ButtonSpacing,
                ToolTipText = "Redo".Localize(),
                Enabled     = false,
                VAnchor     = VAnchor.Center
            };
            redoButton.Click += (sender, e) =>
            {
                sceneContext.Scene.Redo();
                view3DWidget.Object3DControlLayer.Focus();
            };
            this.AddChild(redoButton);

            if (showPrintButton)
            {
                var printButton = new TextButton("Print", theme)
                {
                    Name            = "Print Button",
                    BackgroundColor = theme.AccentMimimalOverlay
                };
                printButton.Click += (s, e) =>
                {
                    view3DWidget.PushToPrinterAndPrint();
                };
                this.AddChild(printButton);
            }

            this.AddChild(new ToolbarSeparator(theme.GetBorderColor(50), theme.SeparatorMargin));

            undoButton.Enabled = undoBuffer.UndoCount > 0;
            redoButton.Enabled = undoBuffer.RedoCount > 0;

            var buttonGroupA = new ObservableCollection <GuiWidget>();

            if (UserSettings.Instance.IsTouchScreen)
            {
                iconPath     = Path.Combine("ViewTransformControls", "rotate.png");
                rotateButton = new RadioIconButton(StaticData.Instance.LoadIcon(iconPath, 32, 32, theme.InvertIcons), theme)
                {
                    SiblingRadioButtonList = buttonGroupA,
                    ToolTipText            = "Rotate (Alt + Left Mouse)".Localize(),
                    Margin = theme.ButtonSpacing
                };
                rotateButton.Click += (s, e) => this.ActiveButton = ViewControls3DButtons.Rotate;
                buttonGroupA.Add(rotateButton);
                AddChild(rotateButton);

                iconPath        = Path.Combine("ViewTransformControls", "translate.png");
                translateButton = new RadioIconButton(StaticData.Instance.LoadIcon(iconPath, 32, 32, theme.InvertIcons), theme)
                {
                    SiblingRadioButtonList = buttonGroupA,
                    ToolTipText            = "Move (Shift + Left Mouse)".Localize(),
                    Margin = theme.ButtonSpacing
                };
                translateButton.Click += (s, e) => this.ActiveButton = ViewControls3DButtons.Translate;
                buttonGroupA.Add(translateButton);
                AddChild(translateButton);

                iconPath    = Path.Combine("ViewTransformControls", "scale.png");
                scaleButton = new RadioIconButton(StaticData.Instance.LoadIcon(iconPath, 32, 32, theme.InvertIcons), theme)
                {
                    SiblingRadioButtonList = buttonGroupA,
                    ToolTipText            = "Zoom (Ctrl + Left Mouse)".Localize(),
                    Margin = theme.ButtonSpacing
                };
                scaleButton.Click += (s, e) => this.ActiveButton = ViewControls3DButtons.Scale;
                buttonGroupA.Add(scaleButton);
                AddChild(scaleButton);

                rotateButton.Checked = true;

                // Add vertical separator
                this.AddChild(new ToolbarSeparator(theme.GetBorderColor(50), theme.SeparatorMargin));

                iconPath         = Path.Combine("ViewTransformControls", "partSelect.png");
                partSelectButton = new RadioIconButton(StaticData.Instance.LoadIcon(iconPath, 32, 32, theme.InvertIcons), theme)
                {
                    SiblingRadioButtonList = buttonGroupA,
                    ToolTipText            = "Select Part".Localize(),
                    Margin = theme.ButtonSpacing
                };
                partSelectButton.Click += (s, e) => this.ActiveButton = ViewControls3DButtons.PartSelect;
                buttonGroupA.Add(partSelectButton);
                AddChild(partSelectButton);
            }

            operationButtons = new Dictionary <GuiWidget, SceneOperation>();

            // Add Selected IObject3D -> Operations to toolbar
            foreach (var namedAction in SceneOperations.All)
            {
                if (namedAction is SceneSelectionSeparator)
                {
                    this.AddChild(new ToolbarSeparator(theme.GetBorderColor(50), theme.SeparatorMargin));
                    continue;
                }

                // add the create support before the align
                if (namedAction is OperationGroup group &&
                    group.Id == "Transform")
                {
                    this.AddChild(CreateSupportButton(theme));
                    this.AddChild(new ToolbarSeparator(theme.GetBorderColor(50), theme.SeparatorMargin));
                }

                GuiWidget button = null;

                if (namedAction is OperationGroup operationGroup)
                {
                    if (operationGroup.Collapse)
                    {
                        var defaultOperation = operationGroup.GetDefaultOperation();

                        PopupMenuButton groupButton = null;

                        groupButton = theme.CreateSplitButton(
                            new SplitButtonParams()
                        {
                            Icon          = defaultOperation.Icon(theme.InvertIcons),
                            DefaultAction = (menuButton) =>
                            {
                                defaultOperation.Action.Invoke(sceneContext);
                            },
                            DefaultActionTooltip = defaultOperation.HelpText ?? defaultOperation.Title,
                            ButtonName           = defaultOperation.Title,
                            ExtendPopupMenu      = (PopupMenu popupMenu) =>
                            {
                                foreach (var operation in operationGroup.Operations)
                                {
                                    var operationMenu = popupMenu.CreateMenuItem(operation.Title, operation.Icon?.Invoke(theme.InvertIcons));

                                    operationMenu.Enabled     = operation.IsEnabled(sceneContext);
                                    operationMenu.ToolTipText = operation.Title;

                                    if (!operationMenu.Enabled &&
                                        !string.IsNullOrEmpty(operation.HelpText))
                                    {
                                        operationMenu.ToolTipText += "\n\n" + operation.HelpText;
                                    }

                                    operationMenu.Click += (s, e) => UiThread.RunOnIdle(() =>
                                    {
                                        if (defaultOperation != operation)
                                        {
                                            // Update button
                                            var iconButton = groupButton.Children.OfType <IconButton>().First();
                                            iconButton.SetIcon(operation.Icon(theme.InvertIcons));
                                            iconButton.ToolTipText = operation.HelpText ?? operation.Title;

                                            UserSettings.Instance.set(operationGroup.GroupRecordId, operationGroup.Operations.IndexOf(operation).ToString());

                                            defaultOperation = operation;

                                            iconButton.Invalidate();
                                        }

                                        operation.Action?.Invoke(sceneContext);
                                    });
                                }
                            }
                        },
                            operationGroup);

                        button = groupButton;
                    }
                    else
                    {
                        if (!(this.ActionArea.Children.LastOrDefault() is ToolbarSeparator))
                        {
                            this.AddChild(new ToolbarSeparator(theme.GetBorderColor(50), theme.SeparatorMargin));
                        }

                        foreach (var operation in operationGroup.Operations)
                        {
                            var operationButton = new OperationIconButton(operation, sceneContext, theme);
                            operationButtons.Add(operationButton, operation);

                            this.AddChild(operationButton);
                        }

                        this.AddChild(new ToolbarSeparator(theme.GetBorderColor(50), theme.SeparatorMargin));
                    }
                }
                else if (namedAction.Icon != null)
                {
                    button = new IconButton(namedAction.Icon(theme.InvertIcons), theme)
                    {
                        Name            = namedAction.Title + " Button",
                        ToolTipText     = namedAction.Title,
                        Margin          = theme.ButtonSpacing,
                        BackgroundColor = theme.ToolbarButtonBackground,
                        HoverColor      = theme.ToolbarButtonHover,
                        MouseDownColor  = theme.ToolbarButtonDown,
                    };
                }
                else
                {
                    button = new TextButton(namedAction.Title, theme)
                    {
                        Name            = namedAction.Title + " Button",
                        Margin          = theme.ButtonSpacing,
                        BackgroundColor = theme.ToolbarButtonBackground,
                        HoverColor      = theme.ToolbarButtonHover,
                        MouseDownColor  = theme.ToolbarButtonDown,
                    };
                }

                if (button != null)
                {
                    operationButtons.Add(button, namedAction);

                    // Only bind Click event if not a SplitButton
                    if (!(button is PopupMenuButton))
                    {
                        button.Click += (s, e) => UiThread.RunOnIdle(() =>
                        {
                            namedAction.Action.Invoke(sceneContext);
                            var partTab = button.Parents <PartTabPage>().FirstOrDefault();
                            var view3D  = partTab.Descendants <View3DWidget>().FirstOrDefault();
                            view3D.Object3DControlLayer.Focus();
                        });
                    }

                    this.AddChild(button);
                }
            }

            // Register listeners
            undoBuffer.Changed += UndoBuffer_Changed;
            sceneContext.Scene.SelectionChanged += UpdateToolbarButtons;
            sceneContext.Scene.ItemsModified    += UpdateToolbarButtons;

            // Run on load
            UpdateToolbarButtons(null, null);
        }
        public ViewToolBarControls(PartWorkspace workspace, ThemeConfig theme, UndoBuffer undoBuffer, bool isPrinterType, bool showPrintButton)
        {
            this.undoBuffer    = undoBuffer;
            this.IsPrinterMode = isPrinterType;
            this.sceneContext  = workspace.SceneContext;
            this.workspace     = workspace;

            this.RowPadding      = 0;
            this.RowBoarder      = new BorderDouble(0, 0, 0, 1);
            this.RowBoarderColor = theme.GetBorderColor(50);

            var openLibraryButton = CreateOpenLibraryButton(sceneContext, theme);

            this.AddChild(CreateOpenFileButton(openLibraryButton, theme));

            this.AddChild(CreateSaveButton(theme));

            this.AddChild(new ToolbarSeparator(theme.GetBorderColor(50), theme.SeparatorMargin));

            bedMenuButton = new PopupMenuButton("Bed".Localize(), StaticData.Instance.LoadIcon("bed.png", 16, 16).SetToColor(theme.TextColor), theme)
            {
                Name      = "Bed Options Menu",
                Enabled   = true,
                Margin    = theme.ButtonSpacing,
                VAnchor   = VAnchor.Center,
                DrawArrow = true
            };

            this.AddChild(bedMenuButton);

            this.AddChild(new ToolbarSeparator(theme.GetBorderColor(50), theme.SeparatorMargin));

            undoButton = new IconButton(StaticData.Instance.LoadIcon("undo.png", 16, 16).SetToColor(theme.TextColor), theme)
            {
                Name        = "3D View Undo",
                ToolTipText = "Undo".Localize(),
                Enabled     = false,
                Margin      = theme.ButtonSpacing,
                VAnchor     = VAnchor.Center
            };
            undoButton.Click += (sender, e) =>
            {
                sceneContext.Scene.Undo();
                view3DWidget.Object3DControlLayer.Focus();
            };
            this.AddChild(undoButton);

            redoButton = new IconButton(StaticData.Instance.LoadIcon("redo.png", 16, 16).SetToColor(theme.TextColor), theme)
            {
                Name        = "3D View Redo",
                Margin      = theme.ButtonSpacing,
                ToolTipText = "Redo".Localize(),
                Enabled     = false,
                VAnchor     = VAnchor.Center
            };
            redoButton.Click += (sender, e) =>
            {
                sceneContext.Scene.Redo();
                view3DWidget.Object3DControlLayer.Focus();
            };
            this.AddChild(redoButton);

            if (showPrintButton)
            {
                var printButton = new TextButton("Print", theme)
                {
                    Name            = "Print Button",
                    BackgroundColor = theme.AccentMimimalOverlay
                };
                printButton.Click += (s, e) =>
                {
                    view3DWidget.PushToPrinterAndPrint();
                };
                this.AddChild(printButton);
            }

            this.AddChild(new ToolbarSeparator(theme.GetBorderColor(50), theme.SeparatorMargin));

            undoButton.Enabled = undoBuffer.UndoCount > 0;
            redoButton.Enabled = undoBuffer.RedoCount > 0;

            operationButtons = new Dictionary <GuiWidget, SceneOperation>();

            // Add Selected IObject3D -> Operations to toolbar
            foreach (var namedAction in SceneOperations.All)
            {
                if (namedAction is SceneSelectionSeparator)
                {
                    this.AddChild(new ToolbarSeparator(theme.GetBorderColor(50), theme.SeparatorMargin));
                    continue;
                }

                // add the create support before the align
                if (namedAction is OperationGroup group &&
                    group.Id == "Transform")
                {
                    this.AddChild(CreateSupportButton(theme));
                    this.AddChild(new ToolbarSeparator(theme.GetBorderColor(50), theme.SeparatorMargin));
                }

                if (namedAction is OperationGroup operationGroup)
                {
                    var expandoSet = new FlowLayoutWidget();

                    var actionDropDown       = CreateActionDropDown(theme, operationGroup);
                    var operationButtonGroup = CreateOperationButtonGroup(theme, operationGroup);

                    void UpdateVisability(object s, EventArgs e)
                    {
                        if (operationGroup.Visible)
                        {
                            if (operationGroup.Collapse)
                            {
                                actionDropDown.Visible       = true;
                                operationButtonGroup.Visible = false;

                                DoWrappingLayout();
                            }
                            else
                            {
                                actionDropDown.Visible       = false;
                                operationButtonGroup.Visible = true;

                                DoWrappingLayout();
                            }
                        }
                        else
                        {
                            actionDropDown.Visible       = false;
                            operationButtonGroup.Visible = false;

                            DoWrappingLayout();
                        }
                    }

                    UserSettings.Instance.SettingChanged += UpdateVisability;
                    operationGroup.CollapseChanged       += UpdateVisability;
                    operationGroup.VisibleChanged        += UpdateVisability;
                    this.Closed += (s, e) =>
                    {
                        UserSettings.Instance.SettingChanged -= UpdateVisability;
                        operationGroup.CollapseChanged       -= UpdateVisability;
                        operationGroup.VisibleChanged        -= UpdateVisability;
                    };

                    UpdateVisability(operationGroup, null);

                    expandoSet.AddChild(actionDropDown);
                    expandoSet.AddChild(operationButtonGroup);

                    this.AddChild(expandoSet);
                }
                else
                {
                    GuiWidget button;

                    if (namedAction.Icon != null)
                    {
                        button = new IconButton(namedAction.Icon(theme), theme)
                        {
                            Name            = namedAction.Title + " Button",
                            ToolTipText     = namedAction.Title,
                            Margin          = theme.ButtonSpacing,
                            BackgroundColor = theme.ToolbarButtonBackground,
                            HoverColor      = theme.ToolbarButtonHover,
                            MouseDownColor  = theme.ToolbarButtonDown,
                        };
                    }
                    else
                    {
                        button = new TextButton(namedAction.Title, theme)
                        {
                            Name            = namedAction.Title + " Button",
                            Margin          = theme.ButtonSpacing,
                            BackgroundColor = theme.ToolbarButtonBackground,
                            HoverColor      = theme.ToolbarButtonHover,
                            MouseDownColor  = theme.ToolbarButtonDown,
                        };
                    }

                    operationButtons.Add(button, namedAction);

                    button.Click += (s, e) => UiThread.RunOnIdle(() =>
                    {
                        namedAction.Action.Invoke(sceneContext);
                        var partTab = button.Parents <PartTabPage>().FirstOrDefault();
                        var view3D  = partTab.Descendants <View3DWidget>().FirstOrDefault();
                        view3D.Object3DControlLayer.Focus();
                    });

                    this.AddChild(button);
                }
            }

            // add the options menu
            this.AddChild(new HorizontalSpacer());

            var overflowIcon  = StaticData.Instance.LoadIcon(Path.Combine("ViewTransformControls", "overflow.png"), 32, 32).SetToColor(theme.TextColor);
            var optionsButton = new PopupMenuButton(overflowIcon, theme)
            {
                AlignToRightEdge = true
            };

            this.AddChild(optionsButton);
            optionsButton.Name                = "ToolBar Overflow Menu";
            optionsButton.ToolTipText         = "Tool Bar Options".Localize();
            optionsButton.DynamicPopupContent = () => GenerateToolBarOptionsMenu(theme);

            // Register listeners
            undoBuffer.Changed += UndoBuffer_Changed;
            sceneContext.Scene.SelectionChanged += UpdateToolbarButtons;
            sceneContext.Scene.ItemsModified    += UpdateToolbarButtons;

            // Run on load
            UpdateToolbarButtons(null, null);
        }