[Perspective] Highlight current view in Menu Bar

I could have sworn I saw another post about this, but I’ve searched for the last 30 min or so and haven’t managed to find it.

Is there a way to make a Navigation Menu Tree highlight the active page?

You should be able to through scripting by using system.gui.getOpenedWindowNames. If you use it in a script and compare the results for your main window to the windowPath in the Items for your tree view then you can set your Selected Item number to the window that is open. This should highlight it per how you have the coloring set up for selectedBackground and selectedForeground. I will admit I’m still using 7.9 but I’m assuming the tree view has the same setup. The script function I mentioned, I linked to from 8.0 though.

This is for perspective which is based around CSS styles for the most part, so that route won’t work in this case.

I’ve tried a few of the element state options in the styles, but none of them seem to stay active once the new view loads.

This is the fun of getting new toys. I haven’t had time to play with perspective much yet. But if there are issues with script like that I know I’ll have fun converting some of my projects over.

Vision still exists so shouldn’t have to do any major overhauls just to move to 8.0, but perspective is going to be its own module with its own set of components, layouts, and quirks.

Any update to this? Any idea if there was a way to do this? I was thinking about setting a parm on the man page and then somehow modify that value as each page is selected. Then bind the WEIGHT class to that number basically, if parm == 3 then bold, etc.

Any updates on this? This has to be added in the next release!

For 1st tier of tabs, I use this (a bit annoying):

  1. onItemClick sets the custom.selectedTab property.
  2. Bind style.classes for each props.items item to look at custom.selectedTab and set a Style which highlights the tab

What it looks like:
image
Horizontal menu onItemClicked event:


Item style.classes:

For 2nd tier tabs, or navigational tabs, I use this:


Replace {parent.custom.currentPageURL} with {page.props.path}

The annoying part is having to change the items array index manually for each binding

3 Likes

I don’t have this in a production system yet, but wanted to throw it out there in case it helps anyone. Instead of binding to every item in the Horizontal Menu and Menu Tree, I wrote a couple scripts that rely on the menu onItemClicked event and the event.path property within that event. The event.path is a list of item indexes that leads to the selected item.

First I created a custom session property for holding the current selected path (this is my main menu, so it’s always visible and it comes in handy to have that path available). I then added a message handler on the menu called menu-main-refresh-selection with the following script :

def onMessageReceived(self, payload):
	"""
	This method will be called when a message with the matching type code
	arrives at this component.

	Arguments:
		self: A reference to this component
		payload: The data object sent along with the message
	"""
	def items_loop(parent_ref, path):
		"""Recursively set menu item style since you do not know ahead of time how many layers the menu may have.
		
		Args:
			parent_ref (Component Reference): Reference to the items component property. This reference is used to recursively
				navigate the menu items.
			path (list, ints): From parent event and used to know which items in the path are part of the selection "route".
		"""
		
		for i in range(len(parent_ref)):
			# If item is in the selection path, set to active style, else inactive style.
			if len(path) and i == path[0]:
				parent_ref[i].style.classes = "Menu/Main/Item_Active"
			else:
				parent_ref[i].style.classes = "Menu/Main/Item_Inactive"
			
			# If there are nested menu items, recursive call to set the nested items accordingly.
			if len(parent_ref[i]):
				# If path is not empty and currently looking at the selected path item, pass in the path minus the first
				# item in the path so that we know what to properly highlight in the next layer of recursion. Else, pass 
				# an empty list to indicate everything should be set to an inactive style.
				if len(path) > 1 and i == path[0]:
					items_loop(parent_ref[i].items, path[1:])
				else:
					items_loop(parent_ref[i].items, [])
		return
	
	# If there is no path payload, set menu selection to first item				
	path = payload.get("path")
	if path is None or not len(path):
		path = [0]
	
	self.session.custom.menu_main_path = path
	items_loop(self.props.items, path)

Used a message handler so that I can refresh the selection from anywhere, easily (i.e. - on startup, etc). The menu then has an onItemClicked event script with:

# Set item style. Only want to change styles if the event resulted in navigating to a 
# new Perspective page (external pages do not start with "/", so I don't want to change 
# the selection if it is an external webpage)
if event.enabled and event.target not in ["", None] and event.target[0] == "/":
	system.perspective.sendMessage("menu-main-refresh-selection", {"path": event.path})

Nice thing is, you can add/remove items to the menu without having to update any bindings or scripts (works on as many nested menus as you want). It does loop through all items every time, so I’d imagine it wouldn’t be very performant on large menus. On normal sized menus, it has been plenty fast for my needs. I could prevent this from ever being an issue by only navigating through the current and new paths (should not have to worry about any other items outside of these two paths). It just hasn’t been a priority.

1 Like

Hello! I solved this in a similar way… For the menuTree component, I added a custom variable ‘pagePath’, binded to ‘page.props.path’ giving the path to the currently open view.

Then in a transform script on the variable, I check if any of the items in the menutree has matching target path, and if so, it sets the style class for thet element to a style with a highlighted backround color. (I guess for menu sub elements, a extra check has to be done for each array element)

2 Likes

This is an interesting topic. Thanks for all of the suggestions. Building on what has been discussed what does everyone think about addressing the following:

How can we update the menu tree view to the selected pagePath?

For example if we had some Main View navigation method (e.g. a navigation via a Map), could we update the Menu Tree view (down to specific sub elements of the navigation) to automatically match the newly opened screen?

This work just fine for me. However I don't know if I did it wrong or if it's supposed to be like that but when is not selected the Style Class is overwrited by null.

I gonna share below how I did with couple more images and description.

1, Create Custom properties into your menu item
image

  1. Go an click right, select Events
    image

  2. Use script below to associate with tags created in you Custom.

  3. Bind Style.Classes
    image

  4. Select you custom property associated to the Tab name

  5. Add a Mapping Transform, make sure to select Input Type: Expression and Output: Style Class. Select the Style Class you want to apply to it.

Steps 5 and 6 must be repeated for all Props.Items.

I gonna share another way that I did using a Change Script.

  1. Add a change script
    image

  2. Add following script, change it for the name of the Style Class you want to apply.

def valueChanged(self, previousValue, currentValue, origin, missedEvents):
	if currentValue.value >= 0:
		arrayLength = len(self.props.items)
		arrayRange = range(arrayLength)
		for i in arrayRange:
			itemIndex = currentValue.value
			if i == itemIndex:
				self.props.items[i].style.classes = "Menu-SelectedButton"
			else:
				self.props.items[i].style.classes = "Menu-DeselectedButton"