I'm working with the Horizontal Menu component and im trying to get something similar to what is on the tab containers where when you select a tab it will highlight. I've gotten a script working that does this for are top level of tabs but if I have more then one layer of tabs the others don't get highlighted and Im looking for some help making it so that they will. I've made a for loop on a test script and was able to get one more layer of those tabs to highlight but Im hopping there is a way to make it dynamic so I don't need to add a for loop each time we add another layer to are menu. If anyone has already made a script for the menu that does what Im talking about.
(Bellow is the script i made that was able to get the first two layers of the menu to be highlighted but things fell apart when i tried adding the 3rd layer)
# look through the entire menu tree
for i in range(len(self.props.items)):
# if the current index is the index we are looking for
if i == currentValue.value[0].value:
# change background color to yellow
self.props.items[i].style.classes = "Components/HorizontalMenu/HorizontalMenu_Selected"
# if we have a sub index tree selected
if self.props.items[i].items is not None:
# perform the same operation as above
for j in range(len(self.props.items[i].items)):
if j == currentValue.value[1].value:
self.props.items[i].items[j].style.classes = "Components/HorizontalMenu/HorizontalMenu_Selected"
if self.props.items[i].items[j].items is not None:
# perform the same operation as above
for t in range(len(self.props.items[i].items[j].items)):
if t == currentValue.value[1].value:
self.props.items[i].items[j].items[t].style.classes = "Components/HorizontalMenu/HorizontalMenu_Selected"
else:
self.props.items[i].items[j].items[t].style.classes = "Components/HorizontalMenu/HorizontalMenu_Deselected"
# deselect the previous selected tabs
else:
self.props.items[i].items[j].style.classes = "Components/HorizontalMenu/HorizontalMenu_Deselected"
else:
# change the background color to black
self.props.items[i].style.classes = "Components/HorizontalMenu/HorizontalMenu_Deselected"
if self.props.items[i].items is not None:
# perform the same operation as above
for j in range(len(self.props.items[i].items)):
self.props.items[i].items[j].style.classes = "Components/HorizontalMenu/HorizontalMenu_Deselected"
if self.props.items[i].items[j].items is not None:
# perform the same operation as above
for t in range(len(self.props.items[i].items[j].items)):
self.props.items[i].items[j].items[t].style.classes = "Components/HorizontalMenu/HorizontalMenu_Deselected"
(Bellow is another attempt at the script above but is slightly different and doesn't have a for loop implemented yet.)
if len(currentValue.value) > 0:
# grab index out of the list for top-level item
itemIndex = currentValue.value[0].value
# # highlight the corresponding menu item's style
self.props.items[itemIndex]["style"]["classes"] = "Components/HorizontalMenu/HorizontalMenu_Selected"
# now, do similar logic for unhighlighting
if len(previousValue.value) > 0:
itemIndex = previousValue.value[0].value
self.props.items[itemIndex]["style"]["classes"] = "Components/HorizontalMenu/HorizontalMenu_Deselected"
Best bet is to make a recursive function. Entirely untested bash of code that I use for highlighting searched terms in a tree display (which has the same item format as the menu):
SELECTED_CLASS = "Components/HorizontalMenu/HorizontalMenu_Selected"
UNSELECTED_CLASS = "Components/HorizontalMenu/HorizontalMenu_Deselected"
def recursiveSetHighlight(items, selection, idx=0):
"""
Recursively searches through a menu structure and highlights selected item and parent items
"""
highlightParent = False
for itemIdx, item in enumerate(items):
if idx < len(selection) and itemIdx == selection[idx]:
item['style']['classes'] = SELECTED_CLASS
highlightParent = True
# Remove leading spaces left over from last search pass
else:
item['style']['classes'] = UNSELECTED_CLASS
if len(item['items']):
item['items'], childHasHighlight = recursiveSetHighlight(item['items'], selection, idx+1)
# If any child has a highlight, mark that the parent of this item needs to be highlighted
if childHasHighlight:
item['style']['classes'] = SELECTED_CLASS
highlightParent = True
return items, highlightParent
selection
is expecting a list of node indexes, like [0,1,2,3,0].
Based on your code you could probably do [item.value for item in currentValue.value]
to convert your selection data to the expected format.
The expected use of this function is
selection = [item.value for item in currentValue.value]
cleanedStructure = project.util.sanitizeIgnitionObject(self.props.items)
highlightedStructure = project.menu.recursiveSetHighlight(cleanedStructure, selection)[0]
self.props.items = highlightedStructure
Util Function:
def sanitizeIgnitionObject(element):
if hasattr(element, '__iter__'):
if hasattr(element, 'keys'):
return dict((k, sanitizeIgnitionObject(element[k])) for k in element.keys())
else:
return list(sanitizeIgnitionObject(x) for x in element)
return element
I will give this a try thanks for the response.
Do yourself a quick favor before testing this code, copy your menu items to another custom property somewhere as a backup in case the function has issues.
If for some reason it mangles your menu items then you can just copy/paste from the backup instead of rebuilding your menu by hand
Good idea thanks
Ok I implemented the code you had given and it seem to work in selecting and deselecting but there is a problem if you have two tabs that can then go a 3rd layer deep they will both be highlighted along with what ever tab you select under on the respective numbered one under the other will also be highlighted.
Ah, I messed up. My code is only looking that the current level item index matches the number in the selection list at the same level, without checking if the parent is selected.
Originally the code was for looking for text in each item in a tree, so it would highlight multiple things in every level. I just took that and modified it for my example code. Whoops.
Fixed code, also smaller:
def recursiveSetHighlight(items, selection, parentSelected=False, idx=0):
"""
Recursively searches through a menu structure and highlights selected item and its parents
"""
selected = False
for itemIdx, item in enumerate(items):
# Allow item highlight if this is first level of menu or
# item index matches number at same level in selection list
if (parentSelected or idx == 0) and idx < len(selection) and itemIdx == selection[idx]:
item['style']['classes'] = SELECTED_CLASS
selected = True
# If this is not the item we want, unselect it
else:
item['style']['classes'] = UNSELECTED_CLASS
selected = False
# Apply Highlighting to child items
if len(item['items']):
item['items'] = recursiveSetHighlight(item['items'], selection, selected, idx+1)
return items
Remove the [0]
after recursiveSetHighlight
in your call to use the function:
selection = [item.value for item in currentValue.value]
cleanedStructure = project.util.sanitizeIgnitionObject(self.props.items)
highlightedStructure = project.menu.recursiveSetHighlight(cleanedStructure, selection)
self.props.items = highlightedStructure
Edit: added missing selected = False
in else statement
Prefect thanks for the help the only thing that i noticed was it was setting some on the 3rd level of it at the same time but if you just add a
selected = False
in the else it starts to work as intended. thanks for the help
def recursiveSetHighlight(items, selection, parentSelected=False, idx=0):
"""
Recursively searches through a menu structure and highlights selected item and its parents
"""
SELECTED_CLASS = "Components/HorizontalMenu/HorizontalMenu_Selected"
UNSELECTED_CLASS = "Components/HorizontalMenu/HorizontalMenu_Deselected"
selected = False
for itemIdx, item in enumerate(items):
# Allow item highlight if this is first level of menu or
# item index matches number at same level in selection list
if (parentSelected or idx == 0) and idx < len(selection) and itemIdx == selection[idx]:
item['style']['classes'] = SELECTED_CLASS
selected = True
# If this is not the item we want, unselect it
else:
item['style']['classes'] = UNSELECTED_CLASS
selected = False
# Apply Highlighting to child items
if len(item['items']):
item['items'] = recursiveSetHighlight(item['items'], selection, selected, idx+1)
return items