diff options
-rw-r--r-- | include/osl/detail/ios-bootstrap.h | 3 | ||||
-rw-r--r-- | include/touch/touch.h | 4 | ||||
-rw-r--r-- | ios/experimental/LibreOffice/LibreOffice/View.m | 42 | ||||
-rw-r--r-- | sw/source/ui/uiview/viewport.cxx | 104 | ||||
-rw-r--r-- | vcl/ios/iosinst.cxx | 17 | ||||
-rw-r--r-- | vcl/source/window/window2.cxx | 133 | ||||
-rw-r--r-- | vcl/source/window/winproc.cxx | 55 |
7 files changed, 258 insertions, 100 deletions
diff --git a/include/osl/detail/ios-bootstrap.h b/include/osl/detail/ios-bootstrap.h index fa3d0c85b460..42c38e493721 100644 --- a/include/osl/detail/ios-bootstrap.h +++ b/include/osl/detail/ios-bootstrap.h @@ -49,7 +49,8 @@ void lo_runMain(); void lo_set_view_size(int width, int height); void lo_render_windows(CGContextRef context, CGRect rect); void lo_tap(int x, int y); -void lo_pan(int x, int y); +void lo_pan(int deltaX, int deltaY); +void lo_zoom(int x, int y, float scale); void lo_keyboard_input(int c); #ifdef __cplusplus diff --git a/include/touch/touch.h b/include/touch/touch.h index 8fa2dd16d26c..2fd7a9a9b6eb 100644 --- a/include/touch/touch.h +++ b/include/touch/touch.h @@ -14,6 +14,10 @@ #if !HAVE_FEATURE_DESKTOP +#define MOBILE_MAX_ZOOM_IN 600 +#define MOBILE_MAX_ZOOM_OUT 80 +#define MOBILE_ZOOM_SCALE_MULTIPLIER 10000 + // Functions to be implemented by the app-specifc upper or less // app-specific but platform-specific medium layer on touch-based // platforms. The same API is used on each such platform. There are diff --git a/ios/experimental/LibreOffice/LibreOffice/View.m b/ios/experimental/LibreOffice/LibreOffice/View.m index 8c490cb88cec..4e347a24f599 100644 --- a/ios/experimental/LibreOffice/LibreOffice/View.m +++ b/ios/experimental/LibreOffice/LibreOffice/View.m @@ -50,21 +50,49 @@ { if ([gestureRecognizer state] == UIGestureRecognizerStateEnded) { CGPoint location = [gestureRecognizer locationInView: self]; + NSLog(@"tapGesture: at: (%d,%d)", (int)location.x, (int)location.y); + lo_tap(location.x, location.y); + [self->textView becomeFirstResponder]; - } else + } else { NSLog(@"tapGesture: %@", gestureRecognizer); + } } - (void)panGesture:(UIPanGestureRecognizer *)gestureRecognizer { - if ([gestureRecognizer state] == UIGestureRecognizerStateEnded) { - CGPoint translation = [gestureRecognizer translationInView: self]; - NSLog(@"panGesture: pan: (%d,%d)", (int)translation.x, (int)translation.y); - lo_pan(translation.x, translation.y); - } else - NSLog(@"panGesture: %@", gestureRecognizer); + static CGFloat previousX = 0.0f, previousY = 0.0f; + + CGPoint translation = [gestureRecognizer translationInView: self]; + + if (gestureRecognizer.state != UIGestureRecognizerStateBegan) { + int deltaX = translation.x - previousX; + int deltaY = translation.y - previousY; + + NSLog(@"panGesture: pan (delta): (%d,%d)", deltaX, deltaY); + + lo_pan(deltaX, deltaY); + } + + previousX = translation.x; + previousY = translation.y; +} + +- (void)pinchGesture:(UIPinchGestureRecognizer *)gestureRecognizer +{ + CGPoint location = [gestureRecognizer locationInView: self]; + CGFloat scale = gestureRecognizer.scale; + + NSLog(@"pinchGesture: pinch: (%f) cords (%d,%d)", (float)scale, (int)location.x, (int)location.y ); + + lo_zoom((int)location.x, (int)location.y, (float)scale); + + // to reset the gesture scaling + if (gestureRecognizer.state==UIGestureRecognizerStateEnded) { + lo_zoom(1, 1, 0.0f); + } } @end diff --git a/sw/source/ui/uiview/viewport.cxx b/sw/source/ui/uiview/viewport.cxx index c137db6ef685..4f34f2a9e0a1 100644 --- a/sw/source/ui/uiview/viewport.cxx +++ b/sw/source/ui/uiview/viewport.cxx @@ -17,6 +17,8 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include <config_features.h> + #include "hintids.hxx" #include <vcl/help.hxx> #include <svx/ruler.hxx> @@ -37,6 +39,7 @@ #include <pagedesc.hxx> #include <workctrl.hxx> #include <crsskip.hxx> +#include <touch/touch.h> #include <PostItMgr.hxx> @@ -298,11 +301,12 @@ void SwView::SetVisArea( const Point &rPt, sal_Bool bUpdateScrollbar ) // (fix: Bild.de, 200%) It does not work completly without alignment // Let's see how far we get with half BrushSize. Point aPt( rPt ); -// const long nTmp = GetWrtShell().IsFrameView() ? BRUSH_SIZE/2 : BRUSH_SIZE; - const long nTmp = GetWrtShell().IsFrameView() ? 4 : 8; aPt = GetEditWin().LogicToPixel( aPt ); +#if HAVE_FEATURE_DESKTOP + const long nTmp = GetWrtShell().IsFrameView() ? 4 : 8; aPt.X() -= aPt.X() % nTmp; aPt.Y() -= aPt.Y() % nTmp; +#endif aPt = GetEditWin().PixelToLogic( aPt ); if ( aPt == m_aVisArea.TopLeft() ) @@ -1258,19 +1262,107 @@ sal_Bool SwView::HandleWheelCommands( const CommandEvent& rCEvt ) } else if( COMMAND_WHEEL_ZOOM_SCALE == pWData->GetMode() ) { - int newZoom = 100 * (m_pWrtShell->GetViewOptions()->GetZoom() / 100.0) * (pWData->GetDelta() / 100.0); - SetZoom( SVX_ZOOM_PERCENT, std::max( 20, std::min( 600, newZoom ) ) ); + // COMMAND_WHEEL_ZOOM_SCALE is de facto used only for Android and iOS, I think + + // mobile touch zoom (pinch) section + // last location in pixels is defaulted to an illegal location + // (coordinates are always positive) + static Point lastLocationInPixels(0,0); + static const double NEW_ZOOM_START= -6666.66; + static double initialZoom = NEW_ZOOM_START; + static int rememberedZoom = 0; + + // the target should remain the same in logic, regardless of eventual zoom + const Point & targetInLogic = GetEditWin().PixelToLogic(rCEvt.GetMousePosPixel()); + double scale = double(pWData->GetDelta()) / double(MOBILE_ZOOM_SCALE_MULTIPLIER); + + if( scale==0 ) + { + // scale 0, means end of gesture, and zoom resets + rememberedZoom=0; + } + else + { + int preZoomByVCL = m_pWrtShell->GetViewOptions()->GetZoom(); + bool isFirst = rememberedZoom != preZoomByVCL; + + if( isFirst ) + { + // If this is the start of a new zoom action, we take the value from VCL. + // Otherwise, we remeber the zoom from the previous action. + // This way we can be more accurate than VCL + initialZoom =(double) preZoomByVCL; + } + + // each zooming event is scaling the initial zoom + int zoomTarget = int(initialZoom * scale); + + // thresholding the zoom + zoomTarget = std::max( MOBILE_MAX_ZOOM_OUT, std::min( MOBILE_MAX_ZOOM_IN, zoomTarget ) ); + long deltaX = 0, deltaY = 0; + + // no point zooming if the target zoom is the same as the current zoom + if( zoomTarget != preZoomByVCL ) + { + + SetZoom( SVX_ZOOM_PERCENT, zoomTarget ); + + // getting the VCL post zoom + rememberedZoom = m_pWrtShell->GetViewOptions()->GetZoom(); + } + else + { + rememberedZoom = preZoomByVCL; + } + + // if there was no zoom + if( rememberedZoom == preZoomByVCL ) + { + if( !isFirst ) + { + // If this is not the first location of the zoom, there is a valid last location. + // Therefore, scroll the center of the gesture. + // Explanation: without a zoom transpiring, the view will not change. + // Therefore, we do a simple scrolll from screen center to screen center + deltaX = rCEvt.GetMousePosPixel().X() - lastLocationInPixels.X(); + deltaY = rCEvt.GetMousePosPixel().Y() - lastLocationInPixels.Y(); + } + } + else + { + // Otherwise, there was a zoom. + // Keep the on screen center of the pinch in the same on screen location + const Point & postZoomTargetInPixels = GetEditWin().LogicToPixel(targetInLogic); + + deltaX = rCEvt.GetMousePosPixel().X() - postZoomTargetInPixels.X(); + deltaY = rCEvt.GetMousePosPixel().Y() - postZoomTargetInPixels.Y(); + } + + if( (deltaX!=0) || (deltaY!=0) ) + { + // Scrolling the deltaX deltaY + Point deltaPoint( deltaX, deltaY ); + CommandWheelData cmd( 0, 0, 0, COMMAND_WHEEL_SCROLL, 0, 0, true); + CommandEvent event(deltaPoint , COMMAND_WHEEL, sal_True, &cmd ); + + m_pEditWin->HandleScrollCommand(event, m_pHScrollbar, m_pVScrollbar); + } + + // store the last location + lastLocationInPixels = rCEvt.GetMousePosPixel(); + } + bOk = sal_True; } else { - if(pWData->GetMode()==COMMAND_WHEEL_SCROLL) + if( pWData->GetMode()==COMMAND_WHEEL_SCROLL ) { // This influences whether quick help is shown m_bWheelScrollInProgress=true; } - if ((COMMAND_WHEEL_SCROLL==pWData->GetMode()) && (((sal_uLong)0xFFFFFFFF) == pWData->GetScrollLines())) + if( (COMMAND_WHEEL_SCROLL==pWData->GetMode()) && (((sal_uLong)0xFFFFFFFF) == pWData->GetScrollLines()) ) { if (pWData->GetDelta()<0) PhyPageDown(); diff --git a/vcl/ios/iosinst.cxx b/vcl/ios/iosinst.cxx index dd92c6e5af2c..e7cec9f9d046 100644 --- a/vcl/ios/iosinst.cxx +++ b/vcl/ios/iosinst.cxx @@ -426,17 +426,28 @@ void lo_tap(int x, int y) } extern "C" -void lo_pan(int x, int y) +void lo_pan(int deltaX, int deltaY) { SalFrame *pFocus = IosSalInstance::getInstance()->getFocusFrame(); if (pFocus) { - SAL_INFO( "vcl.ios", "scroll: " << "(" << x << "," << y << ")" ); - ScrollEvent aEvent( x, y ); + SAL_INFO( "vcl.ios", "pan delta: " << "(" << deltaX << "," << deltaY << ") "); + ScrollEvent aEvent( deltaX, deltaY ); Application::PostScrollEvent(VCLEVENT_WINDOW_SCROLL, pFocus->GetWindow(), &aEvent); } } extern "C" +void lo_zoom(int x, int y, float scale) +{ + SalFrame *pFocus = IosSalInstance::getInstance()->getFocusFrame(); + if (pFocus) { + SAL_INFO( "vcl.ios", "pinch: " << "(" << scale << ") "); + ZoomEvent aEvent( Point(x,y), scale); + Application::PostZoomEvent(VCLEVENT_WINDOW_ZOOM, pFocus->GetWindow(), &aEvent); + } +} + +extern "C" void lo_keyboard_input(int c) { SalFrame *pFocus = IosSalInstance::getInstance()->getFocusFrame(); diff --git a/vcl/source/window/window2.cxx b/vcl/source/window/window2.cxx index 475181cc4373..49f7650786ac 100644 --- a/vcl/source/window/window2.cxx +++ b/vcl/source/window/window2.cxx @@ -1111,6 +1111,38 @@ long Window::GetDrawPixel( OutputDevice* pDev, long nPixels ) const // ----------------------------------------------------------------------- +static void lcl_HandleScrollHelper( ScrollBar* pScrl, long nN, bool isMultiplyByLineSize ) +{ + if ( pScrl && nN && pScrl->IsEnabled() && pScrl->IsInputEnabled() && ! pScrl->IsInModalMode() ) + { + long nNewPos = pScrl->GetThumbPos(); + + if ( nN == -LONG_MAX ) + nNewPos += pScrl->GetPageSize(); + else if ( nN == LONG_MAX ) + nNewPos -= pScrl->GetPageSize(); + else + { + // allowing both chunked and continuous scrolling + if(isMultiplyByLineSize){ + nN*=pScrl->GetLineSize(); + } + + const double fVal = (double)(nNewPos - nN); + + if ( fVal < LONG_MIN ) + nNewPos = LONG_MIN; + else if ( fVal > LONG_MAX ) + nNewPos = LONG_MAX; + else + nNewPos = (long)fVal; + } + + pScrl->DoScroll( nNewPos ); + } + +} + sal_Bool Window::HandleScrollCommand( const CommandEvent& rCmd, ScrollBar* pHScrl, ScrollBar* pVScrl ) { @@ -1152,24 +1184,70 @@ sal_Bool Window::HandleScrollCommand( const CommandEvent& rCmd, if ( pData && (COMMAND_WHEEL_SCROLL == pData->GetMode()) ) { - sal_uLong nScrollLines = pData->GetScrollLines(); - long nLines; - if ( nScrollLines == COMMAND_WHEEL_PAGESCROLL ) + if (!pData->IsDeltaPixel()) { - if ( pData->GetDelta() < 0 ) - nLines = -LONG_MAX; + sal_uLong nScrollLines = pData->GetScrollLines(); + long nLines; + if ( nScrollLines == COMMAND_WHEEL_PAGESCROLL ) + { + if ( pData->GetDelta() < 0 ) + nLines = -LONG_MAX; + else + nLines = LONG_MAX; + } else - nLines = LONG_MAX; - } - else - nLines = pData->GetNotchDelta() * (long)nScrollLines; - if ( nLines ) - { - ImplHandleScroll( NULL, + nLines = pData->GetNotchDelta() * (long)nScrollLines; + if ( nLines ) + { + ImplHandleScroll( NULL, 0L, pData->IsHorz() ? pHScrl : pVScrl, nLines ); - bRet = sal_True; + bRet = sal_True; + } + } + else + { + // Mobile / touch scrolling section + const Point & deltaPoint = rCmd.GetMousePosPixel(); + + double deltaXInPixels = double(deltaPoint.X()); + double deltaYInPixels = double(deltaPoint.Y()); + + double visSizeX = double(pHScrl->GetVisibleSize()); + double visSizeY = double(pVScrl->GetVisibleSize()); + + Size winSize = this->GetOutputSizePixel(); + + double ratioX = deltaXInPixels / double(winSize.getWidth()); + double ratioY = deltaYInPixels / double(winSize.getHeight()); + + long deltaXInLogic = long(visSizeX * ratioX); + long deltaYInLogic = long(visSizeY * ratioY); + + // Touch need to work by pixels. Did not apply this to + // Android, as android code may require adaptations + // to work with this scrolling code +#ifndef IOS + long lineSizeX = pHScrl->GetLineSize(); + long lineSizeY = pVScrl->GetLineSize(); + + deltaXInLogic /= lineSizeX; + deltaYInLogic /= lineSizeY; +#endif + + if ( deltaXInLogic || deltaYInLogic ) + { +#ifndef IOS + bool isMultiplyByLineSize = true; +#else + bool isMultiplyByLineSize = false; +#endif + lcl_HandleScrollHelper( pHScrl, deltaXInLogic, isMultiplyByLineSize ); + lcl_HandleScrollHelper( pVScrl, deltaYInLogic, isMultiplyByLineSize ); + + bRet = sal_True; + } } } } @@ -1197,32 +1275,7 @@ sal_Bool Window::HandleScrollCommand( const CommandEvent& rCmd, // ----------------------------------------------------------------------- -static void lcl_HandleScrollHelper( ScrollBar* pScrl, long nN ) -{ - if ( pScrl && nN && pScrl->IsEnabled() && pScrl->IsInputEnabled() && ! pScrl->IsInModalMode() ) - { - long nNewPos = pScrl->GetThumbPos(); - - if ( nN == -LONG_MAX ) - nNewPos += pScrl->GetPageSize(); - else if ( nN == LONG_MAX ) - nNewPos -= pScrl->GetPageSize(); - else - { - const double fVal = (double)nNewPos - ((double)nN * pScrl->GetLineSize()); - - if ( fVal < LONG_MIN ) - nNewPos = LONG_MIN; - else if ( fVal > LONG_MAX ) - nNewPos = LONG_MAX; - else - nNewPos = (long)fVal; - } - - pScrl->DoScroll( nNewPos ); - } -} // Note that when called for COMMAND_WHEEL above, despite its name, // pVScrl isn't necessarily the vertical scroll bar. Depending on @@ -1233,8 +1286,8 @@ static void lcl_HandleScrollHelper( ScrollBar* pScrl, long nN ) void Window::ImplHandleScroll( ScrollBar* pHScrl, long nX, ScrollBar* pVScrl, long nY ) { - lcl_HandleScrollHelper( pHScrl, nX ); - lcl_HandleScrollHelper( pVScrl, nY ); + lcl_HandleScrollHelper( pHScrl, nX, true ); + lcl_HandleScrollHelper( pVScrl, nY, true ); } DockingManager* Window::GetDockingManager() diff --git a/vcl/source/window/winproc.cxx b/vcl/source/window/winproc.cxx index 052395d35a93..7a93680ab324 100644 --- a/vcl/source/window/winproc.cxx +++ b/vcl/source/window/winproc.cxx @@ -35,6 +35,7 @@ #include <vcl/help.hxx> #include <vcl/dockwin.hxx> #include <vcl/menu.hxx> +#include <touch/touch.h> #include <svdata.hxx> #include <dbggui.hxx> @@ -2623,6 +2624,7 @@ long ImplWindowFrameProc( Window* pWindow, SalFrame* /*pFrame*/, ImplHandleSurroundingTextSelectionChange( pWindow, pEvt->mnStart, pEvt->mnEnd ); + // Fallthrough really intended? } case SALEVENT_STARTRECONVERSION: ImplHandleStartReconversion( pWindow ); @@ -2631,14 +2633,12 @@ long ImplWindowFrameProc( Window* pWindow, SalFrame* /*pFrame*/, { ZoomEvent* pZoomEvent = (ZoomEvent*) pEvent; SalWheelMouseEvent aSalWheelMouseEvent; - aSalWheelMouseEvent.mnTime = Time::GetSystemTicks(); aSalWheelMouseEvent.mnX = pZoomEvent->GetCenter().getX(); aSalWheelMouseEvent.mnY = pZoomEvent->GetCenter().getY(); - - // Pass on the scale as a percentage of current zoom factor - aSalWheelMouseEvent.mnDelta = (long) (pZoomEvent->GetScale() * 100); - + // Pass on the scale as a percentage * 100 of current zoom factor + // so to assure zoom granularity + aSalWheelMouseEvent.mnDelta = long(double(pZoomEvent->GetScale()) * double(MOBILE_ZOOM_SCALE_MULTIPLIER)); // Other SalWheelMouseEvent fields ignored when the // scaleDirectly parameter to ImplHandleWheelEvent() is // true. @@ -2649,49 +2649,18 @@ long ImplWindowFrameProc( Window* pWindow, SalFrame* /*pFrame*/, { ScrollEvent* pScrollEvent = (ScrollEvent*) pEvent; SalWheelMouseEvent aSalWheelMouseEvent; - aSalWheelMouseEvent.mnTime = Time::GetSystemTicks(); - aSalWheelMouseEvent.mnX = 0; // ??? - aSalWheelMouseEvent.mnY = 0; - - // Note that it seems that the delta-is-pixels thing is - // not actually implemented. The field is just passed on - // but its value never tested and has no effect? aSalWheelMouseEvent.mbDeltaIsPixel = sal_True; - - // First scroll vertically, then horizontally - aSalWheelMouseEvent.mnDelta = (long) pScrollEvent->GetYOffset(); - - // No way to figure out correct amount of "lines" to - // scroll, and for touch devices (for which this - // SALEVENBT_EXTERNALSCROLL was introduced) we don't even - // display the scroll bars. This means that the scroll - // bars (which still exist as objects, all the scrolling - // action goes through them) apparently use some dummy - // default values for range, line size and page size - // anyway, not related to actual contents of scrolled - // window. This all is very broken. I really wish the - // delta-is-pixels feature (which would be exactly what - // one wants for touch devices) would work. - aSalWheelMouseEvent.mnScrollLines = aSalWheelMouseEvent.mnDelta; - - if (aSalWheelMouseEvent.mnDelta != 0) + // event location holds delta values instead + aSalWheelMouseEvent.mnX = long(pScrollEvent->GetXOffset()); + aSalWheelMouseEvent.mnY = long(pScrollEvent->GetYOffset()); + aSalWheelMouseEvent.mnScrollLines = 0; + if (aSalWheelMouseEvent.mnX != 0 || aSalWheelMouseEvent.mnY != 0) { - aSalWheelMouseEvent.mnNotchDelta = (aSalWheelMouseEvent.mnDelta < 0) ? -1 : 1; - aSalWheelMouseEvent.mnCode = 0; - aSalWheelMouseEvent.mbHorz = sal_False; nRet = ImplHandleWheelEvent( pWindow, aSalWheelMouseEvent ); } - aSalWheelMouseEvent.mnDelta = (long) pScrollEvent->GetXOffset(); - if (aSalWheelMouseEvent.mnDelta != 0) - { - aSalWheelMouseEvent.mnNotchDelta = (aSalWheelMouseEvent.mnDelta < 0) ? -1 : 1; - aSalWheelMouseEvent.mnCode = 0; - aSalWheelMouseEvent.mbHorz = sal_True; - nRet = ImplHandleWheelEvent( pWindow, aSalWheelMouseEvent ); - } - } - break; + } + break; case SALEVENT_QUERYCHARPOSITION: ImplHandleSalQueryCharPosition( pWindow, (SalQueryCharPositionEvent*)pEvent ); break; |