Notebookbar: PriorityMergedHBox, OptionalBox

Change-Id: I7822fb1b6a342065d66a3fd62f1277e43c2562dd
Reviewed-on: https://gerrit.libreoffice.org/44694
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Szymon Kłos <szymon.klos@collabora.com>
diff --git a/extras/source/glade/libreoffice-catalog.xml.in b/extras/source/glade/libreoffice-catalog.xml.in
index a3f9cc6..3f7c5a7 100644
--- a/extras/source/glade/libreoffice-catalog.xml.in
+++ b/extras/source/glade/libreoffice-catalog.xml.in
@@ -841,6 +841,9 @@
    <glade-widget-class title="Horizontal box hiding children depending on its priorities" name="sfxlo-PriorityHBox"
                        generic-name="PriorityHBox" parent="GtkBox"
                        icon-name="widget-gtk-box"/>
    <glade-widget-class title="Horizontal box hiding children depending on its priorities" name="sfxlo-PriorityMergedHBox"
                        generic-name="PriorityMergedHBox" parent="GtkBox"
                        icon-name="widget-gtk-box"/>
    <glade-widget-class title="Table Design Control" name="sdlo-TableDesignBox"
                        generic-name="TableDesignBox" parent="GtkImage"
                        icon-name="widget-gtk-image"/>
@@ -850,6 +853,9 @@
    <glade-widget-class title="Box which can move own content to the popup" name="sfxlo-DropdownBox"
                        generic-name="DropdownBox" parent="GtkBox"
                        icon-name="widget-gtk-box"/>
    <glade-widget-class title="Box which can hide own content" name="sfxlo-OptionalBox"
                        generic-name="OptionalBox" parent="GtkBox"
                        icon-name="widget-gtk-box"/>
    <glade-widget-class title="Notebookbar ToolBox" name="sfxlo-NotebookbarToolBox"
                        generic-name="Notebookbar ToolBox" parent="sfxlo-SidebarToolBox"
                        icon-name="widget-gtk-toolbar"/>
diff --git a/include/vcl/IPrioritable.hxx b/include/vcl/IPrioritable.hxx
index dda8bbd..29b2fd7 100644
--- a/include/vcl/IPrioritable.hxx
+++ b/include/vcl/IPrioritable.hxx
@@ -39,6 +39,7 @@ public:

    virtual void HideContent() = 0;
    virtual void ShowContent() = 0;
    virtual bool IsHidden() = 0;

private:
    int m_nPriority;
diff --git a/sfx2/Library_sfx.mk b/sfx2/Library_sfx.mk
index 0d9dc14..3dd3d89 100644
--- a/sfx2/Library_sfx.mk
+++ b/sfx2/Library_sfx.mk
@@ -241,8 +241,11 @@ $(eval $(call gb_Library_add_exception_objects,sfx,\
    sfx2/source/inet/inettbc \
    sfx2/source/notebookbar/ContextVBox \
    sfx2/source/notebookbar/DropdownBox \
    sfx2/source/notebookbar/OptionalBox \
    sfx2/source/notebookbar/PriorityHBox \
    sfx2/source/notebookbar/PriorityMergedHBox \
    sfx2/source/notebookbar/SfxNotebookBar \
    sfx2/source/notebookbar/NotebookbarPopup \
    sfx2/source/notebookbar/NotebookbarTabControl \
    sfx2/source/notify/eventsupplier \
    sfx2/source/notify/globalevents \
diff --git a/sfx2/source/notebookbar/DropdownBox.cxx b/sfx2/source/notebookbar/DropdownBox.cxx
index aba34a3..473e5c98 100644
--- a/sfx2/source/notebookbar/DropdownBox.cxx
+++ b/sfx2/source/notebookbar/DropdownBox.cxx
@@ -26,87 +26,6 @@
#define NOTEBOOK_HEADER_HEIGHT 30

/*
 * Popup - shows hidden content, controls are moved to this popup
 * and after close moved to the original parent
 */

class Popup : public FloatingWindow
{
private:
    VclPtr<VclHBox> m_pBox;
    ScopedVclPtr<DropdownBox> m_pParent;

public:
    explicit Popup(const VclPtr<DropdownBox>& pParent)
    : FloatingWindow(pParent, "Popup", "sfx/ui/notebookbarpopup.ui")
    , m_pParent(pParent)
    {
        get(m_pBox, "box");
        m_pBox->SetSizePixel(Size(100, 75));
    }

    virtual ~Popup() override
    {
        disposeOnce();
    }

    VclHBox* getBox()
    {
        return m_pBox.get();
    }

    virtual void PopupModeEnd() override
    {
        hideSeparators(false);
        for (int i = 0; i < m_pBox->GetChildCount(); i++)
        {
            m_pBox->GetChild(i)->Hide();
            m_pBox->GetChild(i)->SetParent(m_pParent);
        }
        FloatingWindow::PopupModeEnd();
    }

    void hideSeparators(bool bHide = true)
    {
        // separator on the beginning
        Window* pWindow = m_pBox->GetChild(0);
        while (pWindow && pWindow->GetType() == WindowType::CONTAINER)
        {
            pWindow = pWindow->GetChild(0);
        }
        if (pWindow && pWindow->GetType() == WindowType::FIXEDLINE)
        {
            if (bHide)
                pWindow->Hide();
            else
                pWindow->Show();
        }

        // separator on the end
        pWindow = m_pBox->GetChild(m_pBox->GetChildCount() - 1);
        while (pWindow && pWindow->GetType() == WindowType::CONTAINER)
        {
            pWindow = pWindow->GetChild(pWindow->GetChildCount() - 1);
        }
        if (pWindow && pWindow->GetType() == WindowType::FIXEDLINE)
        {
            if (bHide)
                pWindow->Hide();
            else
                pWindow->Show();
        }
    }

    void dispose() override
    {
        m_pBox.disposeAndClear();
        m_pParent.clear();

        FloatingWindow::dispose();
    }
};

/*
 * DropdownBox - shows content or moves it to the popup
 * which can be opened by clicking on a button
 */
@@ -152,6 +71,11 @@ void DropdownBox::HideContent()
    }
}

bool DropdownBox::IsHidden()
{
    return !m_bInFullView;
}

void DropdownBox::ShowContent()
{
    if (!m_bInFullView)
@@ -170,7 +94,7 @@ IMPL_LINK(DropdownBox, PBClickHdl, Button*, /*pButton*/, void)
    if (m_pPopup)
        m_pPopup.disposeAndClear();

    m_pPopup = VclPtr<Popup>::Create(this);
    m_pPopup = VclPtr<NotebookbarPopup>::Create(this);

    for (int i = 0; i < GetChildCount(); i++)
    {
@@ -180,6 +104,8 @@ IMPL_LINK(DropdownBox, PBClickHdl, Button*, /*pButton*/, void)
            pChild->Show();

            pChild->SetParent(m_pPopup->getBox());
            // count is decreased because we moved child
            i--;
        }
    }

diff --git a/sfx2/source/notebookbar/DropdownBox.hxx b/sfx2/source/notebookbar/DropdownBox.hxx
index 6a34ae6..6cb62d4 100644
--- a/sfx2/source/notebookbar/DropdownBox.hxx
+++ b/sfx2/source/notebookbar/DropdownBox.hxx
@@ -28,8 +28,7 @@
#include <vcl/floatwin.hxx>
#include <vcl/toolbox.hxx>
#include <sfx2/tbxctrl.hxx>

class Popup;
#include "NotebookbarPopup.hxx"

class SFX2_DLLPUBLIC DropdownBox : public VclHBox,
                                   public vcl::IPrioritable
@@ -37,7 +36,7 @@ class SFX2_DLLPUBLIC DropdownBox : public VclHBox,
private:
    bool m_bInFullView;
    VclPtr<PushButton> m_pButton;
    VclPtr<Popup> m_pPopup;
    VclPtr<NotebookbarPopup> m_pPopup;

public:
    explicit DropdownBox(vcl::Window *pParent);
@@ -46,6 +45,7 @@ public:

    void HideContent() override;
    void ShowContent() override;
    bool IsHidden() override;

private:
    DECL_LINK(PBClickHdl, Button*, void);
diff --git a/sfx2/source/notebookbar/NotebookbarPopup.cxx b/sfx2/source/notebookbar/NotebookbarPopup.cxx
new file mode 100644
index 0000000..4c480af
--- /dev/null
+++ b/sfx2/source/notebookbar/NotebookbarPopup.cxx
@@ -0,0 +1,85 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "NotebookbarPopup.hxx"
#include <vcl/IPrioritable.hxx>
#include <vcl/layout.hxx>

NotebookbarPopup::NotebookbarPopup(const VclPtr<VclHBox>& pParent)
    : FloatingWindow(pParent, "Popup", "sfx/ui/notebookbarpopup.ui")
    , m_pParent(pParent)
{
    get(m_pBox, "box");
    m_pBox->SetSizePixel(Size(100, 75));
}

NotebookbarPopup::~NotebookbarPopup() { disposeOnce(); }

VclHBox* NotebookbarPopup::getBox() { return m_pBox.get(); }

void NotebookbarPopup::PopupModeEnd()
{
    hideSeparators(false);
    while (m_pBox->GetChildCount())
    {
        vcl::IPrioritable* pChild = dynamic_cast<vcl::IPrioritable*>(GetChild(0));
        if (pChild)
            pChild->HideContent();

        vcl::Window* pWindow = m_pBox->GetChild(0);
        pWindow->SetParent(m_pParent);

        if (m_pParent)
            m_pParent->Resize();
    }

    FloatingWindow::PopupModeEnd();
}

void NotebookbarPopup::hideSeparators(bool bHide)
{
    // separator on the beginning
    vcl::Window* pWindow = m_pBox->GetChild(0);
    while (pWindow && pWindow->GetType() == WindowType::CONTAINER)
    {
        pWindow = pWindow->GetChild(0);
    }
    if (pWindow && pWindow->GetType() == WindowType::FIXEDLINE)
    {
        if (bHide)
            pWindow->Hide();
        else
            pWindow->Show();
    }

    // separator on the end
    pWindow = m_pBox->GetChild(m_pBox->GetChildCount() - 1);
    while (pWindow && pWindow->GetType() == WindowType::CONTAINER)
    {
        pWindow = pWindow->GetChild(pWindow->GetChildCount() - 1);
    }
    if (pWindow && pWindow->GetType() == WindowType::FIXEDLINE)
    {
        if (bHide)
            pWindow->Hide();
        else
            pWindow->Show();
    }
}

void NotebookbarPopup::dispose()
{
    PopupModeEnd();
    m_pBox.disposeAndClear();
    m_pParent.clear();

    FloatingWindow::dispose();
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/notebookbar/NotebookbarPopup.hxx b/sfx2/source/notebookbar/NotebookbarPopup.hxx
new file mode 100755
index 0000000..64de9cd
--- /dev/null
+++ b/sfx2/source/notebookbar/NotebookbarPopup.hxx
@@ -0,0 +1,55 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#ifndef INCLUDED_SFX2_NOTEBOOKBAR_NOTEBOOKBARPOPUP_HXX
#define INCLUDED_SFX2_NOTEBOOKBAR_NOTEBOOKBARPOPUP_HXX

#include <vcl/layout.hxx>
#include <sfx2/dllapi.h>
#include <sfx2/viewfrm.hxx>
#include <vcl/floatwin.hxx>

/*
 * Popup - shows hidden content, controls are moved to this popup
 * and after close moved to the original parent
 */

class SFX2_DLLPUBLIC NotebookbarPopup : public FloatingWindow
{
private:
    VclPtr<VclHBox> m_pBox;
    ScopedVclPtr<VclHBox> m_pParent;

public:
    explicit NotebookbarPopup(const VclPtr<VclHBox>& pParent);

    virtual ~NotebookbarPopup() override;

    VclHBox* getBox();

    virtual void PopupModeEnd() override;

    void hideSeparators(bool bHide = true);

    void dispose() override;
};

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/notebookbar/OptionalBox.cxx b/sfx2/source/notebookbar/OptionalBox.cxx
new file mode 100644
index 0000000..6a343ce
--- /dev/null
+++ b/sfx2/source/notebookbar/OptionalBox.cxx
@@ -0,0 +1,68 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <vcl/builderfactory.hxx>
#include <vcl/layout.hxx>
#include <sfx2/dllapi.h>
#include <sfx2/viewfrm.hxx>
#include "OptionalBox.hxx"

/*
 * OptionalBox - shows or hides the content. To use with PriorityHBox
 * or PriorityMergedHBox
 */

OptionalBox::OptionalBox(vcl::Window* pParent)
    : VclHBox(pParent)
    , IPrioritable()
    , m_bInFullView(true)
{
}

OptionalBox::~OptionalBox() { disposeOnce(); }

void OptionalBox::HideContent()
{
    if (m_bInFullView)
    {
        m_bInFullView = false;

        for (int i = 0; i < GetChildCount(); i++)
            GetChild(i)->Hide();

        SetOutputSizePixel(Size(10, GetSizePixel().Height()));
    }
}

void OptionalBox::ShowContent()
{
    if (!m_bInFullView)
    {
        m_bInFullView = true;

        for (int i = 0; i < GetChildCount(); i++)
            GetChild(i)->Show();
    }
}

bool OptionalBox::IsHidden() { return !m_bInFullView; }

VCL_BUILDER_FACTORY(OptionalBox)

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/notebookbar/OptionalBox.hxx b/sfx2/source/notebookbar/OptionalBox.hxx
new file mode 100644
index 0000000..ad36540
--- /dev/null
+++ b/sfx2/source/notebookbar/OptionalBox.hxx
@@ -0,0 +1,48 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#ifndef INCLUDED_SFX2_NOTEBOOKBAR_OPTIONALBOX_HXX
#define INCLUDED_SFX2_NOTEBOOKBAR_OPTIONALBOX_HXX

#include <vcl/builderfactory.hxx>
#include <vcl/IPrioritable.hxx>
#include <vcl/layout.hxx>
#include <sfx2/dllapi.h>
#include <sfx2/viewfrm.hxx>
#include <vcl/floatwin.hxx>
#include <vcl/toolbox.hxx>
#include <sfx2/tbxctrl.hxx>

class SFX2_DLLPUBLIC OptionalBox : public VclHBox, public vcl::IPrioritable
{
private:
    bool m_bInFullView;

public:
    explicit OptionalBox(vcl::Window* pParent);
    virtual ~OptionalBox() override;

    void HideContent() override;
    void ShowContent() override;
    bool IsHidden() override;
};

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/notebookbar/PriorityHBox.cxx b/sfx2/source/notebookbar/PriorityHBox.cxx
index 913ef12..83b6288 100644
--- a/sfx2/source/notebookbar/PriorityHBox.cxx
+++ b/sfx2/source/notebookbar/PriorityHBox.cxx
@@ -22,170 +22,189 @@
#include <sfx2/dllapi.h>
#include <sfx2/viewfrm.hxx>
#include "DropdownBox.hxx"
#include "PriorityHBox.hxx"

#include <vector>

bool lcl_comparePriority(const vcl::IPrioritable* a, const vcl::IPrioritable* b)
namespace
{
    return a->GetPriority() < b->GetPriority();
    bool lcl_comparePriority(const vcl::IPrioritable* a, const vcl::IPrioritable* b)
    {
        return a->GetPriority() < b->GetPriority();
    }
}

/*
 * PriorityHBox is a VclHBox which hides its own children if there is no sufficient space.
 * Hiding order can be modified using child's priorities. If a control have default
 * priority assigned (VCL_PRIORITY_DEFAULT), it is always shown.
 */

class SFX2_DLLPUBLIC PriorityHBox : public VclHBox
PriorityHBox::PriorityHBox(vcl::Window *pParent)
    : VclHBox(pParent)
    , m_bInitialized(false)
{
private:
    bool m_bInitialized;
}

    std::vector<vcl::IPrioritable*> m_aSortedChilds;
PriorityHBox::~PriorityHBox()
{
    disposeOnce();
}

public:
    explicit PriorityHBox(vcl::Window *pParent)
        : VclHBox(pParent)
        , m_bInitialized(false)
void PriorityHBox::Initialize()
{
    m_bInitialized = true;

    GetChildrenWithPriorities();
    SetSizeFromParent();
}

int PriorityHBox::GetHiddenCount() const
{
    int nCount = 0;

    for (auto pWindow : m_aSortedChildren)
        if (pWindow->IsHidden())
            nCount++;

    return nCount;
}

void PriorityHBox::SetSizeFromParent()
{
    vcl::Window* pParent = GetParent();
    if (pParent)
    {
        Size aParentSize = pParent->GetSizePixel();
        SetSizePixel(Size(aParentSize.getWidth(), aParentSize.getHeight()));
    }
}

Size PriorityHBox::calculateRequisition() const
{
    if (!m_bInitialized)
    {
        return VclHBox::calculateRequisition();
    }

    virtual ~PriorityHBox() override
    {
        disposeOnce();
    }
    sal_uInt16 nVisibleChildren = 0;

    void Initialize()
    Size aSize;
    for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
    {
        m_bInitialized = true;
        if (!pChild->IsVisible())
            continue;
        ++nVisibleChildren;
        Size aChildSize = getLayoutRequisition(*pChild);

        GetChildrenWithPriorities();
        SetSizeFromParent();
    }
        bool bAllwaysExpanded = true;

    void SetSizeFromParent()
    {
        vcl::Window* pParent = GetParent();
        if (pParent)
        vcl::IPrioritable* pPrioritable = dynamic_cast<vcl::IPrioritable*>(pChild);
        if (pPrioritable && pPrioritable->GetPriority() != VCL_PRIORITY_DEFAULT)
            bAllwaysExpanded = false;

        if (bAllwaysExpanded)
        {
            Size aParentSize = pParent->GetSizePixel();
            SetSizePixel(Size(aParentSize.getWidth(), aParentSize.getHeight()));
            long nPrimaryDimension = getPrimaryDimension(aChildSize);
            nPrimaryDimension += pChild->get_padding() * 2;
            setPrimaryDimension(aChildSize, nPrimaryDimension);
        }
        else
            setPrimaryDimension(aChildSize, 0);

        accumulateMaxes(aChildSize, aSize);
    }

    virtual Size calculateRequisition() const override
    return finalizeMaxes(aSize, nVisibleChildren);
}

void PriorityHBox::Resize()
{
    if (!m_bInitialized && SfxViewFrame::Current())
        Initialize();

    if (!m_bInitialized)
    {
        if (!m_bInitialized)
        {
            return VclHBox::calculateRequisition();
        }

        sal_uInt16 nVisibleChildren = 0;

        Size aSize;
        for (vcl::Window *pChild = GetWindow(GetWindowType::FirstChild); pChild; pChild = pChild->GetWindow(GetWindowType::Next))
        {
            if (!pChild->IsVisible())
                continue;
            ++nVisibleChildren;
            Size aChildSize = getLayoutRequisition(*pChild);

            bool bAllwaysExpanded = true;

            vcl::IPrioritable* pPrioritable = dynamic_cast<vcl::IPrioritable*>(pChild);
            if (pPrioritable && pPrioritable->GetPriority() != VCL_PRIORITY_DEFAULT)
                bAllwaysExpanded = false;

            if (bAllwaysExpanded)
            {
                long nPrimaryDimension = getPrimaryDimension(aChildSize);
                nPrimaryDimension += pChild->get_padding() * 2;
                setPrimaryDimension(aChildSize, nPrimaryDimension);
            }
            else
                setPrimaryDimension(aChildSize, 0);

            accumulateMaxes(aChildSize, aSize);
        }

        return finalizeMaxes(aSize, nVisibleChildren);
        return VclHBox::Resize();
    }

    virtual void Resize() override
    long nWidth = GetSizePixel().Width();
    long nCurrentWidth = VclHBox::calculateRequisition().getWidth();

    // Hide lower priority controls
    auto pChild = m_aSortedChildren.begin();
    while (nCurrentWidth > nWidth && pChild != m_aSortedChildren.end())
    {
        if (!m_bInitialized && SfxViewFrame::Current())
            Initialize();
        vcl::Window* pWindow = dynamic_cast<vcl::Window*>(*pChild);
        vcl::IPrioritable* pPrioritable = *pChild;

        if (!m_bInitialized)
        if(pWindow->GetParent() != this)
        {
            return VclHBox::Resize();
        }

        long nWidth = GetSizePixel().Width();
        long nCurrentWidth = VclHBox::calculateRequisition().getWidth();

        // Hide lower priority controls
        auto pChild = m_aSortedChilds.begin();
        while (nCurrentWidth > nWidth && pChild != m_aSortedChilds.end())
        {
            // ATM DropdownBox is the only one derived class from IPrioritable
            DropdownBox* pDropdownBox = static_cast<DropdownBox*>(*pChild);

            nCurrentWidth -= pDropdownBox->GetOutputWidthPixel() + get_spacing();
            pDropdownBox->HideContent();
            nCurrentWidth += pDropdownBox->GetOutputWidthPixel() + get_spacing();

            pChild++;
            continue;
        }

        auto pChildR = m_aSortedChilds.rbegin();
        // Show higher priority controls if we already have enough space
        while (pChildR != m_aSortedChilds.rend())
        if (pWindow)
        {
            DropdownBox* pBox = static_cast<DropdownBox*>(*pChildR);
            nCurrentWidth -= pWindow->GetOutputWidthPixel() + get_spacing();
            pWindow->Show();
            pPrioritable->HideContent();
            nCurrentWidth += pWindow->GetOutputWidthPixel() + get_spacing();
        }

            nCurrentWidth -= pBox->GetOutputWidthPixel() + get_spacing();
            pBox->ShowContent();
            nCurrentWidth += getLayoutRequisition(*pBox).Width() + get_spacing();
        pChild++;
    }

    auto pChildR = m_aSortedChildren.rbegin();
    // Show higher priority controls if we already have enough space
    while (pChildR != m_aSortedChildren.rend())
    {
        vcl::Window* pWindow = dynamic_cast<vcl::Window*>(*pChildR);
        vcl::IPrioritable* pPrioritable = *pChildR;

        if(pWindow->GetParent() != this)
        {
            pChildR++;
            continue;
        }

        if (pWindow)
        {
            nCurrentWidth -= pWindow->GetOutputWidthPixel() + get_spacing();
            pWindow->Show();
            pPrioritable->ShowContent();
            nCurrentWidth += getLayoutRequisition(*pWindow).Width() + get_spacing();

            if (nCurrentWidth > nWidth)
            {
                pBox->HideContent();
                pPrioritable->HideContent();
                break;
            }

            pChildR++;
        }

        VclHBox::Resize();
        pChildR++;
    }

    virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override
    VclHBox::Resize();
}

void PriorityHBox::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
{
    if (!m_bInitialized && SfxViewFrame::Current())
        Initialize();

    VclHBox::Paint(rRenderContext, rRect);
}

void PriorityHBox::GetChildrenWithPriorities()
{
    for (sal_uInt16 i = 0; i < GetChildCount(); ++i)
    {
        if (!m_bInitialized && SfxViewFrame::Current())
            Initialize();
        vcl::Window* pChild = GetChild(i);

        VclHBox::Paint(rRenderContext, rRect);
        // Add only containers which have explicitly assigned priority.
        vcl::IPrioritable* pPrioritable = dynamic_cast<vcl::IPrioritable*>(pChild);
        if (pPrioritable && pPrioritable->GetPriority() != VCL_PRIORITY_DEFAULT)
            m_aSortedChildren.push_back(pPrioritable);
    }

    void GetChildrenWithPriorities()
    {
        for (sal_uInt16 i = 0; i < GetChildCount(); ++i)
        {
            vcl::Window* pChild = GetChild(i);
    if (!m_aSortedChildren.size())
        m_bInitialized = false;

            // Add only containers which have explicitly assigned priority.
            vcl::IPrioritable* pPrioritable = dynamic_cast<vcl::IPrioritable*>(pChild);
            if (pPrioritable && pPrioritable->GetPriority() != VCL_PRIORITY_DEFAULT)
                m_aSortedChilds.push_back(pPrioritable);
        }

        if (!m_aSortedChilds.size())
            m_bInitialized = false;

        std::sort(m_aSortedChilds.begin(), m_aSortedChilds.end(), lcl_comparePriority);
    }
};
    std::sort(m_aSortedChildren.begin(), m_aSortedChildren.end(), lcl_comparePriority);
}

VCL_BUILDER_FACTORY(PriorityHBox)

diff --git a/sfx2/source/notebookbar/PriorityHBox.hxx b/sfx2/source/notebookbar/PriorityHBox.hxx
new file mode 100644
index 0000000..8248264
--- /dev/null
+++ b/sfx2/source/notebookbar/PriorityHBox.hxx
@@ -0,0 +1,67 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <vcl/builderfactory.hxx>
#include <vcl/layout.hxx>
#include <sfx2/dllapi.h>
#include <sfx2/viewfrm.hxx>
#include "DropdownBox.hxx"

#include <vector>

#ifndef INCLUDED_SFX2_NOTEBOOKBAR_PRIORITYHBOX_HXX
#define INCLUDED_SFX2_NOTEBOOKBAR_PRIORITYHBOX_HXX

/*
 * PriorityHBox is a VclHBox which hides its own children if there is no sufficient space.
 * Hiding order can be modified using child's priorities. If a control have default
 * priority assigned (VCL_PRIORITY_DEFAULT), it is always shown.
 */

class SFX2_DLLPUBLIC PriorityHBox : public VclHBox
{
private:
    bool m_bInitialized;

    std::vector<vcl::IPrioritable*> m_aSortedChildren;

protected:
    int GetHiddenCount() const;

public:
    explicit PriorityHBox(vcl::Window* pParent);

    virtual ~PriorityHBox() override;

    void Initialize();

    void SetSizeFromParent();

    virtual Size calculateRequisition() const override;

    virtual void Resize() override;

    virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;

    void GetChildrenWithPriorities();
};

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sfx2/source/notebookbar/PriorityMergedHBox.cxx b/sfx2/source/notebookbar/PriorityMergedHBox.cxx
new file mode 100644
index 0000000..e52c467
--- /dev/null
+++ b/sfx2/source/notebookbar/PriorityMergedHBox.cxx
@@ -0,0 +1,111 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
*   Licensed to the Apache Software Foundation (ASF) under one or more
*   contributor license agreements. See the NOTICE file distributed
*   with this work for additional information regarding copyright
*   ownership. The ASF licenses this file to you under the Apache
*   License, Version 2.0 (the "License"); you may not use this file
*   except in compliance with the License. You may obtain a copy of
*   the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/

#include <vcl/builderfactory.hxx>
#include <vcl/layout.hxx>
#include <sfx2/dllapi.h>
#include <sfx2/viewfrm.hxx>
#include "OptionalBox.hxx"
#include "PriorityHBox.hxx"
#include "NotebookbarPopup.hxx"

/*
* PriorityMergedHBox is a VclHBox which hides its own children if there is no sufficient space.
*/

class SFX2_DLLPUBLIC PriorityMergedHBox : public PriorityHBox
{
private:
    VclPtr<PushButton> m_pButton;
    VclPtr<NotebookbarPopup> m_pPopup;

    DECL_LINK(PBClickHdl, Button*, void);

public:
    explicit PriorityMergedHBox(vcl::Window* pParent)
        : PriorityHBox(pParent)
    {
        m_pButton = VclPtr<PushButton>::Create(this, WB_FLATBUTTON);
        m_pButton->SetClickHdl(LINK(this, PriorityMergedHBox, PBClickHdl));
        m_pButton->SetSymbol(SymbolType::NEXT);
        m_pButton->set_width_request(15);
        m_pButton->set_pack_type(VclPackType::End);
        m_pButton->Show();
    }

    virtual ~PriorityMergedHBox() override { disposeOnce(); }

    virtual void Resize() override
    {
        PriorityHBox::Resize();
        if (GetHiddenCount())
            m_pButton->Show();
        else
            m_pButton->Hide();
    }

    virtual void dispose() override
    {
        m_pButton.disposeAndClear();
        if (m_pPopup)
            m_pPopup.disposeAndClear();
        PriorityHBox::dispose();
    }
};

IMPL_LINK(PriorityMergedHBox, PBClickHdl, Button*, /*pButton*/, void)
{
    if (m_pPopup)
        m_pPopup.disposeAndClear();

    m_pPopup = VclPtr<NotebookbarPopup>::Create(this);

    for (int i = 0; i < GetChildCount(); i++)
    {
        vcl::Window* pWindow = GetChild(i);
        if (pWindow != m_pButton)
        {
            vcl::IPrioritable* pChild = dynamic_cast<vcl::IPrioritable*>(pWindow);

            if (pChild && pChild->IsHidden())
            {
                pChild->ShowContent();
                pWindow->Show();
                pWindow->SetParent(m_pPopup->getBox());
                // count is decreased because we moved child
                i--;
            }
        }
    }

    m_pPopup->hideSeparators(true);

    m_pPopup->getBox()->set_height_request(GetSizePixel().Height());

    long x = m_pButton->GetPosPixel().getX();
    long y = m_pButton->GetPosPixel().getY() + GetSizePixel().Height();
    tools::Rectangle aRect(x, y, x, y);

    m_pPopup->StartPopupMode(aRect, FloatWinPopupFlags::Down | FloatWinPopupFlags::GrabFocus
                                        | FloatWinPopupFlags::AllMouseButtonClose);
}

VCL_BUILDER_FACTORY(PriorityMergedHBox)

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/uiconfig/swriter/ui/notebookbar_groupedbar_compact.ui b/sw/uiconfig/swriter/ui/notebookbar_groupedbar_compact.ui
index 711d5e8..d25830d 100644
--- a/sw/uiconfig/swriter/ui/notebookbar_groupedbar_compact.ui
+++ b/sw/uiconfig/swriter/ui/notebookbar_groupedbar_compact.ui
@@ -4379,10 +4379,10 @@
                <property name="can_focus">False</property>
                <property name="orientation">vertical</property>
                <child>
                  <object class="sfxlo-PriorityHBox" id="DefaultContainer">
                  <object class="sfxlo-PriorityMergedHBox" id="DefaultContainer">
                    <property name="can_focus">False</property>
                    <child>
                      <object class="sfxlo-DropdownBox" id="StylesSection">
                      <object class="sfxlo-OptionalBox" id="StylesSection">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="baseline_position">bottom</property>
@@ -4515,7 +4515,7 @@
                      </packing>
                    </child>
                    <child>
                      <object class="sfxlo-DropdownBox" id="FormatSection">
                      <object class="sfxlo-OptionalBox" id="FormatSection">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="baseline_position">bottom</property>
@@ -4725,7 +4725,7 @@
                      </packing>
                    </child>
                    <child>
                      <object class="sfxlo-DropdownBox" id="ParagraphSection">
                      <object class="sfxlo-OptionalBox" id="ParagraphSection">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="baseline_position">bottom</property>
@@ -4956,7 +4956,7 @@
                      </packing>
                    </child>
                    <child>
                      <object class="sfxlo-DropdownBox" id="InsertSection">
                      <object class="sfxlo-OptionalBox" id="InsertSection">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="baseline_position">bottom</property>
@@ -5108,7 +5108,7 @@
                      </packing>
                    </child>
                    <child>
                      <object class="sfxlo-DropdownBox" id="ReferenceSection">
                      <object class="sfxlo-OptionalBox" id="ReferenceSection">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="baseline_position">bottom</property>
@@ -5222,7 +5222,7 @@
                      </packing>
                    </child>
                    <child>
                      <object class="sfxlo-DropdownBox" id="ReviewSection">
                      <object class="sfxlo-OptionalBox" id="ReviewSection">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="baseline_position">bottom</property>
@@ -5336,7 +5336,7 @@
                      </packing>
                    </child>
                    <child>
                      <object class="sfxlo-DropdownBox" id="ViewSection">
                      <object class="sfxlo-OptionalBox" id="ViewSection">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="baseline_position">bottom</property>