Kaydet (Commit) 4e7495ac authored tarafından ptyl@cloudon.com's avatar ptyl@cloudon.com Kaydeden (comit) Tor Lillqvist

Fix for iOS scroll by pixels, and pinch to zoom

Minor further changes by tml to match the coding style of surrounding
code mainly.

Change-Id: Ied6087a264f1c6b00763ea36fba9808329afede4
Reviewed-on: https://gerrit.libreoffice.org/5742Tested-by: 's avatarTor Lillqvist <tml@collabora.com>
Reviewed-by: 's avatarTor Lillqvist <tml@collabora.com>
üst ff3b823e
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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();
......
......@@ -426,16 +426,27 @@ 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)
{
......
......@@ -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()
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment