How to make a particular line to topmost?

General TRichView support forum. Please post your questions here
Post Reply
donwynne
Posts: 1
Joined: Fri Mar 25, 2022 5:38 am

How to make a particular line to topmost?

Post by donwynne »

How can I make the line where the cursor is, to the topmost of a TRichViewEdit?
Last edited by donwynne on Mon Mar 28, 2022 6:33 am, edited 2 times in total.
standay
Posts: 274
Joined: Fri Jun 18, 2021 3:07 pm

Re: How to make a particular line to topmost?

Post by standay »

I tried this and it seems to work:

Code: Select all

procedure ScrollItemToTop(rve: TCustomRichViewEdit);
var
  DItem, DOffs: integer;
begin

  rve.RVData.Item2DrawItem(rve.CurItemNo, rve.OffsetInCurItem, DItem, DOffs );
  rve.ScrollToDrawItem( rve.RVData, DItem, false, false );
  rve.SetFocusSilent;

end;
Sergey Tkachenko
Site Admin
Posts: 17565
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Re: How to make a particular line to topmost?

Post by Sergey Tkachenko »

Yes, this is almost a correct solution. To support caret in table cells:

Code: Select all

procedure ScrollItemToTop(rve: TCustomRichViewEdit);
var
  DItem, DOffs: integer;
  tle: TCustomRichViewEdit;
begin
  tle := rve.TopLevelEditor;
  tle.RVData.Item2DrawItem(tle.CurItemNo, tle.OffsetInCurItem, DItem, DOffs );
  rve.ScrollToDrawItem( tle.RVData, DItem, false, false );
  rve.SetFocusSilent;
end;

It has two small problems:
- it scrolls to the top of the item containing the caret, not to the top of the line (the difference is noticeable if the line has items that are taller than this item
- if a line is wrapped, and not on a space character, the position at the end of this line and at the beginning of the next line has the same (rve.CurItemNo, rve.OffsetInCurItem).

These problems are small, so you can use this solution.
A perfect solution requires undocumented methods, see my next post.
Sergey Tkachenko
Site Admin
Posts: 17565
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Re: How to make a particular line to topmost?

Post by Sergey Tkachenko »

How to scroll to the top of the current line.

Code: Select all

uses CRVFData, RVERVData, DLines, RVCoords;

// Returns a range of drawing items on the RVData's line containing
// the DItemNo-th drawing item
procedure GetDItemsInLine(RVData: TCustomRVFormattedData;
  DItemNo: Integer; out DItemNo1, DItemNo2: Integer);
begin
  DItemNo1 := DItemNo;
  while not RVData.DrawItems[DItemNo1].FromNewLine do
    dec(DItemNo1);
  DItemNo2 := DItemNo + 1;
  while (DItemNo2 < RVData.DrawItems.Count) and
    not RVData.DrawItems[DItemNo2].FromNewLine do
    inc(DItemNo2);
  dec(DItemNo2);
end;

// Returns the top coordinate of the RVData's line containing
// the DItemNo-th drawing item, relative to the top corner of the rv's document.
function GetLineTop(rv: TCustomRichView; RVData: TCustomRVFormattedData;
  DItemNo: Integer): TRVCoord;
var
  i, DItemNo1, DItemNo2: Integer;
  R: TRVCoordRect;

  function GetDrawItemCoords(Index: Integer): TRVCoordRect;
  var
    DItem: TRVDrawLineInfo;
  begin
    DItem := RVData.DrawItems[Index];
    Result := RVCoordBounds(DItem.Left, RVData.GetTransformedDItemTop(Index),
      DItem.Width, DItem.Height);
  end;

begin
  GetDItemsInLine(RVData, DItemNo, DItemNo1, DItemNo2);
  R := GetDrawItemCoords(DItemNo);
  for i := DItemNo1 + 1 to DItemNo2 do
    UnionRect(R, R, GetDrawItemCoords(i));
  RVData.RotateRectFromDocToScreen(R, rvtrbAbsRoot);
  Result := R.Top;
end;
How to call:

Code: Select all

var
  Y: TRVCoord;
begin
  Y := GetLineTop(RichViewEdit1, RichViewEdit1.TopLevelEditor.RVData,
    TRVEditRVData(RichViewEdit1.TopLevelEditor.RVData).CaretDrawItemNo);
  RichViewEdit1.ScrollTo(Y);
end;
Sergey Tkachenko
Site Admin
Posts: 17565
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Re: How to make a particular line to topmost?

Post by Sergey Tkachenko »

if a line is wrapped, and not on a space character, the position at the end of this line and at the beginning of the next line has the same (rve.CurItemNo, rve.OffsetInCurItem).
Your code can be modified to avoid this problem:

Code: Select all

uses RVERVData;
procedure ScrollItemToTop(rve: TCustomRichViewEdit);
var
  DItem: integer;
  tle: TCustomRichViewEdit;
begin
  tle := rve.TopLevelEditor;
  DItem :=  TRVEditRVData(tle.RVData).CaretDrawItemNo;
  rve.ScrollToDrawItem( tle.RVData, DItem, false, false );
  rve.SetFocusSilent;
end;
standay
Posts: 274
Joined: Fri Jun 18, 2021 3:07 pm

Re: How to make a particular line to topmost?

Post by standay »

I had forgotten about tables again. I'm not implementing them as such in my app but I do like to account for them in case I copy and paste one or more tables into my rve.

I hadn't gotten quite as far as using CaretDrawItemNo but yes, that's the better way! I would have probably gotten to that eventually.

I wasn't the original poster for this but I'd been wanting to figure it out at some point so seeing this got me thinking about it again.

Thanks Sergey, great info.
Post Reply