centering selected text by scrolling

ScaleRichView support and discussion (TRichView add-on for WYSIWYG editing)
Post Reply
JohnMirror
Posts: 13
Joined: Fri Feb 04, 2011 12:05 am

centering selected text by scrolling

Post 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.
Sergey Tkachenko
Site Admin
Posts: 17521
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post 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; 
Last edited by Sergey Tkachenko on Thu Feb 17, 2011 2:46 pm, edited 1 time in total.
JohnMirror
Posts: 13
Joined: Fri Feb 04, 2011 12:05 am

Post 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.
JohnMirror
Posts: 13
Joined: Fri Feb 04, 2011 12:05 am

Post 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...
Sergey Tkachenko
Site Admin
Posts: 17521
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post 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;
JohnMirror
Posts: 13
Joined: Fri Feb 04, 2011 12:05 am

Post 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...
JohnMirror
Posts: 13
Joined: Fri Feb 04, 2011 12:05 am

Post 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
Sergey Tkachenko
Site Admin
Posts: 17521
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

I corrected my code (marked in blue)
JohnMirror
Posts: 13
Joined: Fri Feb 04, 2011 12:05 am

Post by JohnMirror »

It is working fine now :)
Thank you very much.
JohnMirror
Posts: 13
Joined: Fri Feb 04, 2011 12:05 am

Post 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.
Sergey Tkachenko
Site Admin
Posts: 17521
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

Sorry for the delay. This is a bug, it will be fixed in the next update.
Post Reply