F360 API Defects in textBoxCommandInput

william-c-anderson
Advocate

F360 API Defects in textBoxCommandInput

william-c-anderson
Advocate
Advocate

An editable textBoxCommandInput (or simply, "textBox") has the following defects when dealing with HTML pre-formatted text (e.g. text that uses the <pre> tag):

 

  1. If the formatted text is loaded via the textBox_var.formattedText property and is unedited by the user and then retrieved via the textBox_var.text property, formatting is retrieved along with the text.
  2. In formatted text, the HTML parameter 'tab-size' is ignored. The tab size is a constant inch or so, which is very large for the scale of a typical screen. This is also true, evidently, for the parameter 'font-size'.
  3. In the case of HTML pre-formatted text (e.g. the <pre> tag), if text is inserted by the user in the middle of existing text, line spacing is normal. However, if the user appends text to the end of the existing text, the line spacing is shown to be double. Retrieved (unformatted) text is as expected.
  4. If pre-formatted text is copied from an HTML file (e.g. a "Help" file) and then pasted into a textBox, the HTML formatting that has come along with the paste evidently causes some garbled formatting to be retrieved along with the text, similar to item 1).
  5. In all cases, a textBox with numRows > 4 fails to render the bottom (blue) border.

Lest you think that these are unimportant appearance-only issues for the API, let me assure you that items 1) and 4) will definitely break code. Also, if you are trying to get a user to input a lengthy parameter list, the formatting does make a very significant impact to readability, which is critical for F360 commands.

 

Here is a script (adapted from the API sampler) wherein a user can demonstrate these defects. Note that a pre-formatted string 'initText' is a global which can be easily modified to test other HTML parameters:

#Author-WCA
#Description-Simple script to test formatted text.
#Adapted from ADSK API Sampler

import adsk.core, adsk.fusion, traceback

cmdId = "YAtextBoxTest"

#initText = "Unformatted text added by formattedText propterty"
initText = '''<html>
<head>
<style>
pre {
    white-space:pre-wrap;
    tab-size: 2;
    display: block;
    line-height: 100%;
	font-family: Courier;
}
</style>
</head>
<body>
<pre>
Pre-formatted text
	one tab
		two tabs
			three tabs
How does the line spacing look?
How does the line spacing look?
How does the line spacing look?
How does the line spacing look?
How does the line spacing look?
How does the line spacing look?
</pre>
</body>
</html>'''

_app = None
_ui  = None
_rowNumber = 0
_textbox = None

# Global set of event handlers to keep them referenced for the duration of the command
_handlers = []

# Input Changed Event Handler
class MyCommandInputChangedHandler(adsk.core.InputChangedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            eventArgs = adsk.core.InputChangedEventArgs.cast(args)
            inputs = eventArgs.inputs
            cmdInput = eventArgs.input
        
            pass

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


# Destruction Event Handler            
class MyCommandDestroyHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            _ui.messageBox('textBox.text:\n{}'.format(_textbox.text))
            adsk.terminate()
        except:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


# Creation Event Handler (called from run())
class MyCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            global _textbox

            # Get the command that was created.
            cmd = adsk.core.Command.cast(args.command)

            # Connect to the command destroyed event.
            onDestroy = MyCommandDestroyHandler()
            cmd.destroy.add(onDestroy)
            _handlers.append(onDestroy)

            # Connect to the input changed event.           
            onInputChanged = MyCommandInputChangedHandler()
            cmd.inputChanged.add(onInputChanged)
            _handlers.append(onInputChanged)    

            # Get the CommandInputs collection associated with the command.
            inputs = cmd.commandInputs

            # Create an editable textbox input.
            textBox = inputs.addTextBoxCommandInput('writable_textBox', '', '', 10, False)
            textBox.formattedText = initText
            #textBox.text = initText
            textBox.isFullWidth = True

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

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

        # Get the existing command definition or create it if it doesn't already exist.
        cmdDef = _ui.commandDefinitions.itemById(cmdId)
        if not cmdDef:
            cmdDef = _ui.commandDefinitions.addButtonDefinition(cmdId, 'TextBox Test', 'TextBox Test')

        # Connect to the command created event.
        onCommandCreated = MyCommandCreatedHandler()
        cmdDef.commandCreated.add(onCommandCreated)
        _handlers.append(onCommandCreated)

        # Execute the command definition.
        cmdDef.execute()

        # Prevent this module from being terminated when the script returns, because we are waiting for event handlers to fire.
        adsk.autoTerminate(False)
    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
0 Likes
Reply
476 Views
3 Replies
Replies (3)

william-c-anderson
Advocate
Advocate

I'm really sorry - I thought I posted this to the Support forum. Is there some way to move it?

0 Likes

william-c-anderson
Advocate
Advocate

(This was originally posted to the F360 API forum, but it is a bug report, so I'm reposting it here - sorry - I couldn't find a way to move the post from there to here...)

 

An editable textBoxCommandInput (or simply, "textBox") has the following defects when dealing with HTML pre-formatted text (e.g. text that uses the <pre> tag):

 

  1. If the formatted text is loaded via the textBox_var.formattedText property and is unedited by the user and then retrieved via the textBox_var.text property, formatting is retrieved along with the text.
  2. In formatted text, the HTML parameter 'tab-size' is ignored. The tab size is a constant inch or so, which is very large for the scale of a typical screen. This is also true, evidently, for the parameter 'font-size'.
  3. In the case of HTML pre-formatted text (e.g. the <pre> tag), if text is inserted by the user in the middle of existing text, line spacing is normal. However, if the user appends text to the end of the existing text, the line spacing is shown to be double. Retrieved (unformatted) text is as expected.
  4. If pre-formatted text is copied from an HTML file (e.g. a "Help" file) and then pasted into a textBox, the HTML formatting that has come along with the paste evidently causes some garbled formatting to be retrieved along with the text, similar to item 1).
  5. In all cases, a textBox with numRows > 4 fails to render the bottom (blue) border.

Lest you think that these are unimportant appearance-only issues for the API, let me assure you that items 1) and 4) will definitely break code. Also, if you are trying to get a user to input a lengthy parameter list, the formatting does make a very significant impact to readability, which is critical for F360 commands.

 

Here is a script (adapted from the API sampler) wherein a user can demonstrate these defects. Note that a pre-formatted string 'initText' is a global which can be easily modified to test other HTML parameters:

 

#Author-WCA
#Description-Simple script to test formatted text.
#Adapted from ADSK API Sampler

import adsk.core, adsk.fusion, traceback

cmdId = "YAtextBoxTest"

#initText = "Unformatted text added by formattedText propterty"
initText = '''<html>
<head>
<style>
pre {
    white-space:pre-wrap;
    tab-size: 2;
    display: block;
    line-height: 100%;
	font-family: Courier;
}
</style>
</head>
<body>
<pre>
Pre-formatted text
	one tab
		two tabs
			three tabs
How does the line spacing look?
How does the line spacing look?
How does the line spacing look?
How does the line spacing look?
How does the line spacing look?
How does the line spacing look?
</pre>
</body>
</html>'''

_app = None
_ui  = None
_rowNumber = 0
_textbox = None

# Global set of event handlers to keep them referenced for the duration of the command
_handlers = []

# Input Changed Event Handler
class MyCommandInputChangedHandler(adsk.core.InputChangedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            eventArgs = adsk.core.InputChangedEventArgs.cast(args)
            inputs = eventArgs.inputs
            cmdInput = eventArgs.input
        
            pass

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


# Destruction Event Handler            
class MyCommandDestroyHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            _ui.messageBox('textBox.text:\n{}'.format(_textbox.text))
            adsk.terminate()
        except:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


# Creation Event Handler (called from run())
class MyCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            global _textbox

            # Get the command that was created.
            cmd = adsk.core.Command.cast(args.command)

            # Connect to the command destroyed event.
            onDestroy = MyCommandDestroyHandler()
            cmd.destroy.add(onDestroy)
            _handlers.append(onDestroy)

            # Connect to the input changed event.           
            onInputChanged = MyCommandInputChangedHandler()
            cmd.inputChanged.add(onInputChanged)
            _handlers.append(onInputChanged)    

            # Get the CommandInputs collection associated with the command.
            inputs = cmd.commandInputs

            # Create an editable textbox input.
            textBox = inputs.addTextBoxCommandInput('writable_textBox', '', '', 10, False)
            textBox.formattedText = initText
            #textBox.text = initText
            textBox.isFullWidth = True

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

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

        # Get the existing command definition or create it if it doesn't already exist.
        cmdDef = _ui.commandDefinitions.itemById(cmdId)
        if not cmdDef:
            cmdDef = _ui.commandDefinitions.addButtonDefinition(cmdId, 'TextBox Test', 'TextBox Test')

        # Connect to the command created event.
        onCommandCreated = MyCommandCreatedHandler()
        cmdDef.commandCreated.add(onCommandCreated)
        _handlers.append(onCommandCreated)

        # Execute the command definition.
        cmdDef.execute()

        # Prevent this module from being terminated when the script returns, because we are waiting for event handlers to fire.
        adsk.autoTerminate(False)
    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
0 Likes

william-c-anderson
Advocate
Advocate

Reposted to Support forum as a bug report - sorry to clutter up this forum.

0 Likes