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);
        }