lazarus-ccr/components/richmemo/qt5/qt5richmemo.pas

351 lines
9.8 KiB
ObjectPascal

unit qt5richmemo;
interface
{$mode delphi}
{$define RMQT5_TEXTFORMATS} // the feature is available in Qt5 Trunk
// it allows to query Qt5TextEdit for character formats array
{$ifdef RMQT5_NOTEXTFORMATS}{$undef RMQT5_TEXTFORMATS}{$endif}
//
// Following class methods are need for the implementation
// QTextCharFormatH
// QTextBlockFormatH
uses
LCLType, Controls, StdCtrls, Graphics,
qt5, qtobjects, qtwidgets, qtprivate,
WSProc,
RichMemo, WSRichMemo;
type
{ TQtWSCustomRichMemo }
TQtWSCustomRichMemo = class(TWSCustomRichMemo)
published
class function CreateHandle(const AWinControl: TWinControl;
const AParams: TCreateParams): HWND; override;
class function GetParaAlignment(const AWinControl: TWinControl; TextStart: Integer;
var AAlign: TIntParaAlignment): Boolean; override;
class procedure SetParaAlignment(const AWinControl: TWinControl; TextStart, TextLen: Integer;
const AAlign: TIntParaAlignment); 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 function Search(const AWinControl: TWinControl; const ANiddle: string; const SearchOpts: TIntSearchOpt): Integer; override;
class function isInternalChange(const AWinControl: TWinControl; Params: TTextModifyMask
): Boolean; override;
class procedure SetTextAttributesInternal(const AWinControl: TWinControl; TextStart, TextLen: Integer;
const AModifyMask: TTextModifyMask; const Params: TIntFontParams); override;
class function GetStyleRange(const AWinControl: TWinControl; TextStart: Integer; var RangeStart, RangeLen: Integer): Boolean; override;
end;
type
TEditorState = record
selst : integer; // selection start
sellen : integer; // selection length
end;
// no sanity check is done in these functions
procedure MakeBackup(te: TQtTextEdit; out backup: TEditorState);
procedure ApplyBackup(te: TQtTextEdit; const backup: TEditorState);
implementation
const
WordWrapMap: array[Boolean] of QTextEditLineWrapMode =
(
QTextEditNoWrap,
QTextEditWidgetWidth
);
AlignmentMap: array[TIntParaAlignment] of QtAlignment =
(
QtAlignLeft,
QtAlignRight,
QtAlignHCenter,
QtAlignJustify
);
{ TQtWSCustomRichMemo }
class function TQtWSCustomRichMemo.CreateHandle(const AWinControl: TWinControl;
const AParams: TCreateParams): HWND;
var
QtTextEdit: TQtTextEdit;
begin
QtTextEdit := TQtTextEdit.Create(AWinControl, AParams);
QtTextEdit.AcceptRichText := True;
QtTextEdit.ClearText;
QtTextEdit.setBorder(TCustomMemo(AWinControl).BorderStyle = bsSingle);
QtTextEdit.setReadOnly(TCustomMemo(AWinControl).ReadOnly);
QtTextEdit.setLineWrapMode(WordWrapMap[TCustomMemo(AWinControl).WordWrap]);
// create our FList helper
QtTextEdit.FList := TQtMemoStrings.Create(TCustomMemo(AWinControl));
QtTextEdit.setScrollStyle(TCustomMemo(AWinControl).ScrollBars);
QtTextEdit.setTabChangesFocus(not TCustomMemo(AWinControl).WantTabs);
QtTextEdit.AttachEvents;
Result := TLCLIntfHandle(QtTextEdit);
end;
class procedure TQtWSCustomRichMemo.SetParaAlignment(
const AWinControl: TWinControl; TextStart, TextLen: Integer;
const AAlign: TIntParaAlignment);
var
w : QTextEditH;
te : TQtTextEdit;
ss, sl : Integer;
begin
if not WSCheckHandleAllocated(AWinControl, 'SetParaAlignment') then
Exit;
te:=TQtTextEdit(AWinControl.Handle);
w:=QTextEditH(te.Widget);
ss:=te.getSelectionStart;
sl:=te.getSelectionLength;
te.setSelection(TextStart, TextLen);
// alignment
QTextEdit_setAlignment(w, AlignmentMap[AAlign]);
te.setSelection(ss, sl);
end;
const
QNormal = 50;
QBold = 75;
class function TQtWSCustomRichMemo.GetTextAttributes(
const AWinControl: TWinControl; TextStart: Integer; var Params: TIntFontParams
): Boolean;
var
w : QTextEditH;
te : TQtTextEdit;
ws : WideString;
clr: TQColor;
bck : TEditorState;
begin
InitFontParams(Params);
if not WSCheckHandleAllocated(AWinControl, 'GetTextAttributes') then begin
Result:=false;
Exit;
end;
te:=TQtTextEdit(AWinControl.Handle);
w:=QTextEditH(te.Widget);
MakeBackup(te, bck);
te.setSelection(TextStart, 1);
//todo!
ws:='';
QTextEdit_fontFamily(w, @ws);
if ws<>'' then Params.Name:=UTF8Encode(ws);
Params.Size:=round(QTextEdit_fontPointSize(w));
if QTextEdit_fontWeight(w)>=QBold then Include(Params.Style, fsBold);
if QTextEdit_fontItalic(w) then Include(Params.Style, fsItalic);
if QTextEdit_fontUnderline(w) then Include(Params.Style, fsUnderline);
FillChar(clr, sizeof(clr), 0);
QTextEdit_textColor(w, @clr);
TQColorToColorRef(clr, TColorRef(params.Color));
FillChar(clr, sizeof(clr), 0);
QTextEdit_textBackgroundColor(w, @clr);
TQColorToColorRef(clr, TColorRef(params.BkColor));
//todo!
params.HasBkClr:=false;
ApplyBackup(te, bck);
Result:=true;
end;
class procedure TQtWSCustomRichMemo.SetTextAttributes(
const AWinControl: TWinControl; TextStart, TextLen: Integer;
const Params: TIntFontParams);
var
w : QTextEditH;
te : TQtTextEdit;
ss, sl : Integer;
ws : WideString;
clr: TQColor;
const
QNormal = 50;
QBold = 75;
const
QIsBold: array [Boolean] of integer = (QNormal, QBold);
begin
if not WSCheckHandleAllocated(AWinControl, 'SetTextAttributes') then
Exit;
te:=TQtTextEdit(AWinControl.Handle);
w:=QTextEditH(te.Widget);
ss:=te.getSelectionStart;
sl:=te.getSelectionLength;
te.setSelection(TextStart, TextLen);
ws:=UTF8Decode(Params.Name);
if ws<>'' then QTextEdit_setFontFamily(w, @ws);
if Params.Size>0 then QTextEdit_setFontPointSize(w, Params.Size);
QTextEdit_setFontUnderline(w, fsUnderline in Params.Style);
QTextEdit_setFontWeight(w, QisBold[fsBold in Params.Style]);
QTextEdit_setFontItalic(w, fsItalic in Params.Style);
ColorRefToTQColor(Params.Color, clr);
QTextEdit_setTextColor(w, @clr);
//todo:
{
if not Params.HasBkClr then begin
ColorRefToTQColor(Params.BkColor, clr);
clr.Alpha:=0;
end else
ColorRefToTQColor(Params.BkColor, clr);
QTextEdit_setTextBackgroundColor(w, @clr);
}
te.setSelection(ss, sl);
end;
class function TQtWSCustomRichMemo.Search(const AWinControl: TWinControl;
const ANiddle: string; const SearchOpts: TIntSearchOpt): Integer;
var
w : QTextEditH;
te : TQtTextEdit;
ws : Widestring;
fl : QTextDocumentFindFlags;
begin
if not WSCheckHandleAllocated(AWinControl, 'SetParaAlignment') then
Exit;
te:=TQtTextEdit(AWinControl.Handle);
w:=QTextEditH(te.Widget);
fl:=0;
if soMatchCase in SearchOpts.Options then fl:=fl or QTextDocumentFindCaseSensitively;
if soWholeWord in SearchOpts.Options then fl:=fl or QTextDocumentFindWholeWords;
if soBackward in SearchOpts.Options then fl:=fl or QTextDocumentFindBackward;
//todo: range filtering in Serach Opts
ws:=UTF8Decode(ANiddle);
if QTextEdit_find(w, @ws, fl) then Result:=te.getSelectionStart
else Result:=-1;
end;
class function TQtWSCustomRichMemo.isInternalChange(
const AWinControl: TWinControl; Params: TTextModifyMask): Boolean;
begin
Result := false;
//Result:=inherited isInternalChange(AWinControl, Params);
end;
class procedure TQtWSCustomRichMemo.SetTextAttributesInternal(
const AWinControl: TWinControl; TextStart, TextLen: Integer;
const AModifyMask: TTextModifyMask; const Params: TIntFontParams);
begin
SetTextAttributes(AWinControl, TextStart, TextLen, Params);
end;
class function TQtWSCustomRichMemo.GetStyleRange(
const AWinControl: TWinControl; TextStart: Integer; var RangeStart,
RangeLen: Integer): Boolean;
var
te : TQtTextEdit;
bck : TEditorState;
al : QtAlignment;
qcur : QTextCursorH;
qblck : QTextBlockH;
qbfmt : QTextBlockFormatH;
i : integer;
cnt : integer;
rng : array of TTextRange;
blckofs: integer;
begin
if not WSCheckHandleAllocated(AWinControl, 'GetStyleRange') then begin
Result:=false;
Exit;
end;
RangeStart:=TextStart;
RangeLen:=1;
Result:=true;
{$ifndef RMQT5_TEXTFORMATS}
Exit;
{$else}
te:=TQtTextEdit(AWinControl.Handle);
MakeBackup(te, bck);
qcur := QTextCursor_Create();
qblck := QTextBlock_Create();
try
te.setSelection(TextStart, 0);
QTextEdit_textCursor(QTextEditH(te.Widget), qcur);
QTextCursor_block(qcur, qblck);
cnt := QTextBlock_textFormatsCount(qblck);
SetLength(rng, cnt);
if cnt>0 then begin
blckofs := QTextBlock_position(qblck);
textStart := textStart - blckofs;
for i:=0 to cnt-1 do begin
if (textStart >= rng[i].start) and (textStart<rng[i].start+rng[i].length) then
begin
RangeStart := rng[i].start + blckofs;
RangeLen := rng[i].length;
break;
end;
end;
end;
finally
QTextBlock_Destroy(qblck);
QTextCursor_Destroy(qcur);
ApplyBackup(te, bck);
end;
{$endif}
end;
class function TQtWSCustomRichMemo.GetParaAlignment(
const AWinControl: TWinControl; TextStart: Integer;
var AAlign: TIntParaAlignment): Boolean;
var
te : TQtTextEdit;
al : QtAlignment;
begin
if not WSCheckHandleAllocated(AWinControl, 'GetParaAlignment') then begin
Result:=false;
Exit;
end;
te:=TQtTextEdit(AWinControl.Handle);
al:=QTextEdit_alignment(QTextEditH(te.Widget));
if QtAlignLeading and al > 0 then AAlign:=paLeft
else if QtAlignTrailing and al > 0 then AAlign:=paRight
else if QtAlignCenter and al > 0 then AAlign:=paCenter
else if QtAlignJustify and al > 0 then AAlign:=paJustify
else AAlign:=paLeft;
Result:=true;
end;
procedure MakeBackup(te: TQtTextEdit; out backup: TEditorState);
begin
backup.selst:=te.getSelectionStart;
backup.sellen:=te.getSelectionLength;
end;
procedure ApplyBackup(te: TQtTextEdit; const backup: TEditorState);
begin
te.setSelection(backup.selst, backup.sellen);
end;
end.