UMG incorrectly positioning widgets

…that, or the “Viewport Size” node returns incorrect values.

I’m trying to place a lock-on cursor and running into some issues. In the pursuit of debugging the problem, I discovered a really irritating bug: positioning a Canvas slot doesn’t ACTUALLY reflect the proper screen size!

See attached pic:

As you can see, I’m PrintString-ing the Viewport X dimension to prove a point: PIE, the dimensions are 1291 x (something). So, for a widget Anchored to the upper-left of the Root Canvas, and with Alignment set to 0.5 x 0.5, this widget SHOULD appear centered over whatever screen dimensions I feed it. Right?

But, see here: I manually feed it a position of 1290. Now, with the reported Viewport size, that should place it halfway off the screen on the right side (with the center of the widget right at the edge of the viewport) Instead, the game just sort of shoves it over. Arbitrarily, it takes an X value of about 1540 to ACTUALLY place the widget on the edge of the screen; this value doesn’t seem to be related to anything at all (since not only is it not the viewport’s size, but the canvas and game target are 1920x1080, so it’s not related to any underlying assumptions about resolution)

I cannot for the life of me figure out why this thing is acting like this. It seems to me that if I feed it screen coordinates, it should appear at those coordinates, but instead it seems to do some sort of arbitrary adjusting of the screen dimensions.

Okay, so not “apropos of nothing” does this happen.

My widget is 256x256. I can get it to move to the right position by taking the viewport size, ADDING 256, and dividing that by the viewport size.

Which means that when UMG places a canvas, it places it along an axis which is defined as “viewport size + widget size”. So a 256 px wide widget on a 1920 px wide viewport will be placed at the right edge when placed at 2176, and the left edge at 0.

I can work around this with some simple math but I can’t imagine that this behavior is INTENTIONAL

Hello RhythmScript,

I would like to start off by saying that both the node “Set Position” and “Get Viewport Size” are working correctly. This being said, it is due to the fact that the “Set position” node goes off of the canvas panel’s size(1920X1080). Whereas the “Get Viewport Size” is going by the resolution of the viewport (which varies depending on your settings). I have an easy mathematical workaround you can use. Please note that this only works if you have your widget anchored is the upper left corner. Canvas Size Divided by Viewport Size and then multiplied by the actual position you would like to end up with. I hope this helps.

Example:

Make it a great day

1 Like

Rudy, it doesn’t actually work that way. It SHOULD, but it doesn’t. See the above post:

Arbitrarily, it takes an X value of about 1540 to ACTUALLY place the widget on the edge of the screen; this value doesn’t seem to be related to anything at all (since not only is it not the viewport’s size, but the canvas and game target are 1920x1080, so it’s not related to any underlying assumptions about resolution)

In order for the math you’ve supplied to work, you must take the viewport size and ADD the dimensions of the canvas you’re moving. Pic related is how I had to set it up and I have no idea why it should be this way.

Hello RhythmScript,

I have a couple of quick questions for you. This will help get us on the same page.

Quick questions:

  1. Where do you have your anchor set for the widget that you are trying to place?
  2. When you are running the game did you do so in a stand alone version or did you run it in the viewport?
  3. What exactly are you trying to accomplish with the math I provided? If I have a better understanding of your end goal I may be able to provide a different solution to the issue.

I have a few images that explain how anchor points can also be helpful in placing items on screen. This may be a viable solution depending on your situation.

21511-anchorhelp3.png

21513-anchorhelp5.png

I have made an alteration to my previous blueprints. This appears to be a more accurate way to position the widgets. I hope this helps.

Note: I am setting the position of the anchor now instead the position of the widget. If you want a more in depth break down of the math feel free to post a comment.

what is the canvas x and y variables on that image?

Hello fanzypantz,

Canvas x and y are equal to the size of the widgets Canvas panel. Typically these will be equal to 1920x1080 (X= 1920 and Y=1080) I hope this information helps.

Two questions:

  1. Why are you setting the anchor rather than the position?
  2. How do I get the size of the canvas? You said it’s “typically” 1920x1080, but how do I actually find that out?

Hello ,

To answer your questions:

  1. I found this method to to be easier to workaround at the time in that version of the engine.
  2. You can change the size of the canvas by setting the Fill Screen drop down to custom and then setting the X and Y sizes. If you would like to get the viewport size during play, you could do this by using get viewport size.

I hope that this information helps.

Make it a great day

You said that this is a workaround for that version of the engine. Will there be changes to UMG about this topic to make this easier in the future? Say maybe 4.13?

Hello Robinson Company,

The comment was in reference to the age of the original post and about how the methods I was using had changed between engine versions due to changes in UMG at the time.

Hi, your answer looks cool. But I’m not sure how you got the variables Canvas X and Canvas Y. Where did you declare it and how you set its values?

Hello Stranger Games,

I just set their default values to 1920 by 1080 (this was the canvas size for my widget). I hope that this information helps.

Make it a great day

Thanks. However something is still wrong. I think if I did this, I should have the image left upper corner at the middle of the screen, which doesn’t happen.
FVector2D newSize(1920.0f/2.0f * 1920.0f / ViewportSize.X, 1080.0f / 2.0f * 1080.0f / ViewportSize.Y);
imageSlot->SetPosition(newSize);
But thanks anyway!

Is there a better way to do something like this in newer versions of UMG? I took and adapted your script for my project, and it works only for the Y axis, but always stays at X 0 (so it only moves up and down.) Any idea why?

Hello lufkin

There have been updates since this was posted. I would suggest using “Get mouse position Scaled by DPI” I have provided an example below. I hope that this information helps.

Example:

Make it a great day

what is canvas size ?

after so many years the developers didn’t do anything about it but i created function that takes in arguments position in screen where widget needs to be and return FMargin if you set this FMargin for the widget the widget will move to the desired position on the screen
I also noticed that for some reason the widget works in a 1920x1080 screen even though the real screen resolution is 2560x1440 so I set constant values for the screen but you can change them

FMargin WidgetAbsolutePositionToMargin(const int AbsolutePositionX, const int AbsolutePositionY, const UCanvasPanelSlot* WidgetSlot)
{
	const int ScreenResolutionX = 1920;
	const int ScreenResolutionY = 1080;

	FMargin Result;
	auto Anchors = WidgetSlot->GetAnchors();
	auto Size = WidgetSlot->GetSize();
	auto Offsets = WidgetSlot->GetOffsets();

	bool IsHorizontalOffsetsAvialible = Anchors.Minimum.X != Anchors.Maximum.X;
	bool IsVerticalOffsetsAvialible = Anchors.Minimum.Y != Anchors.Maximum.Y;

	float DistanceFromLeftAnchorWall, DistanceFromRightAnchorWall, DistanceFromTopAnchorWall, DistanceFromBottomAnchorWall;

	float AbsolutePositionXFromRightWall = ScreenResolutionX - AbsolutePositionX;
	float AbsolutePositionYFromBottomWall = ScreenResolutionY - AbsolutePositionY;

	DistanceFromLeftAnchorWall = ScreenResolutionX * Anchors.Minimum.X;
	if (IsHorizontalOffsetsAvialible)
	{
		DistanceFromRightAnchorWall = ScreenResolutionX * (1 - Anchors.Maximum.X);
		Size.X = ScreenResolutionX * (Anchors.Maximum.X - Anchors.Minimum.X) - (Offsets.Left + Offsets.Right);
	}

	DistanceFromTopAnchorWall = ScreenResolutionY * Anchors.Minimum.Y;
	if (IsVerticalOffsetsAvialible)
	{
		DistanceFromBottomAnchorWall = ScreenResolutionY * (1 - Anchors.Maximum.Y);
		Size.Y = ScreenResolutionY * (Anchors.Maximum.Y - Anchors.Minimum.Y) - (Offsets.Top + Offsets.Bottom);
	}

	
	Result.Right = (IsHorizontalOffsetsAvialible ? AbsolutePositionXFromRightWall - Size.X - DistanceFromRightAnchorWall : Size.X);
	Result.Left = AbsolutePositionX - DistanceFromLeftAnchorWall;
	Result.Bottom = (IsVerticalOffsetsAvialible ? AbsolutePositionYFromBottomWall - Size.Y - DistanceFromBottomAnchorWall : Size.Y);
	Result.Top = AbsolutePositionY - DistanceFromTopAnchorWall;
	return Result;
}