[Libreoffice-commits] core.git: Branch 'feature/tiled-editing' - 2 commits - include/LibreOfficeKit libreofficekit/source sw/source

Miklos Vajna vmiklos at collabora.co.uk
Tue Feb 10 02:14:22 PST 2015


 include/LibreOfficeKit/LibreOfficeKit.h    |   20 ++++++
 include/LibreOfficeKit/LibreOfficeKitGtk.h |    2 
 libreofficekit/source/gtk/lokdocview.c     |   89 +++++++++++++++++++++--------
 sw/source/core/crsr/viscrs.cxx             |   36 +++++++++++
 4 files changed, 122 insertions(+), 25 deletions(-)

New commits:
commit 6d79bf75aa760a4c9e397d496d493d33bca94ff7
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Feb 10 11:10:50 2015 +0100

    lokdocview: draw handles at selection start/end
    
    Change-Id: Ic9b4138619f20a8d35437912784b94f4d1f2af4f

diff --git a/include/LibreOfficeKit/LibreOfficeKitGtk.h b/include/LibreOfficeKit/LibreOfficeKitGtk.h
index def92f9..04d61ad 100644
--- a/include/LibreOfficeKit/LibreOfficeKitGtk.h
+++ b/include/LibreOfficeKit/LibreOfficeKitGtk.h
@@ -52,6 +52,8 @@ struct _LOKDocView
     guint32 m_nLastButtonReleaseTime;
     /// Rectangles of the current text selection.
     GList* m_pTextSelectionRectangles;
+    GdkRectangle m_aTextSelectionStart;
+    GdkRectangle m_aTextSelectionEnd;
 };
 
 struct _LOKDocViewClass
diff --git a/libreofficekit/source/gtk/lokdocview.c b/libreofficekit/source/gtk/lokdocview.c
index 351c7cc..89feeca 100644
--- a/libreofficekit/source/gtk/lokdocview.c
+++ b/libreofficekit/source/gtk/lokdocview.c
@@ -134,6 +134,8 @@ static void lok_docview_init( LOKDocView* pDocView )
     pDocView->m_nLastButtonPressTime = 0;
     pDocView->m_nLastButtonReleaseTime = 0;
     pDocView->m_pTextSelectionRectangles = NULL;
+    memset(&pDocView->m_aTextSelectionStart, 0, sizeof(pDocView->m_aTextSelectionStart));
+    memset(&pDocView->m_aTextSelectionEnd, 0, sizeof(pDocView->m_aTextSelectionEnd));
 
     gtk_signal_connect( GTK_OBJECT(pDocView), "destroy",
                         GTK_SIGNAL_FUNC(lcl_onDestroy), NULL );
@@ -185,6 +187,28 @@ static gboolean lcl_handleTimeout(gpointer pData)
     return G_SOURCE_CONTINUE;
 }
 
+/// Renders pHandle below a pCursor rectangle on pCairo.
+static void lcl_renderHandle(cairo_t* pCairo, GdkRectangle* pCursor, cairo_surface_t* pHandle)
+{
+    GdkPoint aCursorBottom;
+    int nHandleWidth, nHandleHeight;
+    double fHandleScale;
+
+    nHandleWidth = cairo_image_surface_get_width(pHandle);
+    nHandleHeight = cairo_image_surface_get_height(pHandle);
+    // We want to scale down the handle, so that its height is the same as the cursor caret.
+    fHandleScale = twipToPixel(pCursor->height) / nHandleHeight;
+    // We want the top center of the handle bitmap to be at the bottom center of the cursor rectangle.
+    aCursorBottom.x = twipToPixel(pCursor->x) + twipToPixel(pCursor->width) / 2 - (nHandleWidth * fHandleScale) / 2;
+    aCursorBottom.y = twipToPixel(pCursor->y) + twipToPixel(pCursor->height);
+    cairo_save(pCairo);
+    cairo_translate(pCairo, aCursorBottom.x, aCursorBottom.y);
+    cairo_scale(pCairo, fHandleScale, fHandleScale);
+    cairo_set_source_surface(pCairo, pHandle, 0, 0);
+    cairo_paint(pCairo);
+    cairo_restore(pCairo);
+}
+
 static gboolean renderOverlay(GtkWidget* pWidget, GdkEventExpose* pEvent, gpointer pData)
 {
 #if GTK_CHECK_VERSION(2,14,0) // we need gtk_widget_get_window()
@@ -213,26 +237,9 @@ static gboolean renderOverlay(GtkWidget* pWidget, GdkEventExpose* pEvent, gpoint
     if (!lcl_isEmptyRectangle(&pDocView->m_aVisibleCursor) && !pDocView->m_pTextSelectionRectangles)
     {
         // Have a cursor, but no selection: we need the middle handle.
-        GdkPoint aCursorBottom;
-        cairo_surface_t* pSurface;
-        int nHandleWidth, nHandleHeight;
-        double fHandleScale;
-
-        pSurface = cairo_image_surface_create_from_png(CURSOR_HANDLE_DIR "handle_middle.png");
-        nHandleWidth = cairo_image_surface_get_width(pSurface);
-        nHandleHeight = cairo_image_surface_get_height(pSurface);
-        // We want to scale down the handle, so that its height is the same as the cursor caret.
-        fHandleScale = twipToPixel(pDocView->m_aVisibleCursor.height) / nHandleHeight;
-        // We want the top center of the handle bitmap to be at the bottom center of the cursor rectangle.
-        aCursorBottom.x = twipToPixel(pDocView->m_aVisibleCursor.x) + twipToPixel(pDocView->m_aVisibleCursor.width) / 2 - (nHandleWidth * fHandleScale) / 2;
-        aCursorBottom.y = twipToPixel(pDocView->m_aVisibleCursor.y) + twipToPixel(pDocView->m_aVisibleCursor.height);
-        cairo_save(pCairo);
-        cairo_translate(pCairo, aCursorBottom.x, aCursorBottom.y);
-        cairo_scale(pCairo, fHandleScale, fHandleScale);
-        cairo_set_source_surface(pCairo, pSurface, 0, 0);
-        cairo_paint(pCairo);
-        cairo_surface_destroy(pSurface);
-        cairo_restore(pCairo);
+        cairo_surface_t* pHandle = cairo_image_surface_create_from_png(CURSOR_HANDLE_DIR "handle_middle.png");
+        lcl_renderHandle(pCairo, &pDocView->m_aVisibleCursor, pHandle);
+        cairo_surface_destroy(pHandle);
     }
 
     if (pDocView->m_pTextSelectionRectangles)
@@ -247,6 +254,22 @@ static gboolean renderOverlay(GtkWidget* pWidget, GdkEventExpose* pEvent, gpoint
             cairo_rectangle(pCairo, twipToPixel(pRectangle->x), twipToPixel(pRectangle->y), twipToPixel(pRectangle->width), twipToPixel(pRectangle->height));
             cairo_fill(pCairo);
         }
+
+        // Handles
+        if (!lcl_isEmptyRectangle(&pDocView->m_aTextSelectionStart))
+        {
+            // Have a start position: we need a start handle.
+            cairo_surface_t* pHandle = cairo_image_surface_create_from_png(CURSOR_HANDLE_DIR "handle_start.png");
+            lcl_renderHandle(pCairo, &pDocView->m_aTextSelectionStart, pHandle);
+            cairo_surface_destroy(pHandle);
+        }
+        if (!lcl_isEmptyRectangle(&pDocView->m_aTextSelectionEnd))
+        {
+            // Have a start position: we need an end handle.
+            cairo_surface_t* pHandle = cairo_image_surface_create_from_png(CURSOR_HANDLE_DIR "handle_end.png");
+            lcl_renderHandle(pCairo, &pDocView->m_aTextSelectionEnd, pHandle);
+            cairo_surface_destroy(pHandle);
+        }
     }
 
     cairo_destroy(pCairo);
@@ -446,11 +469,29 @@ static gboolean lok_docview_callback(gpointer pData)
     break;
     case LOK_CALLBACK_TEXT_SELECTION:
     {
+        LOKDocView* pDocView = pCallback->m_pDocView;
         GList* pRectangles = lcl_payloadToRectangles(pCallback->m_pPayload);
-        if (pCallback->m_pDocView->m_pTextSelectionRectangles)
-            g_list_free_full(pCallback->m_pDocView->m_pTextSelectionRectangles, g_free);
-        pCallback->m_pDocView->m_pTextSelectionRectangles = pRectangles;
-        gtk_widget_queue_draw(GTK_WIDGET(pCallback->m_pDocView->pEventBox));
+        if (pDocView->m_pTextSelectionRectangles)
+            g_list_free_full(pDocView->m_pTextSelectionRectangles, g_free);
+        pDocView->m_pTextSelectionRectangles = pRectangles;
+
+        // In case the selection is empty, then we get no LOK_CALLBACK_TEXT_SELECTION_START/END events.
+        if (pRectangles == NULL)
+        {
+            memset(&pDocView->m_aTextSelectionStart, 0, sizeof(pDocView->m_aTextSelectionStart));
+            memset(&pDocView->m_aTextSelectionEnd, 0, sizeof(pDocView->m_aTextSelectionEnd));
+        }
+        gtk_widget_queue_draw(GTK_WIDGET(pDocView->pEventBox));
+    }
+    break;
+    case LOK_CALLBACK_TEXT_SELECTION_START:
+    {
+        pCallback->m_pDocView->m_aTextSelectionStart = lcl_payloadToRectangle(pCallback->m_pPayload);
+    }
+    break;
+    case LOK_CALLBACK_TEXT_SELECTION_END:
+    {
+        pCallback->m_pDocView->m_aTextSelectionEnd = lcl_payloadToRectangle(pCallback->m_pPayload);
     }
     break;
     default:
commit 9f294cca96bd690b00e4ee802535390dbbfd9d8f
Author: Miklos Vajna <vmiklos at collabora.co.uk>
Date:   Tue Feb 10 10:45:18 2015 +0100

    LOK: add LOK_CALLBACK_TEXT_SELECTION_START/END
    
    Without this, it's really hard to figure out where to put selection
    handles based on the selection polygon.
    
    Change-Id: I7fde038a33633796a43f0b454a5a7cff701c5dc3

diff --git a/include/LibreOfficeKit/LibreOfficeKit.h b/include/LibreOfficeKit/LibreOfficeKit.h
index 1ef70e5..2044795 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.h
+++ b/include/LibreOfficeKit/LibreOfficeKit.h
@@ -75,7 +75,25 @@ typedef enum
      * LOK_CALLBACK_INVALIDATE_TILES. When there is no selection, an empty
      * string is provided.
      */
-    LOK_CALLBACK_TEXT_SELECTION
+    LOK_CALLBACK_TEXT_SELECTION,
+    /**
+     * The size and/or the position of the cursor rectangle at the text
+     * selection start changed.
+     *
+     * If this callback is emitted, it's always followed by a
+     * LOK_CALLBACK_TEXT_SELECTION one. Rectangle format is the same as
+     * LOK_CALLBACK_INVALIDATE_TILES.
+     */
+    LOK_CALLBACK_TEXT_SELECTION_START,
+    /**
+     * The size and/or the position of the cursor rectangle at the text
+     * selection end changed.
+     *
+     * If this callback is emitted, it's always followed by a
+     * LOK_CALLBACK_TEXT_SELECTION one. Rectangle format is the same as
+     * LOK_CALLBACK_INVALIDATE_TILES.
+     */
+    LOK_CALLBACK_TEXT_SELECTION_END
 }
 LibreOfficeKitCallbackType;
 
diff --git a/sw/source/core/crsr/viscrs.cxx b/sw/source/core/crsr/viscrs.cxx
index 6d7a961..0b0d63c 100644
--- a/sw/source/core/crsr/viscrs.cxx
+++ b/sw/source/core/crsr/viscrs.cxx
@@ -42,6 +42,7 @@
 #include <wrtsh.hxx>
 #include <comcore.hrc>
 #include <view.hxx>
+#include <IDocumentLayoutAccess.hxx>
 
 #include <svx/sdr/overlay/overlaymanager.hxx>
 #include <svx/sdrpaintwindow.hxx>
@@ -256,6 +257,23 @@ void SwSelPaintRects::Hide()
     SwRects::clear();
 }
 
+/**
+ * Return a layout rectangle (typically with minimal width) that represents a
+ * cursor at rPosition.
+ *
+ * @param rPoint layout position as a hint about what layout frame contains
+ * rPosition (there might be multiple frames for a single node)
+ * @param rPosition the doc model position (paragraph / character index)
+ */
+static SwRect lcl_getLayoutRect(const Point& rPoint, const SwPosition& rPosition)
+{
+    const SwCntntNode* pNode = rPosition.nNode.GetNode().GetCntntNode();
+    const SwCntntFrm* pFrm = pNode->getLayoutFrm(pNode->GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout(), &rPoint, &rPosition);
+    SwRect aRect;
+    pFrm->GetCharRect(aRect, rPosition);
+    return aRect;
+}
+
 void SwSelPaintRects::Show()
 {
     SdrView* pView = (SdrView*)pCShell->GetDrawView();
@@ -316,6 +334,24 @@ void SwSelPaintRects::Show()
 
         if (GetShell()->isTiledRendering())
         {
+            if (!empty())
+            {
+                // The selection may be a complex polygon, emit the logical
+                // start/end cursor rectangle of the selection as separate
+                // events, if there is a real selection.
+                // This can be used to easily show selection handles on the
+                // client side.
+                const SwShellCrsr* pCursor = GetShell()->getShellCrsr(false);
+                SwRect aStartRect = lcl_getLayoutRect(pCursor->GetSttPos(), *pCursor->Start());
+                std::stringstream ss;
+                ss << aStartRect.Width() << ", " << aStartRect.Height() << ", " << aStartRect.Left() << ", " << aStartRect.Top();
+                GetShell()->libreOfficeKitCallback(LOK_CALLBACK_TEXT_SELECTION_START, ss.str().c_str());
+                SwRect aEndRect = lcl_getLayoutRect(pCursor->GetEndPos(), *pCursor->End());
+                ss.str("");
+                ss << aEndRect.Width() << ", " << aEndRect.Height() << ", " << aEndRect.Left() << ", " << aEndRect.Top();
+                GetShell()->libreOfficeKitCallback(LOK_CALLBACK_TEXT_SELECTION_END, ss.str().c_str());
+            }
+
             std::stringstream ss;
             for (size_type i = 0; i < size(); ++i)
             {


More information about the Libreoffice-commits mailing list