Eto Control.PointToScreen returns wrong coordinates

Hey Developers,

working with Eto.Forms, I’m trying to get the ClientSize of Rhino.UI.RhinoEtoApp.MainWindow but it isn’t implemented:

I have a Windows-specific hack using user32.dll to get the ClientRectangle but a cross-platform solution would be great.

        [DllImport("user32.dll")]
        private static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);

To be clear, I mean the following window. In my understanding, Eto uses the upper left point of this rectangle as origin for its coordinate system.

1 Like

I need this information to position floating UI elements around other Eto controls. Control.PointToScreen uses a coordinate system with its origin situated below the Windows menu bar, which results in an offset in relation to the parent Eto control.

I currently do this:

        var controlToLogicalScreen = ControlToDockTo.PointToScreen(dockingLocation);
        var logicalScreenToNativeScreen = EtoHelpers.LogicalToScreen(controlToLogicalScreen );
        var screenToAbsolute = new Point(OffsetPoint(logicalScreenToNativeScreen ));
        var absoluteToLogical = new Point(EtoHelpers.ScreenToLogical(logicalToScreen));

Where LogicalToScreen and ScreenToLogical are methods suggested by @curtisw in this thread:

and OffsetPoint is a method using user32.dll to find the ClientRectangle of the main Rhino window.

RhinoView gives us access to ScreenRectangle, which can be nicely translated to Eto’s logical screen coordinates. Is there a similar way of retrieving true screen coordinates of Eto controls?
@CallumSykes, @dale, maybe you can help?

Hey @mrhe,

The RhinoEtoApp.MainWindow is not a true Eto Window, so doesn’t have all of the properties set. That being said, let’s review why you want this. You want to position elements on the screen relative to elements in your panel?

Thanks @CallumSykes,

yes, I want to create custom tooltips whose position is relative to other Eto controls. Some of these will be hosted on the panel, others are attached to viewport as HUD elements. The tooltip is a simple Eto.Forms.Form.

I have solved the offset issue. Control.PointToScreen works as expected and returns the correct screen coordinate.

The reason why it was failing for me, was because the form was attached to a native Window using user32.dll. Commenting it out fixes the offset, but creates another question: how can we make a floating form move with the main Rhino window? I need this to create fixed HUD elements. Win32Window.AddControl does the trick on Windows but is there a cross-platform solution I could use from Eto?

public class DockedForm : Form
{
    public Control ControlToDockTo;
    public bool DockedToViewport;
    public bool DockedToControl;

    public DockedForm()
    {
        //var mainWindow = new System.Windows.Win32Window(RhinoApp.MainWindowHandle());
        //mainWindow.AddControl(new System.Windows.Win32Window(NativeHandle)); // Move with Rhino window when dragging
        base.WindowStyle = WindowStyle.None;
        Style = "transparent";
        RhinoView.Modified -= RhinoView_Modified; // Move with Rhino window when resizing
        RhinoView.Modified += RhinoView_Modified;
    }
// Remaining implementation
}
        public void AddControl(Win32Window Child)
        {
            Child.Style = WinAPI.WindowStyles.WS_CHILD;
            Child.Parent = this;
        }

Awesome!

When you say tooltips, you mean similar to when you hover over a control and a small bit of text pops up then goes away?

Would this be tooltips or other items? Tooltips generally dissapear in this scenario.

I think given the MainWindow is not 100% Eto, this might not (currently) be possible. I’m assuming Window.LocationChanged is not implemented?

@curtisw should be able to clarify :slight_smile:

1 Like

Yeah, there are 2 use cases for this docked form:

  1. Tooltip appearing on hover, and disappearing on mouse leave
  2. More permanent popup either docked to the viewport (HUD), or relative to another Control

For clarity, here is a HUD menu example:

I can subscribe to this event, but it never fires:

            button.ParentWindow.LocationChanged += (o, e) =>
            {
                RhinoApp.WriteLine("Moving");
            };

On another note, is there a way of retrieving the location of this window? Currently, I iterate over all RhinoDoc.ActiveDoc.Views and get the extreme coordinates, but this approach is not robust to scenarios with missing viewports as shown below:


Hmm, it doesn’t seem to be possible to subscribe to any of the events of the main window.

button.ParentWindow.SizeChanged
button.ParentWindow.WindowStateChanged
button.ParentWindow.LocationChanged
button.ParentWindow.GotFocus

None of these work. Eto’s source indicates that at least some of them should be implemented. Any ideas how to fix this?

Hey @mrhe,

As @CallumSykes mentioned, RhinoEtoApp.MainWindow doesn’t return a usable Eto Window. The only real purpose of it is to use a a parent for some other Eto form.

Keep in mind that Rhino on Windows uses MFC for it’s main user interface framework.

If you want to subscribe to the Windows message you’ve mentioned, you might looking to setting up a Windows hook.

– Dale

2 Likes

Ah thinking about this, you mean, even if this view isn’t there.
I’ve not found a better way myself. I’ve only ever cycled through views.

I can see that creating the HUD in the pipeline would solve the movement issue, unless the view doesn’t exist…

I’ve been doing HUDs in the display pipeline for years, but they have one major drawback - the view needs to be redrawn on each mouse move to allow for user interaction. With heavier models things get laggy fast.

It would be great if the events listed above were relayed to their native counterparts. Could this be added to the wish list?