Only allow visible items to be selected in SelectionEventHandler

Only allow visible items to be selected in SelectionEventHandler

ebunn3
Advocate Advocate
825 Views
6 Replies
Message 1 of 7

Only allow visible items to be selected in SelectionEventHandler

ebunn3
Advocate
Advocate

Is there a way to set up a SelectionEventHandler to ignore selections that are not visible. (isVisible = False)?

 

Thanks,

Eric

class MySelectHandler(adsk.core.SelectionEventHandler):
    """When a select button is active and something is selected this function responds to the event.
    Differentiate the select buttons using the activeSelectionInput.id function and build if statements to run specific
    code for the different select buttons"""
    def __init__(self):
        super().__init__()
        self.units = units
    def notify(self, args):
        app = adsk.core.Application.get()
        ui = app.userInterface
        try:
            eventArgs = adsk.core.SelectionEventArgs.cast(args)
            activeSelectionInput = eventArgs.firingEvent.activeInput
            type = args.selection.entity.objectType#;print(type)
            if type == 'adsk::fusion::Occurrence':
                selectedBody = adsk.fusion.Occurrence.cast(args.selection.entity) 
            elif type == 'adsk::fusion::BRepBody':
                selectedBody = adsk.fusion.BRepBody.cast(args.selection.entity) 
            else:
                ui.messageBox("Choose either a component or a single body only.")
                return
            # Get the values from the command inputs.
            inputs = eventArgs.firingEvent.sender.commandInputs

            if selectedBody:
                # #customize this for the number of select buttons on the form.  Find them by id.
                if activeSelectionInput.id == 'cushBody':
                    globList[0].append(selectedBody)
                    
            if activeSelectionInput.id == 'prodBody':
                globList[1].append(selectedBody)

        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

 

0 Likes
Accepted solutions (1)
826 Views
6 Replies
Replies (6)
Message 2 of 7

tykapl.breuil
Advocate
Advocate

I don't see any other way to do it other than adding a check on your selectHandler and when the selected item isn't visible, getting every item from the involved selection on a list, clearing that selection then re-adding every item but the last one. It's a bit clumsy but I don't know of a way to remove an item from a selection input. Maybe setting then removing a limit could work ?

Message 3 of 7

j.han97
Advocate
Advocate

There is this isSelectable property for BRepBody and Occurrence which in theory, could be used to exclude them for selections:

item.isSelectable = item.isVisible

However, I have not tried this method yet though.

Message 4 of 7

kandennti
Mentor
Mentor

Hi @ebunn3 .

 

Instead of deselecting them, how about not letting them select the ones that aren't shown?

 

By using the PreSelect event, it is possible to get the element under the mouse cursor, and depending on the condition, it is possible to prevent selection.

 

In the following sample, a body that is not displayed is not selected.

# Fusion360API Python script

import traceback
import adsk.cam
import adsk.fusion
import adsk.core

_app: adsk.core.Application = None
_ui: adsk.core.UserInterface = None
_handlers = []

class MyPreSelectHandler(adsk.core.SelectionEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.SelectionEventArgs):
        if not args.selection.entity.isVisible:
            args.isSelectable = False

class MyCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()

    def notify(self, args):
        try:
            global _handlers
            cmd = adsk.core.Command.cast(args.command)
            cmd.isOKButtonVisible = False

            inputs: adsk.core.CommandInputs = cmd.commandInputs

            onDestroy = MyCommandDestroyHandler()
            cmd.destroy.add(onDestroy)
            _handlers.append(onDestroy)

            onPreSelect = MyPreSelectHandler()
            cmd.preSelect.add(onPreSelect)
            _handlers.append(onPreSelect)

            selIpt: adsk.core.SelectionCommandInput = inputs.addSelectionInput(
                'selIpt',
                'select',
                'select'
            )
            selIpt.setSelectionLimits(0)
            selIpt.selectionFilters = ['Bodies']

        except:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

class MyCommandDestroyHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()

    def notify(self, args):
        adsk.core.Application.get().log('Call Destroy Event')
        adsk.terminate()

def run(context):
    try:
        global _app, _ui
        _app = adsk.core.Application.get()
        _ui = _app.userInterface

        cmdDef = _ui.commandDefinitions.itemById('test')
        if not cmdDef:
            cmdDef = _ui.commandDefinitions.addButtonDefinition(
                'test', 'Test', 'Test')

        global _handlers
        onCommandCreated = MyCommandCreatedHandler()
        cmdDef.commandCreated.add(onCommandCreated)
        _handlers.append(onCommandCreated)

        cmdDef.execute()

        adsk.autoTerminate(False)

    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
Message 5 of 7

ebunn3
Advocate
Advocate

Thank you @kandennti .  I’ll check this out since it appears that it could be a great solution for me.  Thanks.  

Eric

Message 6 of 7

ebunn3
Advocate
Advocate

@kandennti 

 

The preselect handler works great unless I set the selection filter to occurrences.  When I do this I get an error:

ebunn3_0-1640013474287.png

 

There is not an  isVisible property for an adsk.fusion.component and when I hover over anything in the tree or screen that is not an occurrence or body I get this error. Seems to be anything at the root component level, like a plane, etc.  I have included code below that will throw the error.  I've tried putting in if statements in the handler to try and correct this with no success.  As soon as it enters the handler it throws the error.  Any help here would be greatly appreciated.  This will work for me if I can get it to work.

 

Eric

 

# Fusion360API Python script
import adsk.core, adsk.fusion, traceback

ui = adsk.core.UserInterface.cast(None)
handlers = []
_prodBodies = []
_cushBodies = []

class MyCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            cmd = args.command
            cmd.isExecutedWhenPreEmpted = False

            global _inputs
            inputs = cmd.commandInputs
            
            selectInput = inputs.addSelectionInput(
                'productBodies',
                'productBodies',
                'Please select Bodies'
            )
            selectInput.addSelectionFilter('Occurrences')
            selectInput.setSelectionLimits(1)

            selectInput = inputs.addSelectionInput(
                'cushionBodies',
                'cushionBodies',
                'Please select Bodies'
            )
            selectInput.addSelectionFilter('Bodies')
            selectInput.setSelectionLimits(1)

            # Connect to the command related events.
            onDestroy = MyCommandDestroyHandler()
            cmd.destroy.add(onDestroy)
            handlers.append(onDestroy)

            onSelect = MySelectHandler()
            cmd.select.add(onSelect)
            handlers.append(onSelect)

            onUnSelect = MyUnSelectHandler()
            cmd.unselect.add(onUnSelect)
            handlers.append(onUnSelect)

            onPreSelect = MyPreSelectHandler()
            cmd.preSelect.add(onPreSelect)
            handlers.append(onPreSelect)
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


def stop(context):
    """This function will unload the add-in and icon.  No customization necessary within this function."""
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        #ui.messageBox('Stop addin')

        #deleting the com button definition (use the id created in the run function 
        # (adsk.core.CommandDefinitions.addButtonDefinition(butName))
        cmdDef = ui.commandDefinitions.itemById('SelectionEventsTest')
        if cmdDef:
            cmdDef.deleteMe()

        #deleting the button
        addinsToolbarPanel = ui.allToolbarPanels.itemById('SolidScriptsAddinsPanel' )
        cntrl = addinsToolbarPanel.controls.itemById('SelectionEventsTest')
        if cntrl:
            cntrl.deleteMe()
        
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


class MyCommandDestroyHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            adsk.terminate()
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

class MyPreSelectHandler(adsk.core.SelectionEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.SelectionEventArgs):
        try:
            app = adsk.core.Application.get()
            ui = app.userInterface

            if not args.selection.entity.isVisible:
                args.isSelectable = False
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))     

class MySelectHandler(adsk.core.SelectionEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        app = adsk.core.Application.get()
        ui = app.userInterface
        try:
            eventArgs = adsk.core.SelectionEventArgs.cast(args)
            activeSelectionInput = eventArgs.firingEvent.activeInput
            selectedBody = adsk.fusion.BRepBody.cast(args.selection.entity) 

            if selectedBody:
                if activeSelectionInput.id == 'productBodies':
                    _prodBodies.append(selectedBody)
                if activeSelectionInput.id == 'cushionBodies':
                    _cushBodies.append(selectedBody)

            # dumpSelectionInputItem()

        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

class MyUnSelectHandler(adsk.core.SelectionEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        app = adsk.core.Application.get()
        ui = app.userInterface
        try:
            eventArgs = adsk.core.SelectionEventArgs.cast(args)
            activeSelectionInput = eventArgs.firingEvent.activeInput
            selectedBody = adsk.fusion.BRepBody.cast(args.selection.entity) 

            if selectedBody:
                if activeSelectionInput.id == 'productBodies':
                    _prodBodies.remove(selectedBody)
                if activeSelectionInput.id == 'cushionBodies':
                    _cushBodies.remove(selectedBody)

            # dumpSelectionInputItem()

        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

def run(context):
    global ui
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface

        myCmdDef = ui.commandDefinitions.itemById('SelectionEventsTest')
        if myCmdDef is None:
            myCmdDef = ui.commandDefinitions.addButtonDefinition(
                'SelectionEventsTest',
                'Selection Events Test',
                '',
                ''
            )

        onCommandCreated = MyCommandCreatedHandler()
        myCmdDef.commandCreated.add(onCommandCreated)
        handlers.append(onCommandCreated)

        myCmdDef.execute()

        adsk.autoTerminate(False)

    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

 

 

0 Likes
Message 7 of 7

ebunn3
Advocate
Advocate
Accepted solution

@kandennti 

 

I believe I corrected the problem with an if statement to filter out everything except occurrences and bodies.  See attached.

 

Eric

class MyPreSelectHandler(adsk.core.SelectionEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args: adsk.core.SelectionEventArgs):
        try:
            app = adsk.core.Application.get()
            ui = app.userInterface
            eventArgs = adsk.core.SelectionEventArgs.cast(args)
            type = eventArgs.selection.entity
            if type.objectType == 'adsk::fusion::Occurrence' or type.objectType == 'adsk::fusion::BRepBody':
                if not args.selection.entity.isVisible:
                    args.isSelectable = False
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))    
0 Likes