From 2123ae7101eb632b18e2daeeceacc6a57d18513b Mon Sep 17 00:00:00 2001 From: skalogryz Date: Fri, 2 Sep 2016 03:25:11 +0000 Subject: [PATCH] richmemo: win32 + holding selection direction for GetXXX operations (that are strictly selection based). reduce the number of redundant OnChange events, only call them on real event happening. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5117 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- components/richmemo/win32/win32richmemo.pas | 59 +++++++++++++------ .../richmemo/win32/win32richmemoproc.pas | 59 +++++++++++++++---- 2 files changed, 89 insertions(+), 29 deletions(-) diff --git a/components/richmemo/win32/win32richmemo.pas b/components/richmemo/win32/win32richmemo.pas index cf9dab4a1..c8dcde5e0 100644 --- a/components/richmemo/win32/win32richmemo.pas +++ b/components/richmemo/win32/win32richmemo.pas @@ -250,9 +250,25 @@ begin Result:=false; // we need to catch just notifications, // any other message should be handled in a "Default" manner // So, default result is false; - hdr:=PNMHDR(LParam); case Msg of + WM_COMMAND: begin + case HIWORD(WParam) of + EN_UPDATE: begin + // https://msdn.microsoft.com/en-us/library/windows/desktop/bb761687(v=vs.85).aspx + // EN_UPDATE is just a notification, that the edit is to be redrawn + Result:=true; + end; + EN_CHANGE: begin + // https://msdn.microsoft.com/en-us/library/windows/desktop/hh768384(v=vs.85).aspx + // Despite of what documentation claims (WM_NOTIFY), EN_CHANGE is notified by WM_COMMAND + if Assigned(AWinControl) and (AWinControl is TCustomRichMemo) then + TIntCustomRichMemo(AWinControl).Change; + Result:=true; + end; + end; + end; WM_NOTIFY: begin + hdr:=PNMHDR(LParam); case hdr^.code of EN_SELCHANGE: begin @@ -539,7 +555,7 @@ begin FinishCreateWindow(AWinControl, Params, false); eventmask := SendMessage(AWinControl.Handle, EM_GETEVENTMASK, 0, 0); - eventmask := eventmask or ENM_SELCHANGE or ENM_LINK; + eventmask := eventmask or ENM_SELCHANGE or ENM_LINK or ENM_CHANGE; SendMessage(AWinControl.Handle, EM_SETEVENTMASK, 0, eventmask); // Limitless text. However, the value would be overwritten by a consequent @@ -581,8 +597,7 @@ end; class function TWin32WSCustomRichMemo.GetTextAttributes(const AWinControl: TWinControl; TextStart: Integer; var Params: TIntFontParams): Boolean; var - OrigStart : Integer; - OrigLen : Integer; + Orig : TCHARRANGE; eventmask : LongWord; begin if not Assigned(RichEditManager) or not Assigned(AWinControl) then begin @@ -591,13 +606,15 @@ begin end; InitFontParams(Params); eventmask := RichEditManager.SetEventMask(AWinControl.Handle, 0); - - RichEditManager.GetSelection(AWinControl.Handle, OrigStart, OrigLen); LockRedraw(TCustomRichMemo(AWinControl), AWinControl.Handle); + + RichEditManager.GetSelRange(AWinControl.Handle, Orig); + RichEditManager.SetSelection(AWinControl.Handle, TextStart, 1); Result := RichEditManager.GetSelectedTextStyle(AWinControl.Handle, Params ); - RichEditManager.SetSelection(AWinControl.Handle, OrigStart, OrigLen); + + RichEditManager.SetSelRange(AWinControl.Handle, Orig); UnlockRedraw(TCustomRichMemo(AWinControl), AWinControl.Handle, false); RichEditManager.SetEventMask(AWinControl.Handle,eventmask); @@ -669,8 +686,7 @@ class function TWin32WSCustomRichMemo.GetStyleRange( const AWinControl: TWinControl; TextStart: Integer; var RangeStart, RangeLen: Integer): Boolean; var - OrigStart : Integer; - OrigLen : Integer; + Orig : TCharRange; eventmask : longword; begin if not Assigned(RichEditManager) or not Assigned(AWinControl) then begin @@ -679,17 +695,17 @@ begin end; eventmask := RichEditManager.SetEventMask(AWinControl.Handle, 0); - - RichEditManager.GetSelection(AWinControl.Handle, OrigStart, OrigLen); LockRedraw(TCustomRichMemo(AWinControl), AWinControl.Handle); + RichEditManager.GetSelRange(AWinControl.Handle, Orig); + RichEditManager.SetSelection(AWinControl.Handle, TextStart, 1); try Result := RichEditManager.GetStyleRange(AWinControl.Handle, TextStart, RangeStart, RangeLen); except end; - RichEditManager.SetSelection(AWinControl.Handle, OrigStart, OrigLen); + RichEditManager.SetSelRange(AWinControl.Handle, Orig); UnlockRedraw(TCustomRichMemo(AWinControl), AWinControl.Handle, false); RichEditManager.SetEventMask(AWinControl.Handle, eventmask); @@ -724,8 +740,7 @@ end; class function TWin32WSCustomRichMemo.GetTextUIParams(const AWinControl: TWinControl; TextStart: Integer; var ui: TTextUIParam): Boolean; var - OrigStart : Integer; - OrigLen : Integer; + Orig : TCHARRANGE; eventmask : Integer; begin if not Assigned(RichEditManager) or not Assigned(AWinControl) then begin @@ -734,12 +749,14 @@ begin end; eventmask := RichEditManager.SetEventMask(AWinControl.Handle, 0); - RichEditManager.GetSelection(AWinControl.Handle, OrigStart, OrigLen); - LockRedraw( TCustomRichMemo(AWinControl), AWinControl.Handle); + + RichEditManager.GetSelRange(AWinControl.Handle, Orig); + RichEditManager.SetSelection(AWinControl.Handle, TextStart, 1); RichEditManager.GetTextUIStyle(AWinControl.Handle, ui); - RichEditManager.SetSelection(AWinControl.Handle, OrigStart, OrigLen); + + RichEditManager.SetSelRange(AWinControl.Handle, Orig); UnlockRedraw( TCustomRichMemo(AWinControl), AWinControl.Handle); RichEditManager.SetEventMask(AWinControl.Handle, eventmask); @@ -774,6 +791,8 @@ begin eventmask:=RichEditManager.SetEventMask(AWinControl.Handle, 0); + LockRedraw( TCustomRichMemo(AWinControl), AWinControl.Handle); + RichEditManager.GetPara2(AWinControl.Handle, TextStart, para); case para.wAlignment of PFA_CENTER: AAlign:=paCenter; @@ -782,6 +801,7 @@ begin else AAlign:=paLeft; end; + UnlockRedraw( TCustomRichMemo(AWinControl), AWinControl.Handle ); RichEditManager.SetEventMask(AWinControl.Handle, eventmask); Result:=true; @@ -1063,6 +1083,7 @@ class function TWin32WSCustomRichMemo.GetSubText( var utxt: UnicodeString): Boolean; var eventmask : Integer; + Orig : TCharRange; OrigStart : Integer; OrigLen : Integer; NeedLock : Boolean; @@ -1078,7 +1099,7 @@ begin NeedLock := (OrigStart <> TextStart) or (OrigLen <> TextLen); if NeedLock then begin LockRedraw( TCustomRichMemo(AWinControl), Hnd); - RichEditManager.SetSelection(Hnd, TextStart, TextLen); + RichEditManager.GetSelRange(Hnd, Orig); end; isUnicode:=AsUnicode; @@ -1089,7 +1110,7 @@ begin end; if NeedLock then begin - RichEditManager.SetSelection(Hnd, OrigStart, OrigLen); + RichEditManager.SetSelRange(Hnd, Orig); UnlockRedraw( TCustomRichMemo(AWinControl), Hnd); end; RichEditManager.SetEventMask(Hnd, eventmask); diff --git a/components/richmemo/win32/win32richmemoproc.pas b/components/richmemo/win32/win32richmemoproc.pas index cf5663c4e..df23f09c0 100644 --- a/components/richmemo/win32/win32richmemoproc.pas +++ b/components/richmemo/win32/win32richmemoproc.pas @@ -172,7 +172,12 @@ type class function GetStyleRange(RichEditWnd: Handle; TextStart: Integer; var RangeStart, RangeLen: Integer): Boolean; virtual; class procedure GetSelection(RichEditWnd: Handle; var TextStart, TextLen: Integer); virtual; - class procedure SetSelection(RichEditWnd: Handle; TextStart, TextLen: Integer); virtual; + class procedure SetSelection(RichEditWnd: Handle; TextStart, TextLen: Integer); virtual; + + // WARNING: GetSelRange, is causing changes in Selection! + class procedure GetSelRange(RichEditWnd: Handle; var sr: TCHARRANGE); virtual; + class procedure SetSelRange(RichEditWnd: Handle; const sr: TCHARRANGE); virtual; + class procedure SetHideSelection(RichEditWnd: Handle; AValue: Boolean); virtual; class function LoadRichText(RichEditWnd: Handle; ASrc: TStream): Boolean; virtual; class function SaveRichText(RichEditWnd: Handle; ADst: TStream): Boolean; virtual; @@ -647,6 +652,38 @@ begin SendMessage(RichEditWnd, EM_EXSETSEL, 0, PtrInt(@Range)); end; +class procedure TRichEditManager.GetSelRange(RichEditWnd: Handle; var sr: TCHARRANGE); +var + st: Integer; +begin + sr.cpMax := 0; + sr.cpMin := 0; + st:=0; + SendMessage(RichEditWnd, EM_EXGETSEL, 0, PtrInt(@sr)); + // EM_EXGETSEL - always returns min and max, in the math order + // (where math is lower, than max) + // This, however, doesn't match the seletion direction. + // Selection direction is done by either mouse (right to left) and (left to right) + // or by holding SHIFT key and moving left to right. + // EM_EXSETSEL - repsects the specified sr.cpMax and sr.cpMin order + + // Resetting the selection. + // This is a bit hacky, BUT the selection would be reset + // towards the direction of the selection + SendMessage(RichEditWnd, EM_SETSEL, -1, 0); + SendMessage(RichEditWnd, EM_GETSEL, WPARAM(@st), 0); + + if st=sr.cpMin then begin // right-to-left selection + sr.cpMin:=sr.cpMax; + sr.cpMax:=st; + end; +end; + +class procedure TRichEditManager.SetSelRange(RichEditWnd: Handle; const sr: TCHARRANGE); +begin + SendMessage(RichEditWnd, EM_EXSETSEL, 0, PtrInt(@sr)); +end; + class procedure TRichEditManager.SetHideSelection(RichEditWnd: Handle; AValue: Boolean); var style : LResult; @@ -720,9 +757,9 @@ class procedure TRichEditManager.SetText(RichEditWnd:Handle; var AnsiText : AnsiString; txt : PChar; - s, l : Integer; + sr : TCHARRANGE; begin - GetSelection(RichEditWnd, s, l); + GetSelRange(RichEditWnd, sr); SetSelection(RichEditWnd, TextStart, ReplaceLength); txt:=nil; @@ -735,7 +772,7 @@ begin SendMessageA(RichEditWnd, EM_REPLACESEL, 0, LPARAM(txt)); end; - SetSelection(RichEditWnd, s, l); + SetSelRange(RichEditWnd, sr); end; class function TRichEditManager.GetTextW(RichEditWnd: Handle; @@ -801,9 +838,9 @@ end; class procedure TRichEditManager.GetPara2(RichEditWnd: Handle; TextStart: Integer; var para: PARAFORMAT2); var - s, l : Integer; + sr : TCHARRANGE; begin - GetSelection(RichEditWnd, s, l); + GetSelRange(RichEditWnd, sr); SetSelection(RichEditWnd, TextStart, 0); @@ -811,18 +848,20 @@ begin para.cbSize:=sizeof(para); SendMessagea(RichEditWnd, EM_GETPARAFORMAT, 0, LPARAM(@para)); - SetSelection(RichEditWnd, s, l); + SetSelRange(RichEditWnd, sr); end; class procedure TRichEditManager.SetPara2(RichEditWnd: Handle; TextStart, TextLen: Integer; const para: PARAFORMAT2); var - s, l : Integer; + sr : TCHARRANGE; begin - GetSelection(RichEditWnd, s, l); + GetSelRange(RichEditWnd, sr); + SetSelection(RichEditWnd, TextStart, TextLen); SendMessagea(RichEditWnd, EM_SETPARAFORMAT, 0, LPARAM(@para)); - SetSelection(RichEditWnd, s, l); + + SetSelRange(RichEditWnd, sr); end; class function TRichEditManager.Find(RichEditWnd: THandle; const ANiddle: WideString; const ASearch: TIntSearchOpt): Integer; overload;