Page 1 of 1

centering selected text by scrolling

Posted: Fri Feb 04, 2011 12:30 am
by JohnMirror
Hi.
I'm trying to center the selected text in ScaleRichView but I can't find a function for this.
I mean by scrolling the text in fewest steps possible.
I tried ScrollToCaret and ScrollToItem but they only bring the selected text in the view, they're not placing it in the middle (vertically and even horizontally if possible).
Can anyone please help me make such a function..?
I'm asking for help because I'm new in using ScaleRichView and I only know basic functions not complex ones required for this function to work properly...

Thank you very much for any help.

Posted: Thu Feb 10, 2011 6:09 pm
by Sergey Tkachenko
This code shows the selected text in the middle (only vertically).
(if selection is longer than the editor height, it scrolls to the beginning of this selection).

This code uses undocumented functions.

Code: Select all

uses DLines, CRVFData;

var
     RVData: TCustomRVFormattedData;
     SItemNo, SItemOffs, EItemNo, EItemOffs,
     SDItemNo, SDItemOffs, EDItemNo, EDItemOffs, i, Step,
     Top, Bottom, X, Y: Integer;
begin
  // finding range of selected "drawing items"
  RVData := SRichViewEdit1.RichViewEdit.TopLevelEditor.RVData;
  RVData.GetSelectionBoundsEx(SItemNo, SItemOffs, EItemNo, EItemOffs, True);
  RVData.Item2DrawItem(SItemNo, SItemOffs, SDItemNo, SDItemOffs);
  RVData.Item2DrawItem(EItemNo, EItemOffs, EDItemNo, EDItemOffs);
  // calculating Top and Bottom in coordinates of RVData
  Top := RVData.DrawItems[SDItemNo].Top;
  Bottom := RVData.DrawItems[SDItemNo].Top+RVData.DrawItems[SDItemNo].Height;
  for i := SDItemNo+1 to EDItemNo do begin
    if Top>RVData.DrawItems[i].Top then
      Top := RVData.DrawItems[i].Top;
    if Bottom<RVData.DrawItems[i].Top+RVData.DrawItems[i].Height then
      Bottom := RVData.DrawItems[i].Top+RVData.DrawItems[i].Height;
  end;
  // converting to coordinates of SRichViewEdit1.RichViewEdit
  RVData.GetOriginEx(X, Y);
  inc(Top, Y);
  inc(Bottom, Y);
  // converting to coordinates of SRichViewEdit1
  Step := SRichViewEdit1.RichViewEdit.VSmallStep;
[color=blue]  dec(Top, SRichViewEdit1.RichViewEdit.VScrollPos*Step);
  dec(Bottom, SRichViewEdit1.RichViewEdit.VScrollPos*Step);[/color]
  Top := SRichViewEdit1.ConvertRVtoSRV(Point(0,Top)).Y+SRichViewEdit1.VScrollPos*Step;
  Bottom := SRichViewEdit1.ConvertRVtoSRV(Point(0,Bottom)).Y+SRichViewEdit1.VScrollPos*Step;
  // scrolling
  if Bottom-Top>SRichViewEdit1.ClientHeight then
    SRichViewEdit1.VScrollPos := Top div Step
  else
    SRichViewEdit1.VScrollPos := (Top+Bottom-SRichViewEdit1.ClientHeight) div (Step*2);
end; 

Posted: Thu Feb 10, 2011 8:26 pm
by JohnMirror
Thank you very much.
A friend of mine gave me this code:

Code: Select all

SRichViewEdit1.VScrollPos := ((Round(SRichViewEdit1.CaretPos.Y - SRichViewEdit1.OffsetY) - (SRichViewEdit1.ClientHeight div 2)) div SRichViewEdit1.RichViewEdit.VSmallStep) - 1;
But I think your code is better because it takes also the height of the selection into account.

Posted: Fri Feb 11, 2011 6:02 am
by JohnMirror
By the way, how can you calculate the height of the item from the position of the caret?
I tried to show a window below the text:

GetWindowRect(SRichViewEdit1.Handle, r);
Window.Top := r.Top + SRichViewEdit1.CaretPos.Y + RVData.DrawItems[SRichViewEdit1.RichViewEdit.CurItemNo].Height;

But it was inside the item.


Later edit:
This code seems to work:


GetWindowRect(SRichViewEdit1.Handle, r);
Window.Top := r.Top + SRichViewEdit1.CaretPos.Y + Round(1.3 * SRichViewEdit1.RichViewEdit.RVData.DrawItems[SRichViewEdit1.RichViewEdit.CurItemNo].Height * SRichViewEdit1.ViewProperty.ZoomPercent / 100);

But I'm not so sure that it's 100% fine...

Posted: Fri Feb 11, 2011 9:45 am
by Sergey Tkachenko
This code shows the popup menu of the bottom right corner of the item [part] containing the caret:

Code: Select all

var rve: TCustomRichViewEdit;
    ItemNo, Part: Integer;
    ItemR, PageR: TRect;
    P: TPoint;
begin
  rve := SRichViewEdit1.RichViewEdit.TopLevelEditor;
  ItemNo := rve.CurItemNo;
  Part :=rve.RVData.GetItemPart(ItemNo, rve.OffsetInCurItem);
  ItemR := SRichViewEdit1.GetItemBounds(rve.RVData, ItemNo, Part);
  PageR := SRichViewEdit1.GetPageClientRect(SRichViewEdit1.CurrentPage);
  P := SRichViewEdit1.ClientToScreen(
    Point(PageR.Left+ItemR.Right, PageR.Top+ItemR.Bottom));
  PopupMenu1.Popup(P.x, P.y);
end;

Posted: Fri Feb 11, 2011 12:49 pm
by JohnMirror
Thank you.
I used your code to also popup the context menu at caret position when the user presses "windows context menu" key:

Code: Select all

procedure TForm1.SRichViewEdit1KeyUp(Sender: TObject; var Key: Word;
   Shift: TShiftState);
var P: TPoint;
   Part: Integer;
   ItemR, PageR: TRect;
begin
   if (Key = 93) and (Shift = []) then
      with Sender as TSRichViewEdit do
      begin
         Part := RichViewEdit.TopLevelEditor.RVData.GetItemPart(RichViewEdit.TopLevelEditor.CurItemNo, RichViewEdit.TopLevelEditor.OffsetInCurItem);
         ItemR := GetItemBounds(RichViewEdit.TopLevelEditor.RVData, RichViewEdit.TopLevelEditor.CurItemNo, Part);
         PageR := GetPageClientRect(CurrentPage);
         P := ClientToScreen(Point(CaretPos.X, PageR.Top + ItemR.Bottom));
         RVAPopupMenu1.Popup(P.X, P.Y);
      end;
end;
It works fine when the menu pops up at the bottom (downwards) but not when it pops up at the top (upwards). It covers the item. In this case "+ ItemR.Top" should be used instead of "+ ItemR.Bottom".
But I don't know a good way to find the direction in advance. And I see that Word has the same problem...

Posted: Sat Feb 12, 2011 6:10 pm
by JohnMirror
Problem.
I found some big rtf's on which the centering function doesn't work well. It goes down dozens of pages after the location.
I tried in ActionTest too, no change.

The code from my friend works fine...

For example on this rtf: http://www.mediafire.com/download.php?g7fzq8qk1eqwhq2

Posted: Thu Feb 17, 2011 2:46 pm
by Sergey Tkachenko
I corrected my code (marked in blue)

Posted: Thu Feb 17, 2011 4:37 pm
by JohnMirror
It is working fine now :)
Thank you very much.

Posted: Thu Jul 07, 2011 11:19 am
by JohnMirror
Hi.
I've been using this code for some time and I noticed a problem with some texts and some particular settings in Page setup.
I am able to reproduce the problem in ActionTest: http://www.mediafire.com/download.php?foy9j2tah06hpdh
Just click on Button2 and after that 2 times on Ok.

You'll get this:

Image Image Image

When the caret is at the first line from the page (the second image) it returns value for ItemR like the position of the caret is measured with an additional hole page.

Is there something that can be done..?
Thank you.

Posted: Fri Aug 12, 2011 9:38 am
by Sergey Tkachenko
Sorry for the delay. This is a bug, it will be fixed in the next update.