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 <vmik...@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 <vmik...@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) { _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits