tdf#101443 Calc multiline input bar reworked

Change-Id: Ic35c9898624f0c13b6d64725808e765a64c17081
Reviewed-on: https://gerrit.libreoffice.org/71937
Tested-by: Jenkins
Reviewed-by: Eike Rathke <erack@redhat.com>
diff --git a/include/vcl/toolbox.hxx b/include/vcl/toolbox.hxx
index 19e02a0..8b43fa6 100644
--- a/include/vcl/toolbox.hxx
+++ b/include/vcl/toolbox.hxx
@@ -68,11 +68,13 @@ enum class ToolBoxButtonSize
    Size32,
};

// ToolBoxLayoutMode::Normal   - traditional layout, items are centered in the toolbar
// ToolBoxLayoutMode::LockVert - special mode (currently used for calc input/formula
//                       bar) where item's vertical position is locked, e.g.
//                       toolbox is prevented from centering the items
enum class ToolBoxLayoutMode { Normal, LockVert };
enum class ToolBoxLayoutMode
{
    Normal,  // traditional layout, items are centered in the toolbar
    Locked   // horizontal positions of all items remain unchanged,
             // vertical positions of items smaller than first item are aligned to first item's vertical center,
             // vertical positions of items larger than first item remain unchanged
};

// Position of the text when icon and text are painted
enum class ToolBoxTextPosition { Right, Bottom };
@@ -149,7 +151,8 @@ private:
                        mbIsKeyEvent:1,
                        mbChangingHighlight:1,
                        mbImagesMirrored:1,
                        mbLineSpacing:1;
                        mbLineSpacing:1,
                        mbIsArranged:1;
    WindowAlign         meAlign;
    WindowAlign         meDockAlign;
    ButtonType          meButtonType;
diff --git a/sc/source/ui/app/inputwin.cxx b/sc/source/ui/app/inputwin.cxx
index 031546d..e206a35 100644
--- a/sc/source/ui/app/inputwin.cxx
+++ b/sc/source/ui/app/inputwin.cxx
@@ -72,14 +72,14 @@

namespace com::sun::star::accessibility { class XAccessible; }

#define THESIZE             1000000 // Should be more than enough!
#define TBX_WINDOW_HEIGHT   22 // in pixel - TODO: The same on all systems?
#define MULTILINE_BUTTON_WIDTH 20 // Width of the button which opens the multiline dropdown
#define LEFT_OFFSET         5
#define INPUTWIN_MULTILINES 6
const long BUTTON_OFFSET = 2; ///< space between input line and the button to expand / collapse
const long ADDITIONAL_BORDER = 1; ///< height of the line at the bottom
const long ADDITIONAL_SPACE = 4; ///< additional vertical space when the multiline edit has more lines
const long THESIZE = 1000000;            // Should be more than enough!
const long INPUTLINE_INSET_MARGIN = 2;   // Space between border and interior widgets of input line
const long MIN_FONT_SIZE = 16;           // Minimum font size of input line in pixels
const long LEFT_OFFSET = 5;              // Left offset of input line
const long BUTTON_OFFSET = 2;            // Space between input line and button to expand/collapse
const long MULTILINE_BUTTON_WIDTH = 20;  // Width of the button which opens multiline dropdown
const long INPUTWIN_MULTILINES = 6;      // Initial number of lines within multiline dropdown
const long TOOLBOX_WINDOW_HEIGHT = 22;   // Height of toolbox window in pixels - TODO: The same on all systems?

using com::sun::star::uno::Reference;
using com::sun::star::uno::UNO_QUERY;
@@ -247,6 +247,8 @@ ScInputWindow::ScInputWindow( vcl::Window* pParent, const SfxBindings* pBind ) :
    else if (pViewSh)
        pViewSh->UpdateInputHandler(true); // Absolutely necessary update

    SetToolbarLayoutMode( ToolBoxLayoutMode::Locked );

    SetAccessibleName(ScResId(STR_ACC_TOOLBAR_FORMULA));
}

@@ -390,10 +392,8 @@ void ScInputWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Recta
    ToolBox::Paint(rRenderContext, rRect);

    // draw a line at the bottom to distinguish that from the grid
    // (we have space for that thanks to ADDITIONAL_BORDER)
    const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
    rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());

    Size aSize = GetSizePixel();
    rRenderContext.DrawLine(Point(0, aSize.Height() - 1),
                            Point(aSize.Width() - 1, aSize.Height() - 1));
@@ -402,21 +402,23 @@ void ScInputWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Recta
void ScInputWindow::Resize()
{
    ToolBox::Resize();

    aTextWindow.Resize();
    Size aSize = GetSizePixel();
    aSize.setHeight( CalcWindowSizePixel().Height() + ADDITIONAL_BORDER );
    aSize.setHeight(CalcWindowSizePixel().Height() + 1);
    ScInputBarGroup* pGroupBar = dynamic_cast<ScInputBarGroup*>(pRuntimeWindow.get());
    if (pGroupBar)
    {
        // To ensure smooth display and prevent the items in the toolbar being
        // repositioned ( vertically ) we lock the vertical positioning of the toolbox
        // repositioned (vertically) we lock the vertical positioning of the toolbox
        // items when we are displaying > 1 line.
        // So, we need to adjust the height of the toolbox accordingly. If we don't
        // then the largest item ( e.g. the GroupBar window ) will actually be
        // then the largest item (e.g. the GroupBar window) will actually be
        // positioned such that the toolbar will cut off the bottom of that item
        if (pGroupBar->GetNumLines() > 1)
            aSize.AdjustHeight(pGroupBar->GetVertOffset() + ADDITIONAL_SPACE );
        {
            Size aGroupBarSize = pGroupBar->GetSizePixel();
            aSize.setHeight(aGroupBarSize.Height() + 2 * (pGroupBar->GetVertOffset() + 1));
        }
    }
    SetSizePixel(aSize);
    Invalidate();
@@ -633,7 +635,7 @@ void ScInputWindow::MouseMove( const MouseEvent& rMEvt )
    if (bInResize)
    {
        // detect direction
        long nResizeThreshold = long(TBX_WINDOW_HEIGHT * 0.7);
        long nResizeThreshold = long(TOOLBOX_WINDOW_HEIGHT * 0.7);
        bool bResetPointerPos = false;

        // Detect attempt to expand toolbar too much
@@ -678,9 +680,10 @@ void ScInputWindow::MouseButtonDown( const MouseEvent& rMEvt )
            // calculate an upper limit
            // I'd prefer to leave at least a single column header and a
            // row but I don't know how to get that value in pixels.
            // Use TBX_WINDOW_HEIGHT for the moment
            // Use TOOLBOX_WINDOW_HEIGHT for the moment
            ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
            mnMaxY = GetOutputSizePixel().Height() + (pViewSh->GetGridHeight(SC_SPLIT_TOP) + pViewSh->GetGridHeight(SC_SPLIT_BOTTOM)) - TBX_WINDOW_HEIGHT;
            mnMaxY = GetOutputSizePixel().Height() + (pViewSh->GetGridHeight(SC_SPLIT_TOP)
                   + pViewSh->GetGridHeight(SC_SPLIT_BOTTOM)) - TOOLBOX_WINDOW_HEIGHT;
        }
    }

@@ -700,26 +703,18 @@ void ScInputWindow::MouseButtonUp( const MouseEvent& rMEvt )

ScInputBarGroup::ScInputBarGroup(vcl::Window* pParent, ScTabViewShell* pViewSh)
    : ScTextWndBase(pParent, WinBits(WB_HIDE | WB_TABSTOP)),
      maTextWnd(VclPtr<ScTextWnd>::Create(this, pViewSh)),
      maButton(VclPtr<ImageButton>::Create(this, WB_TABSTOP | WB_RECTSTYLE | WB_SMALLSTYLE)),
      maScrollbar(VclPtr<ScrollBar>::Create(this, WB_TABSTOP | WB_VERT | WB_DRAG)),
      maTextWndGroup(VclPtr<ScTextWndGroup>::Create(this, pViewSh)),
      maButton(VclPtr<ImageButton>::Create(this, WB_TABSTOP | WB_FLATBUTTON | WB_SMALLSTYLE | WB_NOPOINTERFOCUS)),
      mnVertOffset(0)
{
    maTextWnd->Show();
    maTextWnd->SetQuickHelpText(ScResId(SCSTR_QHELP_INPUTWND));
    maTextWnd->SetHelpId(HID_INSWIN_INPUT);

    Size aSize(MULTILINE_BUTTON_WIDTH, maTextWnd->GetPixelHeightForLines(1));

    maTextWndGroup->Show();
    Size aSize(MULTILINE_BUTTON_WIDTH, maTextWndGroup->GetPixelHeightForLines(1));
    maButton->SetClickHdl(LINK(this, ScInputBarGroup, ClickHdl));
    maButton->SetSizePixel(aSize);
    maButton->Enable();
    maButton->SetSymbol(SymbolType::SPIN_DOWN);
    maButton->SetQuickHelpText(ScResId(SCSTR_QHELP_EXPAND_FORMULA));
    maButton->Show();

    maScrollbar->SetSizePixel(aSize);
    maScrollbar->SetScrollHdl(LINK(this, ScInputBarGroup, Impl_ScrollHdl));
}

ScInputBarGroup::~ScInputBarGroup()
@@ -729,138 +724,111 @@ ScInputBarGroup::~ScInputBarGroup()

void ScInputBarGroup::dispose()
{
    maTextWnd.disposeAndClear();
    maTextWndGroup.disposeAndClear();
    maButton.disposeAndClear();
    maScrollbar.disposeAndClear();
    ScTextWndBase::dispose();
}

void ScInputBarGroup::InsertAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
{
    maTextWnd->InsertAccessibleTextData( rTextData );
    maTextWndGroup->InsertAccessibleTextData(rTextData);
}

void ScInputBarGroup::RemoveAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
{
    maTextWnd->RemoveAccessibleTextData( rTextData );
    maTextWndGroup->RemoveAccessibleTextData(rTextData);
}

const OUString& ScInputBarGroup::GetTextString() const
{
    return maTextWnd->GetTextString();
    return maTextWndGroup->GetTextString();
}

void ScInputBarGroup::SetTextString( const OUString& rString )
{
    maTextWnd->SetTextString(rString);
    maTextWndGroup->SetTextString(rString);
}

void ScInputBarGroup::Resize()
{
    vcl::Window*w = GetParent();
    vcl::Window* pWindow = GetParent();
    ScInputWindow *pParent;
    pParent = dynamic_cast<ScInputWindow*>(w);

    pParent = dynamic_cast<ScInputWindow*>(pWindow);
    if (pParent == nullptr)
    {
        OSL_FAIL("The parent window pointer pParent is null");
        return;
    }

    long nWidth = pParent->GetSizePixel().Width();
    long nLeft  = GetPosPixel().X();

    Size aSize  = GetSizePixel();
    aSize.setWidth( std::max(long(nWidth - nLeft - LEFT_OFFSET), long(0)) );

    maScrollbar->SetPosPixel(Point( aSize.Width() - maButton->GetSizePixel().Width(), maButton->GetSizePixel().Height() ) );

    Size aTmpSize( aSize );
    aTmpSize.setWidth( aTmpSize.Width() - maButton->GetSizePixel().Width() - BUTTON_OFFSET );
    maTextWnd->SetSizePixel(aTmpSize);

    maTextWnd->Resize();

    aSize.setHeight( maTextWnd->GetSizePixel().Height() );

    Size aSize = GetSizePixel();
    aSize.setWidth(pParent->GetSizePixel().Width() - GetPosPixel().X() - LEFT_OFFSET);
    aSize.setHeight(maTextWndGroup->GetPixelHeightForLines(maTextWndGroup->GetNumLines()));
    SetSizePixel(aSize);

    if (maTextWnd->GetNumLines() > 1)
    aSize.setWidth(aSize.Width() - maButton->GetSizePixel().Width() - BUTTON_OFFSET);
    maTextWndGroup->SetSizePixel(aSize);
    maTextWndGroup->Resize();

    if (maTextWndGroup->GetNumLines() > 1)
    {
        maButton->SetSymbol( SymbolType::SPIN_UP  );
        maButton->SetQuickHelpText( ScResId( SCSTR_QHELP_COLLAPSE_FORMULA ) );
        Size scrollSize = maButton->GetSizePixel();
        scrollSize.setHeight( maTextWnd->GetSizePixel().Height() - maButton->GetSizePixel().Height() );
        maScrollbar->SetSizePixel( scrollSize );

        Size aOutSz = maTextWnd->GetOutputSize();

        maScrollbar->SetVisibleSize( aOutSz.Height() );
        maScrollbar->SetPageSize( aOutSz.Height() );
        maScrollbar->SetLineSize( maTextWnd->GetTextHeight() );
        maScrollbar->SetRange( Range( 0, maTextWnd->GetEditEngTxtHeight() ) );

        maScrollbar->Resize();
        maScrollbar->Show();
        maButton->SetQuickHelpText(ScResId( SCSTR_QHELP_COLLAPSE_FORMULA));
    }
    else
    {
        maButton->SetSymbol( SymbolType::SPIN_DOWN  );
        maButton->SetQuickHelpText( ScResId( SCSTR_QHELP_EXPAND_FORMULA ) );
        maScrollbar->Hide();
        maButton->SetQuickHelpText(ScResId( SCSTR_QHELP_EXPAND_FORMULA));
    }

    maButton->SetPosPixel(Point(aSize.Width() - maButton->GetSizePixel().Width(), 0));

    maButton->SetPosPixel(Point(aSize.Width(), 0));
    Invalidate();
}

void ScInputBarGroup::StopEditEngine( bool bAll )
void ScInputBarGroup::StopEditEngine(bool bAll)
{
    maTextWnd->StopEditEngine( bAll );
    maTextWndGroup->StopEditEngine(bAll);
}

void ScInputBarGroup::StartEditEngine()
{
    maTextWnd->StartEditEngine();
    maTextWndGroup->StartEditEngine();
}

void ScInputBarGroup::MakeDialogEditView()
{
    maTextWnd->MakeDialogEditView();
    maTextWndGroup->MakeDialogEditView();
}

EditView* ScInputBarGroup::GetEditView()
{
    return maTextWnd->GetEditView();
    return maTextWndGroup->GetEditView();
}

bool ScInputBarGroup::HasEditView() const
{
    return maTextWnd->HasEditView();
    return maTextWndGroup->HasEditView();
}

bool ScInputBarGroup::IsInputActive()
{
    return maTextWnd->IsInputActive();
    return maTextWndGroup->IsInputActive();
}

void ScInputBarGroup::SetFormulaMode(bool bSet)
{
    maTextWnd->SetFormulaMode(bSet);
    maTextWndGroup->SetFormulaMode(bSet);
}

void ScInputBarGroup::IncrementVerticalSize()
{
    maTextWnd->SetNumLines( maTextWnd->GetNumLines() + 1 );
    maTextWndGroup->SetNumLines(maTextWndGroup->GetNumLines() + 1);
    TriggerToolboxLayout();
}

void ScInputBarGroup::DecrementVerticalSize()
{
    if ( maTextWnd->GetNumLines() > 1 )
    if (maTextWndGroup->GetNumLines() > 1)
    {
        maTextWnd->SetNumLines( maTextWnd->GetNumLines() - 1 );
        maTextWndGroup->SetNumLines(maTextWndGroup->GetNumLines() - 1);
        TriggerToolboxLayout();
    }
}
@@ -955,20 +923,20 @@ IMPL_LINK_NOARG(ScInputBarGroup, ClickHdl, Button*, void)
        OSL_FAIL("The parent window pointer pParent is null");
        return;
    }
    if (maTextWnd->GetNumLines() > 1)
    if (maTextWndGroup->GetNumLines() > 1)
    {
        maTextWnd->SetNumLines(1);
        maTextWndGroup->SetNumLines(1);
    }
    else
    {
        maTextWnd->SetNumLines(maTextWnd->GetLastNumExpandedLines());
        maTextWndGroup->SetNumLines(maTextWndGroup->GetLastNumExpandedLines());
    }
    TriggerToolboxLayout();

    // Restore focus to input line(s) if necessary
    ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
    if ( pHdl && pHdl->IsTopMode() )
        maTextWnd->GrabFocus();
        maTextWndGroup->GrabFocus();
}

void ScInputBarGroup::TriggerToolboxLayout()
@@ -996,10 +964,6 @@ void ScInputBarGroup::TriggerToolboxLayout()

        if ( xLayoutManager.is() )
        {
            if ( maTextWnd->GetNumLines() > 1)
                rParent.SetToolbarLayoutMode( ToolBoxLayoutMode::LockVert );
            else
                rParent.SetToolbarLayoutMode( ToolBoxLayoutMode::Normal );
            xLayoutManager->lock();
            DataChangedEvent aFakeUpdate( DataChangedEventType::SETTINGS, nullptr,  AllSettingsFlags::STYLE );

@@ -1022,16 +986,177 @@ void ScInputBarGroup::TriggerToolboxLayout()
    }
}

IMPL_LINK_NOARG(ScInputBarGroup, Impl_ScrollHdl, ScrollBar*, void)
{
    maTextWnd->DoScroll();
}

void ScInputBarGroup::TextGrabFocus()
{
    maTextWndGroup->TextGrabFocus();
}

ScTextWndGroup::ScTextWndGroup(vcl::Window* pParent, ScTabViewShell* pViewSh)
    : ScTextWndBase(pParent, WinBits(WB_TABSTOP)),
      maTextWnd(VclPtr<ScTextWnd>::Create(this, pViewSh)),
      maScrollBar(VclPtr<ScrollBar>::Create(this, WB_TABSTOP | WB_VERT | WB_DRAG))
{
    mnBorderWidth = INPUTLINE_INSET_MARGIN + 1;
    mnBorderHeight = INPUTLINE_INSET_MARGIN + 1;
    maTextWnd->SetPosPixel(Point(mnBorderWidth, mnBorderHeight));
    Size aSize = GetSizePixel();
    maTextWnd->SetSizePixel(Size(aSize.Width() - 2 * mnBorderWidth, aSize.Height() - 2 * mnBorderHeight));
    maTextWnd->Show();
    maTextWnd->SetQuickHelpText(ScResId(SCSTR_QHELP_INPUTWND));
    maTextWnd->SetHelpId(HID_INSWIN_INPUT);
    maScrollBar->SetScrollHdl(LINK(this, ScTextWndGroup, Impl_ScrollHdl));
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
    Color aBackgroundColor = rStyleSettings.GetWindowColor();
    SetBackground(aBackgroundColor);
}

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

void ScTextWndGroup::dispose()
{
    maTextWnd.disposeAndClear();
    maScrollBar.disposeAndClear();
    ScTextWndBase::dispose();
}

void ScTextWndGroup::InsertAccessibleTextData(ScAccessibleEditLineTextData& rTextData)
{
    maTextWnd->InsertAccessibleTextData(rTextData);
}

EditView* ScTextWndGroup::GetEditView()
{
    return maTextWnd->GetEditView();
}

long ScTextWndGroup::GetLastNumExpandedLines()
{
    return maTextWnd->GetLastNumExpandedLines();
}

long ScTextWndGroup::GetNumLines()
{
    return maTextWnd->GetNumLines();
}

long ScTextWndGroup::GetPixelHeightForLines(long nLines)
{
    return maTextWnd->GetPixelHeightForLines(nLines) + 2 * mnBorderHeight;
}

ScrollBar& ScTextWndGroup::GetScrollBar()
{
    return *maScrollBar.get();
}

const OUString& ScTextWndGroup::GetTextString() const
{
    return maTextWnd->GetTextString();
}

bool ScTextWndGroup::HasEditView() const
{
    return maTextWnd->HasEditView();
}

bool ScTextWndGroup::IsInputActive()
{
    return maTextWnd->IsInputActive();
}

void ScTextWndGroup::MakeDialogEditView()
{
    maTextWnd->MakeDialogEditView();
}

void ScTextWndGroup::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
{
    ScTextWndBase::Paint(rRenderContext, rRect);
    const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
    rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
    Size aSize = GetSizePixel();
    rRenderContext.DrawLine(Point(0, 0),
                            Point(aSize.Width() - 1, 0));
    rRenderContext.DrawLine(Point(aSize.Width() - 1, 0),
                            Point(aSize.Width() - 1, aSize.Height() - 1));
    rRenderContext.DrawLine(Point(aSize.Width() - 1, aSize.Height() - 1),
                            Point(0, aSize.Height() - 1));
    rRenderContext.DrawLine(Point(0, aSize.Height() - 1),
                            Point(0, 0));
}

void ScTextWndGroup::RemoveAccessibleTextData(ScAccessibleEditLineTextData& rTextData)
{
    maTextWnd->RemoveAccessibleTextData(rTextData);
}

void ScTextWndGroup::Resize()
{
    Size aSize = GetSizePixel();
    aSize.setHeight(GetPixelHeightForLines(GetNumLines()));
    SetSizePixel(aSize);
    if (maTextWnd->GetNumLines() > 1)
    {
        Size aScrollBarSize = maScrollBar->GetSizePixel();
        aScrollBarSize.setHeight(aSize.Height() - 2);
        maScrollBar->SetPosPixel(Point(aSize.Width() - aScrollBarSize.Width() - 1, 1));
        maScrollBar->SetSizePixel(aScrollBarSize);
        Size aOutputSize = maTextWnd->GetOutputSize();
        maScrollBar->SetVisibleSize(aOutputSize.Height());
        maScrollBar->SetPageSize(aOutputSize.Height());
        maScrollBar->SetLineSize(maTextWnd->GetTextHeight());
        maScrollBar->Resize();
        maScrollBar->Show();
        maTextWnd->SetSizePixel(Size(aSize.Width() - aScrollBarSize.Width() - mnBorderWidth - 1,
                                     aSize.Height() - 2 * mnBorderHeight));
    }
    else
    {
        maScrollBar->Hide();
        maTextWnd->SetSizePixel(Size(aSize.Width() - 2 * mnBorderWidth, aSize.Height() - 2 * mnBorderHeight));
    }
    maTextWnd->Resize();
    Invalidate();
}

void ScTextWndGroup::SetNumLines(long nLines)
{
    maTextWnd->SetNumLines(nLines);
}

void ScTextWndGroup::SetFormulaMode(bool bSet)
{
    maTextWnd->SetFormulaMode(bSet);
}

void ScTextWndGroup::SetTextString(const OUString& rString)
{
    maTextWnd->SetTextString(rString);
}

void ScTextWndGroup::StartEditEngine()
{
    maTextWnd->StartEditEngine();
}

void ScTextWndGroup::StopEditEngine(bool bAll)
{
    maTextWnd->StopEditEngine( bAll );
}

void ScTextWndGroup::TextGrabFocus()
{
    maTextWnd->TextGrabFocus();
}

IMPL_LINK_NOARG(ScTextWndGroup, Impl_ScrollHdl, ScrollBar*, void)
{
    maTextWnd->DoScroll();
}

void ScTextWnd::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect )
{
    EditView* pView = GetEditView();
@@ -1057,8 +1182,8 @@ bool ScTextWnd::HasEditView() const { return mpEditView != nullptr; }

long ScTextWnd::GetPixelHeightForLines(long nLines)
{
    // add padding ( for the borders of the window )
    return ( nLines * LogicToPixel( Size( 0, GetTextHeight() ) ).Height() ) + mnBorderHeight;
    // add padding (for the borders of the window)
    return LogicToPixel(Size(0, nLines * GetTextHeight())).Height() + 1;
}

void ScTextWnd::SetNumLines(long nLines)
@@ -1289,8 +1414,8 @@ void ScTextWnd::InitEditEngine()
    }
}

ScTextWnd::ScTextWnd(ScInputBarGroup* pParent, ScTabViewShell* pViewSh)
    :   ScTextWndBase(pParent, WinBits(WB_HIDE | WB_BORDER)),
ScTextWnd::ScTextWnd(ScTextWndGroup* pParent, ScTabViewShell* pViewSh)
    :   ScTextWndBase(pParent, WinBits(WB_HIDE)),
        DragSourceHelper(this),
        bIsInsertMode(true),
        bFormulaMode (false),
@@ -1305,10 +1430,13 @@ ScTextWnd::ScTextWnd(ScInputBarGroup* pParent, ScTabViewShell* pViewSh)

    bIsRTL = AllSettings::GetLayoutRTL();

    //  always use application font, so a font with cjk chars can be installed
    // always use application font, so a font with cjk chars can be installed
    vcl::Font aAppFont = GetFont();
    aTextFont = aAppFont;
    aTextFont.SetFontSize(PixelToLogic(aAppFont.GetFontSize(), MapMode(MapUnit::MapTwip)));  // AppFont is in pixels
    Size aFontSize = aAppFont.GetFontSize();
    if (aFontSize.Height() < MIN_FONT_SIZE)
        aFontSize.setHeight(MIN_FONT_SIZE);
    aTextFont.SetFontSize(PixelToLogic(aFontSize, MapMode(MapUnit::MapTwip)));

    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();

@@ -1320,10 +1448,10 @@ ScTextWnd::ScTextWnd(ScInputBarGroup* pParent, ScTabViewShell* pViewSh)
    aTextFont.SetColor(aTxtColor);
    aTextFont.SetWeight(WEIGHT_NORMAL);

    Size aSize(1,TBX_WINDOW_HEIGHT);
    Size aMinEditSize( Edit::GetMinimumEditSize() );
    if( aMinEditSize.Height() > aSize.Height() )
        aSize.setHeight( aMinEditSize.Height() );
    Size aSize(1, GetPixelHeightForLines(1));
    Size aMinEditSize(Edit::GetMinimumEditSize());
    if(aMinEditSize.Height() > aSize.Height())
        aSize.setHeight(aMinEditSize.Height());

    SetSizePixel(aSize);
    SetBackground(aBgColor);
@@ -1332,9 +1460,6 @@ ScTextWnd::ScTextWnd(ScInputBarGroup* pParent, ScTabViewShell* pViewSh)
    SetPointer(PointerStyle::Text);
    SetFont(aTextFont);

    Size aBorder = CalcWindowSize(Size());
    mnBorderHeight = aBorder.Height();

    set_id("sc_input_window");
}

diff --git a/sc/source/ui/inc/inputwin.hxx b/sc/source/ui/inc/inputwin.hxx
index 8f13b2c..6d5c91c 100644
--- a/sc/source/ui/inc/inputwin.hxx
+++ b/sc/source/ui/inc/inputwin.hxx
@@ -35,6 +35,7 @@
class EditView;
class ScAccessibleEditLineTextData;
class ScEditEngineDefaulter;
class ScTextWndGroup;
class ScInputBarGroup;
class ScInputHandler;
class ScTabViewShell;
@@ -61,7 +62,7 @@ public:
class ScTextWnd : public ScTextWndBase, public DragSourceHelper     // edit window
{
public:
    ScTextWnd(ScInputBarGroup* pParent, ScTabViewShell* pViewSh);
    ScTextWnd(ScTextWndGroup* pParent, ScTabViewShell* pViewSh);
    virtual         ~ScTextWnd() override;
    virtual void    dispose() override;

@@ -142,10 +143,9 @@ private:
    bool        bInputMode;

    ScTabViewShell* mpViewShell;
    ScInputBarGroup& mrGroupBar;
    ScTextWndGroup& mrGroupBar;
    long mnLines;
    long mnLastExpandedLines;
    long mnBorderHeight;
    bool mbInvalidate;
};

@@ -181,42 +181,75 @@ private:
    void            ReleaseFocus_Impl();
};

class ScTextWndGroup : public ScTextWndBase
{
public:
                 ScTextWndGroup(vcl::Window* pParent, ScTabViewShell* pViewSh);
    virtual      ~ScTextWndGroup() override;
    virtual void dispose() override;

    virtual void            InsertAccessibleTextData(ScAccessibleEditLineTextData& rTextData) override;
    virtual EditView*       GetEditView() override;
    long                    GetLastNumExpandedLines();
    long                    GetNumLines();
    long                    GetPixelHeightForLines(long nLines);
    ScrollBar&              GetScrollBar();
    virtual const OUString& GetTextString() const override;
    virtual bool            HasEditView() const override;
    virtual bool            IsInputActive() override;
    virtual void            MakeDialogEditView() override;
    virtual void            Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
    virtual void            RemoveAccessibleTextData(ScAccessibleEditLineTextData& rTextData) override;
    virtual void            Resize() override;
    void                    SetNumLines(long nLines);
    virtual void            SetFormulaMode(bool bSet) override;
    virtual void            SetTextString(const OUString& rString) override;
    virtual void            StartEditEngine() override;
    virtual void            StopEditEngine(bool bAll) override;
    virtual void            TextGrabFocus() override;

private:
    VclPtr<ScTextWnd> maTextWnd;
    VclPtr<ScrollBar> maScrollBar;

    long mnBorderWidth, mnBorderHeight;

    DECL_LINK(Impl_ScrollHdl, ScrollBar*, void);
};

class ScInputBarGroup : public ScTextWndBase
{

public:
                    ScInputBarGroup( vcl::Window* Parent, ScTabViewShell* pViewSh );
    virtual         ~ScInputBarGroup() override;
    virtual void    dispose() override;
    virtual void    InsertAccessibleTextData( ScAccessibleEditLineTextData& rTextData ) override;
    virtual void    RemoveAccessibleTextData( ScAccessibleEditLineTextData& rTextData ) override;
    void            SetTextString( const OUString& rString ) override;
    void            StartEditEngine() override;
    virtual EditView* GetEditView() override;
    virtual bool HasEditView() const override;
    virtual void    Resize() override;
    virtual const OUString&   GetTextString() const override;
    virtual void            StopEditEngine( bool bAll ) override;
                            ScInputBarGroup(vcl::Window* Parent, ScTabViewShell* pViewSh);
    virtual                 ~ScInputBarGroup() override;
    virtual void            dispose() override;
    virtual void            InsertAccessibleTextData(ScAccessibleEditLineTextData& rTextData) override;
    virtual void            RemoveAccessibleTextData(ScAccessibleEditLineTextData& rTextData) override;
    void                    SetTextString(const OUString& rString) override;
    void                    StartEditEngine() override;
    virtual EditView*       GetEditView() override;
    virtual bool            HasEditView() const override;
    virtual void            Resize() override;
    virtual const OUString& GetTextString() const override;
    virtual void            StopEditEngine(bool bAll) override;
    virtual void            TextGrabFocus() override;
    void            SetFormulaMode( bool bSet ) override;
    void            MakeDialogEditView() override;
    bool            IsInputActive() override;
    ScrollBar&      GetScrollBar() { return *maScrollbar; }
    void            IncrementVerticalSize();
    void            DecrementVerticalSize();
    long            GetNumLines() { return maTextWnd->GetNumLines(); }
    long            GetVertOffset() { return  mnVertOffset; }
    void                    SetFormulaMode(bool bSet) override;
    void                    MakeDialogEditView() override;
    bool                    IsInputActive() override;
    ScrollBar&              GetScrollBar() { return maTextWndGroup->GetScrollBar(); }
    void                    IncrementVerticalSize();
    void                    DecrementVerticalSize();
    long                    GetNumLines() { return maTextWndGroup->GetNumLines(); }
    long                    GetVertOffset() { return  mnVertOffset; }

private:
    void            TriggerToolboxLayout();

    VclPtr<ScTextWnd> maTextWnd;
    VclPtr<ImageButton> maButton;
    VclPtr<ScrollBar> maScrollbar;
    long            mnVertOffset;
    VclPtr<ScTextWndGroup> maTextWndGroup;
    VclPtr<ImageButton>    maButton;
    long                   mnVertOffset;

    DECL_LINK( ClickHdl, Button*, void );
    DECL_LINK( Impl_ScrollHdl, ScrollBar*, void );
    DECL_LINK(ClickHdl, Button*, void);
};

class ScInputWindow final : public ToolBox                        // Parent toolbox
diff --git a/vcl/source/window/toolbox.cxx b/vcl/source/window/toolbox.cxx
index c2dfb856..f7fd673 100644
--- a/vcl/source/window/toolbox.cxx
+++ b/vcl/source/window/toolbox.cxx
@@ -1097,58 +1097,61 @@ void ToolBox::ImplInitToolBoxData()
    // initialize variables
    ImplGetWindowImpl()->mbToolBox  = true;
    mpData.reset(new ImplToolBoxPrivateData);
    mpFloatWin        = nullptr;
    mnDX              = 0;
    mnDY              = 0;
    mnMaxItemWidth    = 0;
    mnMaxItemHeight   = 0;
    mnWinHeight       = 0;
    mnLeftBorder      = 0;
    mnTopBorder       = 0;
    mnRightBorder     = 0;
    mnBottomBorder    = 0;
    mnLastResizeDY    = 0;
    mnOutStyle        = TOOLBOX_STYLE_FLAT; // force flat buttons since NWF
    mnHighItemId      = 0;
    mnCurItemId       = 0;
    mnDownItemId      = 0;
    mnCurPos          = ITEM_NOTFOUND;
    mnLines           = 1;
    mnCurLine         = 1;
    mnCurLines        = 1;
    mnVisLines        = 1;
    mnFloatLines      = 0;
    mnDockLines       = 0;
    mnMouseModifier   = 0;
    mbDrag            = false;
    mbSelection       = false;
    mbUpper           = false;
    mbLower           = false;
    mbIn              = false;
    mbCalc            = true;
    mbFormat          = false;
    mbFullPaint       = false;
    mbHorz            = true;
    mbScroll          = false;
    mbLastFloatMode   = false;
    mbCustomize       = false;
    mbDragging        = false;
    mbIsKeyEvent = false;
    mbChangingHighlight = false;
    mbImagesMirrored  = false;
    mbLineSpacing     = false;
    meButtonType      = ButtonType::SYMBOLONLY;
    meAlign           = WindowAlign::Top;
    meDockAlign       = WindowAlign::Top;
    meLastStyle       = PointerStyle::Arrow;
    mnWinStyle        = 0;
    meLayoutMode      = ToolBoxLayoutMode::Normal;
    meTextPosition    = ToolBoxTextPosition::Right;
    mnLastFocusItemId = 0;
    mnKeyModifier     = 0;
    mnActivateCount   = 0;

    mpFloatWin            = nullptr;
    mnDX                  = 0;
    mnDY                  = 0;
    mnMaxItemWidth        = 0;
    mnMaxItemHeight       = 0;
    mnWinHeight           = 0;
    mnLeftBorder          = 0;
    mnTopBorder           = 0;
    mnRightBorder         = 0;
    mnBottomBorder        = 0;
    mnLastResizeDY        = 0;
    mnOutStyle            = TOOLBOX_STYLE_FLAT; // force flat buttons since NWF
    mnHighItemId          = 0;
    mnCurItemId           = 0;
    mnDownItemId          = 0;
    mnCurPos              = ITEM_NOTFOUND;
    mnLines               = 1;
    mnCurLine             = 1;
    mnCurLines            = 1;
    mnVisLines            = 1;
    mnFloatLines          = 0;
    mnDockLines           = 0;
    mnMouseModifier       = 0;
    mbDrag                = false;
    mbSelection           = false;
    mbUpper               = false;
    mbLower               = false;
    mbIn                  = false;
    mbCalc                = true;
    mbFormat              = false;
    mbFullPaint           = false;
    mbHorz                = true;
    mbScroll              = false;
    mbLastFloatMode       = false;
    mbCustomize           = false;
    mbDragging            = false;
    mbIsKeyEvent          = false;
    mbChangingHighlight   = false;
    mbImagesMirrored      = false;
    mbLineSpacing         = false;
    mbIsArranged          = false;
    meButtonType          = ButtonType::SYMBOLONLY;
    meAlign               = WindowAlign::Top;
    meDockAlign           = WindowAlign::Top;
    meLastStyle           = PointerStyle::Arrow;
    mnWinStyle            = 0;
    meLayoutMode          = ToolBoxLayoutMode::Normal;
    meTextPosition        = ToolBoxTextPosition::Right;
    mnLastFocusItemId     = 0;
    mnKeyModifier         = 0;
    mnActivateCount       = 0;
    mnImagesRotationAngle = 0;
    mpStatusListener  = new VclStatusListener<ToolBox>(this, ".uno:ImageOrientation");

    mpStatusListener = new VclStatusListener<ToolBox>(this, ".uno:ImageOrientation");
    mpStatusListener->startListening();

    mpIdle.reset(new Idle("vcl::ToolBox maIdle update"));
@@ -2141,6 +2144,7 @@ void ToolBox::ImplFormat( bool bResize )
            else if ( mnCurLine+mnVisLines-1 > mnCurLines )
                mnCurLine = mnCurLines - (mnVisLines-1);

            long firstItemCenter = 0;
            for (auto & item : mpData->m_aItems)
            {
                item.mbShowWindow = false;
@@ -2184,35 +2188,32 @@ void ToolBox::ImplFormat( bool bResize )
                    Size aCurrentItemSize( item.GetSize( mbHorz, mbScroll, nMax, Size(mnMaxItemWidth, mnMaxItemHeight) ) );

                    // 2. position item rect and use size from step 1
                    //  items will be centered horizontally (if mbHorz) or vertically
                    //  advance nX and nY accordingly
                    // items will be centered horizontally (if mbHorz) or vertically
                    // advance nX and nY accordingly

                    if ( mbHorz )
                    {
                        // In special mode Locked horizontal positions of all items remain unchanged.

                        if ( mbIsArranged && meLayoutMode == ToolBoxLayoutMode::Locked && mnLines == 1 && item.maRect.Left() > 0 )
                            nX = item.maRect.Left();
                        item.maCalcRect.SetLeft( nX );
                        // if special ToolBoxLayoutMode::LockVert lock vertical position
                        // don't recalculate the vertical position of the item
                        if ( meLayoutMode == ToolBoxLayoutMode::LockVert && mnLines == 1 )
                        {
                            // Somewhat of a hack here, calc deletes and re-adds
                            // the sum/assign & ok/cancel items dynamically.
                            // Because ToolBoxLayoutMode::LockVert effectively prevents
                            // recalculation of the vertical pos of an item the
                            // item.maRect.Top() for those newly added items is
                            // 0. The hack here is that we want to effectively
                            // recalculate the vertical pos for those added
                            // items here. ( Note: assume mnMaxItemHeight is
                            // equal to the LineSize when multibar has a single
                            // line size )
                            if ( item.maRect.Top() ||
                                 (item.mpWindow && item.mpWindow->GetType() == WindowType::CALCINPUTLINE) ) // tdf#83099
                            {
                                item.maCalcRect.SetTop( item.maRect.Top() );
                            }

                        // In special mode Locked first item's vertical position remains unchanged. Consecutive items vertical
                        // positions are centered around first item's vertical position. If an item's height exceeds available
                        // space, item's vertical position remains unchanged too.

                        if ( mbIsArranged && meLayoutMode == ToolBoxLayoutMode::Locked && mnLines == 1 )
                            if ( firstItemCenter > 0 )
                                if ( firstItemCenter-aCurrentItemSize.Height()/2 > nY  )
                                    item.maCalcRect.SetTop( firstItemCenter-aCurrentItemSize.Height()/2 );
                                else
                                    item.maCalcRect.SetTop( item.maRect.Top() );
                            else
                            {
                                item.maCalcRect.SetTop( nY+(mnMaxItemHeight-aCurrentItemSize.Height())/2 );
                                item.maCalcRect.SetTop( item.maRect.Top() );
                                firstItemCenter = item.maRect.Top()+aCurrentItemSize.Height()/2;
                            }
                        }
                        else
                            item.maCalcRect.SetTop( nY+(nLineSize-aCurrentItemSize.Height())/2 );
                        item.maCalcRect.SetRight( nX+aCurrentItemSize.Width()-1 );
@@ -2245,6 +2246,7 @@ void ToolBox::ImplFormat( bool bResize )
                        item.mpWindow->Hide();
                }
            } // end of loop over all items
            mbIsArranged = true;
        }
        else
            // we have no toolbox items