Disabling a MenuGroupModel

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Disabling a MenuGroupModel

hernanmd
Hi guys,

If you develop an application window with multiple grouped menu items,
you will certainly be able to enable/disable menu groups at once.
Currently it is not possible with MenuGroupModel (Morphic).

- A menu (item or group) model manages its state using enabledHolder
instance variable (the enabledHolder is configured in its superclass'
initialize)
-- Being a value holder, one might think there is a propagation of
state (enabled/disabled) changes to subwidgets, but it does not happen
currently.
--- Longer explanation: On static menu building, MenuGroupModel does
not propagate #enable: state changes to its widget because "widget"
i.v. is nil. The reason is a MenuGroupModel #enabled: is evaluated
BEFORE its widget is built.

How to reproduce:
| mm |
mm := MenuModel new
    addGroup: [ :group |
        group
            addItem: [ :item |
                item
                    name: 'File';
                    icon: #openIcon asIcon;
                    subMenu: (MenuModel new
                        addGroup: [ : gp |
                            gp
                                disable;           " <------ HERE we
disable the group "
                                    addItem: [ : it |
                                it
                                    name: 'Open';
                                    icon: #openIcon asIcon;
                                    shortcut: $o meta;
                                    action: [ self inform: 'Open' ] ];
                            addItem: [ : it |
                                it
                                    name: 'Save';
                                    icon: #smallSaveIcon asIcon;
                                    shortcut: $s meta;
                                    action: [ self inform: 'Save' ] ] ]) ] ];
    yourself.
mm extent: 200 @ 100.
mm openWithSpec.
mm inspect.

(it doesn't matter if #disable is sent after the #addItem: block evaluation)

- Even after all MenuGroupModel widgets were built, if you try to
disable a menu group dinamically:

mm menuGroups anyOne menuItems anyOne subMenu menuGroups anyOne disable.

you would get "Instance of OrderedCollection did not understand
#enabled:" (the widget of a MenuGroupModel is an OrderedCollection!!).

- However disabling/enabling MenuItemModel works:

mm menuGroups anyOne menuItems anyOne subMenu menuGroups anyOne
menuItems first disable.

- MenuItemModel gets actually disabled in the
ToggleMenuItemMorph/UpdatingMenuMorph (#isEnabled:) when the Canvas
draws it.

- Incredibly, all disabled groups are re-enabled from several places
in the image.

-- When the menu is clicked, a ToolDockingBarMorph triggers
re-enablement of the MenuMorph in
#removeMatchString/#displayFiltered:. This is presumably the code
triggered when a menu is displayed and you type to filter the menu
items. Something like this: "As initially there is no matchString in
the activeSubMenu, then enable all menu items". Obviously it cleans
disabled items.

The message flow is:

DockingBarMorph>>activeSubmenu: ->  MenuMorph>>removeMatchString ->
MenuMorph>>displayFiltered: --> m isEnabled: isMatch

- Another place where menu items are automatically disabled is this flow:

FormCanvas>>draw: -> ToggleMenuItemMorph>>drawOn: -->
ToggleMenuItemMorph>>isEnabled --> ToggleMenuItemMorph>>isEnabled: !!!
 --> MorphicMenuItemAdapter>>enabled (This actually CHANGES the
enabled state on the Model, disconnecting enabled state between the
morph and the model adapter)

This seem to have multiple paths of resolution. I'm going to propose a
fix that I  tested in Pharo 6.1 and Pharo 7.
I don't know yet how to fix the menu search auto-enable on key-press
but would be glad to read a solution to distinguish between both uses.
My idea for now is to have a Morphic property which sets
#doNotAutoReEnableItems.

However I will open an issue and let people check.

You can test it with

" Disable the group "
mm menuGroups anyOne menuItems anyOne subMenu menuGroups anyOne disable.

" Enable the group "
mm menuGroups anyOne menuItems anyOne subMenu menuGroups anyOne enable.

Cheers,

Hernán

Reply | Threaded
Open this post in threaded view
|

Re: Disabling a MenuGroupModel

hernanmd
https://pharo.fogbugz.com/f/cases/21233/Disabling-a-MenuGroupModel-bug


2018-02-02 10:10 GMT-03:00 Hernán Morales Durand <[hidden email]>:

> Hi guys,
>
> If you develop an application window with multiple grouped menu items,
> you will certainly be able to enable/disable menu groups at once.
> Currently it is not possible with MenuGroupModel (Morphic).
>
> - A menu (item or group) model manages its state using enabledHolder
> instance variable (the enabledHolder is configured in its superclass'
> initialize)
> -- Being a value holder, one might think there is a propagation of
> state (enabled/disabled) changes to subwidgets, but it does not happen
> currently.
> --- Longer explanation: On static menu building, MenuGroupModel does
> not propagate #enable: state changes to its widget because "widget"
> i.v. is nil. The reason is a MenuGroupModel #enabled: is evaluated
> BEFORE its widget is built.
>
> How to reproduce:
> | mm |
> mm := MenuModel new
>     addGroup: [ :group |
>         group
>             addItem: [ :item |
>                 item
>                     name: 'File';
>                     icon: #openIcon asIcon;
>                     subMenu: (MenuModel new
>                         addGroup: [ : gp |
>                             gp
>                                 disable;           " <------ HERE we
> disable the group "
>                                     addItem: [ : it |
>                                 it
>                                     name: 'Open';
>                                     icon: #openIcon asIcon;
>                                     shortcut: $o meta;
>                                     action: [ self inform: 'Open' ] ];
>                             addItem: [ : it |
>                                 it
>                                     name: 'Save';
>                                     icon: #smallSaveIcon asIcon;
>                                     shortcut: $s meta;
>                                     action: [ self inform: 'Save' ] ] ]) ] ];
>     yourself.
> mm extent: 200 @ 100.
> mm openWithSpec.
> mm inspect.
>
> (it doesn't matter if #disable is sent after the #addItem: block evaluation)
>
> - Even after all MenuGroupModel widgets were built, if you try to
> disable a menu group dinamically:
>
> mm menuGroups anyOne menuItems anyOne subMenu menuGroups anyOne disable.
>
> you would get "Instance of OrderedCollection did not understand
> #enabled:" (the widget of a MenuGroupModel is an OrderedCollection!!).
>
> - However disabling/enabling MenuItemModel works:
>
> mm menuGroups anyOne menuItems anyOne subMenu menuGroups anyOne
> menuItems first disable.
>
> - MenuItemModel gets actually disabled in the
> ToggleMenuItemMorph/UpdatingMenuMorph (#isEnabled:) when the Canvas
> draws it.
>
> - Incredibly, all disabled groups are re-enabled from several places
> in the image.
>
> -- When the menu is clicked, a ToolDockingBarMorph triggers
> re-enablement of the MenuMorph in
> #removeMatchString/#displayFiltered:. This is presumably the code
> triggered when a menu is displayed and you type to filter the menu
> items. Something like this: "As initially there is no matchString in
> the activeSubMenu, then enable all menu items". Obviously it cleans
> disabled items.
>
> The message flow is:
>
> DockingBarMorph>>activeSubmenu: ->  MenuMorph>>removeMatchString ->
> MenuMorph>>displayFiltered: --> m isEnabled: isMatch
>
> - Another place where menu items are automatically disabled is this flow:
>
> FormCanvas>>draw: -> ToggleMenuItemMorph>>drawOn: -->
> ToggleMenuItemMorph>>isEnabled --> ToggleMenuItemMorph>>isEnabled: !!!
>  --> MorphicMenuItemAdapter>>enabled (This actually CHANGES the
> enabled state on the Model, disconnecting enabled state between the
> morph and the model adapter)
>
> This seem to have multiple paths of resolution. I'm going to propose a
> fix that I  tested in Pharo 6.1 and Pharo 7.
> I don't know yet how to fix the menu search auto-enable on key-press
> but would be glad to read a solution to distinguish between both uses.
> My idea for now is to have a Morphic property which sets
> #doNotAutoReEnableItems.
>
> However I will open an issue and let people check.
>
> You can test it with
>
> " Disable the group "
> mm menuGroups anyOne menuItems anyOne subMenu menuGroups anyOne disable.
>
> " Enable the group "
> mm menuGroups anyOne menuItems anyOne subMenu menuGroups anyOne enable.
>
> Cheers,
>
> Hernán

Reply | Threaded
Open this post in threaded view
|

Re: Disabling a MenuGroupModel

Stephane Ducasse-3
Tx!

On Sat, Feb 3, 2018 at 12:25 AM, Hernán Morales Durand
<[hidden email]> wrote:

> https://pharo.fogbugz.com/f/cases/21233/Disabling-a-MenuGroupModel-bug
>
>
> 2018-02-02 10:10 GMT-03:00 Hernán Morales Durand <[hidden email]>:
>> Hi guys,
>>
>> If you develop an application window with multiple grouped menu items,
>> you will certainly be able to enable/disable menu groups at once.
>> Currently it is not possible with MenuGroupModel (Morphic).
>>
>> - A menu (item or group) model manages its state using enabledHolder
>> instance variable (the enabledHolder is configured in its superclass'
>> initialize)
>> -- Being a value holder, one might think there is a propagation of
>> state (enabled/disabled) changes to subwidgets, but it does not happen
>> currently.
>> --- Longer explanation: On static menu building, MenuGroupModel does
>> not propagate #enable: state changes to its widget because "widget"
>> i.v. is nil. The reason is a MenuGroupModel #enabled: is evaluated
>> BEFORE its widget is built.
>>
>> How to reproduce:
>> | mm |
>> mm := MenuModel new
>>     addGroup: [ :group |
>>         group
>>             addItem: [ :item |
>>                 item
>>                     name: 'File';
>>                     icon: #openIcon asIcon;
>>                     subMenu: (MenuModel new
>>                         addGroup: [ : gp |
>>                             gp
>>                                 disable;           " <------ HERE we
>> disable the group "
>>                                     addItem: [ : it |
>>                                 it
>>                                     name: 'Open';
>>                                     icon: #openIcon asIcon;
>>                                     shortcut: $o meta;
>>                                     action: [ self inform: 'Open' ] ];
>>                             addItem: [ : it |
>>                                 it
>>                                     name: 'Save';
>>                                     icon: #smallSaveIcon asIcon;
>>                                     shortcut: $s meta;
>>                                     action: [ self inform: 'Save' ] ] ]) ] ];
>>     yourself.
>> mm extent: 200 @ 100.
>> mm openWithSpec.
>> mm inspect.
>>
>> (it doesn't matter if #disable is sent after the #addItem: block evaluation)
>>
>> - Even after all MenuGroupModel widgets were built, if you try to
>> disable a menu group dinamically:
>>
>> mm menuGroups anyOne menuItems anyOne subMenu menuGroups anyOne disable.
>>
>> you would get "Instance of OrderedCollection did not understand
>> #enabled:" (the widget of a MenuGroupModel is an OrderedCollection!!).
>>
>> - However disabling/enabling MenuItemModel works:
>>
>> mm menuGroups anyOne menuItems anyOne subMenu menuGroups anyOne
>> menuItems first disable.
>>
>> - MenuItemModel gets actually disabled in the
>> ToggleMenuItemMorph/UpdatingMenuMorph (#isEnabled:) when the Canvas
>> draws it.
>>
>> - Incredibly, all disabled groups are re-enabled from several places
>> in the image.
>>
>> -- When the menu is clicked, a ToolDockingBarMorph triggers
>> re-enablement of the MenuMorph in
>> #removeMatchString/#displayFiltered:. This is presumably the code
>> triggered when a menu is displayed and you type to filter the menu
>> items. Something like this: "As initially there is no matchString in
>> the activeSubMenu, then enable all menu items". Obviously it cleans
>> disabled items.
>>
>> The message flow is:
>>
>> DockingBarMorph>>activeSubmenu: ->  MenuMorph>>removeMatchString ->
>> MenuMorph>>displayFiltered: --> m isEnabled: isMatch
>>
>> - Another place where menu items are automatically disabled is this flow:
>>
>> FormCanvas>>draw: -> ToggleMenuItemMorph>>drawOn: -->
>> ToggleMenuItemMorph>>isEnabled --> ToggleMenuItemMorph>>isEnabled: !!!
>>  --> MorphicMenuItemAdapter>>enabled (This actually CHANGES the
>> enabled state on the Model, disconnecting enabled state between the
>> morph and the model adapter)
>>
>> This seem to have multiple paths of resolution. I'm going to propose a
>> fix that I  tested in Pharo 6.1 and Pharo 7.
>> I don't know yet how to fix the menu search auto-enable on key-press
>> but would be glad to read a solution to distinguish between both uses.
>> My idea for now is to have a Morphic property which sets
>> #doNotAutoReEnableItems.
>>
>> However I will open an issue and let people check.
>>
>> You can test it with
>>
>> " Disable the group "
>> mm menuGroups anyOne menuItems anyOne subMenu menuGroups anyOne disable.
>>
>> " Enable the group "
>> mm menuGroups anyOne menuItems anyOne subMenu menuGroups anyOne enable.
>>
>> Cheers,
>>
>> Hernán
>