8.1.4 Perspective openPopup new arg viewportBound doesn't and doesn't resize apply if position supplied opens it off screen


If you use the system.perspective.openPopup function to open a popup at the mouse cursor and resize popup via the position arg with the new viewportBound option set to True, then the popup may open off the screen and if so, it won’t resize. If the off-screen popup is then moved, its position is then correctly bound to the viewport, but the popup is not sized according to the width/height specified in the position argument.

If the popup is opened within the bounds, then all is good.

1 Like

Could you post a screenshot of the Popup configuration you have in place? I’m trying to replicate this and have so far been unable to. Part of it could be the wording in your post; it reads as if you’re using a script and the Popup action at the same time, because you call out a script, but then you specify that the checkbox is checked.

I updated the wording in my post, I’m using purely scripting to open the popup.

This is my script, might be hard to test it without the stuff it relies on… but you could just pull out the call to the openPopup function:

def openDevicePopup(self, event):
	Opens up the standard device popup and sizes it according to the typeId of the device using the lookup table tag.
	controlEnable =  self.view.params.controlEnable
	deviceParentPath = self.view.params.deviceParentPath
	deviceName = self.view.params.deviceName
	popupID = 'device-popup-%s-%s' % (deviceParentPath, deviceName)
	popupHeightDefault = 550
	popupHeight = popupHeightDefault
		TypeId = system.tag.readBlocking([deviceParentPath + '/' + deviceName + '.typeId'])[0].value
#		system.perspective.print('TypeID: {}'.format(TypeId))
		UDTLookupData = system.dataset.toPyDataSet(system.tag.readBlocking(['[default]System/Datasets/UDTPopupPaths_Perspective'])[0].value)
#		system.perspective.print('UDTLookupData: {}'.format(UDTLookupData))
		for i, row in enumerate(UDTLookupData):
			if row['UDTParentType'] == TypeId:
				popupHeight = row['PopupHeight']
		# TODO: error checking...
	system.perspective.print('popupHeight: {}'.format(popupHeight if popupHeight != 0 else '<default>'))
	if popupHeight == 0:
		popupHeight = popupDefaultHeight
								 view='_Templates/Devices/Control/Device Popup Individual'
										 ,'popupId': popupID
										 ,'popupHeight': popupHeight}

So, wait… You’re intentionally opening it out of bounds, but you’re also trying to restrict it to be bound to the viewport?

Well, I can’t check the bounds myself and I want to do more stuff than I can do using the Popup action, so I have to do my own “open at mouse cursor” code. But due to not being able to check how large the viewport is, I was relying on the viewportBound to constrain it. To me, if the condition is checked, then it shouldn’t let a popup open outside of the bounds

The viewportBound property will do it’s best to resize or re-position a popup such that the popup is not opened off of the viewport, but if you expressly define a position which is off the viewport, then we have to abide by your very specific demands as to where the popup should open. Once the popup is moved, we then take the opportunity to “snap” the popup to be within the viewport.

The problem here is you are defining two very contradictory behaviors. Your script is expressly telling the application to open a popup outside the viewport, and then you’re telling the application to not allow the popup to open outside the viewport.

That’s fair enough, but I can’t do this any other way as I don’t have any visibility of how large the viewport is :confused: So I’m stuck either opening every device popup in the middle of the screen, or opening the popup for devices on the bottom half of the page half off the screen, neither of which are ideal.

Do you know when the viewport dimensions will be available in Perspective?

In your script, what do clientX and clientY refer to? I guess what I would like to know is why you need to open the Popup “up” 200px…

They come from the event passed into it from a button onActionPerformed action.

So couldn’t you perform your own check to see if clientY-200 is less than 0? Also, I suspect this is actually an onClick action.

These are clientY/X below. They’re just the mouse coords, I don’t have any context of where that is in relation to the bounds of the viewport

That’s a good question… The script wasn’t working and I just jumped back onto it, so from memory it was just part of testing. It shouldn’t be in there. It’s gone now :slight_smile: I think it was there for any devices on the very bottom of the screen so that the operator could actually see at least some of the popup… I think I still need it in there for now

I just checked in a browser, and the clientY is the distance from the top of the viewport to the pixel in which the click event occurred. So you don’t need to know anything about the viewport, you just need to know if the clientY value is more than 200. If it is not, then you need to adjust that “top” position to be clientY.

That works for buttons calling popups at the top of the page, but not for those at the bottom. There’s no way to know how ‘deep’ the page is with just a from-top and left mouse coord. The 200px “up” was just to lift up those opened when the mouse was positioned at the bottom of the screen, otherwise you end up with this (black bottom part is “off the screen”) i.e. you just see the titlebar and nothing else:

What I need to do is not fix the 200px, and make it dynamic based on the viewport dimensions and the height of the popup, and the mouse coord

Ah, yes. The only way to handle cases like that via scripting at this time is to make an educated guess in the logic you’re using to open the popup.

Something like

if event.clientY >= popupDefaultHeight:
    # build positional array here, using "bottom" instead of top.
    # build positional array as you've been doing, but minus the 200 modifier.
1 Like

Oh… I totally missed that I could use that :upside_down_face: that’s what I get for working till 3am :confused:

Actually, this works too:

	position = {'left':event.clientX
	if event.clientY >= popupHeight:
		# a bit dodgy but it's the best we can do without knowing the viewport dimensions...
		position['top'] = event.clientY - popupHeight
		position['top'] = event.clientY	

I think there’s still a bug with the resizing though if it’s opened off the screen - it makes it far taller when you drag it. I set the height to 450, but if opened off the page and dragged into view, it’s about 750.

Is this the same problem, or am I just doing something wrong?

Example with viewportbound:

Example without viewportbound:

Thank you.

There are three things going on in the example which includes use of viewportBound:

  1. Even when viewportBound is True, we must above all else honor the specified position of the Popup. As a result, your Popup absolutely will be opened at the event.clientX and event.clientY position. This means that your Popup will be opened with some of the content partially outside of the viewport. (Working as expected)
  2. When a Popup is viewport-bound, and has any portion of itself outside the viewport bounds, and the Popup is dragged/resized, the Popup will immediately reposition itself inside the viewport boundaries. (Working as expected)
  3. When the popup repositions itself, it must redraw itself by calculating the new origin (top-left corner) and overall dimensions of the Popup based on the current position and the dimensions of the Popup. (NOT working as expected)

I’ll open an internal ticket to track this issue and get it resolved.

In the meantime, this can be worked around by not specifying a position for the Popup, OR by using the Popup Action instead and using a relative positioning approach.