Page 1 of 1

RichView/RichViewEdit - Getting The Text

Posted: Sun Mar 17, 2013 11:05 am
by Graham
I create some text in a RichViewEdit. I then copy this text Item by Item into a RichView of a fixed width which will define the word wrapping. I now need to get the text on each line. Each Item will return the text which may cover several lines.

Is this possible?

Is there some function like:

tStr := rv.GetLineText (LineNo: integer);

Posted: Sun Mar 17, 2013 4:13 pm
by Sergey Tkachenko
There is only GetCurrentLineText in RVGetText.pas (ansi version) and RVGetTextW.pas (Unicode version).

If you want, I can create a function filling a stringlist with text of lines.
But how do you want to process lines in table cells?

Posted: Sun Mar 17, 2013 8:22 pm
by Graham
GetCurrentLineText almost does what I would like.

Is it possible to provide a routine like this:

function GetSpecifiedLineText (rve: TRichViewEdit;
LineNo: integer;
var StyleNo: integer) : TRvUnicodeString;

LineNo is the line number from the top of the display area of rve.
So LineNo = 0 and the function returns the first line of visible text displayed and the associated style number.

Posted: Mon Mar 18, 2013 10:07 am
by Sergey Tkachenko
The first visible line is not strictly defined, because lines may be visible partially.
And line may contain text of multiple styles.
And, does your document contain tables?

Posted: Tue Mar 19, 2013 9:31 am
by Graham
Ok, lets try and make my requirement slightly simpler (or possibly not).

I'm scrolling the text in a RichViewEdit and I need to determine the text at a particular offset from the top of the visible area. So maybe its easier to use the scroll offset. The top line will be at VScrollOffset, so lets say I would like to get the text at VScrollOffset + 50.

There are no tables involved here but the text on a particular line could contain different styles.

So ideally I would like to have returned some sort of structure that contains the text(Unicode) and a mechanism for determining the style of each character in that text string.

Posted: Tue Mar 19, 2013 12:37 pm
by Sergey Tkachenko
I can suggest the following solution.

1) Finding the position in the document at VScrollOffset+50

Code: Select all

var RVData: TCustomRVFormattedData;
     ItemNo, OffsetInItem: Integer;

RichViewEdit1.GetItemAt(0, RichViewEdit1.VScrollPos*RichViewEdit1.VSmallStep[color=red]+50[/color], RVData, ItemNo, OffsetInItem, False);
Without tables, this function always returns RVData = RichViewEdit1.RVData, so we can ignore this variable and use only ItemNo and OffsetInItem.

2) Here is the modified version of GetCurrentLineText from RVGetTextW that returns the line for the specified position (ItemNo, OffsetInItem) instead of the current line:

Code: Select all

function GetineText(rve: TCustomRichViewEdit; ItemNo, OffsetInItem: Integer): TRVUnicodeString;
var i, DNo1, DNo2, DOffs: Integer;
    No1, No2, Offs1, Offs2: Integer;
    s: TRVUnicodeString;
begin
  Result := '';
  rve.RVData.Item2DrawItem(ItemNo, OffsetInItem, DNo1, DOffs, rvdpBetterBelow);
  DNo2 := DNo1+1;
  while not rve.RVData.DrawItems[DNo1].FromNewLine do
    dec(DNo1);
  while (DNo2<rve.ItemCount) and not rve.RVData.DrawItems[DNo2].FromNewLine do
    inc(DNo2);
  dec(DNo2);
  rve.RVData.DrawItem2Item(DNo1, rve.RVData.GetOffsBeforeDrawItem(DNo1), No1, Offs1);
  rve.RVData.DrawItem2Item(DNo2, rve.RVData.GetOffsAfterDrawItem(DNo2), No2, Offs2);
  if No1<>No2 then begin
    if rve.GetItemStyle(No1)>=0 then begin
      s := rve.GetItemTextW(No1);
      Result := Copy(s, Offs1, Length(s));
    end;
    for i := No1+1 to No2-1 do
      if rve.GetItemStyle(i)>=0 then
        Result := Result+rve.GetItemTextW(i);
    if rve.GetItemStyle(No2)>=0 then begin
      s := rve.GetItemTextW(No2);
      Result := Result+Copy(s, 1, Offs2-1);
    end;
    end
  else if rve.GetItemStyle(No1)<0 then
    Result := GetItemText(rve, No1)
  else
    Result := Copy(rve.GetItemTextW(No1), Offs1, Offs2-Offs1);
end;

Posted: Tue Mar 19, 2013 12:43 pm
by Sergey Tkachenko
How to get styles of items on this line.

In the procedure above, you can see DrawItem2Item-s return No1 and No2.
To get item styles:

Code: Select all

for i := No1 to No2 do
  add to the list rve.GetItemStyle(i)

Posted: Tue Mar 19, 2013 5:58 pm
by Graham
Perfect. I have changed it slightly such that I pass No1 and No2 as var parameters to the function.

Thanks for your quick response.

Posted: Wed Mar 20, 2013 7:33 am
by Sergey Tkachenko
I forgot "+50", added in the code

Posted: Wed Mar 20, 2013 9:06 am
by Graham
Yes, I spotted that. I am going to make a further change to your routine such that instead of getting back No1 and No2 I will return a string that contains the style number of each character. So I call the routine and I will get the text for the displayed line and a string of equal length of style numbers.

Posted: Wed Mar 20, 2013 10:01 am
by Graham
This my current attempt which seems to work.

Code: Select all

function GetSpecifiedLineText(rve: TCustomRichView; ItemNo, OffsetInItem: Integer;
                              var StyleStr: string): TRVUnicodeString;
var i, j, DNo1, DNo2, DOffs: Integer;
    No1, No2, Offs1, Offs2: Integer;
    s: TRVUnicodeString;
    IStyle: integer;

begin
  Result := '';
  rve.RVData.Item2DrawItem(ItemNo, OffsetInItem, DNo1, DOffs, rvdpBetterBelow);
  DNo2 := DNo1+1;
  while not rve.RVData.DrawItems[DNo1].FromNewLine do
    dec(DNo1);
  while (DNo2<rve.ItemCount) and not rve.RVData.DrawItems[DNo2].FromNewLine do
    inc(DNo2);
  dec(DNo2);
  rve.RVData.DrawItem2Item(DNo1, rve.RVData.GetOffsBeforeDrawItem(DNo1), No1, Offs1);
  rve.RVData.DrawItem2Item(DNo2, rve.RVData.GetOffsAfterDrawItem(DNo2), No2, Offs2);

  if No1<>No2 then
  begin
    IStyle := rve.GetItemStyle(No1);

    if IStyle >= 0 then
    begin
      s := rve.GetItemTextW(No1);

      for j := 1 to Length(s) do
        styleStr := styleStr + Char(IStyle);

      Result := Copy(s, Offs1, Length(s));
    end;

    for i := No1+1 to No2-1 do
    begin
      IStyle := rve.GetItemStyle(i);

      if IStyle >= 0 then
      begin
        s := rve.GetItemTextW(i);

        for j := 1 to Length(s) do
          styleStr := styleStr + Char(IStyle);

        Result := Result+s;
      end;
    end;

    IStyle := rve.GetItemStyle(No2);

    if IStyle >= 0 then
    begin
      s := rve.GetItemTextW(No2);
      s := Copy(s, 1, Offs2-1);

      for j := 1 to Length(s) do
        styleStr := styleStr + Char(IStyle);

      Result := Result+s;
    end;
  end
  else
  begin
    IStyle := rve.GetItemStyle(No1);

    if IStyle < 0 then
      s := GetItemText(rve, No1)
    else
      s := Copy(rve.GetItemTextW(No1), Offs1, Offs2-Offs1);

    for j := 1 to Length(s) do
      styleStr := styleStr + Char(IStyle);

    Result := s;
  end;
end;