{ win32richmemo.pas Author: Dmitry 'skalogryz' Boyarintsev ***************************************************************************** * * * This file is part of the Lazarus Component Library (LCL) * * * * See the file COPYING.modifiedLGPL.txt, included in this distribution, * * for details about the copyright. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * * ***************************************************************************** } unit Win32RichMemo; {$mode objfpc}{$H+} interface uses // Win32 headers Windows, // RTL headers Classes, SysUtils, // LCL headers LCLType, LCLIntf, LCLProc, WSLCLClasses, Controls, StdCtrls, // Win32WidgetSet Win32WSControls, Win32Int, // RichMemo headers WSRichMemo, Win32RichMemoProc, Win32WSStdCtrls; type { TWin32WSCustomRichMemo } TWin32WSCustomRichMemo = class(TWSCustomRichMemo) published class procedure SetSelStart(const ACustomEdit: TCustomEdit; NewStart: integer); override; class procedure SetSelLength(const ACustomEdit: TCustomEdit; NewLength: integer); override; class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): HWND; override; class function GetTextAttributes(const AWinControl: TWinControl; TextStart: Integer; var Params: TIntFontParams): Boolean; override; class procedure SetTextAttributes(const AWinControl: TWinControl; TextStart, TextLen: Integer; const Params: TIntFontParams); override; class procedure SetHideSelection(const AWinControl: TWinControl; AHideSelection: Boolean); override; class function GetStyleRange(const AWinControl: TWinControl; TextStart: Integer; var RangeStart, RangeLen: Integer): Boolean; override; class function LoadRichText(const AWinControl: TWinControl; Source: TStream): Boolean; override; class function SaveRichText(const AWinControl: TWinControl; Dst: TStream): Boolean; override; end; implementation const AlignmentToEditFlags: array[TAlignment] of DWord = ( { taLeftJustify } ES_LEFT, { taRightJustify } ES_RIGHT, { taCenter } ES_CENTER ); procedure LockRedraw(AHandle: HWND); begin SendMessage(AHandle, WM_SETREDRAW, 0, 0); end; procedure UnlockRedraw(AHandle: HWND; NeedInvalidate: Boolean = true); begin SendMessage(AHandle, WM_SETREDRAW, 1, 0); if NeedInvalidate then Windows.InvalidateRect(AHandle, nil, true); end; function RichEditProc(Window: HWnd; Msg: UInt; WParam: Windows.WParam; LParam: Windows.LParam): LResult; stdcall; begin if Msg = WM_PAINT then begin //todo: LCL WM_PAINT handling prevents richedit from drawing correctly Result := CallDefaultWindowProc(Window, Msg, WParam, LParam) //Result := WindowProc(Window, Msg, WParam, LParam) end else Result := WindowProc(Window, Msg, WParam, LParam); end; { TWin32WSCustomRichMemo } class procedure TWin32WSCustomRichMemo.SetSelStart(const ACustomEdit: TCustomEdit; NewStart: integer); var range : Tcharrange; begin range.cpMin := NewStart; range.cpMax := NewStart; SendMessage(ACustomEdit.Handle, EM_EXSETSEL, 0, LPARAM(@range)); InvalidateRect(ACustomEdit.Handle, nil, false); end; class procedure TWin32WSCustomRichMemo.SetSelLength(const ACustomEdit: TCustomEdit; NewLength: integer); var range : Tcharrange; begin SendMessage(ACustomEdit.Handle, EM_EXGETSEL, 0, LPARAM(@range)); range.cpMax := range.cpMin + NewLength; SendMessage(ACustomEdit.Handle, EM_EXSETSEL, 0, LPARAM(@range)); InvalidateRect(ACustomEdit.Handle, nil, false); end; class function TWin32WSCustomRichMemo.CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): HWND; var Params : TCreateWindowExParams; RichClass : AnsiString; ACustomMemo : TCustomMemo; begin InitRichEdit; RichClass := GetRichEditClass; if RichClass = '' then begin Result := 0; Exit; end; // general initialization of Params PrepareCreateWindow(AWinControl, Params); Params.SubClassWndProc := @RichEditProc; // customization of Params ACustomMemo := TCustomMemo(AWinControl); with Params do begin Flags := Flags or ES_AUTOVSCROLL or ES_MULTILINE or ES_WANTRETURN; if ACustomMemo.ReadOnly then Flags := Flags or ES_READONLY; Flags := Flags or AlignmentToEditFlags[ACustomMemo.Alignment]; case ACustomMemo.ScrollBars of ssHorizontal, ssAutoHorizontal: Flags := Flags or WS_HSCROLL; ssVertical, ssAutoVertical: Flags := Flags or WS_VSCROLL; ssBoth, ssAutoBoth: Flags := Flags or WS_HSCROLL or WS_VSCROLL; end; if ACustomMemo.WordWrap then Flags := Flags and not WS_HSCROLL else Flags := Flags or ES_AUTOHSCROLL; if ACustomMemo.BorderStyle=bsSingle then FlagsEx := FlagsEx or WS_EX_CLIENTEDGE; pClassName := @RichClass[1]; WindowTitle := StrCaption; end; // create window FinishCreateWindow(AWinControl, Params, false); // memo is not a transparent control -> no need for parentpainting Params.WindowInfo^.needParentPaint := false; Result := Params.Window; end; class procedure TWin32WSCustomRichMemo.SetTextAttributes(const AWinControl: TWinControl; TextStart, TextLen: Integer; const Params: TIntFontParams); var OrigStart : Integer; OrigLen : Integer; NeedLock : Boolean; begin if not Assigned(RichEditManager) or not Assigned(AWinControl) then Exit; RichEditManager.GetSelection(AWinControl.Handle, OrigStart, OrigLen); NeedLock := (OrigStart <> TextStart) or (OrigLen <> TextLen); if NeedLock then begin LockRedraw(AWinControl.Handle); RichEditManager.SetSelection(AWinControl.Handle, TextStart, TextLen); RichEditManager.SetSelectedTextStyle(AWinControl.Handle, Params ); RichEditManager.SetSelection(AWinControl.Handle, OrigStart, OrigLen); UnlockRedraw(AWinControl.Handle); end else RichEditManager.SetSelectedTextStyle(AWinControl.Handle, Params); end; class function TWin32WSCustomRichMemo.GetTextAttributes( const AWinControl: TWinControl; TextStart: Integer; var Params: TIntFontParams ): Boolean; var OrigStart : Integer; OrigLen : Integer; NeedLock : Boolean; begin if not Assigned(RichEditManager) or not Assigned(AWinControl) then begin Result := false; Exit; end; RichEditManager.GetSelection(AWinControl.Handle, OrigStart, OrigLen); NeedLock := (OrigStart <> TextStart); if NeedLock then begin LockRedraw(AWinControl.Handle); RichEditManager.SetSelection(AWinControl.Handle, TextStart, 1); Result := RichEditManager.GetSelectedTextStyle(AWinControl.Handle, Params ); RichEditManager.SetSelection(AWinControl.Handle, OrigStart, OrigLen); UnlockRedraw(AWinControl.Handle); end else Result := RichEditManager.GetSelectedTextStyle(AWinControl.Handle, Params); end; class procedure TWin32WSCustomRichMemo.SetHideSelection( const AWinControl: TWinControl; AHideSelection: Boolean); begin if not Assigned(RichEditManager) or not Assigned(AWinControl) then Exit; RichEditManager.SetHideSelection(AWinControl.Handle, AHideSelection); end; procedure InitScrollInfo(var info: TScrollInfo); begin FillChar(info, sizeof(info), 0); info.cbSize := sizeof(info); info.fMask := SIF_ALL; end; class function TWin32WSCustomRichMemo.GetStyleRange( const AWinControl: TWinControl; TextStart: Integer; var RangeStart, RangeLen: Integer): Boolean; var OrigStart : Integer; OrigLen : Integer; hInfo : TScrollInfo; vInfo : TScrollInfo; hVisible : Boolean; vVisible : Boolean; begin if not Assigned(RichEditManager) or not Assigned(AWinControl) then begin Result := false; Exit; end; RichEditManager.GetSelection(AWinControl.Handle, OrigStart, OrigLen); LockRedraw(AWinControl.Handle); InitScrollInfo(hInfo); InitScrollInfo(vInfo); hVisible:=GetScrollbarVisible(AWinControl.Handle, SB_Horz); vVisible:=GetScrollbarVisible(AWinControl.Handle, SB_Vert); GetScrollInfo(AWinControl.Handle, SB_Horz, hInfo); GetScrollInfo(AWinControl.Handle, SB_Vert, vInfo); RichEditManager.SetSelection(AWinControl.Handle, TextStart, 1); try Result := RichEditManager.GetStyleRange(AWinControl.Handle, TextStart, RangeStart, RangeLen); except end; if hVisible then SetScrollInfo(AWinControl.Handle, SB_Horz, hInfo, false); if vVisible then SetScrollInfo(AWinControl.Handle, SB_Vert, vInfo, false); RichEditManager.SetSelection(AWinControl.Handle, OrigStart, OrigLen); UnlockRedraw(AWinControl.Handle, false); end; class function TWin32WSCustomRichMemo.LoadRichText( const AWinControl: TWinControl; Source: TStream): Boolean; begin Result := false; if not Assigned(RichEditManager) or not Assigned(AWinControl) then Exit; Result := RichEditManager.LoadRichText(AWinControl.Handle, Source); end; class function TWin32WSCustomRichMemo.SaveRichText( const AWinControl: TWinControl; Dst: TStream): Boolean; begin Result := false; if not Assigned(RichEditManager) or not Assigned(AWinControl) then Exit; Result := RichEditManager.SaveRichText(AWinControl.Handle, Dst); end; end.