lok: show Math selection

Change-Id: I950ae3e5fb000d6acec4c26ff143b918a4e48a27
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142342
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
diff --git a/starmath/inc/cursor.hxx b/starmath/inc/cursor.hxx
index a1491c5..0a8a350 100644
--- a/starmath/inc/cursor.hxx
+++ b/starmath/inc/cursor.hxx
@@ -187,6 +187,7 @@ public:
    void Draw(OutputDevice& pDev, Point Offset, bool isCaretVisible);

    tools::Rectangle GetCaretRectangle(OutputDevice& rOutDev) const;
    tools::Rectangle GetSelectionRectangle(OutputDevice& rOutDev) const;

    bool IsAtTailOfBracket(SmBracketType eBracketType) const;

@@ -275,7 +276,7 @@ private:
    bool SetCaretPosition(SmCaretPos pos);

    /** Set selected on nodes of the tree */
    void AnnotateSelection();
    void AnnotateSelection() const;

    /** Clone list of nodes in a clipboard (creates a deep clone) */
    static std::unique_ptr<SmNodeList> CloneList(SmClipboard& rClipboard);
diff --git a/starmath/inc/visitors.hxx b/starmath/inc/visitors.hxx
index b29bb26..eaf3290 100644
--- a/starmath/inc/visitors.hxx
+++ b/starmath/inc/visitors.hxx
@@ -424,31 +424,40 @@ private:
};


// SmSelectionDrawingVisitor
// SmSelectionRectanglesVisitor: collect selection

class SmSelectionDrawingVisitor final : public SmDefaultingVisitor
class SmSelectionRectanglesVisitor : public SmDefaultingVisitor
{
public:
    /** Draws a selection on rDevice for the selection on pTree */
    SmSelectionDrawingVisitor( OutputDevice& rDevice, SmNode* pTree, const Point& rOffset );
    virtual ~SmSelectionDrawingVisitor() {}
    SmSelectionRectanglesVisitor(OutputDevice& rDevice, SmNode* pTree);
    virtual ~SmSelectionRectanglesVisitor() = default;
    void Visit( SmTextNode* pNode ) override;
    using SmDefaultingVisitor::Visit;

    const tools::Rectangle& GetSelection() { return maSelectionArea; }

private:
    /** Reference to drawing device */
    OutputDevice& mrDev;
    /** True if  aSelectionArea have been initialized */
    bool mbHasSelectionArea;
    /** The current area that is selected */
    tools::Rectangle maSelectionArea;
    /** Extend the area that must be selected  */
    void ExtendSelectionArea(const tools::Rectangle& rArea);
    void ExtendSelectionArea(const tools::Rectangle& rArea) { maSelectionArea.Union(rArea); }
    /** Default visiting method */
    void DefaultVisit( SmNode* pNode ) override;
    /** Visit the children of a given pNode */
    void VisitChildren( SmNode* pNode );
};

// SmSelectionDrawingVisitor

class SmSelectionDrawingVisitor final : public SmSelectionRectanglesVisitor
{
public:
    /** Draws a selection on rDevice for the selection on pTree */
    SmSelectionDrawingVisitor( OutputDevice& rDevice, SmNode* pTree, const Point& rOffset );
};

// SmNodeToTextVisitor

/** Extract command text from pNodes */
diff --git a/starmath/source/cursor.cxx b/starmath/source/cursor.cxx
index f6d93b8..c7c2761 100644
--- a/starmath/source/cursor.cxx
+++ b/starmath/source/cursor.cxx
@@ -165,7 +165,7 @@ bool SmCursor::SetCaretPosition(SmCaretPos pos){
    return false;
}

void SmCursor::AnnotateSelection(){
void SmCursor::AnnotateSelection() const {
    //TODO: Manage a state, reset it upon modification and optimize this call
    SmSetSelectionVisitor(mpAnchor->CaretPos, mpPosition->CaretPos, mpTree);
}
@@ -179,6 +179,12 @@ tools::Rectangle SmCursor::GetCaretRectangle(OutputDevice& rOutDev) const
    return SmCaretRectanglesVisitor(rOutDev, GetPosition()).getCaret();
}

tools::Rectangle SmCursor::GetSelectionRectangle(OutputDevice& rOutDev) const
{
    AnnotateSelection();
    return SmSelectionRectanglesVisitor(rOutDev, mpTree).GetSelection();
}

void SmCursor::DeletePrev(OutputDevice* pDev){
    //Delete only a selection if there's a selection
    if(HasSelection()){
diff --git a/starmath/source/view.cxx b/starmath/source/view.cxx
index 95a1750..1bcfc0d 100644
--- a/starmath/source/view.cxx
+++ b/starmath/source/view.cxx
@@ -2324,10 +2324,28 @@ std::optional<OString> SmViewShell::getLOKPayload(int nType, int nViewId) const
            }
            return SfxLokHelper::makeVisCursorInvalidation(nViewId, sRectangle, false, {});
        }
        case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
        case LOK_CALLBACK_TEXT_SELECTION:
        {
            OString sRectangle;
            if (const SmGraphicWidget& widget = GetGraphicWidget(); widget.IsCursorVisible())
            {
                SmCursor& rCursor = GetDoc()->GetCursor();
                OutputDevice& rOutDev = const_cast<SmGraphicWidget&>(widget).GetOutputDevice();
                tools::Rectangle aSelection = rCursor.GetSelectionRectangle(rOutDev);
                if (!aSelection.IsEmpty())
                {
                    LokStarMathHelper helper(SfxViewShell::Current());
                    tools::Rectangle aBounds = helper.GetBoundingBox();

                    aSelection.Move(aBounds.Left(), aBounds.Top());
                    sRectangle = aSelection.toString();
                }
            }
            return sRectangle;
        }
        case LOK_CALLBACK_TEXT_SELECTION_START:
        case LOK_CALLBACK_TEXT_SELECTION_END:
        case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
        case LOK_CALLBACK_TEXT_VIEW_SELECTION:
            return {};
    }
@@ -2342,6 +2360,10 @@ void SmViewShell::SendCaretToLOK() const
        libreOfficeKitViewCallbackWithViewId(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR,
                                             payload->getStr(), nViewId);
    }
    if (const auto& payload = getLOKPayload(LOK_CALLBACK_TEXT_SELECTION, nViewId))
    {
        libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, payload->getStr());
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/starmath/source/visitors.cxx b/starmath/source/visitors.cxx
index fdf268b..6efe993 100644
--- a/starmath/source/visitors.cxx
+++ b/starmath/source/visitors.cxx
@@ -1888,49 +1888,45 @@ void SmCloningVisitor::Visit( SmVerticalBraceNode* pNode )
// SmSelectionDrawingVisitor

SmSelectionDrawingVisitor::SmSelectionDrawingVisitor( OutputDevice& rDevice, SmNode* pTree, const Point& rOffset )
    : mrDev( rDevice )
    , mbHasSelectionArea( false )
    : SmSelectionRectanglesVisitor( rDevice, pTree )
{
    //Visit everything
    SAL_WARN_IF( !pTree, "starmath", "pTree can't be null!" );
    if( pTree )
        pTree->Accept( this );

    //Draw selection if there's any
    if( !mbHasSelectionArea )        return;
    if(GetSelection().IsEmpty())        return;

    maSelectionArea.Move( rOffset.X( ), rOffset.Y( ) );
    tools::Rectangle aSelectionArea = GetSelection() + rOffset;

    //Save device state
    mrDev.Push( vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR );
    rDevice.Push( vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR );
    //Change colors
    mrDev.SetLineColor( );
    mrDev.SetFillColor( COL_LIGHTGRAY );
    rDevice.SetLineColor( );
    rDevice.SetFillColor( COL_LIGHTGRAY );

    //Draw rectangle
    mrDev.DrawRect( maSelectionArea );
    rDevice.DrawRect( aSelectionArea );

    //Restore device state
    mrDev.Pop( );
    rDevice.Pop( );
}

void SmSelectionDrawingVisitor::ExtendSelectionArea(const tools::Rectangle& rArea)
// SmSelectionRectanglesVisitor

SmSelectionRectanglesVisitor::SmSelectionRectanglesVisitor(OutputDevice& rDevice, SmNode* pTree)
    : mrDev(rDevice)
{
    if ( ! mbHasSelectionArea ) {
        maSelectionArea = rArea;
        mbHasSelectionArea = true;
    } else
        maSelectionArea.Union(rArea);
    // Visit everything
    SAL_WARN_IF(!pTree, "starmath", "pTree can't be null!");
    if (pTree)
        pTree->Accept(this);
}

void SmSelectionDrawingVisitor::DefaultVisit( SmNode* pNode )
void SmSelectionRectanglesVisitor::DefaultVisit( SmNode* pNode )
{
    if( pNode->IsSelected( ) )
        ExtendSelectionArea( pNode->AsRectangle( ) );
    VisitChildren( pNode );
}

void SmSelectionDrawingVisitor::VisitChildren( SmNode* pNode )
void SmSelectionRectanglesVisitor::VisitChildren( SmNode* pNode )
{
    if(pNode->GetNumSubNodes() == 0)
        return;
@@ -1942,7 +1938,7 @@ void SmSelectionDrawingVisitor::VisitChildren( SmNode* pNode )
    }
}

void SmSelectionDrawingVisitor::Visit( SmTextNode* pNode )
void SmSelectionRectanglesVisitor::Visit( SmTextNode* pNode )
{
    if( !pNode->IsSelected())
        return;