Smart indent/unindent, MS Word style
This code changes FirstIndent and LeftIndent of paragraph, if Tab/Backspace is pressed when the caret is at the beginning of paragraph. First, it changes FirstIndent. Next, if FirstIndent is already changed, it changes LeftIndent.
This code changes indents only if the caret is at the beginning of non-empty paragraph.
When the caret is at the beginning of a bulleted/numbered paragraph, Tab increases the list level.
This code uses its own procedures for OnParaStyleConversion event. Of course, you can integrate this code in existing event handler instead. But in this way, it's easy to integrate this code in existing application, even if it uses RichViewActions.
Code: Select all
// Procedure for OnParaStyleConversion event.
// Changes paragraph's FirstIndent to UserData
procedure TForm3.ChangeFirstIndentConversion(Sender: TCustomRichViewEdit;
StyleNo, UserData: Integer; AppliedToText: Boolean;
var NewStyleNo: Integer);
var ParaStyle: TParaInfo;
begin
ParaStyle := TParaInfo.Create(nil);
ParaStyle.Assign(Sender.Style.ParaStyles[StyleNo]);
ParaStyle.FirstIndent := UserData;
ParaStyle.Standard := False;
NewStyleNo := Sender.Style.ParaStyles.FindSuchStyle(StyleNo, ParaStyle,
RVAllParaInfoProperties);
if NewStyleNo<0 then begin
Sender.Style.ParaStyles.Add.Assign(ParaStyle);
NewStyleNo := Sender.Style.ParaStyles.Count-1;
end;
ParaStyle.Free;
end;
// Procedure for OnParaStyleConversion event.
// Changes paragraph's LeftIndent to UserData
// If UserData=0, resets FirstIndent as well.
procedure TForm3.ChangeLeftIndentConversion(Sender: TCustomRichViewEdit;
StyleNo, UserData: Integer; AppliedToText: Boolean;
var NewStyleNo: Integer);
var ParaStyle: TParaInfo;
begin
ParaStyle := TParaInfo.Create(nil);
ParaStyle.Assign(Sender.Style.ParaStyles[StyleNo]);
ParaStyle.LeftIndent := UserData;
if ParaStyle.LeftIndent=0 then
ParaStyle.FirstIndent := 0;
ParaStyle.Standard := False;
NewStyleNo := Sender.Style.ParaStyles.FindSuchStyle(StyleNo, ParaStyle,
RVAllParaInfoProperties);
if NewStyleNo<0 then begin
Sender.Style.ParaStyles.Add.Assign(ParaStyle);
NewStyleNo := Sender.Style.ParaStyles.Count-1;
end;
ParaStyle.Free;
end;
function TForm3.ChangeIndent(rve: TCustomRichViewEdit;
Step, Max: Integer): Boolean;
var OldParaStyleConversion: TRVStyleConversionEvent;
FirstIndent, LeftIndent: Integer;
ListNo, ListLevel, StartFrom: Integer;
Reset: Boolean;
begin
Result := False;
OldParaStyleConversion := rve.OnParaStyleConversion;
try
rve := rve.TopLevelEditor;
if rve.SelectionExists then
exit;
if (rve.OffsetInCurItem<=rve.GetOffsBeforeItem(rve.CurItemNo)) and
(rve.CurItemNo>0) and (rve.GetItemStyle(rve.CurItemNo-1)=rvsListMarker) then begin
// changing list level
rve.GetListMarkerInfo(rve.CurItemNo, ListNo, ListLevel, StartFrom, Reset);
if (ListNo>=0) and (ListNo<rve.Style.ListStyles.Count) then
if (Step>0) and (ListLevel+1<rve.Style.ListStyles[ListNo].Levels.Count) then begin
rve.ChangeListLevels(+1);
Result := True;
end
else if (Step<0) and (ListLevel>0) then begin
rve.ChangeListLevels(-1);
Result := True;
end;
exit;
end;
if (rve.OffsetInCurItem>rve.GetOffsBeforeItem(rve.CurItemNo)) or
not rve.IsParaStart(rve.CurItemNo) then
exit; // not at the beginning of paragraph
if (rve.OffsetInCurItem>=rve.GetOffsAfterItem(rve.CurItemNo)) and
((rve.CurItemNo=rve.ItemCount-1) or rve.IsParaStart(rve.CurItemNo)) then
exit; // empty paragraph, exiting
FirstIndent := rve.Style.ParaStyles[rve.GetItemPara(rve.CurItemNo)].FirstIndent;
LeftIndent := rve.Style.ParaStyles[rve.GetItemPara(rve.CurItemNo)].LeftIndent;
if Step>0 then begin
if FirstIndent=0 then begin
rve.OnParaStyleConversion := ChangeFirstIndentConversion;
rve.ApplyParaStyleConversion(Step);
Result := True;
end
else begin
inc(LeftIndent, Step);
if LeftIndent>Max then
LeftIndent := Max;
if LeftIndent>rve.Style.ParaStyles[rve.GetItemPara(rve.CurItemNo)].LeftIndent then begin
rve.OnParaStyleConversion := ChangeLeftIndentConversion;
rve.ApplyParaStyleConversion(LeftIndent);
Result := True;
end;
end
end
else begin
if FirstIndent>0 then begin
rve.OnParaStyleConversion := ChangeFirstIndentConversion;
rve.ApplyParaStyleConversion(0);
Result := True;
end
else begin
inc(LeftIndent, Step);
if LeftIndent<0 then
LeftIndent := 0;
if (LeftIndent<rve.Style.ParaStyles[rve.GetItemPara(rve.CurItemNo)].LeftIndent) or
(FirstIndent<>0) then begin
rve.OnParaStyleConversion := ChangeLeftIndentConversion;
rve.ApplyParaStyleConversion(LeftIndent);
Result := True;
end;
end;
end;
finally
rve.OnParaStyleConversion := OldParaStyleConversion;
end;
end;
// OnKeyDown event
procedure TForm3.RichViewEdit1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if (Key=VK_BACK) and ChangeIndent(TCustomRichViewEdit(Sender), -48, 480) then
Key := 0;
end;
// OnKeyPress event
procedure TForm3.RichViewEdit1KeyPress(Sender: TObject; var Key: Char);
begin
if (Key=#9) and ChangeIndent(TCustomRichViewEdit(Sender), +48, 480) then
Key := #0;
end;
Upd: 2011-Jun-26: changing list levels on Tab
Upd: 2015-Jan-14: changing list levels on Backspace