summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Lillqvist <tml@collabora.com>2013-10-18 15:15:29 +0300
committerTor Lillqvist <tml@collabora.com>2013-10-18 15:45:20 +0300
commit24f8446c9e7d1a0ea01cc11ca87abf85ba43342d (patch)
treec307f5c3eb4730d6776b974dd0dff8f91d7149e9
parent359472b2b50165966c27c239eccd3ecfb03e2acc (diff)
Work in progress: Text selection handling for iOS
Change-Id: I31c6bcb9a4b26653d439601f78d71fd94d938eeb
-rw-r--r--include/touch/touch.h45
-rw-r--r--ios/experimental/LibreOffice/LibreOffice/AppDelegate.m29
-rw-r--r--ios/experimental/LibreOffice/LibreOffice/View.h3
-rw-r--r--ios/experimental/LibreOffice/LibreOffice/View.m179
-rw-r--r--sw/inc/viscrs.hxx4
-rw-r--r--sw/source/core/crsr/viscrs.cxx45
6 files changed, 290 insertions, 15 deletions
diff --git a/include/touch/touch.h b/include/touch/touch.h
index c8af48edabc8..11440f16062b 100644
--- a/include/touch/touch.h
+++ b/include/touch/touch.h
@@ -18,8 +18,24 @@
#if !HAVE_FEATURE_DESKTOP
+// Let's try this way: Use Quartz 2D types for iOS, and LO's basegfx
+// types for others, when/if this API is used for others. But of
+// course, it is quite likely that some degree of redesign is needed
+// at such a stage anyway...
+
+#ifdef IOS
+#include <premac.h>
+#include <CoreGraphics/CoreGraphics.h>
+#include <postmac.h>
+#else
+#include <basegfx/range/b2ibox.hxx>
+#endif
+
#ifdef __cplusplus
extern "C" {
+#if 0
+} // To avoid an editor indenting all inside the extern "C"
+#endif
#endif
// These functions are the interface between the upper GUI layers of a
@@ -41,6 +57,31 @@ void touch_ui_show_keyboard();
void touch_ui_hide_keyboard();
bool touch_ui_keyboard_visible();
+typedef enum {
+ MLOSelectionNone,
+ MLOSelectionText,
+ MLOSelectionGraphic
+} MLOSelectionKind;
+
+#ifdef IOS
+typedef CGRect MLORect;
+#else
+typedef basegfx::B2IBox MLORect;
+#endif
+
+void touch_ui_selection_start(MLOSelectionKind kind,
+ const void *documentHandle,
+ MLORect *rectangles,
+ int rectangleCount,
+ void *preview);
+
+void touch_ui_selection_resize_done(bool success,
+ const void *documentHandle,
+ MLORect *rectangles,
+ int rectangleCount);
+
+void touch_ui_selection_none();
+
// 2) Those implmented in the lower layers to be called by the upper
// layer, in cases where we don't want to include a bunch of the
// "normal" LibreOffice C++ headers in an otherwise purely Objective-C
@@ -69,6 +110,10 @@ typedef enum { DOWN, MOVE, UP} MLOMouseButtonState;
void touch_lo_mouse_drag(int x, int y, MLOMouseButtonState state);
+void touch_lo_selection_attempt_resize(const void *documentHandle,
+ MLORect *selectedRectangles,
+ int numberOfRectangles);
+
#ifdef __cplusplus
}
#endif
diff --git a/ios/experimental/LibreOffice/LibreOffice/AppDelegate.m b/ios/experimental/LibreOffice/LibreOffice/AppDelegate.m
index c3ed9ebb7832..b4d027e44620 100644
--- a/ios/experimental/LibreOffice/LibreOffice/AppDelegate.m
+++ b/ios/experimental/LibreOffice/LibreOffice/AppDelegate.m
@@ -219,4 +219,33 @@ bool touch_ui_keyboard_visible()
return keyboardShows;
}
+void touch_ui_selection_start(MLOSelectionKind kind,
+ const void *documentHandle,
+ MLORect *rectangles,
+ int rectangleCount,
+ void *preview)
+{
+ (void) preview;
+
+ // Note that this is called on the LO thread
+ NSLog(@"==> touch_ui_selection_start");
+ for(int i = 0; i < rectangleCount; ++i){
+ NSLog(@" %fx%f@(%f,%f)",
+ rectangles[i].size.width,
+ rectangles[i].size.height,
+ rectangles[i].origin.x,
+ rectangles[i].origin.y);
+ }
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [theView startSelectionOfType:kind withNumber:rectangleCount ofRectangles:rectangles forDocument:documentHandle];
+ });
+}
+
+void touch_ui_selection_none()
+{
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [theView startSelectionOfType:MLOSelectionNone withNumber:0 ofRectangles:NULL forDocument:NULL];
+ });
+}
+
// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/ios/experimental/LibreOffice/LibreOffice/View.h b/ios/experimental/LibreOffice/LibreOffice/View.h
index f036c488c338..aecc606425be 100644
--- a/ios/experimental/LibreOffice/LibreOffice/View.h
+++ b/ios/experimental/LibreOffice/LibreOffice/View.h
@@ -9,6 +9,8 @@
#import <UIKit/UIKit.h>
+#import <touch/touch.h>
+
@interface View : UIView
{
@public
@@ -18,6 +20,7 @@
- (void)tapGesture:(UITapGestureRecognizer *)gestureRecognizer;
- (void)panGesture:(UIPanGestureRecognizer *)gestureRecognizer;
- (void)longPressGesture:(UILongPressGestureRecognizer *)gestureRecognizer;
+- (void)startSelectionOfType:(MLOSelectionKind)kind withNumber:(int)number ofRectangles:(CGRect *)rects forDocument:(const void *)document;
@end
diff --git a/ios/experimental/LibreOffice/LibreOffice/View.m b/ios/experimental/LibreOffice/LibreOffice/View.m
index de7b31144ac3..2e5f3ef26e73 100644
--- a/ios/experimental/LibreOffice/LibreOffice/View.m
+++ b/ios/experimental/LibreOffice/LibreOffice/View.m
@@ -10,15 +10,112 @@
#include <touch/touch.h>
+@interface View ()
+@property const void *documentHandle;
+@property CGRect *selectionRectangles;
+@property int selectionRectangleCount;
+@end
+
+#define HANDLE_BLOB 20
+#define HANDLE_STEM_WIDTH 6
+#define HANDLE_STEM_HEIGHT 20
+
@implementation View
+#if 0
+- (id) initWithFrame:(CGRect)rect
+{
+ self = [super initWithFrame:rect];
+ if (self) {
+ self.selectionRectangles = NULL;
+ self.selectionRectangleCount = 0;
+ }
+ return self;
+}
+#endif
+
+- (CGRect) topLeftResizeHandle
+{
+ if (self.selectionRectangleCount == 0)
+ return CGRectNull;
+
+ return CGRectMake(self.selectionRectangles[0].origin.x - HANDLE_STEM_WIDTH/2 - HANDLE_BLOB/2,
+ self.selectionRectangles[0].origin.y - HANDLE_STEM_HEIGHT - HANDLE_BLOB,
+ HANDLE_BLOB, HANDLE_BLOB);
+}
+
+- (CGRect) bottomRightResizeHandle
+{
+ const int N = self.selectionRectangleCount;
+
+ if (N == 0)
+ return CGRectNull;
+
+ return CGRectMake(self.selectionRectangles[N-1].origin.x +
+ self.selectionRectangles[N-1].size.width + HANDLE_STEM_WIDTH/2 - HANDLE_BLOB/2,
+ self.selectionRectangles[N-1].origin.y +
+ self.selectionRectangles[N-1].size.height + HANDLE_STEM_HEIGHT,
+ HANDLE_BLOB, HANDLE_BLOB);
+}
+
+- (void) requestSelectionRedisplay
+{
+ if (self.selectionRectangleCount == 0)
+ return;
+
+ CGRect r = CGRectNull;
+ for (int i = 0; i < self.selectionRectangleCount; i++) {
+ r = CGRectUnion(r, self.selectionRectangles[i]);
+ }
+ r = CGRectUnion(r, [self topLeftResizeHandle]);
+ r = CGRectUnion(r, [self bottomRightResizeHandle]);
+
+ [self setNeedsDisplayInRect:r];
+}
+
+- (void) drawSelectionIntoContext:(CGContextRef)context
+{
+ if (self.selectionRectangleCount == 0)
+ return;
+
+ const int N = self.selectionRectangleCount;
+
+ CGContextSetFillColorWithColor(context, [[UIColor colorWithRed:0 green:0 blue:1 alpha:0.5] CGColor]);
+
+#if 0
+ for (int i = 0; i < N; i++) {
+ NSLog(@"UIRectFill: %fx%f@(%f,%f)",
+ self.selectionRectangles[i].size.width, self.selectionRectangles[i].size.height,
+ self.selectionRectangles[i].origin.x, self.selectionRectangles[i].origin.y);
+ UIRectFillUsingBlendMode(CGRectMake(self.selectionRectangles[i].origin.x, self.selectionRectangles[i].origin.y,
+ self.selectionRectangles[i].size.width, self.selectionRectangles[i].size.height),
+ kCGBlendModeNormal);
+ }
+#else
+ CGContextSetBlendMode(context, kCGBlendModeNormal);
+ CGContextFillRects(context, self.selectionRectangles, self.selectionRectangleCount);
+#endif
+
+ CGContextFillRect(context,
+ CGRectMake(self.selectionRectangles[0].origin.x - HANDLE_STEM_WIDTH,
+ self.selectionRectangles[0].origin.y - HANDLE_STEM_HEIGHT,
+ HANDLE_STEM_WIDTH, self.selectionRectangles[0].size.height + HANDLE_STEM_HEIGHT));
+
+ CGContextFillRect(context,
+ CGRectMake(self.selectionRectangles[N-1].origin.x +
+ self.selectionRectangles[N-1].size.width,
+ self.selectionRectangles[N-1].origin.y,
+ HANDLE_STEM_WIDTH, self.selectionRectangles[N-1].size.height + HANDLE_STEM_HEIGHT));
+
+ CGContextFillEllipseInRect(context, [self topLeftResizeHandle]);
+ CGContextFillEllipseInRect(context, [self bottomRightResizeHandle]);
+}
+
- (void)drawRect:(CGRect)rect
{
- // NSLog(@"drawRect: %dx%d@(%d,%d)", (int) rect.size.width, (int) rect.size.height, (int) rect.origin.x, (int) rect.origin.y);
+ NSLog(@"View drawRect: %dx%d@(%d,%d)", (int) rect.size.width, (int) rect.size.height, (int) rect.origin.x, (int) rect.origin.y);
// NSLog(@"statusBarOrientation: %ld", (long)[[UIApplication sharedApplication] statusBarOrientation]);
- // NSDate *startDate = [NSDate date];
-
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
@@ -41,15 +138,23 @@
break;
}
touch_lo_render_windows(context, rect.origin.y, rect.origin.y, rect.size.width, rect.size.height);
+
CGContextRestoreGState(context);
- // NSLog(@"drawRect: touch_lo_render_windows took %f s", [[NSDate date] timeIntervalSinceDate: startDate]);
+ [self drawSelectionIntoContext:context];
}
+#if 0
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ NSLog(@"===> View touchesBegan!");
+}
+#endif
+
- (void)tapGesture:(UITapGestureRecognizer *)gestureRecognizer
{
if ([gestureRecognizer state] == UIGestureRecognizerStateEnded) {
- CGPoint location = [gestureRecognizer locationInView: self];
+ CGPoint location = [gestureRecognizer locationInView:self];
// NSLog(@"tapGesture: at: (%d,%d)", (int)location.x, (int)location.y);
@@ -63,7 +168,37 @@
{
static CGFloat previousX = 0.0f, previousY = 0.0f;
- CGPoint translation = [gestureRecognizer translationInView: self];
+ CGPoint translation = [gestureRecognizer translationInView:self];
+
+ if ([gestureRecognizer numberOfTouches] == 1) {
+ if (CGRectContainsPoint([self topLeftResizeHandle],
+ [gestureRecognizer locationInView:self])) {
+
+ self.selectionRectangles[0].origin.x += translation.x;
+ self.selectionRectangles[0].origin.y += translation.y;
+ self.selectionRectangles[0].size.width -= translation.x;
+ self.selectionRectangles[0].size.height -= translation.y;
+
+ touch_lo_selection_attempt_resize(self.documentHandle,
+ self.selectionRectangles,
+ self.selectionRectangleCount);
+ return;
+ } else if (CGRectContainsPoint([self bottomRightResizeHandle],
+ [gestureRecognizer locationInView:self])) {
+
+ const int N = self.selectionRectangleCount - 1;
+
+ self.selectionRectangles[N].origin.x += translation.x;
+ self.selectionRectangles[N].origin.y += translation.y;
+ self.selectionRectangles[N].size.width -= translation.x;
+ self.selectionRectangles[N].size.height -= translation.y;
+
+ touch_lo_selection_attempt_resize(self.documentHandle,
+ self.selectionRectangles,
+ self.selectionRectangleCount);
+ return;
+ }
+ }
if (gestureRecognizer.state != UIGestureRecognizerStateBegan) {
int deltaX = translation.x - previousX;
@@ -80,7 +215,7 @@
- (void)pinchGesture:(UIPinchGestureRecognizer *)gestureRecognizer
{
- CGPoint location = [gestureRecognizer locationInView: self];
+ CGPoint location = [gestureRecognizer locationInView:self];
CGFloat scale = gestureRecognizer.scale;
// NSLog(@"pinchGesture: pinch: (%f) cords (%d,%d)", (float)scale, (int)location.x, (int)location.y );
@@ -88,7 +223,7 @@
touch_lo_zoom((int)location.x, (int)location.y, (float)scale);
// to reset the gesture scaling
- if (gestureRecognizer.state==UIGestureRecognizerStateEnded) {
+ if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
touch_lo_zoom(1, 1, 0.0f);
}
}
@@ -97,16 +232,34 @@
{
CGPoint point = [gestureRecognizer locationInView:self];
- UIGestureRecognizerState state = gestureRecognizer.state;
-
- // NSLog(@"longPressGesture: state %d cords (%d,%d)",state ,(int)point.x,(int)point.y);
-
- if (state == UIGestureRecognizerStateEnded) {
+ if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
touch_lo_tap(point.x, point.y);
touch_lo_tap(point.x, point.y);
}
}
+- (void)startSelectionOfType:(MLOSelectionKind)kind withNumber:(int)number ofRectangles:(CGRect *)rects forDocument:(const void *)document
+{
+ (void) kind;
+
+ // First request the old selection area to be redisplayed
+ [self requestSelectionRedisplay];
+
+ free(self.selectionRectangles);
+ self.selectionRectangles = NULL;
+ self.selectionRectangleCount = 0;
+ self.documentHandle = NULL;
+
+ if (number == 0)
+ return;
+
+ self.selectionRectangles = rects;
+ self.selectionRectangleCount = number;
+ self.documentHandle = document;
+
+ [self requestSelectionRedisplay];
+}
+
@end
// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sw/inc/viscrs.hxx b/sw/inc/viscrs.hxx
index a38fc3e257bc..aef159dc2f3e 100644
--- a/sw/inc/viscrs.hxx
+++ b/sw/inc/viscrs.hxx
@@ -19,6 +19,8 @@
#ifndef _VISCRS_HXX
#define _VISCRS_HXX
+#include <config_features.h>
+
#include <vcl/cursor.hxx>
#include "swcrsr.hxx"
#include "swrect.hxx"
@@ -71,11 +73,13 @@ class SwSelPaintRects : public SwRects
virtual void Paint( const Rectangle& rRect );
virtual void FillRects() = 0;
+#if HAVE_FEATURE_DESKTOP
sdr::overlay::OverlayObject* mpCursorOverlay;
// access to mpCursorOverlay for swapContent
sdr::overlay::OverlayObject* getCursorOverlay() const { return mpCursorOverlay; }
void setCursorOverlay(sdr::overlay::OverlayObject* pNew) { mpCursorOverlay = pNew; }
+#endif
public:
SwSelPaintRects( const SwCrsrShell& rCSh );
diff --git a/sw/source/core/crsr/viscrs.cxx b/sw/source/core/crsr/viscrs.cxx
index 8f73dc9cd68d..a369f65778b2 100644
--- a/sw/source/core/crsr/viscrs.cxx
+++ b/sw/source/core/crsr/viscrs.cxx
@@ -17,6 +17,8 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
+#include <config_features.h>
+
#include <vcl/dialog.hxx>
#include <vcl/msgbox.hxx>
#include <vcl/wrkwin.hxx>
@@ -42,6 +44,8 @@
#include <vcl/svapp.hxx>
#include <svx/sdr/overlay/overlayselection.hxx>
+#include <touch/touch.h>
+
extern void SwCalcPixStatics( OutputDevice *pOut );
// Here static members are defined. They will get changed on alteration of the
@@ -184,8 +188,10 @@ void SwVisCrsr::_SetPosAndShow()
SwSelPaintRects::SwSelPaintRects( const SwCrsrShell& rCSh )
: SwRects(),
- pCShell( &rCSh ),
- mpCursorOverlay(0)
+ pCShell( &rCSh )
+#if HAVE_FEATURE_DESKTOP
+ , mpCursorOverlay(0)
+#endif
{
}
@@ -198,19 +204,23 @@ void SwSelPaintRects::swapContent(SwSelPaintRects& rSwap)
{
SwRects::swap(rSwap);
+#if HAVE_FEATURE_DESKTOP
// #i75172# also swap mpCursorOverlay
sdr::overlay::OverlayObject* pTempOverlay = getCursorOverlay();
setCursorOverlay(rSwap.getCursorOverlay());
rSwap.setCursorOverlay(pTempOverlay);
+#endif
}
void SwSelPaintRects::Hide()
{
+#if HAVE_FEATURE_DESKTOP
if(mpCursorOverlay)
{
delete mpCursorOverlay;
mpCursorOverlay = 0;
}
+#endif
SwRects::clear();
}
@@ -225,6 +235,7 @@ void SwSelPaintRects::Show()
SwRects::clear();
FillRects();
+#if HAVE_FEATURE_DESKTOP
// get new rects
std::vector< basegfx::B2DRange > aNewRanges;
@@ -250,8 +261,27 @@ void SwSelPaintRects::Show()
mpCursorOverlay = 0;
}
}
+#else
+ if (false)
+ ;
+#endif
else if(!empty())
{
+#if !HAVE_FEATURE_DESKTOP && defined IOS
+ const OutputDevice* pOut = GetShell()->GetWin();
+ if ( ! pOut )
+ pOut = GetShell()->GetOut();
+ // Buffer will be deallocated in the UI layer
+ CGRect *rects = (CGRect *) malloc((sizeof(CGRect))*size());
+ for (size_t i = 0; i < size(); ++i)
+ {
+ Point origin = pOut->LogicToPixel((*this)[i].Pos());
+ Size size = pOut->LogicToPixel((*this)[i].SSize());
+ rects[i] = CGRectMake(origin.X(), origin.Y(),
+ size.Width(), size.Height());
+ }
+ touch_ui_selection_start(MLOSelectionText, GetShell(), rects, size(), NULL);
+#else
SdrPaintWindow* pCandidate = pView->GetPaintWindow(0);
rtl::Reference< ::sdr::overlay::OverlayManager > xTargetOverlay = pCandidate->GetOverlayManager();
@@ -270,10 +300,21 @@ void SwSelPaintRects::Show()
xTargetOverlay->add(*mpCursorOverlay);
}
+#endif
}
}
}
+#if !HAVE_FEATURE_DESKTOP
+
+extern "C" void touch_lo_selection_attempt_resize(const void * /* documentHandle */,
+ MLORect * /* selectedRectangles */,
+ int /* numberOfRectangles */)
+{
+}
+
+#endif
+
void SwSelPaintRects::Invalidate( const SwRect& rRect )
{
sal_uInt16 nSz = size();