diff --git a/dev/pyRevitLoader/pyRevitAssemblyBuilder/UIManager/Buttons/PulldownButtonBuilder.cs b/dev/pyRevitLoader/pyRevitAssemblyBuilder/UIManager/Buttons/PulldownButtonBuilder.cs index b6414847b..8a8c219ba 100644 --- a/dev/pyRevitLoader/pyRevitAssemblyBuilder/UIManager/Buttons/PulldownButtonBuilder.cs +++ b/dev/pyRevitLoader/pyRevitAssemblyBuilder/UIManager/Buttons/PulldownButtonBuilder.cs @@ -391,6 +391,18 @@ private void UpdateExistingChildren( existingBtn.Enabled = true; existingBtn.Visible = true; + // Handle SmartButton-specific initialization on update; + // __selfinit__ must re-run after post-processing since it may override the bundle icon + if (sub.Type == CommandComponentType.SmartButton && _smartButtonScriptInitializer != null) + { + var shouldActivate = _smartButtonScriptInitializer.ExecuteSelfInit(sub, existingBtn); + if (!shouldActivate) + { + existingBtn.Enabled = false; + Logger.Debug($"SmartButton '{sub.DisplayName}' in pulldown deactivated by __selfinit__ during update."); + } + } + Logger.Debug($"Updated existing child button '{sub.DisplayName}' in pulldown '{component.DisplayName}'. New text: '{buttonText}'"); } catch (Exception ex) diff --git a/dev/pyRevitLoader/pyRevitAssemblyBuilder/UIManager/Buttons/SplitButtonBuilder.cs b/dev/pyRevitLoader/pyRevitAssemblyBuilder/UIManager/Buttons/SplitButtonBuilder.cs index 1563273a7..e6f1f979d 100644 --- a/dev/pyRevitLoader/pyRevitAssemblyBuilder/UIManager/Buttons/SplitButtonBuilder.cs +++ b/dev/pyRevitLoader/pyRevitAssemblyBuilder/UIManager/Buttons/SplitButtonBuilder.cs @@ -465,6 +465,18 @@ private void UpdateExistingChildren( if (!wasVisible && IsRibbonItemVisible(existingBtn, fallbackVisible: false)) newlyVisibleNames.Add(sub.DisplayName); + // Handle SmartButton-specific initialization on update; + // __selfinit__ must re-run after post-processing since it may override the bundle icon + if (sub.Type == CommandComponentType.SmartButton && _smartButtonScriptInitializer != null) + { + var shouldActivate = _smartButtonScriptInitializer.ExecuteSelfInit(sub, existingBtn); + if (!shouldActivate) + { + existingBtn.Enabled = false; + Logger.Debug($"SmartButton '{sub.DisplayName}' in split button deactivated by __selfinit__ during update."); + } + } + Logger.Debug($"Updated existing child button '{sub.DisplayName}' in split button '{component.DisplayName}'. New text: '{buttonText}'"); } catch (Exception ex) diff --git a/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/Update.smartbutton/script.py b/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/Update.smartbutton/script.py index 717526658..56b06ca04 100644 --- a/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/Update.smartbutton/script.py +++ b/extensions/pyRevitCore.extension/pyRevit.tab/pyRevit.panel/Update.smartbutton/script.py @@ -14,18 +14,18 @@ def __selfinit__(script_cmp, ui_button_cmp, __rvt__): # do not load the tool if user should not update if not user_config.user_can_update: return False - # otherwise set icon depending on if updates are available + # set icon if updates available; a failed availability check must not + # deactivate the tool that performs the update try: - has_update_icon = script_cmp.get_bundle_file('icon_hasupdates.png') if user_config.check_updates \ and not user_config.auto_update \ and updater.check_for_updates(): + has_update_icon = script_cmp.get_bundle_file('icon_hasupdates.png') ui_button_cmp.set_icon(has_update_icon, icon_size=ribbon.ICON_LARGE) - return True except Exception as ex: - logger.error('Error in checking updates: {}'.format(ex)) - return False + logger.error('Error in checking updates: %s', ex) + return True if __name__ == '__main__': diff --git a/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/bundle.yaml b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/bundle.yaml new file mode 100644 index 000000000..a4e8baf34 --- /dev/null +++ b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/bundle.yaml @@ -0,0 +1,11 @@ +title: >- + Test Reload + + Icon Toggle +tooltip: >- + SmartButton that mirrors Update.smartbutton: click to toggle a state + stored in the user config ini; __selfinit__ applies the orange dot icon + when the state is on and leaves the default bundle icon when off. After a + reload the icon must match the stored state - default shown while on + means __selfinit__ was not re-run in this pulldown, orange shown while + off means the loader failed to restore the bundle icon. diff --git a/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/icon.dark.png b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/icon.dark.png new file mode 100644 index 000000000..dc6b0c4d0 Binary files /dev/null and b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/icon.dark.png differ diff --git a/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/icon.png b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/icon.png new file mode 100644 index 000000000..5da357996 Binary files /dev/null and b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/icon.png differ diff --git a/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/off.dark.png b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/off.dark.png new file mode 100644 index 000000000..dc6b0c4d0 Binary files /dev/null and b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/off.dark.png differ diff --git a/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/off.png b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/off.png new file mode 100644 index 000000000..5da357996 Binary files /dev/null and b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/off.png differ diff --git a/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/on.png b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/on.png new file mode 100644 index 000000000..0e59c02ff Binary files /dev/null and b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/on.png differ diff --git a/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/script.py b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/script.py new file mode 100644 index 000000000..218ae3a8a --- /dev/null +++ b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/Test Reload Icon Toggle.smartbutton/script.py @@ -0,0 +1,45 @@ +"""Test SmartButton icon persistence across reloads inside pulldowns. + +Mirrors the Update.smartbutton pattern: __selfinit__ applies the orange dot +icon only when the stored state is on, and leaves the loader-applied default +icon otherwise. Click the button to toggle the state; it is stored in the +user config ini so it can be inspected while troubleshooting. + +After a reload the icon must match the stored state: orange when on, the +default bundle icon when off. A mismatch means __selfinit__ was not re-run +(default shown while state is on) or the loader failed to restore the bundle +icon (orange shown while state is off). +""" +#pylint: disable=C0103,E0401 +from pyrevit import script +from pyrevit.coreutils.ribbon import ICON_MEDIUM + +CONFIG_SECTION = 'devtools_reload_tests' +STATE_OPTION = 'pulldown_state' + + +def __selfinit__(script_cmp, ui_button_cmp, __rvt__): + # apply the stored state; the loader is responsible for restoring the + # default bundle icon when the state is off + config = script.get_config(CONFIG_SECTION) + if config.get_option(STATE_OPTION, default_value=False): + icon = script_cmp.get_bundle_file('on.png') + ui_button_cmp.set_icon(icon, icon_size=ICON_MEDIUM) + return True + + +if __name__ == '__main__': + from pyrevit.userconfig import user_config + + config = script.get_config(CONFIG_SECTION) + state = not config.get_option(STATE_OPTION, default_value=False) + config.set_option(STATE_OPTION, state) + script.save_config() + # the default bundle icon stands in for the off state so the click + # result matches what a reload would show + script.toggle_icon(state, off_icon_path=script.get_bundle_file('icon.png')) + + print('Config file: {}'.format(user_config.config_file)) + print('[{}] {} = {}'.format(CONFIG_SECTION, STATE_OPTION, state)) + print('Icon should now be {} and must stay that way after a reload.' + .format('the orange dot' if state else 'the default bundle icon')) diff --git a/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/bundle.yaml b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/bundle.yaml index a55e156c4..d6ee3cd4a 100644 --- a/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/bundle.yaml +++ b/extensions/pyRevitDevTools.extension/pyRevitDev.tab/Debug.panel/Bundle Tests.pulldown/bundle.yaml @@ -3,6 +3,7 @@ layout: - Test pyRevit Bundle - Test pyRevit Button - Test Smart Button + - Test Reload Icon Toggle - Test C# Script - Test Direct Invoke - Test Direct Invoke (ExecParams)