Slide Out Side Menu / Off-Screen Pop-Up

I am creating an West Side Menu (Pop-Up window) that slides in from off-screen. There is also a Modal Window (Main Window) which fades in and covers the remainder of the working area.

When the side menu slides back off screen its final location is (-150, 100). Any application re-paint events like opening or closing other windows or re-sizing the application force the side menu back to location (0, 100).

I tried closing the side menu when it is off-screen so it will not be moved during application re-paint events, but it still ends up at x location 0 upon opening.

I was able to get a working method (shown below). I set the side menu’s InternalFrame to transparent, and set rootContainer.visible = False before closing. After opening again, I move the window off-screen then set rootContainer.visible = True.

Is there a better way to implement a slide-out menu? Can I keep the InternalFrame transparent between closing and opening? Could I setup the application repaint event to ignore my pop-up, and keep the pop-up open and off-screen?

from time import sleep
from java.awt import Color
def menuSlide(btn):
	menuSlide.btn = btn
	system.util.invokeAsynchronous(slide)
def slide():
	m = system.nav.openWindow('101 sideMenu')
	o = system.nav.openWindow('101a overlay')
	flag = system.tag.read('CSS\sFlag').value
	if not flag:
		m.setLocation(-150,100)
		m.rootContainer.visible = True
	for i in range (151):
		if flag:
			x = -i
			a = 150 - i
		else:
			x = -150 + i
			a = i
		def paint():
			m.setLocation(x, 100)
			o.rootContainer.setBackground(Color(100,100,100,a))
		system.util.invokeLater(paint)
		sleep(0.0022)
	if flag:
		m.rootContainer.visible = False
		system.nav.closeWindow(m)
		system.nav.closeWindow(o)
	menuSlide.btn.visible = True
	system.tag.write('CSS\sFlag', not flag)

Instead of moving the window you could resize it. I am using a normal floating window for a flyout menu. When the menu button is pressed, the window’s size is changed in the property change event of a timer component:

if event.propertyName=='value':
	window = system.gui.getParentWindow(event)
	currentWidth=window.size.width
	targetWidth=event.source.parent.windowWidth
	step = 4
	
	if targetWidth<currentWidth:
		newWidth = currentWidth - step
		if newWidth <= targetWidth:
			newWidth = targetWidth
			event.source.running = 0
	else:
		newWidth = currentWidth + step
		if newWidth >= targetWidth:
			newWidth = targetWidth
			event.source.running = 0		
	
	if event.newValue>=99:
		event.source.running = 0
		newWidth = targetWidth
		
	window.size=(newWidth,window.size.height)

The components in the menu window are wrapped in a container with anchored layout.

1 Like

I would use system.gui.transform. It will deal with the animation for you. Also, its a single call, no need for the loop. Also, I wouldn’t close the window, just keep it off screen if it is not hitting the db too often.

2 Likes

Definitely the best option, I do the same thing (on components though usually not windows) a lot and it works out pretty well. Make sure to use the callback parameter to do anything that needs to be done after its changed.

The system.gui.transform accepts a JComponent - I know the windows inherit from JComponent, but if I send a window or rootContainer reference I get an error:

win = system.nav.openWindow('window')
system.gui.transform(win, newX=-150, duraiton=0.333)

I get an error caused by RuntimeException: Component is not in a standard container.

Ah yes, you are correct. I normally place my slides outs inside a transparent window and slide it in and out that way. Sorry.

Can you access content behind the transparent window once the menu slides out? I tried it and it didn’t seem to let me click a button behind the window.

Do you play with the layers?

Yes, remove the mouse event and mouse motion events from the transparent window.

1 Like

Hey sorry Kyle, I’m stuck there - I rebuilt my flyout menu in order to use system.gui.transform and it is working splendidly. However I’ve searched around and cannot figure out how to remove the default event handlers. Could you offer some more direction?

My window has an InternalFrameActivated script

win = fpmi.gui.getParentWindow(event) 
win.setOpaque(0)

And my RootContainer has no scripts or actions assigned.

I placed some buttons behind my flyout menu. When the content container is moved off screen I can see the buttons but not interact with them.

I was unable to allow mouse events to penetrate an open window to reach components behind the window.

However, using system.gui.transform to slide a container in a window off-screen instead of sliding the entire window off-screen meant the negative X-coordinate of the container was saved between closing and opening of the window.

As a result, I opted to close the flyout menu window and overlay window using a callback from the system.gui.transform method. Since the X-coordinate of the container is saved I was able to eliminate extra flags and use the coordinates as my conditionals.

This code will:

  • Open a floating window called sideMenu that is configured with position(0,0) and layout anchored to North, South, West

  • Move a container in sideMenu on and off the screen. This container holds navigation buttons

  • Simultaneously open a floating full-screen window called overlay

  • Fade the overlay background color transparency up and down

  • Close both sideMenu and Overlay upon retraction / fade down

#In project library script 'CSS'
#Call with this line of code: system.util.invokeAsynchronous(project.CSS.flyout)
from time import sleep
from java.awt import Color
def flyout():
	w = system.nav.openWindow('101 sideMenu')
	c = w.getRootContainer().getComponent('cont menu')
	o = system.nav.openWindow('101a overlay')
	if c.location().x == 0:
		system.gui.transform(c, newX = -c.size.width, duration = 250, callback=project.CSS.cleanup)
		fade(o, 0, -3, 0.0033)
	if c.location().x < 0:
		system.gui.transform(c, newX = 0, duration = 250)
		fade(o, 150, 3, 0.0033)

def fade(o, a2, s, d):
	a = o.getRootContainer().getBackground().getAlpha()
	def run():
		for i in range(a,a2,s):
			def paint():
				o.rootContainer.setBackground(Color(255,255,255,i))
			system.util.invokeLater(paint)
			sleep(d)
	system.util.invokeAsynchronous(run)

def cleanup():
	system.nav.closeWindow('101 sideMenu')
	system.nav.closeWindow('101a overlay')
1 Like