This is a migrated thread and some comments may be shown as answers.

Mouse Over Custom Annotation Effect

10 Answers 313 Views
RichTextBox
This is a migrated thread and some comments may be shown as answers.
Robert
Top achievements
Rank 1
Robert asked on 09 May 2012, 02:39 AM
Hi there,

Does anyone know how to go about creating mouse over effects for custom annotations?
For example, if I "mouse over" between a custom annotation range I may want the font colour, or font size to change or to even highlight the annotation. Going even further, maybe have some way to activate a little popup window which in turn may display more detailed information about the annotation properties (I guess that's similar to the Comments Annotations feature).

Any information would be really handy.

Thanks for your time,

Rob

10 Answers, 1 is accepted

Sort by
0
Alex
Telerik team
answered on 14 May 2012, 09:48 AM
Hi,

The suggested approach in scenarios like these is to create custom UILayer. You can read more about how to do that in this help article or check out out this online demo. However, there are some limitations when using UILayers, as they are updated after the layout of the document is already calculated. So you can add additional UI within the RadRichTextBox control, but you cannot affect the current layout of the document inside it. For example, you can add highlight over the elements in your custom annotation, but changing the font size means that  document's layout should be invalidated and it is not recommended to do that, inside the UILayer. 

The other part of the API that you will probably need are the GetDocumentPositionFromViewPoint and GetViewPointFromDocumentPosition methods of the current presenter that is showing the document (accessible trough the ActiveEditorPresenter property of the RadRichTextBox). These will help you to translate the coordinates that you get form the MouseMove event to an actual position inside the document you are editing and vice versa.

Please don't hesitate to contact us again if you need more help.

Kind regards,
Alex
the Telerik team

Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

0
Robert
Top achievements
Rank 1
answered on 25 May 2012, 07:16 PM
Thank you Alex. I will certainly look into these points you made when I come to this job.
0
Robert
Top achievements
Rank 1
answered on 20 Jun 2012, 11:06 AM
Hi Alex,

I have tried the following but I don't ge the correct result.
Any suggestions?

private void radRichTextBox_MouseMove(object sender, MouseEventArgs e)
{
    Point mousePosition = PointToScreen(Mouse.GetPosition(this));
 
    DocumentPosition mouseDocumentPosition = this.radRichTextBox.ActiveEditorPresenter.GetDocumentPositionFromViewPoint(mousePosition);
    AnnotationRangeMarkerBase annotation = RadDocumentExtensions.GetPreviousAnnotationMarkerEndAndStartRanges(mouseDocumentPosition);
    MessageBox.Show(annotation.ToString());
}


Here's the code I use to get the annotation marker from the mouse position:
public static AnnotationRangeMarkerBase GetPreviousAnnotationMarkerEndAndStartRanges(DocumentPosition position)
{
    InlineLayoutBox inlineLayoutBox = position.GetCurrentInlineBox();
 
    do
    {
        inlineLayoutBox = (InlineLayoutBox)DocumentStructureCollection.GetPreviousElementOfType(inlineLayoutBox, typeof(AnnotationMarkerLayoutBox));
    }
    while (inlineLayoutBox != null && (!(inlineLayoutBox.AssociatedInline is AnnotationRangeStart) && !(inlineLayoutBox.AssociatedInline is AnnotationRangeEnd)));
 
 
    if (inlineLayoutBox == null)
    {
        return null;
    }
 
    return inlineLayoutBox.AssociatedInline as AnnotationRangeMarkerBase;
}


thanks,

Rob

0
Robert
Top achievements
Rank 1
answered on 20 Jun 2012, 11:46 AM
Ok this works a little bit better but the point location isn't accurate.

private void radRichTextBox_MouseMove(object sender, MouseEventArgs e)
{
    Point mousePoint = PointToScreen(Mouse.GetPosition(this));
    Point docPoint = this.radRichTextBox.ActiveEditorPresenter.GetDocumentPointFromViewPoint(mousePoint);
 
    DocumentPosition mouseDocumentPosition = this.radRichTextBox.ActiveEditorPresenter.GetDocumentPositionFromViewPoint(docPoint);
 
    AnnotationRangeMarkerBase annotation = RadDocumentExtensions.GetPreviousAnnotationMarkerEndAndStartRanges(mouseDocumentPosition);
    if (annotation != null)
    {
        //MessageBox.Show(annotation.ToString());
        if (annotation is SemanticRangeStart || annotation is SemanticRangeEnd)
        {
            SemanticRangeStart product = RadDocumentExtensions.GetPreviousAnnotationRangeStart<SemanticRangeStart>(mouseDocumentPosition);
            MessageBox.Show(product.Product.Name + "    " + product.Product.ID);
        }
    }
}
0
Robert
Top achievements
Rank 1
answered on 20 Jun 2012, 02:12 PM
Ok I managed to find one of your old posts showing a similar example.

http://www.telerik.com/community/forums/silverlight/richtextbox/moving-image.aspx

This now works for me (although I do have to offset the Y value slightly).

private void radRichTextBox_MouseMove(object sender, MouseEventArgs e)
{
    Point mousePoint = e.GetPosition(this);
    mousePoint.Y -= 20;
 
    DocumentPosition mouseDocumentPosition = this.radRichTextBox.ActiveEditorPresenter.GetDocumentPositionFromViewPoint(mousePoint);
 
    AnnotationRangeMarkerBase annotation = RadDocumentExtensions.GetPreviousAnnotationMarkerEndAndStartRanges(mouseDocumentPosition);
    if (annotation != null)
    {
        //MessageBox.Show(annotation.ToString());
        if (annotation is SemanticRangeStart || annotation is SemanticRangeEnd)
        {
            SemanticRangeStart product = RadDocumentExtensions.GetPreviousAnnotationRangeStart<SemanticRangeStart>(mouseDocumentPosition);
            MessageBox.Show(product.Product.Name + "    " + product.Product.ID);
        }
    }
}
0
Robert
Top achievements
Rank 1
answered on 20 Jun 2012, 03:35 PM
I have an example that turns on annotation UILayers from one of your demos which works well. However, I can't figure out how to assign the layer only to a specific annotation at the mouse position and for it to turn off when the mouse leaves.

I can see from the demo example, HightlightCurrentLine & HighlightCurrentWord, you override the OnDocumentChanged & Changing methods and assign CaretPositionChanged events.

protected override void OnDocumentChanged()
{
    base.OnDocumentChanged();
    if (this.Document != null)
    {
        this.Document.CaretPosition.PositionChanged += CaretPosition_PositionChanged;
    }
}
 
protected override void OnDocumentChanging()
{
    base.OnDocumentChanging();
    if (this.Document != null)
    {
        this.Document.CaretPosition.PositionChanged -= CaretPosition_PositionChanged;
    }
}
 
 
 
private void CaretPosition_PositionChanged(object sender, EventArgs e)
{
    this.UpdateViewPort(this.LastUpdateContext);
}

I can't find a way to assign RadRichTextBox_MouseMove event. ** if that is the correct way to achieve what I'm looking for **
0
Alex
Telerik team
answered on 25 Jun 2012, 02:30 PM
Hi,

You can get to the RadRichTextBox control from the UILayerUpdateContext like this: (RadRichTextBox)context.Presenter.Owner. However I can suggest you a slightly different approach. You can create elements needed for the highlight and add them to the layer but with a low opacity. This way you can attach the mouse events directly to them and only change their opacity when the mouse is over them. You can also add a tool tip with the additional information you need to show about the elements.
I've attached a simple project that demonstrates this approach. There is a layer that will highlight only the words with text "test" in the document when the mouse is over them and also show a tooltip . 
I hope this will help you to move on.

All the best,
Alex
the Telerik team

Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

0
Robert
Top achievements
Rank 1
answered on 26 Jun 2012, 12:21 AM
I Alex,

Thank you very much for your demo. It was a huge help. I now have a much better idea of how the custom layers work.

I have modified your code so that the annotations are applied to my semantic ranges (please let me know if you think there is a better way of achieving this).
public override void UpdateUIViewPortOverride(UILayerUpdateContext context)
{
    foreach (AnnotationMarkerLayoutBox annotationMarkerLayoutBox in context.GetVisibleLayoutBoxes().Where(s => s.AssociatedDocumentElement is SemanticRangeStart))
    {
        AnnotationMarkerLayoutBox endAnnotationLayoutBox = annotationMarkerLayoutBox;
         
        while (!(endAnnotationLayoutBox.AssociatedDocumentElement is SemanticRangeEnd))
        {
            endAnnotationLayoutBox = (AnnotationMarkerLayoutBox)DocumentStructureCollection.GetNextElementOfType(endAnnotationLayoutBox, typeof(AnnotationMarkerLayoutBox));
        }
 
        this.AddRectangle(annotationMarkerLayoutBox, endAnnotationLayoutBox);
    }
}

private void AddRectangle(InlineLayoutBox startRect, InlineLayoutBox endRect)
{
    Rectangle rectangle = new Rectangle();
    rectangle.Width = Math.Max(0, (endRect.BoundingRectangle.Location.X - startRect.BoundingRectangle.Location.X));
 
    rectangle.Height = startRect.LineInfo.Height;
 
    Canvas.SetTop(rectangle, startRect.ControlBoundingRectangle.Top);
    Canvas.SetLeft(rectangle, startRect.BoundingRectangle.Left);
 
    rectangle.Fill = FillBrush;
    rectangle.Opacity = MouseOverHighlightLayer.MouseOutOpacity;
    rectangle.MouseEnter += (s, e) => { ((Rectangle)s).Opacity = MouseOverHighlightLayer.MouseInOpacity; };
    rectangle.MouseLeave += (s, e) => { ((Rectangle)s).Opacity = MouseOverHighlightLayer.MouseOutOpacity; };
    ToolTipService.SetToolTip(rectangle, "This is a sample tooltip");
 
    base.AddDecorationElement(rectangle);
}

The only problem I have is that the Top and bottom positions are not reporting the correct locations. It is as if the bounding rectangle is offset. You can see what I mean by taking a look at the attached image.
 
It is obvious to see that the top edge of the rectangle layer should be the bottom position. I came across this issue in another situation when trying to record the location of an annotation. I guess I can manually offset the Y position to compensate for this. Do you know of any other solutions?

Thank you again for all of your help.

Rob




0
Robert
Top achievements
Rank 1
answered on 26 Jun 2012, 12:40 AM
I can offset the top position by doing the following:
Canvas.SetTop(rectangle, startInline.ControlBoundingRectangle.Top - (startInline.LineInfo.Height / 1.5));

It isn't ideal, but it will do for now as fairly good quick fix.

0
Alex
Telerik team
answered on 29 Jun 2012, 07:21 AM
Hello,

You've made great progress so far. The reason for the strange offset is that the bounding rectangles of the annotations are really small ant they are positioned on baseline of the current line. So using the Top of the bounding rectangle of the AnnotationLayoutBox, for positioning the UI elements you've created, will produce such results.
However there is a solution to your problem -  to calculate the Y coordinate of the line that contains the annotation box. Here is how this can be done (similar method is used in the online demo:

private static float GetLineY(InlineLayoutBox box)
{
    return box.ControlBoundingRectangle.Top - (box.LineInfo.BaselineOffset - box.BaselineOffset);
}

Now that you have this method , you can set the Canvas.Top property of the Rectangle element you've created this way:
Canvas.SetTop(rectangle, GetLineY(startRect));

I hope this makes sense. 

Kind regards,
Alex
the Telerik team

Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

Tags
RichTextBox
Asked by
Robert
Top achievements
Rank 1
Answers by
Alex
Telerik team
Robert
Top achievements
Rank 1
Share this question
or