浏览代码

#266 multiclick on text

Johann ELSASS 3 年之前
父节点
当前提交
b80a41d718

+ 1 - 1
lazpaint/tools/utoolvectorial.pas

@@ -2093,7 +2093,7 @@ begin
     begin
     begin
       shapePt := AffineMatrixInverse(VectorTransform(true))*FLastPos;
       shapePt := AffineMatrixInverse(VectorTransform(true))*FLastPos;
       If Editor.GridActive then shapePt := Editor.SnapToGrid(shapePt, false);
       If Editor.GridActive then shapePt := Editor.SnapToGrid(shapePt, false);
-      FShape.MouseDown(rightBtn, ShiftState, shapePt.X,shapePt.Y, cur, handled);
+      FShape.MouseDown(rightBtn, Editor.ConsecutiveClickCount, ShiftState, shapePt.X,shapePt.Y, cur, handled);
     end;
     end;
     UpdateCursor(cur);
     UpdateCursor(cur);
     if handled then exit
     if handled then exit

+ 4 - 3
lazpaintcontrols/lcvectororiginal.pas

@@ -281,7 +281,7 @@ type
     procedure LoadFromStorage(AStorage: TBGRACustomOriginalStorage); virtual;
     procedure LoadFromStorage(AStorage: TBGRACustomOriginalStorage); virtual;
     procedure SaveToStorage(AStorage: TBGRACustomOriginalStorage); virtual;
     procedure SaveToStorage(AStorage: TBGRACustomOriginalStorage); virtual;
     procedure MouseMove({%H-}Shift: TShiftState; {%H-}X, {%H-}Y: single; var {%H-}ACursor: TOriginalEditorCursor; var {%H-}AHandled: boolean); virtual;
     procedure MouseMove({%H-}Shift: TShiftState; {%H-}X, {%H-}Y: single; var {%H-}ACursor: TOriginalEditorCursor; var {%H-}AHandled: boolean); virtual;
-    procedure MouseDown({%H-}RightButton: boolean; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: single; var {%H-}ACursor: TOriginalEditorCursor; var {%H-}AHandled: boolean); virtual;
+    procedure MouseDown({%H-}RightButton: boolean; {%H-}ClickCount: integer; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: single; var {%H-}ACursor: TOriginalEditorCursor; var {%H-}AHandled: boolean); virtual;
     procedure MouseUp({%H-}RightButton: boolean; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: single; var {%H-}ACursor: TOriginalEditorCursor; var {%H-}AHandled: boolean); virtual;
     procedure MouseUp({%H-}RightButton: boolean; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: single; var {%H-}ACursor: TOriginalEditorCursor; var {%H-}AHandled: boolean); virtual;
     procedure KeyDown({%H-}Shift: TShiftState; {%H-}Key: TSpecialKey; var {%H-}AHandled: boolean); virtual;
     procedure KeyDown({%H-}Shift: TShiftState; {%H-}Key: TSpecialKey; var {%H-}AHandled: boolean); virtual;
     procedure KeyUp({%H-}Shift: TShiftState; {%H-}Key: TSpecialKey; var {%H-}AHandled: boolean); virtual;
     procedure KeyUp({%H-}Shift: TShiftState; {%H-}Key: TSpecialKey; var {%H-}AHandled: boolean); virtual;
@@ -1409,7 +1409,8 @@ begin
   begin
   begin
     ptF := ViewCoordToOriginal(PointF(ViewX,ViewY));
     ptF := ViewCoordToOriginal(PointF(ViewX,ViewY));
     if GridActive then ptF := SnapToGrid(ptF, False);
     if GridActive then ptF := SnapToGrid(ptF, False);
-    with ptF do FOriginal.SelectedShape.MouseDown(RightButton, Shift, X,Y, ACursor, AHandled);
+    with ptF do FOriginal.SelectedShape.MouseDown(RightButton,
+      ConsecutiveClickCount, Shift, X,Y, ACursor, AHandled);
   end;
   end;
 end;
 end;
 
 
@@ -2469,7 +2470,7 @@ begin
   //nothing
   //nothing
 end;
 end;
 
 
-procedure TVectorShape.MouseDown(RightButton: boolean; Shift: TShiftState; X,
+procedure TVectorShape.MouseDown(RightButton: boolean; ClickCount: integer; Shift: TShiftState; X,
   Y: single; var ACursor: TOriginalEditorCursor; var AHandled: boolean);
   Y: single; var ACursor: TOriginalEditorCursor; var AHandled: boolean);
 begin
 begin
   //nothing
   //nothing

+ 2 - 2
lazpaintcontrols/lcvectorpolyshapes.pas

@@ -117,7 +117,7 @@ type
     procedure InsertPoint(AIndex: integer; APoint: TPointF);
     procedure InsertPoint(AIndex: integer; APoint: TPointF);
     function GetPointBounds(AMatrix: TAffineMatrix): TRectF;
     function GetPointBounds(AMatrix: TAffineMatrix): TRectF;
     procedure MouseMove({%H-}Shift: TShiftState; X, Y: single; var {%H-}ACursor: TOriginalEditorCursor; var AHandled: boolean); override;
     procedure MouseMove({%H-}Shift: TShiftState; X, Y: single; var {%H-}ACursor: TOriginalEditorCursor; var AHandled: boolean); override;
-    procedure MouseDown(RightButton: boolean; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: single; var {%H-}ACursor: TOriginalEditorCursor; var AHandled: boolean); override;
+    procedure MouseDown(RightButton: boolean; {%H-}ClickCount: integer; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: single; var {%H-}ACursor: TOriginalEditorCursor; var AHandled: boolean); override;
     procedure KeyDown({%H-}Shift: TShiftState; Key: TSpecialKey; var AHandled: boolean); override;
     procedure KeyDown({%H-}Shift: TShiftState; Key: TSpecialKey; var AHandled: boolean); override;
     procedure KeyUp(Shift: TShiftState; Key: TSpecialKey; var AHandled: boolean); override;
     procedure KeyUp(Shift: TShiftState; Key: TSpecialKey; var AHandled: boolean); override;
     procedure QuickDefine(constref APoint1,APoint2: TPointF); override;
     procedure QuickDefine(constref APoint1,APoint2: TPointF); override;
@@ -979,7 +979,7 @@ begin
 end;
 end;
 
 
 procedure TCustomPolypointShape.MouseDown(RightButton: boolean;
 procedure TCustomPolypointShape.MouseDown(RightButton: boolean;
-  Shift: TShiftState; X, Y: single; var ACursor: TOriginalEditorCursor; var
+  ClickCount: integer; Shift: TShiftState; X, Y: single; var ACursor: TOriginalEditorCursor; var
   AHandled: boolean);
   AHandled: boolean);
 begin
 begin
   FMousePos := PointF(X,Y);
   FMousePos := PointF(X,Y);

+ 3 - 3
lazpaintcontrols/lcvectorrectshapes.pas

@@ -184,7 +184,7 @@ type
     function AppendToSVG(AContent: TSVGContent; ADefs: TSVGDefine): TSVGElement; override;
     function AppendToSVG(AContent: TSVGContent; ADefs: TSVGDefine): TSVGElement; override;
     function GetAlignBounds(const ALayoutRect: TRect; const AMatrix: TAffineMatrix): TRectF; override;
     function GetAlignBounds(const ALayoutRect: TRect; const AMatrix: TAffineMatrix): TRectF; override;
     procedure ConfigureCustomEditor(AEditor: TBGRAOriginalEditor); override;
     procedure ConfigureCustomEditor(AEditor: TBGRAOriginalEditor); override;
-    procedure MouseDown(RightButton: boolean; Shift: TShiftState; X, Y: single; var ACursor: TOriginalEditorCursor; var AHandled: boolean); override;
+    procedure MouseDown(RightButton: boolean; {%H-}ClickCount: integer; Shift: TShiftState; X, Y: single; var ACursor: TOriginalEditorCursor; var AHandled: boolean); override;
     procedure LoadFromStorage(AStorage: TBGRACustomOriginalStorage); override;
     procedure LoadFromStorage(AStorage: TBGRACustomOriginalStorage); override;
     procedure SaveToStorage(AStorage: TBGRACustomOriginalStorage); override;
     procedure SaveToStorage(AStorage: TBGRACustomOriginalStorage); override;
     procedure Render(ADest: TBGRABitmap; AMatrix: TAffineMatrix; ADraft: boolean); overload; override;
     procedure Render(ADest: TBGRABitmap; AMatrix: TAffineMatrix; ADraft: boolean); overload; override;
@@ -1676,10 +1676,10 @@ begin
     TVectorOriginalEditor(AEditor).AddLabel(idxLight, rsLightPosition, taCenter, tlTop);
     TVectorOriginalEditor(AEditor).AddLabel(idxLight, rsLightPosition, taCenter, tlTop);
 end;
 end;
 
 
-procedure TPhongShape.MouseDown(RightButton: boolean; Shift: TShiftState; X,
+procedure TPhongShape.MouseDown(RightButton: boolean; ClickCount: integer; Shift: TShiftState; X,
   Y: single; var ACursor: TOriginalEditorCursor; var AHandled: boolean);
   Y: single; var ACursor: TOriginalEditorCursor; var AHandled: boolean);
 begin
 begin
-  inherited MouseDown(RightButton, Shift, X, Y, ACursor, AHandled);
+  inherited MouseDown(RightButton, ClickCount, Shift, X, Y, ACursor, AHandled);
   if not AHandled then
   if not AHandled then
   begin
   begin
     if RightButton then
     if RightButton then

+ 96 - 9
lazpaintcontrols/lcvectortextshapes.pas

@@ -149,6 +149,8 @@ type
     procedure DeleteTextAfter(ACount: integer);
     procedure DeleteTextAfter(ACount: integer);
     procedure InsertText(ATextUTF8: string);
     procedure InsertText(ATextUTF8: string);
     procedure SelectWithMouse(X,Y: single; AExtend: boolean);
     procedure SelectWithMouse(X,Y: single; AExtend: boolean);
+    procedure SelectWordWithMouse(X,Y: single);
+    procedure SelectParagraphWithMouse(X,Y: single);
     function HasOutline: boolean;
     function HasOutline: boolean;
     procedure InsertUnicodeValue;
     procedure InsertUnicodeValue;
     procedure FillChange(ASender: TObject; var ADiff: TCustomVectorialFillDiff); override;
     procedure FillChange(ASender: TObject; var ADiff: TCustomVectorialFillDiff); override;
@@ -178,7 +180,7 @@ type
     function GetIsSlow(const {%H-}AMatrix: TAffineMatrix): boolean; override;
     function GetIsSlow(const {%H-}AMatrix: TAffineMatrix): boolean; override;
     function GetGenericCost: integer; override;
     function GetGenericCost: integer; override;
     procedure MouseMove({%H-}Shift: TShiftState; {%H-}X, {%H-}Y: single; var {%H-}ACursor: TOriginalEditorCursor; var {%H-}AHandled: boolean); override;
     procedure MouseMove({%H-}Shift: TShiftState; {%H-}X, {%H-}Y: single; var {%H-}ACursor: TOriginalEditorCursor; var {%H-}AHandled: boolean); override;
-    procedure MouseDown({%H-}RightButton: boolean; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: single; var {%H-}ACursor: TOriginalEditorCursor; var {%H-}AHandled: boolean); override;
+    procedure MouseDown({%H-}RightButton: boolean; {%H-}ClickCount: integer; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: single; var {%H-}ACursor: TOriginalEditorCursor; var {%H-}AHandled: boolean); override;
     procedure MouseUp({%H-}RightButton: boolean; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: single; var {%H-}ACursor: TOriginalEditorCursor; var {%H-}AHandled: boolean); override;
     procedure MouseUp({%H-}RightButton: boolean; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: single; var {%H-}ACursor: TOriginalEditorCursor; var {%H-}AHandled: boolean); override;
     procedure KeyDown({%H-}Shift: TShiftState; {%H-}Key: TSpecialKey; var {%H-}AHandled: boolean); override;
     procedure KeyDown({%H-}Shift: TShiftState; {%H-}Key: TSpecialKey; var {%H-}AHandled: boolean); override;
     procedure KeyPress({%H-}UTF8Key: string; var {%H-}AHandled: boolean); override;
     procedure KeyPress({%H-}UTF8Key: string; var {%H-}AHandled: boolean); override;
@@ -188,6 +190,7 @@ type
     function CutSelection: boolean;
     function CutSelection: boolean;
     function PasteSelection: boolean;
     function PasteSelection: boolean;
     function DeleteSelection: boolean;
     function DeleteSelection: boolean;
+    procedure SelectAll;
     function GetAlignBounds(const {%H-}ALayoutRect: TRect; const AMatrix: TAffineMatrix): TRectF; override;
     function GetAlignBounds(const {%H-}ALayoutRect: TRect; const AMatrix: TAffineMatrix): TRectF; override;
     procedure Transform(const AMatrix: TAffineMatrix); override;
     procedure Transform(const AMatrix: TAffineMatrix); override;
     function AllowShearTransform: boolean; override;
     function AllowShearTransform: boolean; override;
@@ -999,6 +1002,14 @@ begin
     result := false;
     result := false;
 end;
 end;
 
 
+procedure TTextShape.SelectAll;
+begin
+  BeginEditingUpdate;
+  FSelStart:= 0;
+  FSelEnd:= GetTextLayout.CharCount;
+  EndEditingUpdate;
+end;
+
 function TTextShape.GetAlignBounds(const ALayoutRect: TRect;
 function TTextShape.GetAlignBounds(const ALayoutRect: TRect;
   const AMatrix: TAffineMatrix): TRectF;
   const AMatrix: TAffineMatrix): TRectF;
 var
 var
@@ -1048,6 +1059,79 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TTextShape.SelectWordWithMouse(X, Y: single);
+const letterClasses = [ubcLeftToRight, ubcEuropeanNumber, ubcRightToLeft, ubcArabicLetter, ubcArabicNumber];
+var
+  tl: TBidiTextLayout;
+  function IsInWord(AIndex: integer): boolean;
+  var c: TUTF8Char;
+  begin
+    c := tl.UTF8Char[AIndex];
+    result := GetBidiClassUTF8(@c[1]) in letterClasses;
+  end;
+
+var
+  newPos, paraIndex, startIndex, endIndex: Integer;
+  zoom: Single;
+  untransformed: TAffineMatrix;
+  inWord: boolean;
+begin
+  if UserMode <> vsuEditText then exit;
+  tl := GetTextLayout;
+  zoom := GetTextRenderZoom;
+  untransformed := GetUntransformedMatrix;
+  if not IsAffineMatrixInversible(untransformed) then exit;
+  newPos := tl.GetCharIndexAt(AffineMatrixScale(zoom,zoom)*AffineMatrixInverse(untransformed)*PointF(X,Y), false);
+  if newPos<>-1 then
+  begin
+    paraIndex := tl.GetParagraphAt(newPos);
+    if (newPos < tl.ParagraphStartIndex[paraIndex]) or
+       (newPos >= tl.ParagraphEndIndex[paraIndex]) then exit;
+    startIndex := newPos;
+    endIndex := newPos+1;
+    inWord := IsInWord(newPos);
+    while (startIndex > tl.ParagraphStartIndex[paraIndex])
+      and (IsInWord(startIndex-1) = inWord) do dec(startIndex);
+    while (endIndex < tl.ParagraphEndIndex[paraIndex])
+      and (IsInWord(endIndex) = inWord) do inc(endIndex);
+    if (FSelStart <> startIndex) or
+       (FSelEnd <> endIndex) then
+    begin
+      BeginEditingUpdate;
+      FSelStart := startIndex;
+      FSelEnd:= endIndex;
+      EndEditingUpdate;
+    end;
+  end;
+end;
+
+procedure TTextShape.SelectParagraphWithMouse(X, Y: single);
+var
+  newPos, paraIndex: Integer;
+  tl: TBidiTextLayout;
+  zoom: Single;
+  untransformed: TAffineMatrix;
+begin
+  if UserMode <> vsuEditText then exit;
+  tl := GetTextLayout;
+  zoom := GetTextRenderZoom;
+  untransformed := GetUntransformedMatrix;
+  if not IsAffineMatrixInversible(untransformed) then exit;
+  newPos := tl.GetCharIndexAt(AffineMatrixScale(zoom,zoom)*AffineMatrixInverse(untransformed)*PointF(X,Y), false);
+  if newPos<>-1 then
+  begin
+    paraIndex := tl.GetParagraphAt(newPos);
+    if (FSelStart <> tl.ParagraphStartIndex[paraIndex]) or
+       (FSelEnd <> tl.ParagraphEndIndex[paraIndex]) then
+    begin
+      BeginEditingUpdate;
+      FSelStart := tl.ParagraphStartIndex[paraIndex];
+      FSelEnd:= tl.ParagraphEndIndex[paraIndex];
+      EndEditingUpdate;
+    end;
+  end;
+end;
+
 function TTextShape.HasOutline: boolean;
 function TTextShape.HasOutline: boolean;
 begin
 begin
   result := not OutlineFill.IsFullyTransparent and (OutlineWidth > 0);
   result := not OutlineFill.IsFullyTransparent and (OutlineWidth > 0);
@@ -2126,14 +2210,20 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TTextShape.MouseDown(RightButton: boolean; Shift: TShiftState; X,
+procedure TTextShape.MouseDown(RightButton: boolean; ClickCount: integer; Shift: TShiftState; X,
   Y: single; var ACursor: TOriginalEditorCursor; var AHandled: boolean);
   Y: single; var ACursor: TOriginalEditorCursor; var AHandled: boolean);
 begin
 begin
-  inherited MouseDown(RightButton, Shift, X, Y, ACursor, AHandled);
+  inherited MouseDown(RightButton, ClickCount, Shift, X, Y, ACursor, AHandled);
   if not AHandled and not RightButton and PointInShape(PointF(X,Y)) then
   if not AHandled and not RightButton and PointInShape(PointF(X,Y)) then
   begin
   begin
-    FMouseSelecting:= true;
-    SelectWithMouse(X,Y, ssShift in Shift);
+    case ClickCount mod 3 of
+    1: begin
+         FMouseSelecting:= true;
+         SelectWithMouse(X,Y, ssShift in Shift);
+       end;
+    2: SelectWordWithMouse(X, Y);
+    0 {3}: SelectParagraphWithMouse(X, Y)
+    end;
     AHandled:= true;
     AHandled:= true;
   end;
   end;
   if (ACursor = oecDefault) and PointInShape(PointF(X,Y)) then ACursor := oecText;
   if (ACursor = oecDefault) and PointInShape(PointF(X,Y)) then ACursor := oecText;
@@ -2286,10 +2376,7 @@ begin
   end else
   end else
   if (Key = skA) and (ssCtrl in Shift) then
   if (Key = skA) and (ssCtrl in Shift) then
   begin
   begin
-    BeginEditingUpdate;
-    FSelStart:= 0;
-    FSelEnd:= GetTextLayout.CharCount;
-    EndEditingUpdate;
+    SelectAll;
     AHandled := true;
     AHandled := true;
   end;
   end;
 end;
 end;