/// <summary>
        /// Creates an ItemStackInfo element.
        /// </summary>
        /// <param name="capi">The client API</param>
        /// <param name="bounds">The bounds of the object.</param>
        /// <param name="OnRequireInfoText">The function that is called when an item information is called.</param>
        public GuiElementItemstackInfo(ICoreClientAPI capi, ElementBounds bounds, InfoTextDelegate OnRequireInfoText) : base(capi, "", CairoFont.WhiteSmallText(), bounds)
        {
            this.OnRequireInfoText = OnRequireInfoText;

            texture = new LoadedTexture(capi);

            ElementBounds textBounds = bounds.CopyOnlySize();
            ElementBounds descBounds = textBounds.CopyOffsetedSibling(ItemStackSize + 50, MarginTop, -ItemStackSize - 50, 0);

            descBounds.WithParent(bounds);
            textBounds.WithParent(bounds);

            descriptionElement = new GuiElementRichtext(capi, new RichTextComponentBase[0], descBounds);
            //new GuiElementStaticText(capi, "", EnumTextOrientation.Left, textBounds.CopyOffsetedSibling(ItemStackSize + 50, MarginTop, -ItemStackSize - 50, 0), Font);
            descriptionElement.zPos = 1001;


            titleFont            = Font.Clone();
            titleFont.FontWeight = FontWeight.Bold;

            titleElement      = new GuiElementRichtext(capi, new RichTextComponentBase[0], textBounds);
            titleElement.zPos = 1001;

            maxWidth = bounds.fixedWidth;
        }
        public GuiDialogBlockEntityInventory(string dialogTitle, InventoryBase inventory, BlockPos blockEntityPos, int cols, ICoreClientAPI capi)
            : base(dialogTitle, inventory, blockEntityPos, capi)
        {
            if (IsDuplicate)
            {
                return;
            }
            this.cols = cols;


            double elemToDlgPad = GuiStyle.ElementToDialogPadding;
            double pad          = GuiElementItemSlotGrid.unscaledSlotPadding;
            int    rows         = (int)Math.Ceiling(inventory.Count / (float)cols);
            int    visibleRows  = Math.Min(rows, 7);

            // 1. The bounds of the slot grid itself. It is offseted by slot padding. It determines the size of the dialog, so we build the dialog from the bottom up
            ElementBounds slotGridBounds = ElementStdBounds.SlotGrid(EnumDialogArea.None, pad, pad, cols, visibleRows);

            // 1a.) Determine the full size of scrollable area, required to calculate scrollbar handle size
            ElementBounds fullGridBounds = ElementStdBounds.SlotGrid(EnumDialogArea.None, 0, 0, cols, rows);

            // 2. Around that is the 3 wide inset stroke
            ElementBounds insetBounds = slotGridBounds.ForkBoundingParent(6, 6, 6, 6);

            screenPos = GetFreePos("smallblockgui");

            if (visibleRows < rows)
            {
                // 2a. The scrollable bounds is also the clipping bounds. Needs it's parent to be set.
                ElementBounds clippingBounds = slotGridBounds.CopyOffsetedSibling();
                clippingBounds.fixedHeight -= 3; // Why?

                // 3. Around all that is the dialog centered to screen middle, with some extra spacing right for the scrollbar
                ElementBounds dialogBounds = insetBounds
                                             .ForkBoundingParent(elemToDlgPad, elemToDlgPad + 30, elemToDlgPad + 20, elemToDlgPad)
                                             .WithFixedAlignmentOffset(IsRight(screenPos) ? -GuiStyle.DialogToScreenPadding : GuiStyle.DialogToScreenPadding, 0)
                                             .WithAlignment(IsRight(screenPos) ? EnumDialogArea.RightMiddle :EnumDialogArea.LeftMiddle)
                ;

                if (!capi.Settings.Bool["immersiveMouseMode"])
                {
                    dialogBounds.fixedOffsetY += (dialogBounds.fixedHeight + 10) * YOffsetMul(screenPos);
                }

                // 4. Right of the slot grid is the scrollbar
                ElementBounds scrollbarBounds = ElementStdBounds.VerticalScrollbar(insetBounds).WithParent(dialogBounds);

                SingleComposer = capi.Gui
                                 .CreateCompo("blockentityinventory" + blockEntityPos, dialogBounds)
                                 .AddShadedDialogBG(ElementBounds.Fill)
                                 .AddDialogTitleBar(dialogTitle, CloseIconPressed)
                                 .AddInset(insetBounds)
                                 .AddVerticalScrollbar(OnNewScrollbarvalue, scrollbarBounds, "scrollbar")
                                 .BeginClip(clippingBounds)
                                 .AddItemSlotGrid(inventory, DoSendPacket, cols, fullGridBounds, "slotgrid")
                                 .EndClip()
                                 .Compose();

                SingleComposer.GetScrollbar("scrollbar").SetHeights(
                    (float)(slotGridBounds.fixedHeight),
                    (float)(fullGridBounds.fixedHeight + pad)
                    );
            }
            else
            {
                // 3. Around all that is the dialog centered to screen middle, with some extra spacing right for the scrollbar
                ElementBounds dialogBounds = insetBounds
                                             .ForkBoundingParent(elemToDlgPad, elemToDlgPad + 20, elemToDlgPad, elemToDlgPad)
                                             .WithFixedAlignmentOffset(IsRight(screenPos) ? -GuiStyle.DialogToScreenPadding : GuiStyle.DialogToScreenPadding, 0)
                                             .WithAlignment(IsRight(screenPos) ? EnumDialogArea.RightMiddle : EnumDialogArea.LeftMiddle)
                ;

                if (!capi.Settings.Bool["immersiveMouseMode"])
                {
                    dialogBounds.fixedOffsetY += (dialogBounds.fixedHeight + 10) * YOffsetMul(screenPos);
                }

                SingleComposer = capi.Gui
                                 .CreateCompo("blockentityinventory" + blockEntityPos, dialogBounds)
                                 .AddShadedDialogBG(ElementBounds.Fill)
                                 .AddDialogTitleBar(dialogTitle, CloseIconPressed)
                                 .AddInset(insetBounds)
                                 .AddItemSlotGrid(inventory, DoSendPacket, cols, slotGridBounds, "slotgrid")
                                 .Compose();
            }

            SingleComposer.UnfocusOwnElements();
        }