weld SmGraphicWindow

Change-Id: Ie163640d6453f30d1cebdaf75ecd41374b2b9ec3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114351
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/solenv/clang-format/excludelist b/solenv/clang-format/excludelist
index ae149d0..99d83dc 100644
--- a/solenv/clang-format/excludelist
+++ b/solenv/clang-format/excludelist
@@ -10977,7 +10977,6 @@ starmath/inc/helpids.h
starmath/inc/node.hxx
starmath/inc/parse.hxx
starmath/inc/rect.hxx
starmath/inc/scrwin.hxx
starmath/inc/smmod.hxx
starmath/inc/symbol.hxx
starmath/inc/unomodel.hxx
@@ -11009,7 +11008,6 @@ starmath/source/ooxmlimport.cxx
starmath/source/ooxmlimport.hxx
starmath/source/parse.cxx
starmath/source/rect.cxx
starmath/source/scrwin.cxx
starmath/source/smdetect.cxx
starmath/source/smdetect.hxx
starmath/source/smdll.cxx
diff --git a/starmath/Library_sm.mk b/starmath/Library_sm.mk
index 2e3cc03..0c27c07 100644
--- a/starmath/Library_sm.mk
+++ b/starmath/Library_sm.mk
@@ -84,7 +84,6 @@ $(eval $(call gb_Library_add_exception_objects,sm,\
        starmath/source/parse \
        starmath/source/parse5 \
        starmath/source/rect \
        starmath/source/scrwin \
        starmath/source/smdll \
        starmath/source/smmod \
        starmath/source/symbol \
diff --git a/starmath/UIConfig_smath.mk b/starmath/UIConfig_smath.mk
index c243742..2a39af9 100644
--- a/starmath/UIConfig_smath.mk
+++ b/starmath/UIConfig_smath.mk
@@ -36,6 +36,7 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/smath,\
	starmath/uiconfig/smath/ui/fontdialog \
	starmath/uiconfig/smath/ui/fontsizedialog \
	starmath/uiconfig/smath/ui/fonttypedialog \
	starmath/uiconfig/smath/ui/mathwindow \
	starmath/uiconfig/smath/ui/printeroptions \
	starmath/uiconfig/smath/ui/savedefaultsdialog \
	starmath/uiconfig/smath/ui/smathsettings \
diff --git a/starmath/inc/scrwin.hxx b/starmath/inc/scrwin.hxx
deleted file mode 100644
index 348779e..0000000
--- a/starmath/inc/scrwin.hxx
+++ /dev/null
@@ -1,68 +0,0 @@
/* -*- 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 .
 */

#pragma once

#include <vcl/window.hxx>
#include <vcl/vclptr.hxx>

class DataChangedEvent;
class ScrollBar;
class ScrollBarBox;

class ScrollableWindow : public vcl::Window
{
private:
    Point           aPixOffset;         // offset to virtual window (pixel)
    Size            aTotPixSz;          // total size of virtual window (pixel)
    tools::Long            nLinePixH;          // size of a line/column (pixel)
    tools::Long            nColumnPixW;

    VclPtr<ScrollBar>    aVScroll;      // the scrollbars
    VclPtr<ScrollBar>    aHScroll;
    VclPtr<ScrollBarBox> aCornerWin;    // window in the bottom right corner
    bool            bScrolling:1;       // user controlled scrolling

    DECL_LINK( ScrollHdl, ScrollBar *, void );
    DECL_LINK( EndScrollHdl, ScrollBar *, void );

public:
                    ScrollableWindow( vcl::Window* pParent );
    virtual         ~ScrollableWindow() override;
    virtual void    dispose() override;

    virtual void    Resize() override;
    virtual void    Command( const CommandEvent& rCEvt ) override;
    virtual void    DataChanged( const DataChangedEvent& rDEvt ) override;

    using OutputDevice::SetMapMode;
    virtual void    SetMapMode( const MapMode& rNewMapMode ) override;
    MapMode GetMapMode() const;

    void            SetTotalSize( const Size& rNewSize );
    Size            GetTotalSize() const { return PixelToLogic( aTotPixSz ); }

    using Window::Scroll;
    virtual void    Scroll( tools::Long nDeltaX, tools::Long nDeltaY, ScrollFlags nFlags = ScrollFlags::NONE ) override;

private:
    Size         GetOutputSizePixel() const;
};

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/starmath/inc/view.hxx b/starmath/inc/view.hxx
index 4119041..94733e2 100644
--- a/starmath/inc/view.hxx
+++ b/starmath/inc/view.hxx
@@ -30,16 +30,61 @@
#include <vcl/timer.hxx>
#include "document.hxx"
#include "edit.hxx"
#include "scrwin.hxx"

class SmViewShell;
class SmPrintUIOptions;
class SmGraphicAccessible;
class SmGraphicWidget;
class SmElementsDockingWindow;

namespace svtools { class ColorConfig; }

class SmGraphicWindow final : public ScrollableWindow
class SmGraphicWindow final : public InterimItemWindow
{
private:
    Point aPixOffset; // offset to virtual window (pixel)
    Size aTotPixSz; // total size of virtual window (pixel)
    tools::Long nLinePixH; // size of a line/column (pixel)
    tools::Long nColumnPixW;
    sal_uInt16 nZoom;

    std::unique_ptr<weld::ScrolledWindow> mxScrolledWindow;
    std::unique_ptr<SmGraphicWidget> mxGraphic;
    std::unique_ptr<weld::CustomWeld> mxGraphicWin;

    DECL_LINK(ScrollHdl, weld::ScrolledWindow&, void);

    void SetGraphicMapMode(const MapMode& rNewMapMode);
    MapMode GetGraphicMapMode() const;

public:
    explicit SmGraphicWindow(SmViewShell& rShell);
    virtual void dispose() override;
    virtual ~SmGraphicWindow() override;

    void SetTotalSize(const Size& rNewSize);
    Size GetTotalSize() const;

    void SetZoom(sal_uInt16 Factor);
    sal_uInt16 GetZoom() const { return nZoom; }

    void ZoomToFitInWindow();

    virtual void Resize() override;
    void ShowContextMenu(const CommandEvent& rCEvt);

    SmGraphicWidget& GetGraphicWidget()
    {
        return *mxGraphic;
    }

    const SmGraphicWidget& GetGraphicWidget() const
    {
        return *mxGraphic;
    }
};

class SmGraphicWidget final : public weld::CustomWidgetController
{
public:
    bool IsCursorVisible() const
@@ -54,28 +99,21 @@ public:
    void ShowLine(bool bShow);
    const SmNode * SetCursorPos(sal_uInt16 nRow, sal_uInt16 nCol);

    explicit SmGraphicWindow(SmViewShell* pShell);
    virtual ~SmGraphicWindow() override;
    virtual void dispose() override;
    explicit SmGraphicWidget(SmViewShell& rShell, SmGraphicWindow& rGraphicWindow);
    virtual ~SmGraphicWidget() override;

    // Window
    virtual void ApplySettings(vcl::RenderContext&) override;
    virtual void MouseButtonDown(const MouseEvent &rMEvt) override;
    virtual void MouseMove(const MouseEvent &rMEvt) override;
    // CustomWidgetController
    virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
    virtual bool MouseButtonDown(const MouseEvent &rMEvt) override;
    virtual bool MouseMove(const MouseEvent &rMEvt) override;
    virtual void GetFocus() override;
    virtual void LoseFocus() override;

    SmViewShell* GetView()
    {
        return pViewShell;
    }
    void SetTotalSize();

    using Window::SetZoom;
    void SetZoom(sal_uInt16 Factor);
    using Window::GetZoom;
    sal_uInt16 GetZoom() const
    SmViewShell& GetView()
    {
        return nZoom;
        return mrViewShell;
    }

    const Point& GetFormulaDrawPos() const
@@ -83,14 +121,9 @@ public:
        return aFormulaDrawPos;
    }

    void ZoomToFitInWindow();
    using ScrollableWindow::SetTotalSize;
    void SetTotalSize();

    // for Accessibility
    virtual css::uno::Reference<css::accessibility::XAccessible> CreateAccessible() override;

    using Window::GetAccessible;
    SmGraphicAccessible* GetAccessible_Impl()
    {
        return mxAccessible.get();
@@ -101,15 +134,13 @@ private:
    {
        bIsCursorVisible = bVis;
    }
    using Window::SetCursor;
    void SetCursor(const SmNode *pNode);
    void SetCursor(const tools::Rectangle &rRect);
    static bool IsInlineEditEnabled();

    virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override;
    virtual void KeyInput(const KeyEvent& rKEvt) override;
    virtual void Command(const CommandEvent& rCEvt) override;
    virtual void StateChanged( StateChangedType eChanged ) override;
    virtual bool KeyInput(const KeyEvent& rKEvt) override;
    virtual bool Command(const CommandEvent& rCEvt) override;

    void RepaintViewShellDoc();
    DECL_LINK(CaretBlinkTimerHdl, Timer *, void);
@@ -117,6 +148,8 @@ private:
    void CaretBlinkStart();
    void CaretBlinkStop();

    SmGraphicWindow& mrGraphicWindow;

    Point aFormulaDrawPos;
    // old style editing pieces
    tools::Rectangle aCursorRect;
@@ -124,15 +157,14 @@ private:
    bool bIsLineVisible;
    AutoTimer aCaretBlinkTimer;
    rtl::Reference<SmGraphicAccessible> mxAccessible;
    SmViewShell* pViewShell;
    sal_uInt16 nZoom;
    SmViewShell& mrViewShell;
};

class SmGraphicController final : public SfxControllerItem
{
    SmGraphicWindow &rGraphic;
    SmGraphicWidget &rGraphic;
public:
    SmGraphicController(SmGraphicWindow &, sal_uInt16, SfxBindings & );
    SmGraphicController(SmGraphicWidget &, sal_uInt16, SfxBindings & );
    virtual void StateChanged(sal_uInt16             nSID,
                              SfxItemState       eState,
                              const SfxPoolItem* pState) override;
@@ -209,7 +241,7 @@ class SmViewShell: public SfxViewShell
{
    std::unique_ptr<sfx2::DocumentInserter> mpDocInserter;
    std::unique_ptr<SfxRequest> mpRequest;
    VclPtr<SmGraphicWindow> mpGraphic;
    VclPtr<SmGraphicWindow> mxGraphicWindow;
    SmGraphicController maGraphicController;
    OUString maStatusText;
    bool mbPasteState;
@@ -266,13 +298,18 @@ public:

    SmEditWindow * GetEditWindow();

    SmGraphicWidget& GetGraphicWidget()
    {
        return mxGraphicWindow->GetGraphicWidget();
    }
    const SmGraphicWidget& GetGraphicWidget() const
    {
        return mxGraphicWindow->GetGraphicWidget();
    }

    SmGraphicWindow& GetGraphicWindow()
    {
        return *mpGraphic;
    }
    const SmGraphicWindow& GetGraphicWindow() const
    {
        return *mpGraphic;
        return *mxGraphicWindow;
    }

    SmElementsDockingWindow* GetDockingWindow();
@@ -299,7 +336,7 @@ public:

    /** Set bInsertIntoEditWindow so we know where to insert
     *
     * This method is called whenever SmGraphicWindow or SmEditWindow gets focus,
     * This method is called whenever SmGraphicWidget or SmEditWindow gets focus,
     * so that when text is inserted from catalog or elsewhere we know whether to
     * insert for the visual editor, or the text editor.
     */
diff --git a/starmath/source/accessibility.cxx b/starmath/source/accessibility.cxx
index bab8d77..0ca0863 100644
--- a/starmath/source/accessibility.cxx
+++ b/starmath/source/accessibility.cxx
@@ -32,6 +32,7 @@
#include <cppuhelper/supportsservice.hxx>
#include <osl/diagnose.h>
#include <svx/AccessibleTextHelper.hxx>
#include <tools/diagnose_ex.h>
#include <vcl/svapp.hxx>
#include <vcl/window.hxx>
#include <vcl/unohelp2.hxx>
@@ -59,50 +60,7 @@ using namespace com::sun::star::lang;
using namespace com::sun::star::uno;
using namespace com::sun::star::accessibility;


static awt::Rectangle lcl_GetBounds( vcl::Window const *pWin )
{
    // !! see VCLXAccessibleComponent::implGetBounds()

    //! the coordinates returned are relative to the parent window !
    //! Thus the top-left point may be different from (0, 0) !

    awt::Rectangle aBounds;
    if (pWin)
    {
        tools::Rectangle aRect = pWin->GetWindowExtentsRelative( nullptr );
        aBounds.X       = aRect.Left();
        aBounds.Y       = aRect.Top();
        aBounds.Width   = aRect.GetWidth();
        aBounds.Height  = aRect.GetHeight();
        vcl::Window* pParent = pWin->GetAccessibleParentWindow();
        if (pParent)
        {
            tools::Rectangle aParentRect = pParent->GetWindowExtentsRelative( nullptr );
            awt::Point aParentScreenLoc( aParentRect.Left(), aParentRect.Top() );
            aBounds.X -= aParentScreenLoc.X;
            aBounds.Y -= aParentScreenLoc.Y;
        }
    }
    return aBounds;
}

static awt::Point lcl_GetLocationOnScreen( vcl::Window const *pWin )
{
    // !! see VCLXAccessibleComponent::getLocationOnScreen()

    awt::Point aPos;
    if (pWin)
    {
        tools::Rectangle aRect = pWin->GetWindowExtentsRelative( nullptr );
        aPos.X = aRect.Left();
        aPos.Y = aRect.Top();
    }
    return aPos;
}


SmGraphicAccessible::SmGraphicAccessible( SmGraphicWindow *pGraphicWin ) :
SmGraphicAccessible::SmGraphicAccessible(SmGraphicWidget *pGraphicWin) :
    aAccName            (SmResId(RID_DOCUMENTSTR)),
    nClientId           (0),
    pWin                (pGraphicWin)
@@ -114,10 +72,9 @@ SmGraphicAccessible::~SmGraphicAccessible()
{
}


SmDocShell * SmGraphicAccessible::GetDoc_Impl()
{
    SmViewShell *pView = pWin ? pWin->GetView() : nullptr;
    SmViewShell *pView = pWin ? &pWin->GetView() : nullptr;
    return pView ? pView->GetDoc() : nullptr;
}

@@ -171,7 +128,7 @@ sal_Bool SAL_CALL SmGraphicAccessible::containsPoint( const awt::Point& aPoint )
    if (!pWin)
        throw RuntimeException();

    Size aSz( pWin->GetSizePixel() );
    Size aSz( pWin->GetOutputSizePixel() );
    return  aPoint.X >= 0  &&  aPoint.Y >= 0  &&
            aPoint.X < aSz.Width()  &&  aPoint.Y < aSz.Height();
}
@@ -191,9 +148,17 @@ awt::Rectangle SAL_CALL SmGraphicAccessible::getBounds()
    SolarMutexGuard aGuard;
    if (!pWin)
        throw RuntimeException();
    OSL_ENSURE(pWin->GetParent()->GetAccessible() == getAccessibleParent(),
            "mismatch of window parent and accessible parent" );
    return lcl_GetBounds( pWin );

    const Point aOutPos;
    const Size aOutSize(pWin->GetOutputSizePixel());
    css::awt::Rectangle aRet;

    aRet.X = aOutPos.X();
    aRet.Y = aOutPos.Y();
    aRet.Width = aOutSize.Width();
    aRet.Height = aOutSize.Height();

    return aRet;
}

awt::Point SAL_CALL SmGraphicAccessible::getLocation()
@@ -201,10 +166,14 @@ awt::Point SAL_CALL SmGraphicAccessible::getLocation()
    SolarMutexGuard aGuard;
    if (!pWin)
        throw RuntimeException();
    OSL_ENSURE(pWin->GetParent()->GetAccessible() == getAccessibleParent(),
            "mismatch of window parent and accessible parent" );
    awt::Rectangle aRect( lcl_GetBounds( pWin ) );
    return awt::Point( aRect.X, aRect.Y );

    const css::awt::Rectangle aRect(getBounds());
    css::awt::Point aRet;

    aRet.X = aRect.X;
    aRet.Y = aRect.Y;

    return aRet;
}

awt::Point SAL_CALL SmGraphicAccessible::getLocationOnScreen()
@@ -212,9 +181,28 @@ awt::Point SAL_CALL SmGraphicAccessible::getLocationOnScreen()
    SolarMutexGuard aGuard;
    if (!pWin)
        throw RuntimeException();
    OSL_ENSURE(pWin->GetParent()->GetAccessible() == getAccessibleParent(),
            "mismatch of window parent and accessible parent" );
    return lcl_GetLocationOnScreen( pWin );

    css::awt::Point aScreenLoc(0, 0);

    css::uno::Reference<css::accessibility::XAccessible> xParent(getAccessibleParent());
    if (xParent)
    {
        css::uno::Reference<css::accessibility::XAccessibleContext> xParentContext(
            xParent->getAccessibleContext());
        css::uno::Reference<css::accessibility::XAccessibleComponent> xParentComponent(
            xParentContext, css::uno::UNO_QUERY);
        OSL_ENSURE(xParentComponent.is(),
                   "WeldEditAccessible::getLocationOnScreen: no parent component!");
        if (xParentComponent.is())
        {
            css::awt::Point aParentScreenLoc(xParentComponent->getLocationOnScreen());
            css::awt::Point aOwnRelativeLoc(getLocation());
            aScreenLoc.X = aParentScreenLoc.X + aOwnRelativeLoc.X;
            aScreenLoc.Y = aParentScreenLoc.Y + aOwnRelativeLoc.Y;
        }
    }

    return aScreenLoc;
}

awt::Size SAL_CALL SmGraphicAccessible::getSize()
@@ -222,16 +210,8 @@ awt::Size SAL_CALL SmGraphicAccessible::getSize()
    SolarMutexGuard aGuard;
    if (!pWin)
        throw RuntimeException();
    OSL_ENSURE(pWin->GetParent()->GetAccessible() == getAccessibleParent(),
            "mismatch of window parent and accessible parent" );

    Size aSz( pWin->GetSizePixel() );
#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
    awt::Rectangle aRect( lcl_GetBounds( pWin ) );
    Size aSz2( aRect.Width, aRect.Height );
    assert(aSz == aSz2 && "mismatch in width" );
#endif
    return awt::Size( aSz.Width(), aSz.Height() );
    Size aSz(pWin->GetOutputSizePixel());
    return css::awt::Size(aSz.Width(), aSz.Height());
}

void SAL_CALL SmGraphicAccessible::grabFocus()
@@ -246,22 +226,28 @@ void SAL_CALL SmGraphicAccessible::grabFocus()
sal_Int32 SAL_CALL SmGraphicAccessible::getForeground()
{
    SolarMutexGuard aGuard;

    if (!pWin)
        throw RuntimeException();
    return static_cast<sal_Int32>(pWin->GetTextColor());

    weld::DrawingArea* pDrawingArea = pWin->GetDrawingArea();
    OutputDevice& rDevice = pDrawingArea->get_ref_device();

    return static_cast<sal_Int32>(rDevice.GetTextColor());
}

sal_Int32 SAL_CALL SmGraphicAccessible::getBackground()
{
    SolarMutexGuard aGuard;

    if (!pWin)
        throw RuntimeException();
    Wallpaper aWall( pWin->GetDisplayBackground() );

    weld::DrawingArea* pDrawingArea = pWin->GetDrawingArea();
    OutputDevice& rDevice = pDrawingArea->get_ref_device();

    Wallpaper aWall(rDevice.GetBackground());
    Color nCol;
    if (aWall.IsBitmap() || aWall.IsGradient())
        nCol = pWin->GetSettings().GetStyleSettings().GetWindowColor();
        nCol = Application::GetSettings().GetStyleSettings().GetWindowColor();
    else
        nCol = aWall.GetColor();
    return static_cast<sal_Int32>(nCol);
@@ -284,24 +270,44 @@ Reference< XAccessible > SAL_CALL SmGraphicAccessible::getAccessibleParent()
    if (!pWin)
        throw RuntimeException();

    vcl::Window *pAccParent = pWin->GetAccessibleParentWindow();
    OSL_ENSURE( pAccParent, "accessible parent missing" );
    return pAccParent ? pAccParent->GetAccessible() : Reference< XAccessible >();
    return pWin->GetDrawingArea()->get_accessible_parent();
}

sal_Int32 SAL_CALL SmGraphicAccessible::getAccessibleIndexInParent()
{
    SolarMutexGuard aGuard;
    sal_Int32 nIdx = -1;
    vcl::Window *pAccParent = pWin ? pWin->GetAccessibleParentWindow() : nullptr;
    if (pAccParent)

    // -1 for child not found/no parent (according to specification)
    sal_Int32 nRet = -1;

    css::uno::Reference<css::accessibility::XAccessible> xParent(getAccessibleParent());
    if (!xParent)
        return nRet;

    try
    {
        sal_uInt16 nCnt = pAccParent->GetAccessibleChildWindowCount();
        for (sal_uInt16 i = 0;  i < nCnt  &&  nIdx == -1;  ++i)
            if (pAccParent->GetAccessibleChildWindow( i ) == pWin)
                nIdx = i;
        css::uno::Reference<css::accessibility::XAccessibleContext> xParentContext(
            xParent->getAccessibleContext());

        //  iterate over parent's children and search for this object
        if (xParentContext.is())
        {
            sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
            for (sal_Int32 nChild = 0; (nChild < nChildCount) && (-1 == nRet); ++nChild)
            {
                css::uno::Reference<css::accessibility::XAccessible> xChild(
                    xParentContext->getAccessibleChild(nChild));
                if (xChild.get() == this)
                    nRet = nChild;
            }
        }
    }
    return nIdx;
    catch (const css::uno::Exception&)
    {
        TOOLS_WARN_EXCEPTION("svx", "WeldEditAccessible::getAccessibleIndexInParent");
    }

    return nRet;
}

sal_Int16 SAL_CALL SmGraphicAccessible::getAccessibleRole()
@@ -349,7 +355,9 @@ Reference< XAccessibleStateSet > SAL_CALL SmGraphicAccessible::getAccessibleStat
            pStateSet->AddState( AccessibleStateType::SHOWING );
        if (pWin->IsReallyVisible())
            pStateSet->AddState( AccessibleStateType::VISIBLE );
        if (COL_TRANSPARENT != pWin->GetBackground().GetColor())
        weld::DrawingArea* pDrawingArea = pWin->GetDrawingArea();
        OutputDevice& rDevice = pDrawingArea->get_ref_device();
        if (COL_TRANSPARENT != rDevice.GetBackground().GetColor())
            pStateSet->AddState( AccessibleStateType::OPAQUE );
    }

@@ -443,8 +451,7 @@ awt::Rectangle SAL_CALL SmGraphicAccessible::getCharacterBounds( sal_Int32 nInde
        throw RuntimeException();

    // get accessible text
    SmViewShell *pView = pWin->GetView();
    SmDocShell  *pDoc  = pView ? pView->GetDoc() : nullptr;
    SmDocShell* pDoc  = pWin->GetView().GetDoc();
    if (!pDoc)
        throw RuntimeException();
    OUString aTxt( GetAccessibleText_Impl() );
@@ -477,15 +484,18 @@ awt::Rectangle SAL_CALL SmGraphicAccessible::getCharacterBounds( sal_Int32 nInde
            Point aTLPos (pWin->GetFormulaDrawPos() + aOffset);
            Size  aSize (pNode->GetSize());

            weld::DrawingArea* pDrawingArea = pWin->GetDrawingArea();
            OutputDevice& rDevice = pDrawingArea->get_ref_device();

            std::unique_ptr<tools::Long[]> pXAry(new tools::Long[ aNodeText.getLength() ]);
            pWin->SetFont( pNode->GetFont() );
            pWin->GetTextArray( aNodeText, pXAry.get(), 0, aNodeText.getLength() );
            rDevice.SetFont( pNode->GetFont() );
            rDevice.GetTextArray( aNodeText, pXAry.get(), 0, aNodeText.getLength() );
            aTLPos.AdjustX(nNodeIndex > 0 ? pXAry[nNodeIndex - 1] : 0 );
            aSize.setWidth( nNodeIndex > 0 ? pXAry[nNodeIndex] - pXAry[nNodeIndex - 1] : pXAry[nNodeIndex] );
            pXAry.reset();

            aTLPos = pWin->LogicToPixel( aTLPos );
            aSize  = pWin->LogicToPixel( aSize );
            aTLPos = rDevice.LogicToPixel( aTLPos );
            aSize  = rDevice.LogicToPixel( aSize );
            aRes.X = aTLPos.X();
            aRes.Y = aTLPos.Y();
            aRes.Width  = aSize.Width();
@@ -513,15 +523,18 @@ sal_Int32 SAL_CALL SmGraphicAccessible::getIndexAtPoint( const awt::Point& aPoin
    sal_Int32 nRes = -1;
    if (pWin)
    {
        const SmNode *pTree = pWin->GetView()->GetDoc()->GetFormulaTree();
        const SmNode *pTree = pWin->GetView().GetDoc()->GetFormulaTree();
        // can be NULL! e.g. if one clicks within the window already during loading of the
        // document (before the parser even started)
        if (!pTree)
            return nRes;

        weld::DrawingArea* pDrawingArea = pWin->GetDrawingArea();
        OutputDevice& rDevice = pDrawingArea->get_ref_device();

        // get position relative to formula draw position
        Point  aPos( aPoint.X, aPoint.Y );
        aPos = pWin->PixelToLogic( aPos );
        aPos = rDevice.PixelToLogic( aPos );
        aPos -= pWin->GetFormulaDrawPos();

        // if it was inside the formula then get the appropriate node
@@ -548,8 +561,8 @@ sal_Int32 SAL_CALL SmGraphicAccessible::getIndexAtPoint( const awt::Point& aPoin
                tools::Long nNodeX = pNode->GetLeft();

                std::unique_ptr<tools::Long[]> pXAry(new tools::Long[ aTxt.getLength() ]);
                pWin->SetFont( pNode->GetFont() );
                pWin->GetTextArray( aTxt, pXAry.get(), 0, aTxt.getLength() );
                rDevice.SetFont( pNode->GetFont() );
                rDevice.GetTextArray( aTxt, pXAry.get(), 0, aTxt.getLength() );
                for (sal_Int32 i = 0;  i < aTxt.getLength()  &&  nRes == -1;  ++i)
                {
                    if (pXAry[i] + nNodeX > aPos.X())
@@ -691,7 +704,7 @@ sal_Bool SAL_CALL SmGraphicAccessible::copyText(
    if (!pWin)
        throw RuntimeException();

    Reference< datatransfer::clipboard::XClipboard > xClipboard = pWin->GetClipboard();
    Reference< datatransfer::clipboard::XClipboard > xClipboard = GetSystemClipboard();
    if ( xClipboard.is() )
    {
        OUString sText( getTextRange(nStartIndex, nEndIndex) );
diff --git a/starmath/source/accessibility.hxx b/starmath/source/accessibility.hxx
index 817c4ca..5431b9f 100644
--- a/starmath/source/accessibility.hxx
+++ b/starmath/source/accessibility.hxx
@@ -61,7 +61,7 @@ class SmGraphicAccessible final :
    /// client id in the AccessibleEventNotifier queue
    sal_uInt32                          nClientId;

    VclPtr<SmGraphicWindow>             pWin;
    SmGraphicWidget*                    pWin;

    SmGraphicAccessible( const SmGraphicAccessible & ) = delete;
    SmGraphicAccessible & operator = ( const SmGraphicAccessible & ) = delete;
@@ -70,7 +70,7 @@ class SmGraphicAccessible final :
    OUString        GetAccessibleText_Impl();

public:
    explicit SmGraphicAccessible( SmGraphicWindow *pGraphicWin );
    explicit SmGraphicAccessible( SmGraphicWidget *pGraphicWin );
    virtual ~SmGraphicAccessible() override;

    void                ClearWin();     // to be called when view is destroyed
diff --git a/starmath/source/cursor.cxx b/starmath/source/cursor.cxx
index a839b0e..e2dbdc4 100644
--- a/starmath/source/cursor.cxx
+++ b/starmath/source/cursor.cxx
@@ -1320,7 +1320,7 @@ void SmCursor::RequestRepaint(){
        if ( SfxObjectCreateMode::EMBEDDED == mpDocShell->GetCreateMode() )
            mpDocShell->Repaint();
        else
            pViewSh->GetGraphicWindow().Invalidate();
            pViewSh->GetGraphicWidget().Invalidate();
    }
}

diff --git a/starmath/source/document.cxx b/starmath/source/document.cxx
index c3faff2..10fee0c 100644
--- a/starmath/source/document.cxx
+++ b/starmath/source/document.cxx
@@ -174,7 +174,7 @@ void SmDocShell::SetText(const OUString& rBuffer)
            Repaint();
        }
        else
            pViewSh->GetGraphicWindow().Invalidate();
            pViewSh->GetGraphicWidget().Invalidate();
    }

    if ( bIsEnabled )
@@ -182,7 +182,7 @@ void SmDocShell::SetText(const OUString& rBuffer)
    SetModified();

    // launch accessible event if necessary
    SmGraphicAccessible *pAcc = pViewSh ? pViewSh->GetGraphicWindow().GetAccessible_Impl() : nullptr;
    SmGraphicAccessible *pAcc = pViewSh ? pViewSh->GetGraphicWidget().GetAccessible_Impl() : nullptr;
    if (pAcc)
    {
        Any aOldValue, aNewValue;
@@ -260,7 +260,7 @@ void SmDocShell::ArrangeFormula()
    {
        SmViewShell *pView = SmGetActiveView();
        if (pView)
            pOutDev = &pView->GetGraphicWindow();
            pOutDev = &pView->GetGraphicWidget().GetDrawingArea()->get_ref_device();
        else
        {
            pOutDev = &SM_MOD()->GetDefaultVirtualDev();
@@ -622,7 +622,7 @@ void SmDocShell::Repaint()
    SetVisAreaSize(aVisSize);
    SmViewShell* pViewSh = SmGetActiveView();
    if (pViewSh)
        pViewSh->GetGraphicWindow().Invalidate();
        pViewSh->GetGraphicWidget().Invalidate();

    if (bIsEnabled)
        EnableSetModified(bIsEnabled);
@@ -1145,7 +1145,7 @@ void SmDocShell::GetState(SfxItemSet &rSet)
            break;

        case SID_GRAPHIC_SM:
            //! very old (pre UNO) and ugly hack to invalidate the SmGraphicWindow.
            //! very old (pre UNO) and ugly hack to invalidate the SmGraphicWidget.
            //! If mnModifyCount gets changed then the call below will implicitly notify
            //! SmGraphicController::StateChanged and there the window gets invalidated.
            //! Thus all the 'mnModifyCount++' before invalidating this slot.
diff --git a/starmath/source/edit.cxx b/starmath/source/edit.cxx
index 4c3549ec..2aa3c31 100644
--- a/starmath/source/edit.cxx
+++ b/starmath/source/edit.cxx
@@ -265,7 +265,7 @@ IMPL_LINK_NOARG(SmEditTextWindow, CursorMoveTimerHdl, Timer *, void)
            sal_Int32  nRow;
            sal_uInt16 nCol;
            SmGetLeftSelectionPart(aNewSelection, nRow, nCol);
            pViewSh->GetGraphicWindow().SetCursorPos(static_cast<sal_uInt16>(nRow), nCol);
            pViewSh->GetGraphicWidget().SetCursorPos(static_cast<sal_uInt16>(nRow), nCol);
            aOldSelection = aNewSelection;
        }
    }
@@ -424,7 +424,7 @@ bool SmEditTextWindow::KeyInput(const KeyEvent& rKEvt)
            // SFX has maybe called a slot of the view and thus (because of a hack in SFX)
            // set the focus to the view
            SmViewShell* pVShell = mrEditWindow.GetView();
            if ( pVShell && pVShell->GetGraphicWindow().HasFocus() )
            if ( pVShell && pVShell->GetGraphicWidget().HasFocus() )
            {
                GrabFocus();
            }
diff --git a/starmath/source/scrwin.cxx b/starmath/source/scrwin.cxx
deleted file mode 100644
index 596ed799..0000000
--- a/starmath/source/scrwin.cxx
+++ /dev/null
@@ -1,345 +0,0 @@
/* -*- 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/commandevent.hxx>
#include <vcl/event.hxx>
#include <vcl/settings.hxx>
#include <vcl/scrbar.hxx>
#include <scrwin.hxx>

ScrollableWindow::ScrollableWindow( vcl::Window* pParent ) :
    Window( pParent, WB_CLIPCHILDREN ),
    aVScroll( VclPtr<ScrollBar>::Create(this, WinBits(WB_VSCROLL | WB_DRAG)) ),
    aHScroll( VclPtr<ScrollBar>::Create(this, WinBits(WB_HSCROLL | WB_DRAG)) ),
    aCornerWin( VclPtr<ScrollBarBox>::Create(this) )
{
    bScrolling = false;

    // set the handlers for the scrollbars
    aVScroll->SetScrollHdl( LINK(this, ScrollableWindow, ScrollHdl) );
    aHScroll->SetScrollHdl( LINK(this, ScrollableWindow, ScrollHdl) );
    aVScroll->SetEndScrollHdl( LINK(this, ScrollableWindow, EndScrollHdl) );
    aHScroll->SetEndScrollHdl( LINK(this, ScrollableWindow, EndScrollHdl) );

    nColumnPixW = nLinePixH = GetSettings().GetStyleSettings().GetScrollBarSize();
}


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

void ScrollableWindow::dispose()
{
    aVScroll.disposeAndClear();
    aHScroll.disposeAndClear();
    aCornerWin.disposeAndClear();
    Window::dispose();
}


void ScrollableWindow::Command( const CommandEvent& rCEvt )
{
    if ( (rCEvt.GetCommand() == CommandEventId::Wheel) ||
         (rCEvt.GetCommand() == CommandEventId::StartAutoScroll) ||
         (rCEvt.GetCommand() == CommandEventId::AutoScroll) )
    {
        ScrollBar* pHScrBar;
        ScrollBar* pVScrBar;
        if ( aHScroll->IsVisible() )
            pHScrBar = aHScroll.get();
        else
            pHScrBar = nullptr;
        if ( aVScroll->IsVisible() )
            pVScrBar = aVScroll.get();
        else
            pVScrBar = nullptr;
        if ( HandleScrollCommand( rCEvt, pHScrBar, pVScrBar ) )
            return;
    }

    Window::Command( rCEvt );
}


void ScrollableWindow::DataChanged( const DataChangedEvent& rDCEvt )
{
    if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
         (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
    {
        Resize();
        Invalidate();
    }

    Window::DataChanged( rDCEvt );
}


Size ScrollableWindow::GetOutputSizePixel() const
{
    Size aSz( Window::GetOutputSizePixel() );

    tools::Long nTmp = GetSettings().GetStyleSettings().GetScrollBarSize();
    if ( aHScroll->IsVisible() )
        aSz.AdjustHeight( -nTmp );
    if ( aVScroll->IsVisible() )
        aSz.AdjustWidth( -nTmp );
    return aSz;
}


IMPL_LINK( ScrollableWindow, EndScrollHdl, ScrollBar *, /*pScroll*/, void )
{
    // notify the end of scrolling
    bScrolling = false;
}


IMPL_LINK( ScrollableWindow, ScrollHdl, ScrollBar *, pScroll, void )
{
    // notify the start of scrolling, if not already scrolling
    if ( !bScrolling )
        bScrolling = true;

    // get the delta in logic coordinates
    Size aDelta( PixelToLogic(
        Size( aHScroll->GetDelta(), aVScroll->GetDelta() ) ) );
    if ( pScroll == aHScroll.get() )
        Scroll( aDelta.Width(), 0 );
    else
        Scroll( 0, aDelta.Height() );
}


void ScrollableWindow::Resize()
{
    // get the new output-size in pixel
    Size aOutPixSz = Window::GetOutputSizePixel();

    // determine the size of the output-area and if we need scrollbars
    const tools::Long nScrSize = GetSettings().GetStyleSettings().GetScrollBarSize();
    bool bVVisible = false; // by default no vertical-ScrollBar
    bool bHVisible = false; // by default no horizontal-ScrollBar
    bool bChanged;          // determines if a visiblility was changed
    do
    {
        bChanged = false;

        // does we need a vertical ScrollBar
        if ( aOutPixSz.Width() < aTotPixSz.Width() && !bHVisible )
        {
            bHVisible = true;
            aOutPixSz.AdjustHeight( -nScrSize );
            bChanged = true;
        }

        // does we need a horizontal ScrollBar
        if ( aOutPixSz.Height() < aTotPixSz.Height() && !bVVisible )
        {
            bVVisible = true;
            aOutPixSz.AdjustWidth( -nScrSize );
            bChanged = true;
        }

    }
    while ( bChanged );   // until no visibility has changed

    // store the old offset and map-mode
    MapMode aMap( GetMapMode() );
    Point aOldPixOffset( aPixOffset );

    // justify (right/bottom borders should never exceed the virtual window)
    Size aPixDelta;
    if ( aPixOffset.X() < 0 &&
         aPixOffset.X() + aTotPixSz.Width() < aOutPixSz.Width() )
        aPixDelta.setWidth(
            aOutPixSz.Width() - ( aPixOffset.X() + aTotPixSz.Width() ) );
    if ( aPixOffset.Y() < 0 &&
         aPixOffset.Y() + aTotPixSz.Height() < aOutPixSz.Height() )
        aPixDelta.setHeight(
            aOutPixSz.Height() - ( aPixOffset.Y() + aTotPixSz.Height() ) );
    if ( aPixDelta.Width() || aPixDelta.Height() )
    {
        aPixOffset.AdjustX(aPixDelta.Width() );
        aPixOffset.AdjustY(aPixDelta.Height() );
    }

    // for axis without scrollbar restore the origin
    if ( !bVVisible || !bHVisible )
    {
        aPixOffset = Point(
                     bHVisible
                     ? aPixOffset.X()
                     : (aOutPixSz.Width()-aTotPixSz.Width()) / 2,
                     bVVisible
                     ? aPixOffset.Y()
                     : (aOutPixSz.Height()-aTotPixSz.Height()) / 2 );
    }
    if ( bHVisible && !aHScroll->IsVisible() )
        aPixOffset.setX( 0 );
    if ( bVVisible && !aVScroll->IsVisible() )
        aPixOffset.setY( 0 );

    // select the shifted map-mode
    if ( aPixOffset != aOldPixOffset )
    {
        Window::SetMapMode( MapMode( MapUnit::MapPixel ) );
        Window::Scroll(
            aPixOffset.X() - aOldPixOffset.X(),
            aPixOffset.Y() - aOldPixOffset.Y() );
        SetMapMode( aMap );
    }

    // show or hide scrollbars
    aVScroll->Show( bVVisible );
    aHScroll->Show( bHVisible );

    // disable painting in the corner between the scrollbars
    if ( bVVisible && bHVisible )
    {
        aCornerWin->SetPosSizePixel(Point(aOutPixSz.Width(), aOutPixSz.Height()),
            Size(nScrSize, nScrSize) );
        aCornerWin->Show();
    }
    else
        aCornerWin->Hide();

    // resize scrollbars and set their ranges
    if ( bHVisible )
    {
        aHScroll->SetPosSizePixel(
            Point( 0, aOutPixSz.Height() ),
            Size( aOutPixSz.Width(), nScrSize ) );
        aHScroll->SetRange( Range( 0, aTotPixSz.Width() ) );
        aHScroll->SetPageSize( aOutPixSz.Width() );
        aHScroll->SetVisibleSize( aOutPixSz.Width() );
        aHScroll->SetLineSize( nColumnPixW );
        aHScroll->SetThumbPos( -aPixOffset.X() );
    }
    if ( bVVisible )
    {
        aVScroll->SetPosSizePixel(
            Point( aOutPixSz.Width(), 0 ),
            Size( nScrSize,aOutPixSz.Height() ) );
        aVScroll->SetRange( Range( 0, aTotPixSz.Height() ) );
        aVScroll->SetPageSize( aOutPixSz.Height() );
        aVScroll->SetVisibleSize( aOutPixSz.Height() );
        aVScroll->SetLineSize( nLinePixH );
        aVScroll->SetThumbPos( -aPixOffset.Y() );
    }
}


void ScrollableWindow::SetMapMode( const MapMode& rNewMapMode )
{
    MapMode aMap( rNewMapMode );
    aMap.SetOrigin( aMap.GetOrigin() + PixelToLogic( aPixOffset, aMap ) );
    Window::SetMapMode( aMap );
}


MapMode ScrollableWindow::GetMapMode() const
{
    MapMode aMap( Window::GetMapMode() );
    aMap.SetOrigin( aMap.GetOrigin() - PixelToLogic( aPixOffset ) );
    return aMap;
}


void ScrollableWindow::SetTotalSize( const Size& rNewSize )
{
    aTotPixSz = LogicToPixel( rNewSize );
    ScrollableWindow::Resize();
}


void ScrollableWindow::Scroll( tools::Long nDeltaX, tools::Long nDeltaY, ScrollFlags )
{
    // get the delta in pixel
    Size aDeltaPix( LogicToPixel( Size(nDeltaX, nDeltaY) ) );
    Size aOutPixSz( GetOutputSizePixel() );
    MapMode aMap( GetMapMode() );
    Point aNewPixOffset( aPixOffset );

    // scrolling horizontally?
    if ( nDeltaX != 0 )
    {
        aNewPixOffset.AdjustX( -(aDeltaPix.Width()) );
        if ( ( aOutPixSz.Width() - aNewPixOffset.X() ) > aTotPixSz.Width() )
            aNewPixOffset.setX( - ( aTotPixSz.Width() - aOutPixSz.Width() ) );
        else if ( aNewPixOffset.X() > 0 )
            aNewPixOffset.setX( 0 );
    }

    // scrolling vertically?
    if ( nDeltaY != 0 )
    {
        aNewPixOffset.AdjustY( -(aDeltaPix.Height()) );
        if ( ( aOutPixSz.Height() - aNewPixOffset.Y() ) > aTotPixSz.Height() )
            aNewPixOffset.setY( - ( aTotPixSz.Height() - aOutPixSz.Height() ) );
        else if ( aNewPixOffset.Y() > 0 )
            aNewPixOffset.setY( 0 );
    }

    // recompute the logical scroll units
    aDeltaPix.setWidth( aPixOffset.X() - aNewPixOffset.X() );
    aDeltaPix.setHeight( aPixOffset.Y() - aNewPixOffset.Y() );
    Size aDelta( PixelToLogic(aDeltaPix) );
    nDeltaX = aDelta.Width();
    nDeltaY = aDelta.Height();
    aPixOffset = aNewPixOffset;

    // scrolling?
    if ( nDeltaX != 0 || nDeltaY != 0 )
    {
        PaintImmediately();

        // does the new area overlap the old one?
        if ( std::abs( static_cast<int>(aDeltaPix.Height()) ) < aOutPixSz.Height() ||
             std::abs( static_cast<int>(aDeltaPix.Width()) ) < aOutPixSz.Width() )
        {
            // scroll the overlapping area
            SetMapMode( aMap );

            // never scroll the scrollbars itself!
            Window::Scroll(-nDeltaX, -nDeltaY,
                PixelToLogic( tools::Rectangle( Point(0, 0), aOutPixSz ) ) );
        }
        else
        {
            // repaint all
            SetMapMode( aMap );
            Invalidate();
        }

        PaintImmediately();
    }

    if ( !bScrolling )
    {
        if ( nDeltaX )
            aHScroll->SetThumbPos( -aPixOffset.X() );
        if ( nDeltaY )
            aVScroll->SetThumbPos( -aPixOffset.Y() );
    }
}


/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/starmath/source/view.cxx b/starmath/source/view.cxx
index 73b52e9..a007d1d 100644
--- a/starmath/source/view.cxx
+++ b/starmath/source/view.cxx
@@ -92,18 +92,209 @@ using namespace css;
using namespace css::accessibility;
using namespace css::uno;

SmGraphicWindow::SmGraphicWindow(SmViewShell* pShell)
    : ScrollableWindow(&pShell->GetViewFrame()->GetWindow())
    , pViewShell(pShell)
SmGraphicWindow::SmGraphicWindow(SmViewShell& rShell)
    : InterimItemWindow(&rShell.GetViewFrame()->GetWindow(), "modules/smath/ui/mathwindow.ui", "MathWindow")
    , nZoom(100)
    // continue to use user-scrolling to make this work equivalent to how it 'always' worked
    , mxScrolledWindow(m_xBuilder->weld_scrolled_window("scrolledwindow", true))
    , mxGraphic(new SmGraphicWidget(rShell, *this))
    , mxGraphicWin(new weld::CustomWeld(*m_xBuilder, "mathview", *mxGraphic))
{
    assert(pViewShell);
    nColumnPixW = nLinePixH = GetSettings().GetStyleSettings().GetScrollBarSize();

    mxScrolledWindow->connect_hadjustment_changed(LINK(this, SmGraphicWindow, ScrollHdl));
    mxScrolledWindow->connect_vadjustment_changed(LINK(this, SmGraphicWindow, ScrollHdl));

    // docking windows are usually hidden (often already done in the
    // resource) and will be shown by the sfx framework.
    Hide();
}

void SmGraphicWindow::dispose()
{
    mxGraphicWin.reset();
    mxGraphic.reset();
    mxScrolledWindow.reset();
    InterimItemWindow::dispose();
}

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

void SmGraphicWindow::Resize()
{
    InterimItemWindow::Resize();

    // get the new output-size in pixel
    Size aOutPixSz = GetOutputSizePixel();

    // determine the size of the output-area and if we need scrollbars
    const auto nScrSize = mxScrolledWindow->get_scroll_thickness();
    bool bVVisible = false; // by default no vertical-ScrollBar
    bool bHVisible = false; // by default no horizontal-ScrollBar
    bool bChanged;          // determines if a visiblility was changed
    do
    {
        bChanged = false;

        // does we need a vertical ScrollBar
        if ( aOutPixSz.Width() < aTotPixSz.Width() && !bHVisible )
        {
            bHVisible = true;
            aOutPixSz.AdjustHeight( -nScrSize );
            bChanged = true;
        }

        // does we need a horizontal ScrollBar
        if ( aOutPixSz.Height() < aTotPixSz.Height() && !bVVisible )
        {
            bVVisible = true;
            aOutPixSz.AdjustWidth( -nScrSize );
            bChanged = true;
        }

    }
    while ( bChanged );   // until no visibility has changed

    // store the old offset and map-mode
    MapMode aMap(GetGraphicMapMode());
    Point aOldPixOffset(aPixOffset);

    // justify (right/bottom borders should never exceed the virtual window)
    Size aPixDelta;
    if ( aPixOffset.X() < 0 &&
         aPixOffset.X() + aTotPixSz.Width() < aOutPixSz.Width() )
        aPixDelta.setWidth(
            aOutPixSz.Width() - ( aPixOffset.X() + aTotPixSz.Width() ) );
    if ( aPixOffset.Y() < 0 &&
         aPixOffset.Y() + aTotPixSz.Height() < aOutPixSz.Height() )
        aPixDelta.setHeight(
            aOutPixSz.Height() - ( aPixOffset.Y() + aTotPixSz.Height() ) );
    if ( aPixDelta.Width() || aPixDelta.Height() )
    {
        aPixOffset.AdjustX(aPixDelta.Width() );
        aPixOffset.AdjustY(aPixDelta.Height() );
    }

    // for axis without scrollbar restore the origin
    if ( !bVVisible || !bHVisible )
    {
        aPixOffset = Point(
                     bHVisible
                     ? aPixOffset.X()
                     : (aOutPixSz.Width()-aTotPixSz.Width()) / 2,
                     bVVisible
                     ? aPixOffset.Y()
                     : (aOutPixSz.Height()-aTotPixSz.Height()) / 2 );
    }
    if (bHVisible && mxScrolledWindow->get_hpolicy() == VclPolicyType::NEVER)
        aPixOffset.setX( 0 );
    if (bVVisible && mxScrolledWindow->get_vpolicy() == VclPolicyType::NEVER)
        aPixOffset.setY( 0 );

    // select the shifted map-mode
    if (aPixOffset != aOldPixOffset)
        SetGraphicMapMode(aMap);

    // show or hide scrollbars
    mxScrolledWindow->set_vpolicy(bVVisible ? VclPolicyType::ALWAYS : VclPolicyType::NEVER);
    mxScrolledWindow->set_hpolicy(bHVisible ? VclPolicyType::ALWAYS : VclPolicyType::NEVER);

    // resize scrollbars and set their ranges
    if ( bHVisible )
    {
        mxScrolledWindow->hadjustment_configure(-aPixOffset.X(), 0, aTotPixSz.Width(), nColumnPixW,
                                                aOutPixSz.Width(), aOutPixSz.Width());
    }
    if ( bVVisible )
    {
        mxScrolledWindow->vadjustment_configure(-aPixOffset.Y(), 0, aTotPixSz.Height(), nLinePixH,
                                                aOutPixSz.Height(), aOutPixSz.Height());
    }
}

IMPL_LINK_NOARG(SmGraphicWindow, ScrollHdl, weld::ScrolledWindow&, void)
{
    MapMode aMap(GetGraphicMapMode());
    Point aNewPixOffset(aPixOffset);

    // scrolling horizontally?
    if (mxScrolledWindow->get_hpolicy() == VclPolicyType::ALWAYS)
        aNewPixOffset.setX(-mxScrolledWindow->hadjustment_get_value());

    // scrolling vertically?
    if (mxScrolledWindow->get_vpolicy() == VclPolicyType::ALWAYS)
        aNewPixOffset.setY(-mxScrolledWindow->vadjustment_get_value());

    // scrolling?
    if (aPixOffset == aNewPixOffset)
        return;

    // recompute the logical scroll units
    aPixOffset = aNewPixOffset;

    SetGraphicMapMode(aMap);
}

void SmGraphicWindow::SetGraphicMapMode(const MapMode& rNewMapMode)
{
    OutputDevice& rDevice = mxGraphic->GetDrawingArea()->get_ref_device();
    MapMode aMap( rNewMapMode );
    aMap.SetOrigin( aMap.GetOrigin() + rDevice.PixelToLogic( aPixOffset, aMap ) );
    rDevice.SetMapMode( aMap );
    mxGraphic->Invalidate();
}

MapMode SmGraphicWindow::GetGraphicMapMode() const
{
    OutputDevice& rDevice = mxGraphic->GetDrawingArea()->get_ref_device();
    MapMode aMap(rDevice.GetMapMode());
    aMap.SetOrigin( aMap.GetOrigin() - rDevice.PixelToLogic( aPixOffset ) );
    return aMap;
}

void SmGraphicWindow::SetTotalSize( const Size& rNewSize )
{
    OutputDevice& rDevice = mxGraphic->GetDrawingArea()->get_ref_device();
    aTotPixSz = rDevice.LogicToPixel(rNewSize);
    Resize();
}

Size SmGraphicWindow::GetTotalSize() const
{
    OutputDevice& rDevice = mxGraphic->GetDrawingArea()->get_ref_device();
    return rDevice.PixelToLogic(aTotPixSz);
}

void SmGraphicWindow::ShowContextMenu(const CommandEvent& rCEvt)
{
    GetParent()->ToTop();
    Point aPos(5, 5);
    if (rCEvt.IsMouseEvent())
        aPos = rCEvt.GetMousePosPixel();

    // added for replaceability of context menus
    SfxDispatcher::ExecutePopup( this, &aPos );
}

SmGraphicWidget::SmGraphicWidget(SmViewShell& rShell, SmGraphicWindow& rGraphicWindow)
    : mrGraphicWindow(rGraphicWindow)
    , mrViewShell(rShell)
{
}

void SmGraphicWidget::SetDrawingArea(weld::DrawingArea* pDrawingArea)
{
    weld::CustomWidgetController::SetDrawingArea(pDrawingArea);

    OutputDevice& rDevice = pDrawingArea->get_ref_device();

    rDevice.SetBackground(SM_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor);

    const Fraction aFraction(1, 1);
    SetMapMode(MapMode(MapUnit::Map100thMM, Point(), aFraction, aFraction));
    rDevice.SetMapMode(MapMode(MapUnit::Map100thMM, Point(), aFraction, aFraction));

    SetTotalSize();

@@ -113,31 +304,16 @@ SmGraphicWindow::SmGraphicWindow(SmViewShell* pShell)
    CaretBlinkInit();
}

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

void SmGraphicWindow::dispose()
SmGraphicWidget::~SmGraphicWidget()
{
    if (mxAccessible.is())
        mxAccessible->ClearWin();    // make Accessible nonfunctional
    mxAccessible.clear();
    CaretBlinkStop();
    ScrollableWindow::dispose();
}

void SmGraphicWindow::StateChanged(StateChangedType eType)
bool SmGraphicWidget::MouseButtonDown(const MouseEvent& rMEvt)
{
    if (eType == StateChangedType::InitShow)
        Show();
    ScrollableWindow::StateChanged(eType);
}

void SmGraphicWindow::MouseButtonDown(const MouseEvent& rMEvt)
{
    ScrollableWindow::MouseButtonDown(rMEvt);

    GrabFocus();

    // set formula-cursor and selection of edit window according to the
@@ -145,19 +321,19 @@ void SmGraphicWindow::MouseButtonDown(const MouseEvent& rMEvt)

    SAL_WARN_IF( rMEvt.GetClicks() == 0, "starmath", "0 clicks" );
    if ( !rMEvt.IsLeft() )
        return;
        return true;

    OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
    // get click position relative to formula
    Point  aPos (PixelToLogic(rMEvt.GetPosPixel())
                 - GetFormulaDrawPos());
    Point aPos(rDevice.PixelToLogic(rMEvt.GetPosPixel()) - GetFormulaDrawPos());

    const SmNode *pTree = pViewShell->GetDoc()->GetFormulaTree();
    const SmNode *pTree = mrViewShell.GetDoc()->GetFormulaTree();
    if (!pTree)
        return;
        return true;

    if (IsInlineEditEnabled()) {
        pViewShell->GetDoc()->GetCursor().MoveTo(this, aPos, !rMEvt.IsShift());
        return;
        mrViewShell.GetDoc()->GetCursor().MoveTo(&rDevice, aPos, !rMEvt.IsShift());
        return true;
    }
    const SmNode *pNode = nullptr;
    // if it was clicked inside the formula then get the appropriate node
@@ -165,11 +341,11 @@ void SmGraphicWindow::MouseButtonDown(const MouseEvent& rMEvt)
        pNode = pTree->FindRectClosestTo(aPos);

    if (!pNode)
        return;
        return true;

    SmEditWindow  *pEdit = pViewShell->GetEditWindow();
    SmEditWindow* pEdit = mrViewShell.GetEditWindow();
    if (!pEdit)
        return;
        return true;
    const SmToken  aToken (pNode->GetToken());

    // set selection to the beginning of the token
@@ -179,46 +355,47 @@ void SmGraphicWindow::MouseButtonDown(const MouseEvent& rMEvt)
    // allow for immediate editing and
    //! implicitly synchronize the cursor position mark in this window
    pEdit->GrabFocus();

    return true;
}

void SmGraphicWindow::MouseMove(const MouseEvent &rMEvt)
bool SmGraphicWidget::MouseMove(const MouseEvent &rMEvt)
{
    ScrollableWindow::MouseMove(rMEvt);

    if (rMEvt.IsLeft() && IsInlineEditEnabled())
    {
        Point aPos(PixelToLogic(rMEvt.GetPosPixel()) - GetFormulaDrawPos());
        pViewShell->GetDoc()->GetCursor().MoveTo(this, aPos, false);
        OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
        Point aPos(rDevice.PixelToLogic(rMEvt.GetPosPixel()) - GetFormulaDrawPos());
        mrViewShell.GetDoc()->GetCursor().MoveTo(&rDevice, aPos, false);

        CaretBlinkStop();
        SetIsCursorVisible(true);
        CaretBlinkStart();
        RepaintViewShellDoc();
    }
    return true;
}

bool SmGraphicWindow::IsInlineEditEnabled()
bool SmGraphicWidget::IsInlineEditEnabled()
{
    return SmViewShell::IsInlineEditEnabled();
}

void SmGraphicWindow::GetFocus()
void SmGraphicWidget::GetFocus()
{
    if (!IsInlineEditEnabled())
        return;
    if (pViewShell->GetEditWindow())
        pViewShell->GetEditWindow()->Flush();
    if (mrViewShell.GetEditWindow())
        mrViewShell.GetEditWindow()->Flush();
    //Let view shell know what insertions should be done in visual editor
    pViewShell->SetInsertIntoEditWindow(false);
    mrViewShell.SetInsertIntoEditWindow(false);
    SetIsCursorVisible(true);
    ShowLine(true);
    CaretBlinkStart();
    RepaintViewShellDoc();
}

void SmGraphicWindow::LoseFocus()
void SmGraphicWidget::LoseFocus()
{
    ScrollableWindow::LoseFocus();
    if (mxAccessible.is())
    {
        uno::Any aOldValue, aNewValue;
@@ -235,14 +412,14 @@ void SmGraphicWindow::LoseFocus()
    RepaintViewShellDoc();
}

void SmGraphicWindow::RepaintViewShellDoc()
void SmGraphicWidget::RepaintViewShellDoc()
{
    SmDocShell* pDoc = pViewShell->GetDoc();
    SmDocShell* pDoc = mrViewShell.GetDoc();
    if (pDoc)
        pDoc->Repaint();
}

IMPL_LINK_NOARG(SmGraphicWindow, CaretBlinkTimerHdl, Timer *, void)
IMPL_LINK_NOARG(SmGraphicWidget, CaretBlinkTimerHdl, Timer *, void)
{
    if (IsCursorVisible())
        SetIsCursorVisible(false);
@@ -252,13 +429,13 @@ IMPL_LINK_NOARG(SmGraphicWindow, CaretBlinkTimerHdl, Timer *, void)
    RepaintViewShellDoc();
}

void SmGraphicWindow::CaretBlinkInit()
void SmGraphicWidget::CaretBlinkInit()
{
    aCaretBlinkTimer.SetInvokeHandler(LINK(this, SmGraphicWindow, CaretBlinkTimerHdl));
    aCaretBlinkTimer.SetTimeout( ScrollableWindow::GetSettings().GetStyleSettings().GetCursorBlinkTime() );
    aCaretBlinkTimer.SetInvokeHandler(LINK(this, SmGraphicWidget, CaretBlinkTimerHdl));
    aCaretBlinkTimer.SetTimeout(Application::GetSettings().GetStyleSettings().GetCursorBlinkTime());
}

void SmGraphicWindow::CaretBlinkStart()
void SmGraphicWidget::CaretBlinkStart()
{
    if (!IsInlineEditEnabled())
        return;
@@ -266,28 +443,30 @@ void SmGraphicWindow::CaretBlinkStart()
        aCaretBlinkTimer.Start();
}

void SmGraphicWindow::CaretBlinkStop()
void SmGraphicWidget::CaretBlinkStop()
{
    if (!IsInlineEditEnabled())
        return;
    aCaretBlinkTimer.Stop();
}

void SmGraphicWindow::ShowCursor(bool bShow)
    // shows or hides the formula-cursor depending on 'bShow' is true or not
// shows or hides the formula-cursor depending on 'bShow' is true or not
void SmGraphicWidget::ShowCursor(bool bShow)
{
    if (IsInlineEditEnabled())
        return;

    bool  bInvert = bShow != IsCursorVisible();

    bool bInvert = bShow != IsCursorVisible();
    if (bInvert)
        InvertTracking(aCursorRect, ShowTrackFlags::Small | ShowTrackFlags::TrackWindow);
    {
        OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
        InvertFocusRect(rDevice, aCursorRect);
    }

    SetIsCursorVisible(bShow);
}

void SmGraphicWindow::ShowLine(bool bShow)
void SmGraphicWidget::ShowLine(bool bShow)
{
    if (!IsInlineEditEnabled())
        return;
@@ -295,12 +474,12 @@ void SmGraphicWindow::ShowLine(bool bShow)
    bIsLineVisible = bShow;
}

void SmGraphicWindow::SetCursor(const SmNode *pNode)
void SmGraphicWidget::SetCursor(const SmNode *pNode)
{
    if (IsInlineEditEnabled())
        return;

    const SmNode *pTree = pViewShell->GetDoc()->GetFormulaTree();
    const SmNode *pTree = mrViewShell.GetDoc()->GetFormulaTree();

    // get appropriate rectangle
    Point aOffset (pNode->GetTopLeft() - pTree->GetTopLeft()),
@@ -311,7 +490,7 @@ void SmGraphicWindow::SetCursor(const SmNode *pNode)
    SetCursor(tools::Rectangle(aTLPos, aSize));
}

void SmGraphicWindow::SetCursor(const tools::Rectangle &rRect)
void SmGraphicWidget::SetCursor(const tools::Rectangle &rRect)
    // sets cursor to new position (rectangle) 'rRect'.
    // The old cursor will be removed, and the new one will be shown if
    // that is activated in the ConfigItem
@@ -328,7 +507,7 @@ void SmGraphicWindow::SetCursor(const tools::Rectangle &rRect)
        ShowCursor(true);       // draw new cursor
}

const SmNode * SmGraphicWindow::SetCursorPos(sal_uInt16 nRow, sal_uInt16 nCol)
const SmNode * SmGraphicWidget::SetCursorPos(sal_uInt16 nRow, sal_uInt16 nCol)
    // looks for a VISIBLE node in the formula tree with its token at
    // (or around) the position 'nRow', 'nCol' in the edit window
    // (row and column numbering starts with 1 there!).
@@ -340,7 +519,7 @@ const SmNode * SmGraphicWindow::SetCursorPos(sal_uInt16 nRow, sal_uInt16 nCol)
        return nullptr;

    // find visible node with token at nRow, nCol
    const SmNode *pTree = pViewShell->GetDoc()->GetFormulaTree(),
    const SmNode *pTree = mrViewShell.GetDoc()->GetFormulaTree(),
                 *pNode = nullptr;
    if (pTree)
        pNode = pTree->FindTokenAt(nRow, nCol);
@@ -353,30 +532,25 @@ const SmNode * SmGraphicWindow::SetCursorPos(sal_uInt16 nRow, sal_uInt16 nCol)
    return pNode;
}

void SmGraphicWindow::ApplySettings(vcl::RenderContext& rRenderContext)
void SmGraphicWidget::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
{
    rRenderContext.SetBackground(SM_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor);
}

void SmGraphicWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
{
    SmDocShell& rDoc = *pViewShell->GetDoc();
    SmDocShell& rDoc = *mrViewShell.GetDoc();
    Point aPoint;

    rDoc.DrawFormula(rRenderContext, aPoint, true);  //! modifies aPoint to be the topleft
                                //! corner of the formula
                                                     //! corner of the formula
    aFormulaDrawPos = aPoint;
    if (IsInlineEditEnabled())
    {
        //Draw cursor if any...
        if (pViewShell->GetDoc()->HasCursor() && IsLineVisible())
            pViewShell->GetDoc()->GetCursor().Draw(rRenderContext, aPoint, IsCursorVisible());
        if (mrViewShell.GetDoc()->HasCursor() && IsLineVisible())
            mrViewShell.GetDoc()->GetCursor().Draw(rRenderContext, aPoint, IsCursorVisible());
    }
    else
    {
        SetIsCursorVisible(false);  // (old) cursor must be drawn again

        const SmEditWindow* pEdit = pViewShell->GetEditWindow();
        const SmEditWindow* pEdit = mrViewShell.GetEditWindow();
        if (pEdit)
        {   // get new position for formula-cursor (for possible altered formula)
            sal_Int32  nRow;
@@ -391,24 +565,23 @@ void SmGraphicWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rec
    }
}


void SmGraphicWindow::SetTotalSize ()
void SmGraphicWidget::SetTotalSize()
{
    SmDocShell &rDoc = *pViewShell->GetDoc();
    const Size aTmp( PixelToLogic( LogicToPixel( rDoc.GetSize() )));
    if ( aTmp != ScrollableWindow::GetTotalSize() )
        ScrollableWindow::SetTotalSize( aTmp );
    SmDocShell &rDoc = *mrViewShell.GetDoc();
    OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
    const Size aTmp(rDevice.PixelToLogic(rDevice.LogicToPixel(rDoc.GetSize())));
    if (aTmp != mrGraphicWindow.GetTotalSize())
        mrGraphicWindow.SetTotalSize(aTmp);
}

void SmGraphicWindow::KeyInput(const KeyEvent& rKEvt)
bool SmGraphicWidget::KeyInput(const KeyEvent& rKEvt)
{
    if (!IsInlineEditEnabled()) {
        if (! (GetView() && GetView()->KeyInput(rKEvt)) )
            ScrollableWindow::KeyInput(rKEvt);
        return;
    }
    if (!IsInlineEditEnabled())
        return mrViewShell.KeyInput(rKEvt);

    SmCursor& rCursor = pViewShell->GetDoc()->GetCursor();
    bool bConsumed = true;

    SmCursor& rCursor = mrViewShell.GetDoc()->GetCursor();
    KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
    if (eFunc == KeyFuncType::COPY)
        rCursor.Copy();
@@ -417,24 +590,25 @@ void SmGraphicWindow::KeyInput(const KeyEvent& rKEvt)
    else if (eFunc == KeyFuncType::PASTE)
        rCursor.Paste();
    else {
    OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
    sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
    switch(nCode)
    {
        case KEY_LEFT:
        {
            rCursor.Move(this, MoveLeft, !rKEvt.GetKeyCode().IsShift());
            rCursor.Move(&rDevice, MoveLeft, !rKEvt.GetKeyCode().IsShift());
        }break;
        case KEY_RIGHT:
        {
            rCursor.Move(this, MoveRight, !rKEvt.GetKeyCode().IsShift());
            rCursor.Move(&rDevice, MoveRight, !rKEvt.GetKeyCode().IsShift());
        }break;
        case KEY_UP:
        {
            rCursor.Move(this, MoveUp, !rKEvt.GetKeyCode().IsShift());
            rCursor.Move(&rDevice, MoveUp, !rKEvt.GetKeyCode().IsShift());
        }break;
        case KEY_DOWN:
        {
            rCursor.Move(this, MoveDown, !rKEvt.GetKeyCode().IsShift());
            rCursor.Move(&rDevice, MoveDown, !rKEvt.GetKeyCode().IsShift());
        }break;
        case KEY_RETURN:
        {
@@ -444,14 +618,14 @@ void SmGraphicWindow::KeyInput(const KeyEvent& rKEvt)
        case KEY_DELETE:
        {
            if(!rCursor.HasSelection()){
                rCursor.Move(this, MoveRight, false);
                rCursor.Move(&rDevice, MoveRight, false);
                if(rCursor.HasComplexSelection()) break;
            }
            rCursor.Delete();
        }break;
        case KEY_BACKSPACE:
        {
            rCursor.DeletePrev(this);
            rCursor.DeletePrev(&rDevice);
        }break;
        case KEY_ADD:
            rCursor.InsertElement(PlusElement);
@@ -500,13 +674,13 @@ void SmGraphicWindow::KeyInput(const KeyEvent& rKEvt)
                     || (code == ']' && rCursor.IsAtTailOfBracket(SmBracketType::Square))
                     || (code == '}' && rCursor.IsAtTailOfBracket(SmBracketType::Curly)))
            {
                rCursor.Move(this, MoveRight);
                rCursor.Move(&rDevice, MoveRight);
            }
            else{
                if(code != 0){
                    rCursor.InsertText(OUString(code));
                }else if (! (GetView() && GetView()->KeyInput(rKEvt)) )
                    ScrollableWindow::KeyInput(rKEvt);
                }else if (!mrViewShell.KeyInput(rKEvt))
                    bConsumed = false;
            }
        }
    }
@@ -515,28 +689,22 @@ void SmGraphicWindow::KeyInput(const KeyEvent& rKEvt)
    CaretBlinkStart();
    SetIsCursorVisible(true);
    RepaintViewShellDoc();

    return bConsumed;
}


void SmGraphicWindow::Command(const CommandEvent& rCEvt)
bool SmGraphicWidget::Command(const CommandEvent& rCEvt)
{
    bool bCallBase = true;
    if ( !pViewShell->GetViewFrame()->GetFrame().IsInPlace() )
    if (!mrViewShell.GetViewFrame()->GetFrame().IsInPlace())
    {
        switch ( rCEvt.GetCommand() )
        {
            case CommandEventId::ContextMenu:
            {
                GetParent()->ToTop();
                Point aPos(5, 5);
                if (rCEvt.IsMouseEvent())
                    aPos = rCEvt.GetMousePosPixel();

                // added for replaceability of context menus
                SfxDispatcher::ExecutePopup( this, &aPos );

                // purely for "ExecutePopup" taking a vcl::Window and
                // we assume SmGraphicWindow 0,0 is at SmEditWindow 0,0
                mrGraphicWindow.ShowContextMenu(rCEvt);
                bCallBase = false;
            }
            break;

            case CommandEventId::Wheel:
@@ -544,12 +712,12 @@ void SmGraphicWindow::Command(const CommandEvent& rCEvt)
                const CommandWheelData* pWData = rCEvt.GetWheelData();
                if  ( pWData && CommandWheelMode::ZOOM == pWData->GetMode() )
                {
                    sal_uInt16 nTmpZoom = GetZoom();
                    sal_uInt16 nTmpZoom = mrGraphicWindow.GetZoom();
                    if( 0 > pWData->GetDelta() )
                        nTmpZoom -= 10;
                    else
                        nTmpZoom += 10;
                    SetZoom( nTmpZoom );
                    mrGraphicWindow.SetZoom(nTmpZoom);
                    bCallBase = false;
                }
            }
@@ -558,36 +726,31 @@ void SmGraphicWindow::Command(const CommandEvent& rCEvt)
            default: break;
        }
    }
    if ( bCallBase )
        ScrollableWindow::Command (rCEvt);
    return !bCallBase;
}


void SmGraphicWindow::SetZoom(sal_uInt16 Factor)
{
    nZoom = std::clamp(Factor, MINZOOM, MAXZOOM);
    Fraction   aFraction (nZoom, 100);
    SetMapMode( MapMode(MapUnit::Map100thMM, Point(), aFraction, aFraction) );
    SetTotalSize();
    SmViewShell *pViewSh = GetView();
    if (pViewSh)
    {
        pViewSh->GetViewFrame()->GetBindings().Invalidate(SID_ATTR_ZOOM);
        pViewSh->GetViewFrame()->GetBindings().Invalidate(SID_ATTR_ZOOMSLIDER);
    }
    Invalidate();
    Fraction aFraction(nZoom, 100);
    SetGraphicMapMode(MapMode(MapUnit::Map100thMM, Point(), aFraction, aFraction));
    mxGraphic->SetTotalSize();
    SmViewShell& rViewSh = mxGraphic->GetView();
    rViewSh.GetViewFrame()->GetBindings().Invalidate(SID_ATTR_ZOOM);
    rViewSh.GetViewFrame()->GetBindings().Invalidate(SID_ATTR_ZOOMSLIDER);
}


void SmGraphicWindow::ZoomToFitInWindow()
{
    SmDocShell &rDoc = *pViewShell->GetDoc();
    SmViewShell& rViewSh = mxGraphic->GetView();
    SmDocShell& rDoc = *rViewSh.GetDoc();

    // set defined mapmode before calling 'LogicToPixel' below
    SetMapMode(MapMode(MapUnit::Map100thMM));
    SetGraphicMapMode(MapMode(MapUnit::Map100thMM));

    Size       aSize (LogicToPixel(rDoc.GetSize()));
    Size       aWindowSize (GetSizePixel());
    OutputDevice& rDevice = mxGraphic->GetDrawingArea()->get_ref_device();
    Size aSize(rDevice.LogicToPixel(rDoc.GetSize()));
    Size aWindowSize(GetSizePixel());

    if (!aSize.IsEmpty())
    {
@@ -597,7 +760,7 @@ void SmGraphicWindow::ZoomToFitInWindow()
    }
}

uno::Reference< XAccessible > SmGraphicWindow::CreateAccessible()
uno::Reference< XAccessible > SmGraphicWidget::CreateAccessible()
{
    if (!mxAccessible.is())
    {
@@ -607,9 +770,7 @@ uno::Reference< XAccessible > SmGraphicWindow::CreateAccessible()
}

/**************************************************************************/


SmGraphicController::SmGraphicController(SmGraphicWindow &rSmGraphic,
SmGraphicController::SmGraphicController(SmGraphicWidget &rSmGraphic,
                        sal_uInt16          nId_,
                        SfxBindings     &rBindings) :
    SfxControllerItem(nId_, rBindings),
@@ -617,7 +778,6 @@ SmGraphicController::SmGraphicController(SmGraphicWindow &rSmGraphic,
{
}


void SmGraphicController::StateChanged(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState)
{
    rGraphic.SetTotalSize();
@@ -625,10 +785,7 @@ void SmGraphicController::StateChanged(sal_uInt16 nSID, SfxItemState eState, con
    SfxControllerItem::StateChanged (nSID, eState, pState);
}


/**************************************************************************/


SmEditController::SmEditController(SmEditWindow &rSmEdit,
                     sal_uInt16       nId_,
                     SfxBindings  &rBindings) :
@@ -637,8 +794,6 @@ SmEditController::SmEditController(SmEditWindow &rSmEdit,
{
}



void SmEditController::StateChanged(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState)
{
    const SfxStringItem *pItem =  dynamic_cast<const SfxStringItem*>( pState);
@@ -875,28 +1030,26 @@ void SmViewShell::InnerResizePixel(const Point &rOfs, const Size &rSize, bool)
    }

    SetBorderPixel( SvBorder() );
    GetGraphicWindow().SetPosSizePixel(rOfs, rSize);
    GetGraphicWindow().SetTotalSize();
    mxGraphicWindow->SetPosSizePixel(rOfs, rSize);
    GetGraphicWidget().SetTotalSize();
}

void SmViewShell::OuterResizePixel(const Point &rOfs, const Size &rSize)
{
    SmGraphicWindow &rWin = GetGraphicWindow();
    rWin.SetPosSizePixel(rOfs, rSize);
    mxGraphicWindow->SetPosSizePixel(rOfs, rSize);
    if (GetDoc()->IsPreview())
        rWin.ZoomToFitInWindow();
    rWin.PaintImmediately();
        mxGraphicWindow->ZoomToFitInWindow();
}

void SmViewShell::QueryObjAreaPixel( tools::Rectangle& rRect ) const
{
    rRect.SetSize( GetGraphicWindow().GetSizePixel() );
    rRect.SetSize(mxGraphicWindow->GetSizePixel());
}

void SmViewShell::SetZoomFactor( const Fraction &rX, const Fraction &rY )
{
    const Fraction &rFrac = std::min(rX, rY);
    GetGraphicWindow().SetZoom(sal::static_int_cast<sal_uInt16>(tools::Long(rFrac * Fraction( 100, 1 ))));
    mxGraphicWindow->SetZoom(sal::static_int_cast<sal_uInt16>(tools::Long(rFrac * Fraction( 100, 1 ))));

    //To avoid rounding errors base class regulates crooked values too
    //if necessary
@@ -1008,7 +1161,6 @@ void SmViewShell::DrawTextLine(OutputDevice& rDevice, const Point& rPosition, co
        rDevice.DrawText(aPoint, rLine);
}


void SmViewShell::DrawText(OutputDevice& rDevice, const Point& rPosition, const OUString& rText, sal_uInt16 MaxWidth)
{
    if (rText.isEmpty())
@@ -1407,7 +1559,7 @@ void SmViewShell::Execute(SfxRequest& rReq)

            pp->GetConfig()->SetShowFormulaCursor(bVal);
            if (!IsInlineEditEnabled())
                GetGraphicWindow().ShowCursor(bVal);
                GetGraphicWidget().ShowCursor(bVal);
            break;
        }
        case SID_DRAW:
@@ -1421,16 +1573,16 @@ void SmViewShell::Execute(SfxRequest& rReq)
            break;

        case SID_ZOOM_OPTIMAL:
            mpGraphic->ZoomToFitInWindow();
            mxGraphicWindow->ZoomToFitInWindow();
            break;

        case SID_ZOOMIN:
            mpGraphic->SetZoom(mpGraphic->GetZoom() + 25);
            mxGraphicWindow->SetZoom(mxGraphicWindow->GetZoom() + 25);
            break;

        case SID_ZOOMOUT:
            SAL_WARN_IF( mpGraphic->GetZoom() < 25, "starmath", "incorrect sal_uInt16 argument" );
            mpGraphic->SetZoom(mpGraphic->GetZoom() - 25);
            SAL_WARN_IF( mxGraphicWindow->GetZoom() < 25, "starmath", "incorrect sal_uInt16 argument" );
            mxGraphicWindow->SetZoom(mxGraphicWindow->GetZoom() - 25);
            break;

        case SID_COPYOBJECT:
@@ -1540,7 +1692,7 @@ void SmViewShell::Execute(SfxRequest& rReq)
            if (IsInlineEditEnabled() && (GetDoc() && !mbInsertIntoEditWindow))
            {
                GetDoc()->GetCursor().InsertCommandText(rItem.GetValue());
                GetGraphicWindow().GrabFocus();
                GetGraphicWidget().GrabFocus();
            }
            break;

@@ -1701,7 +1853,7 @@ void SmViewShell::Execute(SfxRequest& rReq)
                else
                {
                    SfxItemSet aSet( SmDocShell::GetPool(), svl::Items<SID_ATTR_ZOOM, SID_ATTR_ZOOM>{});
                    aSet.Put( SvxZoomItem( SvxZoomType::PERCENT, mpGraphic->GetZoom()));
                    aSet.Put( SvxZoomItem( SvxZoomType::PERCENT, mxGraphicWindow->GetZoom()));
                    SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
                    ScopedVclPtr<AbstractSvxZoomDialog> xDlg(pFact->CreateSvxZoomDialog(GetViewFrame()->GetWindow().GetFrameWeld(), aSet));
                    xDlg->SetLimits( MINZOOM, MAXZOOM );
@@ -1720,7 +1872,7 @@ void SmViewShell::Execute(SfxRequest& rReq)
            if ( pArgs && SfxItemState::SET == pArgs->GetItemState(SID_ATTR_ZOOMSLIDER, true, &pItem ) )
            {
                const sal_uInt16 nCurrentZoom = static_cast<const SvxZoomSliderItem *>(pItem)->GetValue();
                mpGraphic->SetZoom( nCurrentZoom );
                mxGraphicWindow->SetZoom(nCurrentZoom);
            }
        }
        break;
@@ -1833,7 +1985,7 @@ void SmViewShell::GetState(SfxItemSet &rSet)
            break;

        case SID_ATTR_ZOOM:
            rSet.Put(SvxZoomItem( SvxZoomType::PERCENT, mpGraphic->GetZoom()));
            rSet.Put(SvxZoomItem( SvxZoomType::PERCENT, mxGraphicWindow->GetZoom()));
            [[fallthrough]];
        case SID_ZOOMIN:
        case SID_ZOOMOUT:
@@ -1844,7 +1996,7 @@ void SmViewShell::GetState(SfxItemSet &rSet)

        case SID_ATTR_ZOOMSLIDER :
            {
                const sal_uInt16 nCurrentZoom = mpGraphic->GetZoom();
                const sal_uInt16 nCurrentZoom = mxGraphicWindow->GetZoom();
                SvxZoomSliderItem aZoomSliderItem( nCurrentZoom, MINZOOM, MAXZOOM );
                aZoomSliderItem.AddSnappingPoint( 100 );
                rSet.Put( aZoomSliderItem );
@@ -1889,18 +2041,17 @@ void SmViewShell::GetState(SfxItemSet &rSet)

SmViewShell::SmViewShell(SfxViewFrame *pFrame_, SfxViewShell *)
    : SfxViewShell(pFrame_, SfxViewShellFlags::HAS_PRINTOPTIONS)
    , mpGraphic(VclPtr<SmGraphicWindow>::Create(this))
    , maGraphicController(*mpGraphic, SID_GRAPHIC_SM, pFrame_->GetBindings())
    , mxGraphicWindow(VclPtr<SmGraphicWindow>::Create(*this))
    , maGraphicController(mxGraphicWindow->GetGraphicWidget(), SID_GRAPHIC_SM, pFrame_->GetBindings())
    , mbPasteState(false)
    , mbInsertIntoEditWindow(false)
{
    SetStatusText(OUString());
    SetWindow(mpGraphic.get());
    SetWindow(mxGraphicWindow.get());
    SfxShell::SetName("SmView");
    SfxShell::SetUndoManager( &GetDoc()->GetEditEngine().GetUndoManager() );
}


SmViewShell::~SmViewShell()
{
    //!! this view shell is not active anymore !!
@@ -1909,7 +2060,7 @@ SmViewShell::~SmViewShell()
    SmEditWindow *pEditWin = GetEditWindow();
    if (pEditWin)
        pEditWin->DeleteEditView();
    mpGraphic.disposeAndClear();
    mxGraphicWindow.disposeAndClear();
}

void SmViewShell::Deactivate( bool bIsMDIActivate )
@@ -1995,11 +2146,11 @@ void SmViewShell::ZoomByItemSet(const SfxItemSet *pSet)
    switch( rZoom.GetType() )
    {
        case SvxZoomType::PERCENT:
            mpGraphic->SetZoom(sal::static_int_cast<sal_uInt16>(rZoom.GetValue ()));
            mxGraphicWindow->SetZoom(sal::static_int_cast<sal_uInt16>(rZoom.GetValue ()));
            break;

        case SvxZoomType::OPTIMAL:
            mpGraphic->ZoomToFitInWindow();
            mxGraphicWindow->ZoomToFitInWindow();
            break;

        case SvxZoomType::PAGEWIDTH:
@@ -2013,7 +2164,7 @@ void SmViewShell::ZoomByItemSet(const SfxItemSet *pSet)
            Size       GraphicSize(pPrinter->LogicToPixel(GetDoc()->GetSize(), aMap));
            sal_uInt16 nZ = sal::static_int_cast<sal_uInt16>(std::min(tools::Long(Fraction(OutputSize.Width()  * 100, GraphicSize.Width())),
                                                                      tools::Long(Fraction(OutputSize.Height() * 100, GraphicSize.Height()))));
            mpGraphic->SetZoom (nZ);
            mxGraphicWindow->SetZoom(nZ);
            break;
        }
        default:
diff --git a/starmath/uiconfig/smath/ui/mathwindow.ui b/starmath/uiconfig/smath/ui/mathwindow.ui
new file mode 100644
index 0000000..3737c0d
--- /dev/null
+++ b/starmath/uiconfig/smath/ui/mathwindow.ui
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface domain="sm">
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkBox" id="MathWindow">
    <property name="visible">True</property>
    <property name="can-focus">False</property>
    <property name="hexpand">True</property>
    <property name="vexpand">True</property>
    <property name="spacing">6</property>
    <child>
      <object class="GtkScrolledWindow" id="scrolledwindow">
        <property name="visible">True</property>
        <property name="can-focus">True</property>
        <property name="border-width">0</property>
        <property name="shadow-type">etched-out</property>
        <child>
          <object class="GtkViewport">
            <property name="visible">True</property>
            <property name="can-focus">False</property>
            <child>
              <object class="GtkDrawingArea" id="mathview">
                <property name="visible">True</property>
                <property name="can-focus">True</property>
                <property name="events">GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK | GDK_SCROLL_MASK</property>
              </object>
            </child>
          </object>
        </child>
      </object>
      <packing>
        <property name="expand">True</property>
        <property name="fill">True</property>
        <property name="position">0</property>
      </packing>
    </child>
  </object>
</interface>
diff --git a/starmath/visual-editor-todo b/starmath/visual-editor-todo
index 65f2d7a..7e3cc5d2 100644
--- a/starmath/visual-editor-todo
+++ b/starmath/visual-editor-todo
@@ -12,7 +12,7 @@ on IRC (jopsen) or e-mail me at jopsen@gmail.com.

Easy
----
1. SmGraphicWindow::KeyInput relies on comparison of char, a better way must be available for CTRL+c
1. SmGraphicWidget::KeyInput relies on comparison of char, a better way must be available for CTRL+c
2. Code style (missing spaces, linebreaks and a few renames)
3. More documentation
4. Extend NodeToTextVisitor to update token offsets so SmNode::GetRow and SmNode::GetColumn will work.