Permalink
Browse files

Merge pull request #1268 from Montellese/picture_zoom_rotate

Improved picture zooming and rotating on touch devices
  • Loading branch information...
Montellese committed Sep 3, 2012
2 parents d094268 + cd4ff8f commit e13dcf3cc2e4fca49448986ffb997b6c511c4db2
@@ -99,6 +99,20 @@ bool CAndroidTouch::OnSingleTouchStart(float x, float y)
return true;
}
+bool CAndroidTouch::OnMultiTouchStart(float x, float y, int32_t pointers /* = 2 */)
+{
+ XBMC_TouchGesture(ACTION_GESTURE_BEGIN, x, y, 0.0f, 0.0f);
+
+ return true;
+}
+
+bool CAndroidTouch::OnMultiTouchEnd(float x, float y, int32_t pointers /* = 2 */)
+{
+ XBMC_TouchGesture(ACTION_GESTURE_END, 0.0f, 0.0f, 0.0f, 0.0f);
+
+ return true;
+}
+
bool CAndroidTouch::OnTouchGesturePanStart(float x, float y)
{
XBMC_TouchGesture(ACTION_GESTURE_BEGIN, x, y, 0.0f, 0.0f);
@@ -141,6 +155,11 @@ void CAndroidTouch::OnZoomPinch(float centerX, float centerY, float zoomFactor)
XBMC_TouchGesture(ACTION_GESTURE_ZOOM, centerX, centerY, zoomFactor, 0);
}
+void CAndroidTouch::OnRotate(float centerX, float centerY, float angle)
+{
+ XBMC_TouchGesture(ACTION_GESTURE_ROTATE, centerX, centerY, angle, 0);
+}
+
void CAndroidTouch::XBMC_Touch(uint8_t type, uint8_t button, uint16_t x, uint16_t y)
{
XBMC_Event newEvent;
@@ -165,6 +184,6 @@ void CAndroidTouch::XBMC_TouchGesture(int32_t action, float posX, float posY, fl
CApplicationMessenger::Get().SendAction(CAction(action, 0, posX, posY, offsetX, offsetY), WINDOW_INVALID, false);
else if (action == ACTION_GESTURE_END)
CApplicationMessenger::Get().SendAction(CAction(action, 0, posX, posY, offsetX, offsetY), WINDOW_INVALID, false);
- else if (action == ACTION_GESTURE_ZOOM)
+ else if (action == ACTION_GESTURE_ZOOM || action == ACTION_GESTURE_ROTATE)
CApplicationMessenger::Get().SendAction(CAction(action, 0, posX, posY, offsetX, 0), WINDOW_INVALID, false);
}
@@ -34,13 +34,17 @@ class CAndroidTouch : protected ITouchHandler
protected:
virtual bool OnSingleTouchStart(float x, float y);
+ virtual bool OnMultiTouchStart(float x, float y, int32_t pointers = 2);
+ virtual bool OnMultiTouchEnd(float x, float y, int32_t pointers = 2);
+
virtual bool OnTouchGesturePanStart(float x, float y);
virtual bool OnTouchGesturePan(float x, float y, float offsetX, float offsetY, float velocityX, float velocityY);
virtual bool OnTouchGesturePanEnd(float x, float y, float offsetX, float offsetY, float velocityX, float velocityY);
virtual void OnSingleTap(float x, float y);
virtual void OnSingleLongPress(float x, float y);
virtual void OnZoomPinch(float centerX, float centerY, float zoomFactor);
+ virtual void OnRotate(float centerX, float centerY, float angle);
private:
void XBMC_Touch(uint8_t type, uint8_t button, uint16_t x, uint16_t y);
View
@@ -138,7 +138,8 @@
#define ACTION_CALIBRATE_SWAP_ARROWS 47 // select next arrow. Can b used in: settingsScreenCalibration.xml windowid=11
#define ACTION_CALIBRATE_RESET 48 // reset calibration to defaults. Can b used in: settingsScreenCalibration.xml windowid=11/settingsUICalibration.xml windowid=10
#define ACTION_ANALOG_MOVE 49 // analog thumbstick move. Can b used in: slideshow.xml window id=2007/settingsScreenCalibration.xml windowid=11/settingsUICalibration.xml windowid=10
-#define ACTION_ROTATE_PICTURE 50 // rotate current picture during slideshow. Can b used in slideshow.xml window id=2007
+#define ACTION_ROTATE_PICTURE_CW 50 // rotate current picture clockwise during slideshow. Can be used in slideshow.xml window id=2007
+#define ACTION_ROTATE_PICTURE_CCW 51 // rotate current picture counterclockwise during slideshow. Can be used in slideshow.xml window id=2007
#define ACTION_SUBTITLE_DELAY_MIN 52 // Decrease subtitle/movie Delay. Can b used in videoFullScreen.xml window id=2005
#define ACTION_SUBTITLE_DELAY_PLUS 53 // Increase subtitle/movie Delay. Can b used in videoFullScreen.xml window id=2005
@@ -98,7 +98,8 @@ static const ActionMapping actions[] =
{"nextcalibration" , ACTION_CALIBRATE_SWAP_ARROWS},
{"resetcalibration" , ACTION_CALIBRATE_RESET},
{"analogmove" , ACTION_ANALOG_MOVE},
- {"rotate" , ACTION_ROTATE_PICTURE},
+ {"rotate" , ACTION_ROTATE_PICTURE_CW},
+ {"rotateccw" , ACTION_ROTATE_PICTURE_CCW},
{"close" , ACTION_NAV_BACK}, // backwards compatibility
{"subtitledelayminus", ACTION_SUBTITLE_DELAY_MIN},
{"subtitledelay" , ACTION_SUBTITLE_DELAY},
View
@@ -18,13 +18,20 @@
*
*/
+#include <math.h>
+
#include "TouchInput.h"
#include "threads/SingleLock.h"
#include "utils/log.h"
+#ifndef M_PI
+#define M_PI 3.1415926535897932384626433832795028842
+#endif
+
CTouchInput::CTouchInput()
: m_holdTimeout(1000),
m_handler(NULL),
+ m_fRotateAngle(0.0f),
m_gestureState(TouchGestureUnknown),
m_gestureStateOld(TouchGestureUnknown)
{
@@ -127,6 +134,7 @@ bool CTouchInput::Handle(TouchEvent event, float x, float y, int64_t time, int32
}
setGestureState(TouchGestureMultiTouchStart);
+ m_fRotateAngle = 0.0f;
}
// Otherwise we should ignore this pointer
else
@@ -314,6 +322,7 @@ void CTouchInput::saveLastTouch()
void CTouchInput::handleMultiTouchGesture()
{
handleZoomPinch();
+ handleRotation();
}
void CTouchInput::handleZoomPinch()
@@ -343,6 +352,39 @@ void CTouchInput::handleZoomPinch()
}
}
+void CTouchInput::handleRotation()
+{
+ Pointer& primaryPointer = m_pointers[0];
+ Pointer& secondaryPointer = m_pointers[1];
+
+ CVector last = primaryPointer.last - secondaryPointer.last;
+ CVector current = primaryPointer.current - secondaryPointer.current;
+
+ float length = last.length() * current.length();
+ if (length != 0.0f)
+ {
+ float centerX = (primaryPointer.current.x + secondaryPointer.current.x) / 2;
+ float centerY = (primaryPointer.current.y + secondaryPointer.current.y) / 2;
+
+ float scalar = last.scalar(current);
+ float angle = acos(scalar / length) * 180.0f / M_PI;
+
+ // make sure the result of acos is a valid number
+ if (angle == angle)
+ {
+ // calculate the direction of the rotation using the
+ // z-component of the cross-product of last and current
+ float direction = last.x * current.y - current.x * last.y;
+ if (direction < 0.0f)
+ m_fRotateAngle -= angle;
+ else
+ m_fRotateAngle += angle;
+
+ OnRotate(centerX, centerY, m_fRotateAngle);
+ }
+ }
+}
+
void CTouchInput::OnTimeout()
{
CSingleLock lock(m_critical);
@@ -548,3 +590,11 @@ void CTouchInput::OnZoomPinch(float centerX, float centerY, float zoomFactor)
if (m_handler)
m_handler->OnZoomPinch(centerX, centerY, zoomFactor);
}
+
+void CTouchInput::OnRotate(float centerX, float centerY, float angle)
+{
+ CLog::Log(LOGDEBUG, "%s", __FUNCTION__);
+
+ if (m_handler)
+ m_handler->OnRotate(centerX, centerY, angle);
+}
View
@@ -219,6 +219,16 @@ class ITouchHandler
\sa
*/
virtual void OnZoomPinch(float centerX, float centerY, float zoomFactor) { }
+ /*!
+ \brief Two simultaneous touches have been held down and moved to perform a rotating gesture
+
+ \param centerX The x coordinate (with sub-pixel) of the center of the two touches
+ \param centerY The y coordinate (with sub-pixel) of the center of the two touches
+ \param angle The clockwise angle in degrees of the rotation
+ \return True if the event was handled otherwise false
+ \sa
+ */
+ virtual void OnRotate(float centerX, float centerY, float angle) { }
};
class CTouchInput : private ITouchHandler, private ITimerCallback
@@ -306,6 +316,7 @@ class CTouchInput : private ITouchHandler, private ITimerCallback
void handleMultiTouchGesture();
void handleZoomPinch();
+ void handleRotation();
// implementation of ITimerCallback
virtual void OnTimeout();
@@ -335,13 +346,16 @@ class CTouchInput : private ITouchHandler, private ITimerCallback
virtual void OnDoubleTap(float x1, float y1, float x2, float y2);
virtual void OnDoubleLongPress(float x1, float y1, float x2, float y2);
virtual void OnZoomPinch(float centerX, float centerY, float zoomFactor);
+ virtual void OnRotate(float centerX, float centerY, float angle);
CCriticalSection m_critical;
int32_t m_holdTimeout;
ITouchHandler *m_handler;
CTimer *m_holdTimer;
+ float m_fRotateAngle;
+
class Touch : public CVector {
public:
Touch() { reset(); }
@@ -2151,7 +2151,7 @@ int CXbmcHttp::xbmcAction(int numParas, CStdString paras[], int theAction)
{
CGUIWindowSlideShow *pSlideShow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
if (pSlideShow) {
- pSlideShow->OnAction(CAction(ACTION_ROTATE_PICTURE));
+ pSlideShow->OnAction(CAction(ACTION_ROTATE_PICTURE_CW));
return SetResponse(openTag+"OK");
}
else
@@ -441,7 +441,10 @@ JSONRPC_STATUS CPlayerOperations::Rotate(const CStdString &method, ITransportLay
switch (GetPlayer(parameterObject["playerid"]))
{
case Picture:
- SendSlideshowAction(ACTION_ROTATE_PICTURE);
+ if (parameterObject["value"].asString().compare("clockwise") == 0)
+ SendSlideshowAction(ACTION_ROTATE_PICTURE_CW);
+ else
+ SendSlideshowAction(ACTION_ROTATE_PICTURE_CCW);
return ACK;
case Video:
@@ -1181,7 +1181,8 @@ namespace JSONRPC
"\"transport\": \"Response\","
"\"permission\": \"ControlPlayback\","
"\"params\": ["
- "{ \"name\": \"playerid\", \"$ref\": \"Player.Id\", \"required\": true }"
+ "{ \"name\": \"playerid\", \"$ref\": \"Player.Id\", \"required\": true },"
+ "{ \"name\": \"value\", \"type\": \"string\", \"enum\": [ \"clockwise\", \"counterclockwise\" ], \"default\": \"clockwise\" }"
"],"
"\"returns\": \"string\""
"}",
@@ -318,6 +318,7 @@
"permission": "ControlPlayback",
"params": [
{ "name": "playerid", "$ref": "Player.Id", "required": true }
+ { "name": "value", "type": "string", "enum": [ "clockwise", "counterclockwise" ], "default": "clockwise" }
],
"returns": "string"
},
@@ -29,7 +29,7 @@
@class IOSEAGLView;
-@interface XBMCController : UIViewController
+@interface XBMCController : UIViewController <UIGestureRecognizerDelegate>
{
UIWindow *m_window;
IOSEAGLView *m_glView;
@@ -38,8 +38,6 @@
/* Touch handling */
CGSize screensize;
CGPoint lastGesturePoint;
- CGFloat lastPinchScale;
- CGFloat currentPinchScale;
CGFloat screenScale;
bool touchBeginSignaled;
int m_screenIdx;
@@ -50,8 +48,6 @@
}
@property (readonly, nonatomic, getter=isAnimating) BOOL animating;
@property CGPoint lastGesturePoint;
-@property CGFloat lastPinchScale;
-@property CGFloat currentPinchScale;
@property CGFloat screenScale;
@property bool touchBeginSignaled;
@property int m_screenIdx;
@@ -37,6 +37,13 @@
#include "utils/TimeUtils.h"
#include "Util.h"
#include "threads/Event.h"
+#include <math.h>
+
+#ifndef M_PI
+#define M_PI 3.1415926535897932384626433832795028842
+#endif
+#define RADIANS_TO_DEGREES(radians) ((radians) * (180.0 / M_PI))
+
#undef BOOL
#import "IOSEAGLView.h"
@@ -68,8 +75,6 @@ -(void) terminateWithSuccess;
@implementation XBMCController
@synthesize animating;
@synthesize lastGesturePoint;
-@synthesize lastPinchScale;
-@synthesize currentPinchScale;
@synthesize screenScale;
@synthesize lastEvent;
@synthesize touchBeginSignaled;
@@ -144,6 +149,15 @@ -(void)sendKey:(XBMCKey) key
CWinEventsIOS::MessagePush(&newEvent);
}
//--------------------------------------------------------------
+- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
+{
+ if ([gestureRecognizer isKindOfClass:[UIRotationGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]) {
+ return YES;
+ }
+
+ return NO;
+}
+//--------------------------------------------------------------
- (void)createGestureRecognizers
{
//2 finger single tab - right mouse
@@ -191,10 +205,18 @@ - (void)createGestureRecognizers
initWithTarget:self action:@selector(handlePinch:)];
pinch.delaysTouchesBegan = YES;
+ pinch.delegate = self;
[self.view addGestureRecognizer:pinch];
[pinch release];
- lastPinchScale = 1.0;
- currentPinchScale = lastPinchScale;
+
+ //for rotate gesture
+ UIRotationGestureRecognizer *rotate = [[UIRotationGestureRecognizer alloc]
+ initWithTarget:self action:@selector(handleRotate:)];
+
+ rotate.delaysTouchesBegan = YES;
+ rotate.delegate = self;
+ [self.view addGestureRecognizer:rotate];
+ [rotate release];
}
//--------------------------------------------------------------
- (void) activateKeyboard:(UIView *)view
@@ -214,21 +236,49 @@ -(void)handlePinch:(UIPinchGestureRecognizer*)sender
CGPoint point = [sender locationOfTouch:0 inView:m_glView];
point.x *= screenScale;
point.y *= screenScale;
- currentPinchScale += [sender scale] - lastPinchScale;
- lastPinchScale = [sender scale];
switch(sender.state)
{
case UIGestureRecognizerStateBegan:
- break;
+ CApplicationMessenger::Get().SendAction(CAction(ACTION_GESTURE_BEGIN, 0, (float)point.x, (float)point.y,
+ 0, 0), WINDOW_INVALID,false);
+ break;
case UIGestureRecognizerStateChanged:
CApplicationMessenger::Get().SendAction(CAction(ACTION_GESTURE_ZOOM, 0, (float)point.x, (float)point.y,
- currentPinchScale, 0), WINDOW_INVALID,false);
- break;
+ [sender scale], 0), WINDOW_INVALID,false);
+ break;
case UIGestureRecognizerStateEnded:
- break;
+ CApplicationMessenger::Get().SendAction(CAction(ACTION_GESTURE_END, 0, 0, 0,
+ 0, 0), WINDOW_INVALID,false);
+ break;
default:
- break;
+ break;
+ }
+ }
+}
+//--------------------------------------------------------------
+-(void)handleRotate:(UIRotationGestureRecognizer*)sender
+{
+ if( [m_glView isXBMCAlive] )//NO GESTURES BEFORE WE ARE UP AND RUNNING
+ {
+ CGPoint point = [sender locationOfTouch:0 inView:m_glView];
+ point.x *= screenScale;
+ point.y *= screenScale;
+
+ switch(sender.state)
+ {
+ case UIGestureRecognizerStateBegan:
+ CApplicationMessenger::Get().SendAction(CAction(ACTION_GESTURE_BEGIN, 0, (float)point.x, (float)point.y,
+ 0, 0), WINDOW_INVALID,false);
+ break;
+ case UIGestureRecognizerStateChanged:
+ CApplicationMessenger::Get().SendAction(CAction(ACTION_GESTURE_ROTATE, 0, (float)point.x, (float)point.y,
+ RADIANS_TO_DEGREES([sender rotation]), 0), WINDOW_INVALID,false);
+ break;
+ case UIGestureRecognizerStateEnded:
+ break;
+ default:
+ break;
}
}
}
Oops, something went wrong.

0 comments on commit e13dcf3

Please sign in to comment.